Imported Upstream version 1.1.1
[platform/upstream/libXmu.git] / src / Xct.c
1 /*
2
3 Copyright 1989, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in 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
37 typedef 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  */
83 static void ComputeGLGR(XctData);
84 static int Handle94GR(XctData, int);
85 static int Handle96GR(XctData, int);
86 static int HandleExtended(XctData data, int);
87 static int HandleGL(XctData, int);
88 static int HandleMultiGL(XctData, int);
89 static int HandleMultiGR(XctData data, int);
90 static void ShiftGRToGL(XctData, int);
91
92 /*
93  * Implementation
94  */
95 static void
96 ComputeGLGR(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
111 static int
112 HandleGL(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
132 static int
133 HandleMultiGL(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
165 static int
166 Handle94GR(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
183 static int
184 Handle96GR(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
233 static int
234 HandleMultiGR(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
279 static int
280 HandleExtended(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
323 static void
324 ShiftGRToGL(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. */
352 XctData
353 XctCreate(_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. */
376 void
377 XctReset(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  */
411 XctResult
412 XctNextItem(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. */
667 void
668 XctFree(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 }