/* $XConsortium: Xct.c,v 1.18 93/09/18 18:13:27 kaleb Exp $ */ /* Copyright (c) 1989 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ #include #include "Xct.h" #include #define UsedGraphic 0x0001 #define UsedDirection 0x0002 typedef struct _XctPriv { XctString ptr; XctString ptrend; unsigned flags; XctHDirection *dirstack; unsigned dirsize; char **encodings; unsigned enc_count; XctString itembuf; unsigned buf_count; } *XctPriv; #define IsMore(priv) ((priv)->ptr != (priv)->ptrend) #define AmountLeft(priv) ((priv)->ptrend - (priv)->ptr) extern char *malloc(); extern char *realloc(); #define HT 0x09 #define NL 0x0a #define ESC 0x1b #define CSI 0x9b #define IsLegalC0(data, c) (((c) == HT) || ((c) == NL) || \ (((data)->version > XctVersion) && \ ((data)->flags & XctAcceptC0Extensions))) #define IsLegalC1(priv, c) (((data)->version > XctVersion) && \ ((data)->flags & XctAcceptC1Extensions)) #define IsI2(c) (((c) >= 0x20) && ((c) <= 0x2f)) #define IsI3(c) (((c) >= 0x30) && ((c) <= 0x3f)) #define IsESCF(c) (((c) >= 0x30) && ((c) <= 0x7e)) #define IsCSIF(c) (((c) >= 0x40) && ((c) <= 0x7e)) #define IsC0(c) ((c) <= 0x1f) #define IsGL(c) (((c) >= 0x20) && ((c) <= 0x7f)) #define IsC1(c) (((c) >= 0x80) && ((c) <= 0x9f)) #define IsGR(c) ((c) >= 0xa0) #define HasC 1 #define HasGL 2 #define HasGR 4 #define ToGL 8 static void ComputeGLGR(data) register XctData data; { /* XXX this will need more work if more sets are registered */ if ((data->GL_set_size == 94) && (data->GL_char_size == 1) && (data->GL[0] == '\102') && (data->GR_set_size == 96) && (data->GR_char_size == 1)) data->GLGR_encoding = data->GR_encoding; else if ((data->GL_set_size == 94) && (data->GL_char_size == 1) && (data->GL[0] == '\112') && (data->GR_set_size == 94) && (data->GR_char_size == 1)) data->GLGR_encoding = data->GR_encoding; else data->GLGR_encoding = (char *)NULL; } static int HandleGL(data, c) register XctData data; unsigned char c; { switch (c) { case 0x42: data->GL = "\102"; data->GL_encoding = "ISO8859-1"; break; case 0x4a: data->GL = "\112"; data->GL_encoding = "JISX0201.1976-0"; break; default: return 0; } data->GL_set_size = 94; data->GL_char_size = 1; ComputeGLGR(data); return 1; } static int HandleMultiGL(data, c) register XctData data; unsigned char c; { switch (c) { case 0x41: data->GL = "\101"; data->GL_encoding = "GB2312.1980-0"; break; case 0x42: data->GL = "\102"; data->GL_encoding = "JISX0208.1983-0"; break; case 0x43: data->GL = "\103"; data->GL_encoding = "KSC5601.1987-0"; break; default: return 0; } data->GL_set_size = 94; data->GL_char_size = 2; #ifdef notdef if (c < 0x60) data->GL_char_size = 2; else if (c < 0x70) data->GL_char_size = 3; else data->GL_char_size = 4; #endif data->GLGR_encoding = (char *)NULL; return 1; } static int Handle94GR(data, c) register XctData data; unsigned char c; { switch (c) { case 0x49: data->GR = "\111"; data->GR_encoding = "JISX0201.1976-0"; break; default: return 0; } data->priv->flags &= ~ToGL; data->GR_set_size = 94; data->GR_char_size = 1; data->GLGR_encoding = (char *)NULL; return 1; } static int Handle96GR(data, c) register XctData data; unsigned char c; { switch (c) { case 0x41: data->GR = "\101"; data->GR_encoding = "ISO8859-1"; break; case 0x42: data->GR = "\102"; data->GR_encoding = "ISO8859-2"; break; case 0x43: data->GR = "\103"; data->GR_encoding = "ISO8859-3"; break; case 0x44: data->GR = "\104"; data->GR_encoding = "ISO8859-4"; break; case 0x46: data->GR = "\106"; data->GR_encoding = "ISO8859-7"; break; case 0x47: data->GR = "\107"; data->GR_encoding = "ISO8859-6"; break; case 0x48: data->GR = "\110"; data->GR_encoding = "ISO8859-8"; break; case 0x4c: data->GR = "\114"; data->GR_encoding = "ISO8859-5"; break; case 0x4d: data->GR = "\115"; data->GR_encoding = "ISO8859-9"; break; default: return 0; } data->priv->flags &= ~ToGL; data->GR_set_size = 96; data->GR_char_size = 1; ComputeGLGR(data); return 1; } static int HandleMultiGR(data, c) register XctData data; unsigned char c; { switch (c) { case 0x41: data->GR = "\101"; if (data->flags & XctShiftMultiGRToGL) data->GR_encoding = "GB2312.1980-0"; else data->GR_encoding = "GB2312.1980-1"; break; case 0x42: data->GR = "\102"; if (data->flags & XctShiftMultiGRToGL) data->GR_encoding = "JISX0208.1983-0"; else data->GR_encoding = "JISX0208.1983-1"; break; case 0x43: data->GR = "\103"; if (data->flags & XctShiftMultiGRToGL) data->GR_encoding = "KSC5601.1987-0"; else data->GR_encoding = "KSC5601.1987-1"; break; default: return 0; } if (data->flags & XctShiftMultiGRToGL) data->priv->flags |= ToGL; else data->priv->flags &= ~ToGL; data->GR_set_size = 94; data->GR_char_size = 2; #ifdef notdef if (c < 0x60) data->GR_char_size = 2; else if (c < 0x70) data->GR_char_size = 3; else data->GR_char_size = 4; #endif data->GLGR_encoding = (char *)NULL; return 1; } static int HandleExtended(data, c) register XctData data; unsigned char c; { register XctPriv priv = data->priv; XctString enc = data->item + 6; register XctString ptr = enc; int i, len; while (*ptr != 0x02) { if (!*ptr || (++ptr == priv->ptr)) return 0; } data->item = ptr + 1; data->item_length = priv->ptr - data->item; len = ptr - enc; for (i = 0; (i < priv->enc_count) && strncmp(priv->encodings[i], (char *)enc, len); i++) ; if (i == priv->enc_count) { XctString cp; for (cp = enc; cp != ptr; cp++) { if ((!IsGL(*cp) && !IsGR(*cp)) || (*cp == 0x2a) || (*cp == 0x3f)) return 0; } ptr = (XctString)malloc((unsigned)len + 1); (void) memmove((char *)ptr, (char *)enc, len); ptr[len] = 0x00; priv->enc_count++; if (priv->encodings) priv->encodings = (char **)realloc( (char *)priv->encodings, priv->enc_count * sizeof(char *)); else priv->encodings = (char **)malloc(sizeof(char *)); priv->encodings[i] = (char *)ptr; } data->encoding = priv->encodings[i]; data->char_size = c - 0x30; return 1; } static void ShiftGRToGL(data, hasCdata) register XctData data; int hasCdata; { register XctPriv priv = data->priv; register int i; if (data->item_length > priv->buf_count) { priv->buf_count = data->item_length; if (priv->itembuf) priv->itembuf = (XctString)realloc((char *)priv->itembuf, priv->buf_count); else priv->itembuf = (XctString)malloc(priv->buf_count); } (void) memmove((char *)priv->itembuf, (char *)data->item, data->item_length); data->item = priv->itembuf; if (hasCdata) { for (i = data->item_length; --i >= 0; ) { if (IsGR(data->item[i])) data->item[i] &= 0x7f; } } else { for (i = data->item_length; --i >= 0; ) data->item[i] &= 0x7f; } } /* Create an XctData structure for parsing a Compound Text string. */ #if NeedFunctionPrototypes XctData XctCreate(_Xconst unsigned char *string, int length, XctFlags flags) #else XctData XctCreate(string, length, flags) XctString string; int length; XctFlags flags; #endif { register XctData data; register XctPriv priv; data = (XctData)malloc(sizeof(struct _XctRec) + sizeof(struct _XctPriv)); if (!data) return data; data->priv = priv = (XctPriv)(data + 1); data->total_string = (XctString)string; data->total_length = length; data->flags = flags; priv->dirstack = (XctHDirection *)NULL; priv->dirsize = 0; priv->encodings = (char **)NULL; priv->enc_count = 0; priv->itembuf = (XctString)NULL; priv->buf_count = 0; XctReset(data); return data; } /* Reset the XctData structure to re-parse the string from the beginning. */ void XctReset(data) register XctData data; { register XctPriv priv = data->priv; priv->ptr = data->total_string; priv->ptrend = data->total_string + data->total_length; data->item = (XctString)NULL; data->item_length = 0; data->encoding = (char *)NULL; data->char_size = 1; data->horizontal = XctUnspecified; data->horz_depth = 0; priv->flags = 0; data->GL_set_size = data->GR_set_size = 0; /* XXX */ (void)HandleGL(data, (unsigned char)0x42); (void)Handle96GR(data, (unsigned char)0x41); data->version = 1; data->can_ignore_exts = 0; /* parse version, if present */ if ((data->total_length >= 4) && (priv->ptr[0] == ESC) && (priv->ptr[1] == 0x23) && IsI2(priv->ptr[2]) && ((priv->ptr[3] == 0x30) || (priv->ptr[3] == 0x31))) { data->version = priv->ptr[2] - 0x1f; if (priv->ptr[3] == 0x30) data->can_ignore_exts = 1; priv->ptr += 4; } } /* Parse the next "item" from the Compound Text string. The return value * indicates what kind of item is returned. The item itself, and the current * contextual state, are reported as components of the XctData structure. */ XctResult XctNextItem(data) register XctData data; { register XctPriv priv = data->priv; unsigned char c; int len, bits; #define NEXT data->item_length++; priv->ptr++ while (IsMore(priv)) { data->item = priv->ptr; data->item_length = 0; c = *priv->ptr; if (c == ESC) { NEXT; while (IsMore(priv) && IsI2(*priv->ptr)) { NEXT; } if (!IsMore(priv)) return XctError; c = *priv->ptr; NEXT; if (!IsESCF(c)) return XctError; switch (data->item[1]) { case 0x24: if (data->item_length > 3) { if (data->item[2] == 0x28) { if (HandleMultiGL(data, c)) continue; } else if (data->item[2] == 0x29) { if (HandleMultiGR(data, c)) continue; } } break; case 0x25: if ((data->item_length == 4) && (data->item[2] == 0x2f) && (c <= 0x3f)) { if ((AmountLeft(priv) < 2) || (priv->ptr[0] < 0x80) || (priv->ptr[1] < 0x80)) return XctError; len = *priv->ptr - 0x80; NEXT; len = (len << 7) + (*priv->ptr - 0x80); NEXT; if (AmountLeft(priv) < len) return XctError; data->item_length += len; priv->ptr += len; if (c <= 0x34) { if (!HandleExtended(data, c) || ((data->horz_depth == 0) && (priv->flags & UsedDirection))) return XctError; priv->flags |= UsedGraphic; return XctExtendedSegment; } } break; case 0x28: if (HandleGL(data, c)) continue; break; case 0x29: if (Handle94GR(data, c)) continue; break; case 0x2d: if (Handle96GR(data, c)) continue; break; } } else if (c == CSI) { NEXT; while (IsMore(priv) && IsI3(*priv->ptr)) { NEXT; } while (IsMore(priv) && IsI2(*priv->ptr)) { NEXT; } if (!IsMore(priv)) return XctError; c = *priv->ptr; NEXT; if (!IsCSIF(c)) return XctError; if (c == 0x5d) { if ((data->item_length == 3) && ((data->item[1] == 0x31) || (data->item[1] == 0x32))) { data->horz_depth++; if (priv->dirsize < data->horz_depth) { priv->dirsize += 10; if (priv->dirstack) priv->dirstack = (XctHDirection *) realloc((char *)priv->dirstack, priv->dirsize * sizeof(XctHDirection)); else priv->dirstack = (XctHDirection *) malloc(priv->dirsize * sizeof(XctHDirection)); } priv->dirstack[data->horz_depth - 1] = data->horizontal; if (data->item[1] == 0x31) data->horizontal = XctLeftToRight; else data->horizontal = XctRightToLeft; if ((priv->flags & UsedGraphic) && !(priv->flags & UsedDirection)) return XctError; priv->flags |= UsedDirection; if (data->flags & XctHideDirection) continue; return XctHorizontal; } else if (data->item_length == 2) { if (!data->horz_depth) return XctError; data->horz_depth--; data->horizontal = priv->dirstack[data->horz_depth]; if (data->flags & XctHideDirection) continue; return XctHorizontal; } } } else if (data->flags & XctSingleSetSegments) { NEXT; if IsC0(c) { data->encoding = (char *)NULL; data->char_size = 1; if (IsLegalC0(data, c)) return XctC0Segment; } else if (IsGL(c)) { data->encoding = data->GL_encoding; data->char_size = data->GL_char_size; while (IsMore(priv) && IsGL(*priv->ptr)) { NEXT; } if (((data->char_size > 1) && (data->item_length % data->char_size)) || ((data->horz_depth == 0) && (priv->flags & UsedDirection))) return XctError; priv->flags |= UsedGraphic; return XctGLSegment; } else if (IsC1(c)) { data->encoding = (char *)NULL; data->char_size = 1; if (IsLegalC1(data, c)) return XctC1Segment; } else { data->encoding = data->GR_encoding; data->char_size = data->GR_char_size; while (IsMore(priv) && IsGR(*priv->ptr)) { NEXT; } if (((data->char_size > 1) && (data->item_length % data->char_size)) || ((data->horz_depth == 0) && (priv->flags & UsedDirection))) return XctError; priv->flags |= UsedGraphic; if (!(priv->flags & ToGL)) return XctGRSegment; ShiftGRToGL(data, 0); return XctGLSegment; } } else { bits = 0; while (1) { if (IsC0(c) || IsC1(c)) { if ((c == ESC) || (c == CSI)) break; if (IsC0(c) ? !IsLegalC0(data, c) : !IsLegalC1(data, c)) break; bits |= HasC; NEXT; } else { len = data->item_length; if (IsGL(c)) { if ((data->flags & XctShiftMultiGRToGL) && (bits & HasGR)) break; NEXT; bits |= HasGL; while (IsMore(priv) && IsGL(*priv->ptr)) { NEXT; } if ((data->GL_char_size > 1) && ((data->item_length - len) % data->GL_char_size)) return XctError; } else { if ((data->flags & XctShiftMultiGRToGL) && (bits & HasGL)) break; NEXT; bits |= HasGR; while (IsMore(priv) && IsGR(*priv->ptr)) { NEXT; } if ((data->GR_char_size > 1) && ((data->item_length - len) % data->GR_char_size)) return XctError; } } if (!IsMore(priv)) break; c = *priv->ptr; } if (data->item_length) { if (bits & (HasGL|HasGR)) { priv->flags |= UsedGraphic; if ((data->horz_depth == 0) && (priv->flags & UsedDirection)) return XctError; if ((data->flags & XctShiftMultiGRToGL) && (bits & HasGR)) ShiftGRToGL(data, bits & HasC); } if ((bits == (HasGL|HasGR)) || (data->GLGR_encoding && !(bits & HasC))) { data->encoding = data->GLGR_encoding; if (data->GL_char_size == data->GR_char_size) data->char_size = data->GL_char_size; else data->char_size = 0; } else if (bits == HasGL) { data->encoding = data->GL_encoding; data->char_size = data->GL_char_size; } else if (bits == HasGR) { data->encoding = data->GR_encoding; data->char_size = data->GR_char_size; } else { data->encoding = (char *)NULL; data->char_size = 1; if ((bits & HasGL) && (data->GL_char_size != data->char_size)) data->char_size = 0; if ((bits & HasGR) && (data->GR_char_size != data->char_size)) data->char_size = 0; } return XctSegment; } NEXT; } if (data->version <= XctVersion) return XctError; if (data->flags & XctProvideExtensions) return XctExtension; if (!data->can_ignore_exts) return XctError; } return XctEndOfText; } /* Free all data associated with an XctDataStructure. */ void XctFree(data) register XctData data; { int i; register XctPriv priv = data->priv; if (priv->dirstack) free((char *)priv->dirstack); if (data->flags & XctFreeString) free((char *)data->total_string); for (i = 0; i < priv->enc_count; i++) free(priv->encodings[i]); if (priv->encodings) free((char *)priv->encodings); if (priv->itembuf) free((char *)priv->itembuf); free((char *)data); }