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