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