Xct.c revision 6c321187
1/* $Xorg: Xct.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */
2
3/*
4
5Copyright 1989, 1998  The Open Group
6
7Permission to use, copy, modify, distribute, and sell this software and its
8documentation for any purpose is hereby granted without fee, provided that
9the above copyright notice appear in all copies and that both that
10copyright notice and this permission notice appear in supporting
11documentation.
12
13The above copyright notice and this permission notice shall be included in
14all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall not be
24used in advertising or otherwise to promote the sale, use or other dealings
25in this Software without prior written authorization from The Open Group.
26
27*/
28/* $XFree86: xc/lib/Xmu/Xct.c,v 1.8 2001/07/25 15:04:50 dawes Exp $ */
29
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33#include <X11/Xfuncs.h>
34#include "Xct.h"
35#include <stdio.h>
36
37#define UsedGraphic	0x0001
38#define UsedDirection	0x0002
39
40typedef struct _XctPriv {
41    XctString		ptr;
42    XctString		ptrend;
43    unsigned		flags;
44    XctHDirection	*dirstack;
45    unsigned		dirsize;
46    char		**encodings;
47    unsigned		enc_count;
48    XctString		itembuf;
49    unsigned		buf_count;
50} *XctPriv;
51
52#define IsMore(priv) ((priv)->ptr != (priv)->ptrend)
53#define AmountLeft(priv) ((priv)->ptrend - (priv)->ptr)
54
55#include <stdlib.h>
56
57#define HT	0x09
58#define NL	0x0a
59#define ESC	0x1b
60#define CSI	0x9b
61
62#define IsLegalC0(data, c) (((c) == HT) || ((c) == NL) || \
63			    (((data)->version > XctVersion) && \
64			     ((data)->flags & XctAcceptC0Extensions)))
65
66#define IsLegalC1(priv, c) (((data)->version > XctVersion) && \
67			    ((data)->flags & XctAcceptC1Extensions))
68
69#define IsI2(c) (((c) >= 0x20) && ((c) <= 0x2f))
70#define IsI3(c) (((c) >= 0x30) && ((c) <= 0x3f))
71#define IsESCF(c) (((c) >= 0x30) && ((c) <= 0x7e))
72#define IsCSIF(c) (((c) >= 0x40) && ((c) <= 0x7e))
73#define IsC0(c) ((c) <= 0x1f)
74#define IsGL(c) (((c) >= 0x20) && ((c) <= 0x7f))
75#define IsC1(c) (((c) >= 0x80) && ((c) <= 0x9f))
76#define IsGR(c) ((c) >= 0xa0)
77
78#define HasC  1
79#define HasGL 2
80#define HasGR 4
81#define ToGL  8
82
83/*
84 * Prototypes
85 */
86static void ComputeGLGR(XctData);
87static int Handle94GR(XctData, int);
88static int Handle96GR(XctData, int);
89static int HandleExtended(XctData data, int);
90static int HandleGL(XctData, int);
91static int HandleMultiGL(XctData, int);
92static int HandleMultiGR(XctData data, int);
93static void ShiftGRToGL(XctData, int);
94
95/*
96 * Implementation
97 */
98static void
99ComputeGLGR(register XctData data)
100{
101    /* XXX this will need more work if more sets are registered */
102    if ((data->GL_set_size == 94) && (data->GL_char_size == 1) &&
103	(data->GL[0] == '\102') &&
104	(data->GR_set_size == 96) && (data->GR_char_size == 1))
105	data->GLGR_encoding = data->GR_encoding;
106    else if ((data->GL_set_size == 94) && (data->GL_char_size == 1) &&
107	     (data->GL[0] == '\112') &&
108	     (data->GR_set_size == 94) && (data->GR_char_size == 1))
109	data->GLGR_encoding = data->GR_encoding;
110    else
111	data->GLGR_encoding = (char *)NULL;
112}
113
114static int
115HandleGL(register XctData data, int c)
116{
117    switch (c) {
118    case 0x42:
119	data->GL = "\102";
120	data->GL_encoding = "ISO8859-1";
121	break;
122    case 0x4a:
123	data->GL = "\112";
124	data->GL_encoding = "JISX0201.1976-0";
125	break;
126    default:
127	return 0;
128    }
129    data->GL_set_size = 94;
130    data->GL_char_size = 1;
131    ComputeGLGR(data);
132    return 1;
133}
134
135static int
136HandleMultiGL(register XctData data, int c)
137{
138    switch (c) {
139    case 0x41:
140	data->GL = "\101";
141	data->GL_encoding = "GB2312.1980-0";
142	break;
143    case 0x42:
144	data->GL = "\102";
145	data->GL_encoding = "JISX0208.1983-0";
146	break;
147    case 0x43:
148	data->GL = "\103";
149	data->GL_encoding = "KSC5601.1987-0";
150	break;
151    default:
152	return 0;
153    }
154    data->GL_set_size = 94;
155    data->GL_char_size = 2;
156#ifdef notdef
157    if (c < 0x60)
158	data->GL_char_size = 2;
159    else if (c < 0x70)
160	data->GL_char_size = 3;
161    else
162	data->GL_char_size = 4;
163#endif
164    data->GLGR_encoding = (char *)NULL;
165    return 1;
166}
167
168static int
169Handle94GR(register XctData data, int c)
170{
171    switch (c) {
172    case 0x49:
173	data->GR = "\111";
174	data->GR_encoding = "JISX0201.1976-0";
175	break;
176    default:
177	return 0;
178    }
179    data->priv->flags &= ~ToGL;
180    data->GR_set_size = 94;
181    data->GR_char_size = 1;
182    data->GLGR_encoding = (char *)NULL;
183    return 1;
184}
185
186static int
187Handle96GR(register XctData data, int c)
188{
189    switch (c) {
190    case 0x41:
191	data->GR = "\101";
192	data->GR_encoding = "ISO8859-1";
193	break;
194    case 0x42:
195	data->GR = "\102";
196	data->GR_encoding = "ISO8859-2";
197	break;
198    case 0x43:
199	data->GR = "\103";
200	data->GR_encoding = "ISO8859-3";
201	break;
202    case 0x44:
203	data->GR = "\104";
204	data->GR_encoding = "ISO8859-4";
205	break;
206    case 0x46:
207	data->GR = "\106";
208	data->GR_encoding = "ISO8859-7";
209	break;
210    case 0x47:
211	data->GR = "\107";
212	data->GR_encoding = "ISO8859-6";
213	break;
214    case 0x48:
215	data->GR = "\110";
216	data->GR_encoding = "ISO8859-8";
217	break;
218    case 0x4c:
219	data->GR = "\114";
220	data->GR_encoding = "ISO8859-5";
221	break;
222    case 0x4d:
223	data->GR = "\115";
224	data->GR_encoding = "ISO8859-9";
225	break;
226    default:
227	return 0;
228    }
229    data->priv->flags &= ~ToGL;
230    data->GR_set_size = 96;
231    data->GR_char_size = 1;
232    ComputeGLGR(data);
233    return 1;
234}
235
236static int
237HandleMultiGR(register XctData data, int c)
238{
239    switch (c) {
240    case 0x41:
241	data->GR = "\101";
242	if (data->flags & XctShiftMultiGRToGL)
243	    data->GR_encoding = "GB2312.1980-0";
244	else
245	    data->GR_encoding = "GB2312.1980-1";
246	break;
247    case 0x42:
248	data->GR = "\102";
249	if (data->flags & XctShiftMultiGRToGL)
250	    data->GR_encoding = "JISX0208.1983-0";
251	else
252	    data->GR_encoding = "JISX0208.1983-1";
253	break;
254    case 0x43:
255	data->GR = "\103";
256	if (data->flags & XctShiftMultiGRToGL)
257	    data->GR_encoding = "KSC5601.1987-0";
258	else
259	    data->GR_encoding = "KSC5601.1987-1";
260	break;
261    default:
262	return 0;
263    }
264    if (data->flags & XctShiftMultiGRToGL)
265	data->priv->flags |= ToGL;
266    else
267	data->priv->flags &= ~ToGL;
268    data->GR_set_size = 94;
269    data->GR_char_size = 2;
270#ifdef notdef
271    if (c < 0x60)
272	data->GR_char_size = 2;
273    else if (c < 0x70)
274	data->GR_char_size = 3;
275    else
276	data->GR_char_size = 4;
277#endif
278    data->GLGR_encoding = (char *)NULL;
279    return 1;
280}
281
282static int
283HandleExtended(register XctData data, int c)
284{
285    register XctPriv priv = data->priv;
286    XctString enc = data->item + 6;
287    register XctString ptr = enc;
288    unsigned i, len;
289
290    while (*ptr != 0x02) {
291	if (!*ptr || (++ptr == priv->ptr))
292	    return 0;
293    }
294    data->item = ptr + 1;
295    data->item_length = priv->ptr - data->item;
296    len = ptr - enc;
297    for (i = 0;
298	 (i < priv->enc_count) &&
299	 strncmp(priv->encodings[i], (char *)enc, len);
300	 i++)
301	;
302    if (i == priv->enc_count) {
303	XctString cp;
304
305	for (cp = enc; cp != ptr; cp++) {
306	    if ((!IsGL(*cp) && !IsGR(*cp)) || (*cp == 0x2a) || (*cp == 0x3f))
307		return 0;
308	}
309	ptr = (XctString)malloc((unsigned)len + 1);
310	(void) memmove((char *)ptr, (char *)enc, len);
311	ptr[len] = 0x00;
312	priv->enc_count++;
313	if (priv->encodings)
314	    priv->encodings = (char **)realloc(
315					    (char *)priv->encodings,
316					    priv->enc_count * sizeof(char *));
317	else
318	    priv->encodings = (char **)malloc(sizeof(char *));
319	priv->encodings[i] = (char *)ptr;
320    }
321    data->encoding = priv->encodings[i];
322    data->char_size = c - 0x30;
323    return 1;
324}
325
326static void
327ShiftGRToGL(register XctData data, int hasCdata)
328{
329    register XctPriv priv = data->priv;
330    register int i;
331
332    if (data->item_length > priv->buf_count) {
333	priv->buf_count = data->item_length;
334	if (priv->itembuf)
335	    priv->itembuf = (XctString)realloc((char *)priv->itembuf,
336					       priv->buf_count);
337	else
338	    priv->itembuf = (XctString)malloc(priv->buf_count);
339    }
340    (void) memmove((char *)priv->itembuf, (char *)data->item,
341		   data->item_length);
342    data->item = priv->itembuf;
343    if (hasCdata) {
344	for (i = data->item_length; --i >= 0; ) {
345	    if (IsGR(data->item[i]))
346		data->item[i] &= 0x7f;
347	}
348    } else {
349	for (i = data->item_length; --i >= 0; )
350	    data->item[i] &= 0x7f;
351    }
352}
353
354/* Create an XctData structure for parsing a Compound Text string. */
355XctData
356XctCreate(_Xconst unsigned char *string, int length, XctFlags flags)
357{
358    register XctData data;
359    register XctPriv priv;
360
361    data = (XctData)malloc(sizeof(struct _XctRec) + sizeof(struct _XctPriv));
362    if (!data)
363	return data;
364    data->priv = priv = (XctPriv)(data + 1);
365    data->total_string = (XctString)string;
366    data->total_length = length;
367    data->flags = flags;
368    priv->dirstack = (XctHDirection *)NULL;
369    priv->dirsize = 0;
370    priv->encodings = (char **)NULL;
371    priv->enc_count = 0;
372    priv->itembuf = (XctString)NULL;
373    priv->buf_count = 0;
374    XctReset(data);
375    return data;
376}
377
378/* Reset the XctData structure to re-parse the string from the beginning. */
379void
380XctReset(register XctData data)
381{
382    register XctPriv priv = data->priv;
383
384    priv->ptr = data->total_string;
385    priv->ptrend = data->total_string + data->total_length;
386    data->item = (XctString)NULL;
387    data->item_length = 0;
388    data->encoding = (char *)NULL;
389    data->char_size = 1;
390    data->horizontal = XctUnspecified;
391    data->horz_depth = 0;
392    priv->flags = 0;
393    data->GL_set_size = data->GR_set_size = 0; /* XXX */
394    (void)HandleGL(data, (unsigned char)0x42);
395    (void)Handle96GR(data, (unsigned char)0x41);
396    data->version = 1;
397    data->can_ignore_exts = 0;
398    /* parse version, if present */
399    if ((data->total_length >= 4) &&
400	(priv->ptr[0] == ESC) && (priv->ptr[1] == 0x23) &&
401	IsI2(priv->ptr[2]) &&
402	((priv->ptr[3] == 0x30) || (priv->ptr[3] == 0x31))) {
403	data->version = priv->ptr[2] - 0x1f;
404	if (priv->ptr[3] == 0x30)
405	    data->can_ignore_exts = 1;
406	priv->ptr += 4;
407    }
408}
409
410/* Parse the next "item" from the Compound Text string.  The return value
411 * indicates what kind of item is returned.  The item itself, and the current
412 * contextual state, are reported as components of the XctData structure.
413 */
414XctResult
415XctNextItem(register XctData data)
416{
417    register XctPriv priv = data->priv;
418    unsigned char c;
419    int len, bits;
420
421#define NEXT data->item_length++; priv->ptr++
422
423    while (IsMore(priv)) {
424	data->item = priv->ptr;
425	data->item_length = 0;
426	c = *priv->ptr;
427	if (c == ESC) {
428	    NEXT;
429	    while (IsMore(priv) && IsI2(*priv->ptr)) {
430		NEXT;
431	    }
432	    if (!IsMore(priv))
433		return XctError;
434	    c = *priv->ptr;
435	    NEXT;
436	    if (!IsESCF(c))
437		return XctError;
438	    switch (data->item[1]) {
439	    case 0x24:
440		if (data->item_length > 3) {
441		    if (data->item[2] == 0x28) {
442			if (HandleMultiGL(data, c))
443			    continue;
444		    } else if (data->item[2] == 0x29) {
445			if (HandleMultiGR(data, c))
446			    continue;
447		    }
448		}
449		break;
450	    case 0x25:
451		if ((data->item_length == 4) && (data->item[2] == 0x2f) &&
452		    (c <= 0x3f)) {
453		    if ((AmountLeft(priv) < 2) ||
454			(priv->ptr[0] < 0x80) || (priv->ptr[1] < 0x80))
455			return XctError;
456		    len = *priv->ptr - 0x80;
457		    NEXT;
458		    len = (len << 7) + (*priv->ptr - 0x80);
459		    NEXT;
460		    if (AmountLeft(priv) < len)
461			return XctError;
462		    data->item_length += len;
463		    priv->ptr += len;
464		    if (c <= 0x34) {
465			if (!HandleExtended(data, c) ||
466			    ((data->horz_depth == 0) &&
467			     (priv->flags & UsedDirection)))
468			    return XctError;
469			priv->flags |= UsedGraphic;
470			return XctExtendedSegment;
471		    }
472		}
473		break;
474	    case 0x28:
475		if (HandleGL(data, c))
476		    continue;
477		break;
478	    case 0x29:
479		if (Handle94GR(data, c))
480		    continue;
481		break;
482	    case 0x2d:
483		if (Handle96GR(data, c))
484		    continue;
485		break;
486	    }
487	} else if (c == CSI) {
488	    NEXT;
489	    while (IsMore(priv) && IsI3(*priv->ptr)) {
490		NEXT;
491	    }
492	    while (IsMore(priv) && IsI2(*priv->ptr)) {
493		NEXT;
494	    }
495	    if (!IsMore(priv))
496		return XctError;
497	    c = *priv->ptr;
498	    NEXT;
499	    if (!IsCSIF(c))
500		return XctError;
501	    if (c == 0x5d) {
502		if ((data->item_length == 3) &&
503		    ((data->item[1] == 0x31) || (data->item[1] == 0x32))) {
504		    data->horz_depth++;
505		    if (priv->dirsize < data->horz_depth) {
506			priv->dirsize += 10;
507			if (priv->dirstack)
508			    priv->dirstack = (XctHDirection *)
509					     realloc((char *)priv->dirstack,
510						     priv->dirsize *
511						     sizeof(XctHDirection));
512			else
513			    priv->dirstack = (XctHDirection *)
514					     malloc(priv->dirsize *
515						    sizeof(XctHDirection));
516		    }
517		    priv->dirstack[data->horz_depth - 1] = data->horizontal;
518		    if (data->item[1] == 0x31)
519			data->horizontal = XctLeftToRight;
520		    else
521			data->horizontal = XctRightToLeft;
522		    if ((priv->flags & UsedGraphic) &&
523			!(priv->flags & UsedDirection))
524			return XctError;
525		    priv->flags |= UsedDirection;
526		    if (data->flags & XctHideDirection)
527			continue;
528		    return XctHorizontal;
529		} else if (data->item_length == 2) {
530		    if (!data->horz_depth)
531			return XctError;
532		    data->horz_depth--;
533		    data->horizontal = priv->dirstack[data->horz_depth];
534		    if (data->flags & XctHideDirection)
535			continue;
536		    return XctHorizontal;
537		}
538	    }
539	} else if (data->flags & XctSingleSetSegments) {
540	    NEXT;
541	    if IsC0(c) {
542		data->encoding = (char *)NULL;
543		data->char_size = 1;
544		if (IsLegalC0(data, c))
545		    return XctC0Segment;
546	    } else if (IsGL(c)) {
547		data->encoding = data->GL_encoding;
548		data->char_size = data->GL_char_size;
549		while (IsMore(priv) && IsGL(*priv->ptr)) {
550		    NEXT;
551		}
552		if (((data->char_size > 1) &&
553		     (data->item_length % data->char_size)) ||
554		    ((data->horz_depth == 0) &&
555		     (priv->flags & UsedDirection)))
556		    return XctError;
557		priv->flags |= UsedGraphic;
558		return XctGLSegment;
559	    } else if (IsC1(c)) {
560		data->encoding = (char *)NULL;
561		data->char_size = 1;
562		if (IsLegalC1(data, c))
563		    return XctC1Segment;
564	    } else {
565		data->encoding = data->GR_encoding;
566		data->char_size = data->GR_char_size;
567		while (IsMore(priv) && IsGR(*priv->ptr)) {
568		    NEXT;
569		}
570		if (((data->char_size > 1) &&
571		     (data->item_length % data->char_size)) ||
572		    ((data->horz_depth == 0) &&
573		     (priv->flags & UsedDirection)))
574		    return XctError;
575		priv->flags |= UsedGraphic;
576		if (!(priv->flags & ToGL))
577		    return XctGRSegment;
578		ShiftGRToGL(data, 0);
579		return XctGLSegment;
580	    }
581	} else {
582	    bits = 0;
583	    while (1) {
584		if (IsC0(c) || IsC1(c)) {
585		    if ((c == ESC) || (c == CSI))
586			break;
587		    if (IsC0(c) ? !IsLegalC0(data, c) : !IsLegalC1(data, c))
588			break;
589		    bits |= HasC;
590		    NEXT;
591		} else {
592		    len = data->item_length;
593		    if (IsGL(c)) {
594			if ((data->flags & XctShiftMultiGRToGL) &&
595			    (bits & HasGR))
596			    break;
597			NEXT;
598			bits |= HasGL;
599			while (IsMore(priv) && IsGL(*priv->ptr)) {
600			    NEXT;
601			}
602			if ((data->GL_char_size > 1) &&
603			    ((data->item_length - len) % data->GL_char_size))
604			    return XctError;
605		    } else {
606			if ((data->flags & XctShiftMultiGRToGL) &&
607			    (bits & HasGL))
608			    break;
609			NEXT;
610			bits |= HasGR;
611			while (IsMore(priv) && IsGR(*priv->ptr)) {
612			    NEXT;
613			}
614			if ((data->GR_char_size > 1) &&
615			    ((data->item_length - len) % data->GR_char_size))
616			    return XctError;
617		    }
618		}
619		if (!IsMore(priv))
620		    break;
621		c = *priv->ptr;
622	    }
623	    if (data->item_length) {
624		if (bits & (HasGL|HasGR)) {
625		    priv->flags |= UsedGraphic;
626		    if ((data->horz_depth == 0) &&
627			(priv->flags & UsedDirection))
628			return XctError;
629		    if ((data->flags & XctShiftMultiGRToGL) && (bits & HasGR))
630			ShiftGRToGL(data, bits & HasC);
631		}
632		if ((bits == (HasGL|HasGR)) ||
633		    (data->GLGR_encoding && !(bits & HasC))) {
634		    data->encoding = data->GLGR_encoding;
635		    if (data->GL_char_size == data->GR_char_size)
636			data->char_size = data->GL_char_size;
637		    else
638			data->char_size = 0;
639		} else if (bits == HasGL) {
640		    data->encoding = data->GL_encoding;
641		    data->char_size = data->GL_char_size;
642		} else if (bits == HasGR) {
643		    data->encoding = data->GR_encoding;
644		    data->char_size = data->GR_char_size;
645		} else {
646		    data->encoding = (char *)NULL;
647		    data->char_size = 1;
648		    if ((bits & HasGL) &&
649			(data->GL_char_size != data->char_size))
650			data->char_size = 0;
651		    if ((bits & HasGR) &&
652			(data->GR_char_size != data->char_size))
653			data->char_size = 0;
654		}
655		return XctSegment;
656	    }
657	    NEXT;
658	}
659	if (data->version <= XctVersion)
660	    return XctError;
661	if (data->flags & XctProvideExtensions)
662	    return XctExtension;
663	if (!data->can_ignore_exts)
664	    return XctError;
665    }
666    return XctEndOfText;
667}
668
669/* Free all data associated with an XctDataStructure. */
670void
671XctFree(register XctData data)
672{
673    unsigned i;
674    register XctPriv priv = data->priv;
675
676    if (priv->dirstack)
677	free((char *)priv->dirstack);
678    if (data->flags & XctFreeString)
679	free((char *)data->total_string);
680    for (i = 0; i < priv->enc_count; i++)
681	free(priv->encodings[i]);
682    if (priv->encodings)
683	free((char *)priv->encodings);
684    if (priv->itembuf)
685	free((char *)priv->itembuf);
686    free((char *)data);
687}
688