lib/genx/genx.c (45002B) - raw
1 /* 2 * Copyright (c) 2004 by Tim Bray and Sun Microsystems. For copying 3 * permission, see http://www.tbray.org/ongoing/genx/COPYING 4 */ 5 6 #define GENX_VERSION "beta5" 7 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include "genx.h" 12 13 #define Boolean int 14 #define True 1 15 #define False 0 16 #define STRLEN_XMLNS_COLON 6 17 18 19 /******************************* 20 * writer state 21 */ 22 typedef enum 23 { 24 SEQUENCE_NO_DOC, 25 SEQUENCE_PRE_DOC, 26 SEQUENCE_POST_DOC, 27 SEQUENCE_START_TAG, 28 SEQUENCE_ATTRIBUTES, 29 SEQUENCE_CONTENT 30 } writerSequence; 31 32 /******************************* 33 * generic pointer list 34 */ 35 typedef struct 36 { 37 genxWriter writer; 38 int count; 39 int space; 40 void * * pointers; 41 } plist; 42 43 /******************************* 44 * text collector, for attribute values 45 */ 46 typedef struct 47 { 48 utf8 buf; 49 int used; 50 int space; 51 } collector; 52 53 /******************************* 54 * Structs with opaquely-exposed handles 55 */ 56 57 /* 58 * This one's tricky, to handle stacking namespaces 59 * 'declaration' is the current attribute which would be used to 60 * declare the currently-effective prefix 61 * 'defDeclaration' is a appropriate declaration when this is being 62 * used with the default prefix as passed to genxDeclareNamespace 63 * baroque is true if this namespace has been used with more than one 64 * prefix, or is the default namespace but has been unset 65 */ 66 struct genxNamespace_rec 67 { 68 genxWriter writer; 69 utf8 name; 70 int declCount; 71 Boolean baroque; 72 genxAttribute declaration; 73 genxAttribute defaultDecl; 74 }; 75 76 struct genxElement_rec 77 { 78 genxWriter writer; 79 utf8 type; 80 genxNamespace ns; 81 }; 82 83 typedef enum 84 { 85 ATTR_NSDECL, 86 ATTR_NAKED, 87 ATTR_PREFIXED 88 } attrType; 89 90 struct genxAttribute_rec 91 { 92 genxWriter writer; 93 utf8 name; 94 genxNamespace ns; 95 collector value; 96 int provided; /* provided for current element? */ 97 attrType atype; 98 }; 99 100 /******************************* 101 * genx's sandbox 102 */ 103 struct genxWriter_rec 104 { 105 FILE * file; 106 genxSender * sender; 107 genxStatus status; 108 writerSequence sequence; 109 char xmlChars[0x10000]; 110 void * userData; 111 int nextPrefix; 112 utf8 empty; 113 Boolean defaultNsDeclared; 114 genxAttribute xmlnsEquals; 115 genxElement nowStarting; 116 plist namespaces; 117 plist elements; 118 plist attributes; 119 plist prefixes; 120 plist stack; 121 struct genxAttribute_rec arec; 122 char * etext[100]; 123 void * (* alloc)(void * userData, int bytes); 124 void (* dealloc)(void * userData, void * data); 125 }; 126 127 /******************************* 128 * Forward declarations 129 */ 130 static genxAttribute declareAttribute(genxWriter w, genxNamespace ns, 131 constUtf8 name, constUtf8 valuestr, 132 genxStatus * statusP); 133 static genxStatus addNamespace(genxNamespace ns, utf8 prefix); 134 static genxStatus unsetDefaultNamespace(genxWriter w); 135 static genxStatus addAttribute(genxAttribute a, constUtf8 valuestr); 136 void genxSetCharProps(char * p); 137 138 /******************************* 139 * End of declarations 140 */ 141 142 /******************************* 143 * private memory utilities 144 */ 145 static void * allocate(genxWriter w, int bytes) 146 { 147 if (w->alloc) 148 return (void *) (*w->alloc)(w->userData, bytes); 149 else 150 return (void *) malloc(bytes); 151 } 152 153 static void deallocate(genxWriter w, void * data) 154 { 155 if (w->dealloc) 156 (*w->dealloc)(w->userData, data); 157 else if (w->alloc == NULL) 158 free(data); 159 } 160 161 static utf8 copy(genxWriter w, constUtf8 from) 162 { 163 utf8 temp; 164 165 if ((temp = (utf8) allocate(w, strlen((const char *) from) + 1)) == NULL) 166 return NULL; 167 strcpy((char *) temp, (const char *) from); 168 return temp; 169 } 170 171 static genxStatus initCollector(genxWriter w, collector * c) 172 { 173 c->space = 100; 174 if ((c->buf = (utf8) allocate(w, c->space)) == NULL) 175 return GENX_ALLOC_FAILED; 176 c->used = 0; 177 return GENX_SUCCESS; 178 } 179 180 static genxStatus growCollector(genxWriter w, collector * c, int size) 181 { 182 utf8 newSpace; 183 184 c->space = size * 2; 185 if ((newSpace = (utf8) allocate(w, c->space)) == NULL) 186 return GENX_ALLOC_FAILED; 187 188 strncpy((char *) newSpace, (const char *) c->buf, c->used); 189 newSpace[c->used] = 0; 190 deallocate(w, c->buf); 191 c->buf = newSpace; 192 return GENX_SUCCESS; 193 } 194 195 static void startCollect(collector * c) 196 { 197 c->used = 0; 198 } 199 static void endCollect(collector * c) 200 { 201 c->buf[c->used] = 0; 202 } 203 204 static genxStatus collectString(genxWriter w, collector * c, constUtf8 string) 205 { 206 int sl = strlen((const char *) string); 207 208 if (sl >= c->space) 209 if ((w->status = growCollector(w, c, sl)) != GENX_SUCCESS) 210 return GENX_ALLOC_FAILED; 211 212 strcpy((char *) c->buf, (const char *) string); 213 return GENX_SUCCESS; 214 } 215 216 #define collectPiece(w,c,d,size) {if (((c)->used+(size))>=(c)->space){if (((w)->status=growCollector(w,c,(c)->used+(size)))!=GENX_SUCCESS) return (w)->status;}strncpy((char *)(c)->buf+(c)->used,d,size);(c)->used+=size;} 217 218 /******************************* 219 * private list utilities 220 */ 221 static genxStatus initPlist(genxWriter w, plist * pl) 222 { 223 pl->writer = w; 224 pl->count = 0; 225 pl->space = 10; 226 pl->pointers = (void * *) allocate(w, pl->space * sizeof(void *)); 227 if (pl->pointers == NULL) 228 return GENX_ALLOC_FAILED; 229 230 return GENX_SUCCESS; 231 } 232 233 /* 234 * make room in a plist 235 */ 236 static Boolean checkExpand(plist * pl) 237 { 238 void * * newlist; 239 int i; 240 241 if (pl->count < pl->space) 242 return True; 243 244 pl->space *= 2; 245 newlist = (void * *) allocate(pl->writer, pl->space * sizeof(void *)); 246 if (newlist == NULL) 247 return False; 248 for (i = 0; i < pl->count; i++) 249 newlist[i] = pl->pointers[i]; 250 deallocate(pl->writer, pl->pointers); 251 pl->pointers = newlist; 252 253 return True; 254 } 255 256 /* 257 * stick something on the end of a plist 258 */ 259 static genxStatus listAppend(plist * pl, void * pointer) 260 { 261 if (!checkExpand(pl)) 262 return GENX_ALLOC_FAILED; 263 264 pl->pointers[pl->count++] = pointer; 265 return GENX_SUCCESS; 266 } 267 268 /* 269 * insert in place, shuffling up 270 */ 271 static genxStatus listInsert(plist * pl, void * pointer, int at) 272 { 273 int i; 274 275 if (!checkExpand(pl)) 276 return GENX_ALLOC_FAILED; 277 278 for (i = pl->count; i > at; i--) 279 pl->pointers[i] = pl->pointers[i - 1]; 280 pl->count++; 281 282 pl->pointers[at] = pointer; 283 return GENX_SUCCESS; 284 } 285 286 /******************************* 287 * list lookups 288 */ 289 290 static genxNamespace findNamespace(plist * pl, constUtf8 uri) 291 { 292 int i; 293 genxNamespace * nn = (genxNamespace *) pl->pointers; 294 295 for (i = 0; i < pl->count; i++) 296 if (strcmp((char *) uri, (const char *) nn[i]->name) == 0) 297 return nn[i]; 298 299 return NULL; 300 } 301 302 static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 type) 303 { 304 int i; 305 genxElement * ee = (genxElement *) pl->pointers; 306 307 for (i = 0; i < pl->count; i++) 308 { 309 if (xmlns == NULL) 310 { 311 if (ee[i]->ns == NULL && strcmp((const char *) type, 312 (const char *) ee[i]->type) == 0) 313 return ee[i]; 314 } 315 else 316 { 317 if (ee[i]->ns != NULL && 318 strcmp((const char *) xmlns, (const char *) ee[i]->ns->name) == 0 && 319 strcmp((const char *) type, (const char *) ee[i]->type) == 0) 320 return ee[i]; 321 } 322 } 323 324 return NULL; 325 } 326 327 /* 328 * store & intern a prefix, after giving it the 329 * "xmlns:" prefix. Don't allow storing the same one twice unless 'force' 330 * is set. 331 */ 332 static utf8 storePrefix(genxWriter w, constUtf8 prefix, Boolean force) 333 { 334 int high, low; 335 utf8 * pp = (utf8 *) w->prefixes.pointers; 336 unsigned char buf[1024]; 337 338 if (prefix[0] == 0) 339 prefix = (utf8) "xmlns"; 340 else 341 { 342 sprintf((char *) buf, "xmlns:%s", prefix); 343 prefix = buf; 344 } 345 346 high = w->prefixes.count; low = -1; 347 while (high - low > 1) 348 { 349 int probe = (high + low) / 2; 350 if (strcmp((const char *) prefix, (const char *) pp[probe]) < 0) 351 high = probe; 352 else 353 low = probe; 354 } 355 356 /* already there? */ 357 if (low != -1 && strcmp((const char *) prefix, (const char *) pp[low]) == 0) 358 { 359 if (force) 360 return pp[low]; 361 362 w->status = GENX_DUPLICATE_PREFIX; 363 return NULL; 364 } 365 366 /* copy & insert */ 367 if ((prefix = copy(w, prefix)) == NULL) 368 { 369 w->status = GENX_ALLOC_FAILED; 370 return NULL; 371 } 372 373 w->status = listInsert(&w->prefixes, (void *) prefix, high); 374 if (w->status != GENX_SUCCESS) 375 return NULL; 376 377 return (utf8) prefix; 378 } 379 380 /******************************* 381 * UTF8 bit-banging 382 */ 383 384 /* 385 * Retrieve the character pointed at, and advance the pointer; return -1 on 386 * error 387 */ 388 int genxNextUnicodeChar(constUtf8 * sp) 389 { 390 utf8 s = (utf8) *sp; 391 int c; 392 393 if (*s == 0) 394 return -1; 395 396 if (*s < 0x80) 397 c = *s++; 398 399 /* all this encoding sanity-checking taken from section 3.10 of Unicode 4 */ 400 else if (*s < 0xc2) 401 goto malformed; 402 403 /* 2-byte encodings, first byte c2 .. df */ 404 else if (*s < 0xe0) 405 { 406 c = (*s++ & 0x1f) << 6; 407 408 /* 409 * for this common idiom, if ((c & 0xc0) != 0x80) is slightly faster 410 * on MacOS (PPC) 411 */ 412 if (*s < 0x80 || *s > 0xbf) 413 goto malformed; 414 415 c |= *s++ & 0x3f; 416 } 417 418 /* 3-byte encodings, first byte e0 .. ef */ 419 else if (*s < 0xf0) 420 { 421 int b0 = *s; 422 c = (*s++ & 0x0f) << 12; 423 424 if ((b0 == 0xe0 && (*s < 0xa0 || *s > 0xbf)) || 425 (b0 < 0xed && (*s < 0x80 || *s > 0xbf)) || 426 (b0 == 0xed && (*s < 0x80 || *s > 0x9f)) || 427 (b0 > 0xed && (*s < 0x80 || *s > 0xbf))) 428 goto malformed; 429 430 c |= (*s++ & 0x3f) << 6; 431 432 if (*s < 0x80 || *s > 0xbf) 433 goto malformed; 434 435 c |= *s++ & 0x3f; 436 } 437 438 /* 4-byte encodings, first byte f0 .. f4 */ 439 else if (*s < 0xf5) 440 { 441 int b0 = *s; 442 c = (*s++ & 0x07) << 18; 443 444 if ((b0 == 0xf0 && (*s < 0x90 || *s > 0xbf)) || 445 (b0 < 0xf4 && (*s < 0x80 || *s > 0xbf)) || 446 (b0 >= 0xf4 && (*s < 0x80 || *s > 0x8f))) 447 goto malformed; 448 449 c |= (*s++ & 0x3f) << 12; 450 451 if (*s < 0x80 || *s > 0xbf) 452 goto malformed; 453 454 c |= (*s++ & 0x3f) << 6; 455 456 if (*s < 0x80 || *s > 0xbf) 457 goto malformed; 458 459 c |= *s++ & 0x3f; 460 } 461 else 462 goto malformed; 463 464 *sp = s; 465 return c; 466 467 /* 468 * this is needed by scrubText, which wants to get the pointer moved 469 * past the problem area. 470 */ 471 malformed: 472 if (*s) 473 ++s; 474 *sp = s; 475 return -1; 476 } 477 478 static Boolean isXMLChar(genxWriter w, int c) 479 { 480 if (c < 0) 481 return False; 482 else if (c < 0x10000) 483 return (int) w->xmlChars[c]; 484 else 485 return (c <= 0x10ffff); 486 } 487 488 static Boolean isLetter(genxWriter w, int c) 489 { 490 if (c < 0 || c > 0xffff) 491 return False; 492 else 493 return w->xmlChars[c] & GENX_LETTER; 494 } 495 496 static Boolean isNameChar(genxWriter w, int c) 497 { 498 if (c < 0 || c > 0xffff) 499 return False; 500 else 501 return w->xmlChars[c] & GENX_NAMECHAR; 502 } 503 504 /******************************* 505 * Constructors, setters/getters 506 */ 507 508 /* 509 * Construct a new genxWriter 510 */ 511 genxWriter genxNew(void * (* alloc)(void * userData, int bytes), 512 void (* dealloc)(void * userData, void * data), 513 void * userData) 514 { 515 genxWriter w; 516 genxNamespace xml; 517 518 if (alloc) 519 w = (genxWriter) (*alloc)(userData, sizeof(struct genxWriter_rec)); 520 else 521 w = (genxWriter) malloc(sizeof(struct genxWriter_rec)); 522 523 if (w == NULL) 524 return NULL; 525 526 w->status = GENX_SUCCESS; 527 w->alloc = alloc; 528 w->dealloc = dealloc; 529 w->userData = userData; 530 w->sequence = SEQUENCE_NO_DOC; 531 532 if (initPlist(w, &w->namespaces) != GENX_SUCCESS || 533 initPlist(w, &w->elements) != GENX_SUCCESS || 534 initPlist(w, &w->attributes) != GENX_SUCCESS || 535 initPlist(w, &w->prefixes) != GENX_SUCCESS || 536 initPlist(w, &w->stack) != GENX_SUCCESS) 537 return NULL; 538 539 if ((w->status = initCollector(w, &w->arec.value)) != GENX_SUCCESS) 540 return NULL; 541 542 if ((w->empty = copy(w, (utf8) "")) == NULL) 543 { 544 w->status = GENX_ALLOC_FAILED; 545 return NULL; 546 } 547 548 w->xmlnsEquals = declareAttribute(w, NULL, (utf8) "xmlns", NULL, &w->status); 549 if (w->xmlnsEquals == NULL || w->status != GENX_SUCCESS) 550 return NULL; 551 w->defaultNsDeclared = False; 552 553 w->nextPrefix = 1; 554 555 genxSetCharProps(w->xmlChars); 556 557 w->etext[GENX_SUCCESS] = "Success"; 558 w->etext[GENX_BAD_UTF8] = "Bad UTF8"; 559 w->etext[GENX_NON_XML_CHARACTER] = "Non XML Character"; 560 w->etext[GENX_BAD_NAME] = "Bad NAME"; 561 w->etext[GENX_ALLOC_FAILED] = "Memory allocation failed"; 562 w->etext[GENX_BAD_NAMESPACE_NAME] = "Bad namespace name"; 563 w->etext[GENX_INTERNAL_ERROR] = "Internal error"; 564 w->etext[GENX_DUPLICATE_PREFIX] = "Duplicate prefix"; 565 w->etext[GENX_SEQUENCE_ERROR] = "Call out of sequence"; 566 w->etext[GENX_NO_START_TAG] = "No Start-tag for EndElement call"; 567 w->etext[GENX_IO_ERROR] = "I/O error"; 568 w->etext[GENX_MISSING_VALUE] = "Missing attribute value"; 569 w->etext[GENX_MALFORMED_COMMENT] = "Malformed comment body"; 570 w->etext[GENX_MALFORMED_PI] = "?> in PI"; 571 w->etext[GENX_XML_PI_TARGET] = "Target of PI matches [xX][mM][lL]"; 572 w->etext[GENX_DUPLICATE_ATTRIBUTE] = 573 "Same attribute specified more than once"; 574 w->etext[GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE] = 575 "Attribute cannot be in default namespace"; 576 w->etext[GENX_DUPLICATE_NAMESPACE] = 577 "Declared namespace twice with different prefixes on one element."; 578 w->etext[GENX_BAD_DEFAULT_DECLARATION] = 579 "Declared a default namespace on an element which is in no namespace"; 580 581 /* the xml: namespace is pre-wired */ 582 xml = genxDeclareNamespace(w, (utf8) "http://www.w3.org/XML/1998/namespace", 583 (utf8) "xml", &w->status); 584 if (xml == NULL) 585 return NULL; 586 xml->declCount = 1; 587 xml->declaration = xml->defaultDecl; 588 589 return w; 590 } 591 592 /* 593 * get/set userData 594 */ 595 void genxSetUserData(genxWriter w, void * userData) 596 { 597 w->userData = userData; 598 } 599 void * genxGetUserData(genxWriter w) 600 { 601 return w->userData; 602 } 603 604 /* 605 * get/set allocator 606 */ 607 void genxSetAlloc(genxWriter w, void * (* alloc)(void * userData, int bytes)) 608 { 609 w->alloc = alloc; 610 } 611 void genxSetDealloc(genxWriter w, 612 void (* dealloc)(void * userData, void * data)) 613 { 614 w->dealloc = dealloc; 615 } 616 void * (* genxGetAlloc(genxWriter w))(void * userData, int bytes) 617 { 618 return w->alloc; 619 } 620 void (* genxGetDealloc(genxWriter w))(void * userData, void * data) 621 { 622 return w->dealloc; 623 } 624 625 /* 626 * Clean up 627 */ 628 void genxDispose(genxWriter w) 629 { 630 int i; 631 genxNamespace * nn = (genxNamespace *) w->namespaces.pointers; 632 genxElement * ee = (genxElement *) w->elements.pointers; 633 genxAttribute * aa = (genxAttribute *) w->attributes.pointers; 634 utf8 * pp = (utf8 *) w->prefixes.pointers; 635 636 for (i = 0; i < w->namespaces.count; i++) 637 { 638 deallocate(w, nn[i]->name); 639 deallocate(w, nn[i]); 640 } 641 642 for (i = 0; i < w->elements.count; i++) 643 { 644 deallocate(w, ee[i]->type); 645 deallocate(w, ee[i]); 646 } 647 648 for (i = 0; i < w->attributes.count; i++) 649 { 650 deallocate(w, aa[i]->name); 651 deallocate(w, aa[i]->value.buf); 652 deallocate(w, aa[i]); 653 } 654 655 for(i = 0; i < w->prefixes.count; i++) 656 deallocate(w, pp[i]); 657 658 deallocate(w, w->namespaces.pointers); 659 deallocate(w, w->elements.pointers); 660 deallocate(w, w->attributes.pointers); 661 deallocate(w, w->prefixes.pointers); 662 deallocate(w, w->stack.pointers); 663 664 deallocate(w, w->arec.value.buf); 665 666 deallocate(w, w->empty); 667 668 /* how Oscar dealt with Igli */ 669 deallocate(w, w); 670 } 671 672 /******************************* 673 * External utility routines 674 */ 675 676 /* 677 * scan a buffer and report problems with UTF-8 encoding or non-XML characters 678 */ 679 genxStatus genxCheckText(genxWriter w, constUtf8 s) 680 { 681 while (*s) 682 { 683 int c = genxNextUnicodeChar(&s); 684 if (c == -1) 685 return GENX_BAD_UTF8; 686 687 if (!isXMLChar(w, c)) 688 return GENX_NON_XML_CHARACTER; 689 } 690 return GENX_SUCCESS; 691 } 692 693 /* 694 * Purify some text 695 */ 696 int genxScrubText(genxWriter w, constUtf8 in, utf8 out) 697 { 698 int problems = 0; 699 constUtf8 last = in; 700 701 while (*in) 702 { 703 int c = genxNextUnicodeChar(&in); 704 if (c == -1) 705 { 706 problems++; 707 last = in; 708 continue; 709 } 710 711 if (!isXMLChar(w, c)) 712 { 713 problems++; 714 last = in; 715 continue; 716 } 717 718 while (last < in) 719 *out++ = *last++; 720 } 721 *out = 0; 722 return problems; 723 } 724 725 /* 726 * check one character 727 */ 728 int genxCharClass(genxWriter w, int c) 729 { 730 int ret = 0; 731 732 if (isXMLChar(w, c)) 733 ret |= GENX_XML_CHAR; 734 if (isNameChar(w, c)) 735 ret |= GENX_NAMECHAR; 736 if (isLetter(w, c)) 737 ret |= GENX_LETTER; 738 return ret; 739 } 740 741 static genxStatus checkNCName(genxWriter w, constUtf8 name) 742 { 743 int c; 744 745 if (name == NULL || *name == 0) 746 return GENX_BAD_NAME; 747 748 c = genxNextUnicodeChar(&name); 749 if (!isLetter(w, c) && c != ':' && c != '_') 750 return GENX_BAD_NAME; 751 752 while (*name) 753 { 754 c = genxNextUnicodeChar(&name); 755 if (c == -1) 756 return GENX_BAD_UTF8; 757 if (!isNameChar(w, c)) 758 return GENX_BAD_NAME; 759 } 760 return GENX_SUCCESS; 761 } 762 763 char * genxGetErrorMessage(genxWriter w, genxStatus status) 764 { 765 return w->etext[status]; 766 } 767 char * genxLastErrorMessage(genxWriter w) 768 { 769 return w->etext[w->status]; 770 } 771 772 /******************************* 773 * Declarations: namespace/element/attribute 774 */ 775 776 /* 777 * DeclareNamespace - by far the most complex routine in Genx 778 */ 779 genxNamespace genxDeclareNamespace(genxWriter w, constUtf8 uri, 780 constUtf8 defaultPref, 781 genxStatus * statusP) 782 { 783 genxNamespace ns; 784 genxAttribute defaultDecl; 785 unsigned char newPrefix[100]; 786 787 if (uri == NULL || uri[0] == 0) 788 { 789 w->status = GENX_BAD_NAMESPACE_NAME; 790 goto busted; 791 } 792 793 if ((w->status = genxCheckText(w, uri)) != GENX_SUCCESS) 794 goto busted; 795 796 /* if a prefix is provided, it has to be an NCname */ 797 if (defaultPref != NULL && defaultPref[0] != 0 && 798 (w->status = checkNCName(w, defaultPref)) != GENX_SUCCESS) 799 goto busted; 800 801 /* previously declared? */ 802 if ((ns = findNamespace(&w->namespaces, uri))) 803 { 804 /* just a lookup, really */ 805 if ((defaultPref == NULL) || 806 (defaultPref[0] == 0 && ns->defaultDecl == w->xmlnsEquals) || 807 (strcmp((const char *) ns->defaultDecl->name + STRLEN_XMLNS_COLON, 808 (const char *) defaultPref) == 0)) 809 { 810 w->status = *statusP = GENX_SUCCESS; 811 return ns; 812 } 813 } 814 815 /* wasn't already declared */ 816 else 817 { 818 819 /* make a default prefix if none provided */ 820 if (defaultPref == NULL) 821 { 822 sprintf((char *) newPrefix, "g%d", w->nextPrefix++); 823 defaultPref = newPrefix; 824 } 825 826 ns = (genxNamespace) allocate(w, sizeof(struct genxNamespace_rec)); 827 if (ns == NULL) 828 { 829 w->status = GENX_ALLOC_FAILED; 830 goto busted; 831 } 832 ns->writer = w; 833 ns->baroque = False; 834 835 if ((ns->name = copy(w, uri)) == NULL) 836 { 837 w->status = GENX_ALLOC_FAILED; 838 goto busted; 839 } 840 841 if ((w->status = listAppend(&w->namespaces, ns)) != GENX_SUCCESS) 842 goto busted; 843 ns->defaultDecl = ns->declaration = NULL; 844 ns->declCount = 0; 845 } 846 847 if (defaultPref[0] == 0) 848 { 849 if (w->defaultNsDeclared) 850 { 851 w->status = GENX_DUPLICATE_PREFIX; 852 goto busted; 853 } 854 defaultDecl = w->xmlnsEquals; 855 w->defaultNsDeclared = True; 856 } 857 else 858 { 859 /* this catches dupes too */ 860 if ((defaultPref = storePrefix(w, defaultPref, False)) == NULL) 861 goto busted; 862 863 defaultDecl = declareAttribute(w, NULL, defaultPref, ns->name, statusP); 864 if (defaultDecl == NULL || *statusP != GENX_SUCCESS) 865 { 866 w->status = *statusP; 867 return NULL; 868 } 869 } 870 871 if (ns->defaultDecl != NULL && defaultDecl != ns->defaultDecl) 872 ns->baroque = True; 873 ns->defaultDecl = defaultDecl; 874 875 *statusP = GENX_SUCCESS; 876 return ns; 877 878 busted: 879 *statusP = w->status; 880 return NULL; 881 } 882 883 /* 884 * get namespace prefix 885 */ 886 utf8 genxGetNamespacePrefix(genxNamespace ns) 887 { 888 if (ns->declaration == NULL) 889 return NULL; 890 891 if (ns->declaration == ns->writer->xmlnsEquals) 892 return ns->writer->empty; 893 894 return ns->declaration->name + STRLEN_XMLNS_COLON; 895 } 896 897 /* 898 * DeclareElement - see genx.h for details 899 */ 900 genxElement genxDeclareElement(genxWriter w, 901 genxNamespace ns, constUtf8 type, 902 genxStatus * statusP) 903 { 904 genxElement old; 905 genxElement el; 906 907 if ((w->status = checkNCName(w, type)) != GENX_SUCCESS) 908 { 909 *statusP = w->status; 910 return NULL; 911 } 912 913 /* already declared? */ 914 old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, type); 915 if (old) 916 return old; 917 918 if ((el = (genxElement) allocate(w, sizeof(struct genxElement_rec))) == NULL) 919 { 920 w->status = *statusP = GENX_ALLOC_FAILED; 921 return NULL; 922 } 923 924 el->writer = w; 925 el->ns = ns; 926 if ((el->type = copy(w, type)) == NULL) 927 { 928 w->status = *statusP = GENX_ALLOC_FAILED; 929 return NULL; 930 } 931 932 if ((w->status = listAppend(&w->elements, el)) != GENX_SUCCESS) 933 { 934 *statusP = w->status; 935 return NULL; 936 } 937 938 *statusP = GENX_SUCCESS; 939 return el; 940 } 941 942 /* 943 * C14n ordering for attributes: 944 * - first, namespace declarations by the prefix being declared 945 * - second, unprefixed attributes by attr name 946 * - third, prefixed attrs by ns uri then local part 947 */ 948 static int orderAttributes(genxAttribute a1, genxAttribute a2) 949 { 950 if (a1->atype == a2->atype) 951 { 952 if (a1->atype == ATTR_PREFIXED && a1->ns != a2->ns) 953 return strcmp((const char *) a1->ns->name, (const char *) a2->ns->name); 954 else 955 return strcmp((const char *) a1->name, (const char *) a2->name); 956 } 957 958 else if (a1->atype == ATTR_NSDECL) 959 return -1; 960 961 else if (a1->atype == ATTR_NAKED) 962 { 963 if (a2->atype == ATTR_NSDECL) 964 return 1; 965 else 966 return -1; 967 } 968 969 else 970 return 1; 971 } 972 973 /* 974 * internal declare-attribute. This one allows colonized values for 975 * names, so that you can declare xmlns:-type attributes 976 */ 977 static genxAttribute declareAttribute(genxWriter w, genxNamespace ns, 978 constUtf8 name, constUtf8 valuestr, 979 genxStatus * statusP) 980 { 981 int high, low; 982 genxAttribute * aa = (genxAttribute *) w->attributes.pointers; 983 genxAttribute a; 984 985 w->arec.ns = ns; 986 w->arec.name = (utf8) name; 987 988 if (ns) 989 w->arec.atype = ATTR_PREFIXED; 990 else if (strncmp((const char *) name, "xmlns", STRLEN_XMLNS_COLON - 1) == 0) 991 w->arec.atype = ATTR_NSDECL; 992 else 993 w->arec.atype = ATTR_NAKED; 994 995 if (ns && (ns->defaultDecl == w->xmlnsEquals)) 996 { 997 w->status = GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE; 998 goto busted; 999 } 1000 1001 /* attribute list has to be kept sorted per c14n rules */ 1002 high = w->attributes.count; low = -1; 1003 while (high - low > 1) 1004 { 1005 int probe = (high + low) / 2; 1006 if (orderAttributes(&w->arec, aa[probe]) < 0) 1007 high = probe; 1008 else 1009 low = probe; 1010 } 1011 1012 /* if it was already there */ 1013 if (low != -1 && orderAttributes(&w->arec, aa[low]) == 0) 1014 return aa[low]; 1015 1016 /* not there, build it */ 1017 a = (genxAttribute) allocate(w, sizeof(struct genxAttribute_rec)); 1018 if (a == NULL) 1019 { 1020 w->status = GENX_ALLOC_FAILED; 1021 goto busted; 1022 } 1023 1024 a->writer = w; 1025 a->ns = ns; 1026 a->provided = False; 1027 a->atype = w->arec.atype; 1028 1029 if ((a->name = copy(w, name)) == NULL) 1030 { 1031 w->status = GENX_ALLOC_FAILED; 1032 goto busted; 1033 } 1034 1035 if ((w->status = initCollector(w, &a->value)) != GENX_SUCCESS) 1036 goto busted; 1037 1038 if (valuestr) 1039 if ((w->status = collectString(w, &a->value, valuestr)) != GENX_SUCCESS) 1040 goto busted; 1041 1042 w->status = listInsert(&w->attributes, a, high); 1043 if (w->status != GENX_SUCCESS) 1044 goto busted; 1045 1046 *statusP = GENX_SUCCESS; 1047 return a; 1048 1049 busted: 1050 *statusP = w->status; 1051 return NULL; 1052 } 1053 1054 /* 1055 * genxDeclareAttribute - see genx.h for details 1056 */ 1057 genxAttribute genxDeclareAttribute(genxWriter w, 1058 genxNamespace ns, constUtf8 name, 1059 genxStatus * statusP) 1060 { 1061 if ((w->status = checkNCName(w, name)) != GENX_SUCCESS) 1062 { 1063 *statusP = w->status; 1064 return NULL; 1065 } 1066 1067 return declareAttribute(w, ns, name, NULL, statusP); 1068 } 1069 1070 /******************************* 1071 * I/O 1072 */ 1073 static genxStatus sendx(genxWriter w, constUtf8 s) 1074 { 1075 if (w->sender) 1076 return (*w->sender->send)(w->userData, s); 1077 else 1078 { 1079 if (fputs((const char *) s, w->file) == -1) 1080 return GENX_IO_ERROR; 1081 else 1082 return GENX_SUCCESS; 1083 } 1084 } 1085 1086 static genxStatus sendxBounded(genxWriter w, constUtf8 start, constUtf8 end) 1087 { 1088 if (w->sender) 1089 return (*w->sender->sendBounded)(w->userData, start, end); 1090 else 1091 if (fwrite(start, 1, end - start, w->file) != (unsigned) (end - start)) 1092 return GENX_IO_ERROR; 1093 else 1094 return GENX_SUCCESS; 1095 } 1096 1097 #define SendCheck(w,s) if ((w->status=sendx(w,(utf8)s))!=GENX_SUCCESS) return w->status; 1098 1099 /******************************* 1100 * XML writing routines. The semantics of the externally-facing ones are 1101 * written up in genx.h. Commentary here is implementation notes and 1102 * for internal routines. 1103 */ 1104 1105 /* 1106 * Start a document 1107 */ 1108 genxStatus genxStartDocFile(genxWriter w, FILE * file) 1109 { 1110 if (w->sequence != SEQUENCE_NO_DOC) 1111 return w->status = GENX_SEQUENCE_ERROR; 1112 1113 w->sequence = SEQUENCE_PRE_DOC; 1114 w->file = file; 1115 w->sender = NULL; 1116 return GENX_SUCCESS; 1117 } 1118 1119 genxStatus genxStartDocSender(genxWriter w, genxSender * sender) 1120 { 1121 if (w->sequence != SEQUENCE_NO_DOC) 1122 return w->status = GENX_SEQUENCE_ERROR; 1123 1124 w->sequence = SEQUENCE_PRE_DOC; 1125 w->file = NULL; 1126 w->sender = sender; 1127 return GENX_SUCCESS; 1128 } 1129 1130 /* 1131 * Write out the attributes we've been gathering up for an element. We save 1132 * them until we've gathered them all so they can be writen in canonical 1133 * order. 1134 * Also, we end the start-tag. 1135 * The trick here is that we keep the attribute list properly sorted as 1136 * we build it, then as each attribute is added, we fill in its value and 1137 * mark the fact that it's been added, in the "provided" field. 1138 */ 1139 static genxStatus writeStartTag(genxWriter w) 1140 { 1141 int i; 1142 genxAttribute * aa = (genxAttribute *) w->attributes.pointers; 1143 genxElement e = w->nowStarting; 1144 1145 /* 1146 * make sure the right namespace decls are in effect; 1147 * if they are these might create an error, so ignore it 1148 */ 1149 if (e->ns) 1150 addNamespace(e->ns, NULL); 1151 else 1152 unsetDefaultNamespace(w); 1153 w->status = GENX_SUCCESS; 1154 1155 SendCheck(w, "<"); 1156 if (e->ns && (e->ns->declaration != w->xmlnsEquals)) 1157 { 1158 SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON); 1159 SendCheck(w, ":"); 1160 } 1161 SendCheck(w, e->type); 1162 1163 for (i = 0; i < w->attributes.count; i++) 1164 { 1165 if (aa[i]->provided) 1166 { 1167 if (aa[i]->ns && aa[i]->ns->baroque && 1168 aa[i]->ns->declaration == w->xmlnsEquals) 1169 return w->status = GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE; 1170 1171 SendCheck(w, " "); 1172 1173 if (aa[i]->ns) 1174 { 1175 SendCheck(w, aa[i]->ns->declaration->name + STRLEN_XMLNS_COLON) 1176 SendCheck(w, ":"); 1177 } 1178 SendCheck(w, aa[i]->name); 1179 SendCheck(w, "=\""); 1180 SendCheck(w, aa[i]->value.buf); 1181 SendCheck(w, "\""); 1182 } 1183 } 1184 SendCheck(w, ">"); 1185 return GENX_SUCCESS; 1186 } 1187 1188 /* 1189 * internal clear-er; no sequence checking 1190 */ 1191 static genxStatus unsetDefaultNamespace(genxWriter w) 1192 { 1193 int i; 1194 Boolean found = False; 1195 1196 /* don't put it in if not needed */ 1197 i = w->stack.count - 1; 1198 while (found == False && i > 0) 1199 { 1200 while (w->stack.pointers[i] != NULL) 1201 { 1202 genxAttribute decl = (genxAttribute) w->stack.pointers[i--]; 1203 genxNamespace ns = (genxNamespace) w->stack.pointers[i--]; 1204 1205 /* if already unset */ 1206 if (ns == NULL) 1207 return w->status = GENX_SUCCESS; 1208 1209 /* 1210 * the default namespace was declared. This namespace now 1211 * becomes baroque 1212 */ 1213 if (decl == w->xmlnsEquals) 1214 { 1215 ns->baroque = True; 1216 found = True; 1217 break; 1218 } 1219 } 1220 i -= 2; 1221 } 1222 1223 if (!found) 1224 return GENX_SUCCESS; 1225 1226 /* 1227 * push a signal on the stack 1228 */ 1229 if ((w->status = listAppend(&w->stack, NULL)) != GENX_SUCCESS) 1230 return w->status; 1231 w->status = listAppend(&w->stack, w->xmlnsEquals); 1232 if (w->status != GENX_SUCCESS) 1233 return w->status; 1234 1235 /* add the xmlns= attribute, it must be the first one */ 1236 return addAttribute(w->xmlnsEquals, w->empty); 1237 } 1238 1239 /* 1240 * clear the default namespace declaration 1241 */ 1242 genxStatus genxUnsetDefaultNamespace(genxWriter w) 1243 { 1244 1245 /* can only do this while in start-tag mode */ 1246 if (w->sequence != SEQUENCE_START_TAG) 1247 return w->status = GENX_SEQUENCE_ERROR; 1248 1249 return unsetDefaultNamespace(w); 1250 } 1251 1252 genxStatus genxStartElement(genxElement e) 1253 { 1254 genxWriter w = e->writer; 1255 int i; 1256 1257 switch (w->sequence) 1258 { 1259 case SEQUENCE_NO_DOC: 1260 case SEQUENCE_POST_DOC: 1261 return w->status = GENX_SEQUENCE_ERROR; 1262 case SEQUENCE_START_TAG: 1263 case SEQUENCE_ATTRIBUTES: 1264 if ((w->status = writeStartTag(w)) != GENX_SUCCESS) 1265 return w->status; 1266 break; 1267 case SEQUENCE_PRE_DOC: 1268 case SEQUENCE_CONTENT: 1269 break; 1270 } 1271 1272 w->sequence = SEQUENCE_START_TAG; 1273 1274 /* clear provided attributes */ 1275 for (i = 0; i < w->attributes.count; i++) 1276 ((genxAttribute) w->attributes.pointers[i])->provided = 0; 1277 1278 /* 1279 * push the stack. We push a NULL after a pointer to this element 1280 * because the stack will also contain pointers to the namespace 1281 * attributes that got declared here, so we can keep track of what's 1282 * in effect. I.e. a single stack entry consists logically of a pointer 1283 * to an element object, a NULL, then zero or more pairs of pointers to 1284 * namespace objects/declarations 1285 */ 1286 if ((w->status = listAppend(&w->stack, e)) != GENX_SUCCESS) 1287 return w->status; 1288 if ((w->status = listAppend(&w->stack, NULL)) != GENX_SUCCESS) 1289 return w->status; 1290 1291 w->nowStarting = e; 1292 1293 return GENX_SUCCESS; 1294 } 1295 1296 /* 1297 * internal namespace adder; no sequence checking 1298 */ 1299 static genxStatus addNamespace(genxNamespace ns, utf8 prefix) 1300 { 1301 genxWriter w = ns->writer; 1302 genxAttribute decl; 1303 int i; 1304 genxElement e; 1305 1306 /* 1307 * first, we'll find the declaring attribute 1308 */ 1309 if (prefix == NULL) 1310 decl = ns->defaultDecl; 1311 else 1312 { 1313 if (prefix[0] == 0) 1314 decl = w->xmlnsEquals; 1315 else 1316 { 1317 if ((prefix = storePrefix(w, prefix, True)) == NULL) 1318 return w->status; 1319 decl = declareAttribute(w, NULL, prefix, ns->name, &w->status); 1320 if (decl == NULL || w->status != GENX_SUCCESS) 1321 return w->status; 1322 } 1323 } 1324 1325 if (decl != ns->defaultDecl) 1326 ns->baroque = True; 1327 1328 /* 1329 * avoid doing anything if this namespace is already declared. If 1330 * they've shown good taste we can do this cheaply 1331 */ 1332 if (!ns->baroque) 1333 { 1334 if (ns->declCount > 0) 1335 return w->status = GENX_SUCCESS; 1336 } 1337 else 1338 { 1339 1340 /* 1341 * First, we'll run all the way up the stack to see if there is 1342 * another declaration for this namespace/prefix in scope, in which 1343 * case it's a no-op; or, if there's another declaration for this 1344 * prefix on another namespace, in which case we have to over-ride 1345 */ 1346 i = w->stack.count - 1; 1347 while (i > 0) 1348 { 1349 while (w->stack.pointers[i] != NULL) 1350 { 1351 genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--]; 1352 genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--]; 1353 1354 if (ns == otherNs) 1355 { 1356 if (decl == otherDecl) 1357 return w->status = GENX_SUCCESS; 1358 else 1359 { 1360 i = 0; 1361 break; 1362 } 1363 } 1364 else 1365 { 1366 /* different namespace, same prefix? */ 1367 if (decl == otherDecl) 1368 { 1369 i = 0; 1370 break; 1371 } 1372 } 1373 } 1374 i -= 2; 1375 } 1376 } 1377 1378 /* 1379 * If this namespace is already declared on 1380 * this element (with different prefix/decl) which is an error. 1381 */ 1382 i = w->stack.count - 1; 1383 while (w->stack.pointers[i] != NULL) 1384 { 1385 genxNamespace otherNs; 1386 i--; /* don't need declaration */ 1387 otherNs = (genxNamespace) w->stack.pointers[i--]; 1388 1389 if (ns == otherNs) 1390 return w->status = GENX_DUPLICATE_NAMESPACE; 1391 } 1392 1393 /* move pointer from NULL to element */ 1394 --i; 1395 1396 /* 1397 * It's also an error if this is a default-namespace declaration and the 1398 * element is in no namespace. 1399 */ 1400 e = (genxElement) w->stack.pointers[i]; 1401 if (e->ns == NULL && decl == w->xmlnsEquals) 1402 return w->status = GENX_BAD_DEFAULT_DECLARATION; 1403 1404 if ((w->status = listAppend(&w->stack, ns)) != GENX_SUCCESS) 1405 return w->status; 1406 if ((w->status = listAppend(&w->stack, decl)) != GENX_SUCCESS) 1407 return w->status; 1408 1409 ns->declaration = decl; 1410 ns->declCount++; 1411 return addAttribute(decl, ns->name); 1412 } 1413 1414 /* 1415 * Add a namespace declaration 1416 */ 1417 genxStatus genxAddNamespace(genxNamespace ns, utf8 prefix) 1418 { 1419 if (ns->writer->sequence != SEQUENCE_START_TAG) 1420 return ns->writer->status = GENX_SEQUENCE_ERROR; 1421 1422 return addNamespace(ns, prefix); 1423 } 1424 1425 /* 1426 * Private attribute-adding code 1427 * most of the work here is normalizing the value, which is the same 1428 * as regular normalization except for " is replaced by """ 1429 */ 1430 static genxStatus addAttribute(genxAttribute a, constUtf8 valuestr) 1431 { 1432 utf8 lastv = (utf8) valuestr; 1433 genxWriter w = a->writer; 1434 1435 /* if valuestr not provided, this is an xmlns with a pre-cooked value */ 1436 if (valuestr) 1437 { 1438 startCollect(&a->value); 1439 while (*valuestr) 1440 { 1441 int c = genxNextUnicodeChar(&valuestr); 1442 1443 if (c == -1) 1444 return w->status = GENX_BAD_UTF8; 1445 1446 if (!isXMLChar(w, c)) 1447 return w->status = GENX_NON_XML_CHARACTER; 1448 1449 switch(c) 1450 { 1451 case 9: 1452 collectPiece(w, &a->value, "	", 5); 1453 break; 1454 case 0xa: 1455 collectPiece(w, &a->value, "
", 5); 1456 break; 1457 case 0xd: 1458 collectPiece(w, &a->value, "
", 5); 1459 break; 1460 case '"': 1461 collectPiece(w, &a->value, """, 6); 1462 break; 1463 case '<': 1464 collectPiece(w, &a->value, "<", 4); 1465 break; 1466 case '&': 1467 collectPiece(w, &a->value, "&", 5); 1468 break; 1469 /* 1470 case '>': 1471 collectPiece(w, &a->value, ">", 4); 1472 break; 1473 */ 1474 default: 1475 collectPiece(w, &a->value, (const char *) lastv, valuestr - lastv); 1476 break; 1477 } 1478 lastv = (utf8) valuestr; 1479 } 1480 endCollect(&a->value); 1481 } 1482 1483 /* now add the namespace attribute; might fail if it's bee hand-declared */ 1484 if (a->ns) 1485 addNamespace(a->ns, NULL); 1486 1487 if (valuestr && a->provided) 1488 return w->status = GENX_DUPLICATE_ATTRIBUTE; 1489 a->provided = 1; 1490 1491 return GENX_SUCCESS; 1492 } 1493 1494 /* 1495 * public attribute adder. 1496 * The only difference is that it doesn't allow a NULL value 1497 */ 1498 genxStatus genxAddAttribute(genxAttribute a, constUtf8 valuestr) 1499 { 1500 if (a->writer->sequence != SEQUENCE_START_TAG && 1501 a->writer->sequence != SEQUENCE_ATTRIBUTES) 1502 return a->writer->status = GENX_SEQUENCE_ERROR; 1503 a->writer->sequence = SEQUENCE_ATTRIBUTES; 1504 1505 if (valuestr == NULL) 1506 return a->writer->status = GENX_MISSING_VALUE; 1507 1508 return addAttribute(a, valuestr); 1509 } 1510 1511 genxStatus genxEndElement(genxWriter w) 1512 { 1513 genxElement e; 1514 int i; 1515 1516 switch (w->sequence) 1517 { 1518 case SEQUENCE_NO_DOC: 1519 case SEQUENCE_PRE_DOC: 1520 case SEQUENCE_POST_DOC: 1521 return w->status = GENX_SEQUENCE_ERROR; 1522 case SEQUENCE_START_TAG: 1523 case SEQUENCE_ATTRIBUTES: 1524 if ((w->status = writeStartTag(w)) != GENX_SUCCESS) 1525 return w->status; 1526 break; 1527 case SEQUENCE_CONTENT: 1528 break; 1529 } 1530 1531 /* 1532 * first peek into the stack to find the right namespace declaration 1533 * (if any) so we can properly prefix the end-tag. Have to do this 1534 * before unwinding the stack because that might reset some xmlns 1535 * prefixes to the context in the parent element 1536 */ 1537 for (i = w->stack.count - 1; w->stack.pointers[i] != NULL; i -= 2) 1538 ; 1539 e = (genxElement) w->stack.pointers[--i]; 1540 1541 SendCheck(w, "</"); 1542 if (e->ns && e->ns->declaration != w->xmlnsEquals) 1543 { 1544 SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON); 1545 SendCheck(w, ":"); 1546 } 1547 SendCheck(w, e->type); 1548 SendCheck(w, ">"); 1549 1550 /* 1551 * pop zero or more namespace declarations, then a null, then the 1552 * start-element declaration off the stack 1553 */ 1554 w->stack.count--; 1555 while (w->stack.pointers[w->stack.count] != NULL) 1556 { 1557 genxNamespace ns = (genxNamespace) w->stack.pointers[--w->stack.count]; 1558 w->stack.count--; /* don't need decl */ 1559 1560 /* if not a fake unset-default namespace */ 1561 if (ns) 1562 { 1563 /* 1564 * if they've stupidly jammed in their own namespace-prefix 1565 * declarations, we have to go looking to see if there's another 1566 * one in effect 1567 */ 1568 if (ns->baroque) 1569 { 1570 i = w->stack.count; 1571 while (i > 0) 1572 { 1573 while (w->stack.pointers[i] != NULL) 1574 { 1575 genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--]; 1576 genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--]; 1577 1578 if (otherNs == ns) 1579 { 1580 ns->declaration = otherDecl; 1581 i = 0; 1582 break; 1583 } 1584 } 1585 1586 /* skip NULL & element */ 1587 i -= 2; 1588 } 1589 } 1590 ns->declCount--; 1591 if (ns->declCount == 0) 1592 ns->baroque = False; 1593 } 1594 } 1595 1596 /* pop the NULL */ 1597 --w->stack.count; 1598 if (w->stack.count < 0) 1599 return w->status = GENX_NO_START_TAG; 1600 1601 if (w->stack.count == 0) 1602 w->sequence = SEQUENCE_POST_DOC; 1603 else 1604 w->sequence = SEQUENCE_CONTENT; 1605 1606 return GENX_SUCCESS; 1607 } 1608 1609 /* 1610 * Internal character-adder. It tries to keep the number of sendx() 1611 * calls down by looking at each character but only doing the output 1612 * when it has to escape something; ordinary text gets saved up in 1613 * chunks the start of which is indicated by *breaker. 1614 * c is the character, next points to the UTF8 representing the next 1615 * lastsP indirectly points to the UTF8 representing the 1616 * character, breakerP* indirectly points to the last place genx 1617 * changed the UTF8, e.g. by escaping a '<' 1618 */ 1619 static genxStatus addChar(genxWriter w, int c, constUtf8 next, 1620 constUtf8 * lastsP, constUtf8 * breakerP) 1621 { 1622 if (c == -1) 1623 return GENX_BAD_UTF8; 1624 1625 if (!isXMLChar(w, c)) 1626 return GENX_NON_XML_CHARACTER; 1627 1628 switch(c) 1629 { 1630 case 0xd: 1631 if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) 1632 return w->status; 1633 *breakerP = next; 1634 sendx(w, (utf8) "
"); 1635 break; 1636 case '<': 1637 if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) 1638 return w->status; 1639 *breakerP = next; 1640 sendx(w, (utf8) "<"); 1641 break; 1642 case '&': 1643 if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) 1644 return w->status; 1645 *breakerP = next; 1646 sendx(w, (utf8) "&"); 1647 break; 1648 case '>': 1649 if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS) 1650 return w->status; 1651 *breakerP = next; 1652 sendx(w, (utf8) ">"); 1653 break; 1654 default: 1655 break; 1656 } 1657 *lastsP = next; 1658 return GENX_SUCCESS; 1659 } 1660 1661 genxStatus genxAddText(genxWriter w, constUtf8 start) 1662 { 1663 constUtf8 lasts = start; 1664 constUtf8 breaker = start; 1665 1666 if (w->sequence == SEQUENCE_START_TAG || 1667 w->sequence == SEQUENCE_ATTRIBUTES) 1668 { 1669 if ((w->status = writeStartTag(w)) != GENX_SUCCESS) 1670 return w->status; 1671 w->sequence = SEQUENCE_CONTENT; 1672 } 1673 1674 if (w->sequence != SEQUENCE_CONTENT) 1675 return w->status = GENX_SEQUENCE_ERROR; 1676 1677 while (*start) 1678 { 1679 int c = genxNextUnicodeChar(&start); 1680 1681 w->status = addChar(w, c, start, &lasts, &breaker); 1682 if (w->status != GENX_SUCCESS) 1683 return w->status; 1684 } 1685 return sendxBounded(w, breaker, (utf8) start); 1686 } 1687 1688 genxStatus genxAddBoundedText(genxWriter w, constUtf8 start, constUtf8 end) 1689 { 1690 constUtf8 lasts = start; 1691 constUtf8 breaker = start; 1692 1693 if (w->sequence == SEQUENCE_START_TAG || 1694 w->sequence == SEQUENCE_ATTRIBUTES) 1695 { 1696 if ((w->status = writeStartTag(w)) != GENX_SUCCESS) 1697 return w->status; 1698 w->sequence = SEQUENCE_CONTENT; 1699 } 1700 1701 if (w->sequence != SEQUENCE_CONTENT) 1702 return w->status = GENX_SEQUENCE_ERROR; 1703 1704 while (start < end) 1705 { 1706 int c = genxNextUnicodeChar(&start); 1707 1708 w->status = addChar(w, c, (utf8) start, &lasts, &breaker); 1709 if (w->status != GENX_SUCCESS) 1710 return w->status; 1711 } 1712 return sendxBounded(w, breaker, (utf8) start); 1713 } 1714 1715 genxStatus genxAddCountedText(genxWriter w, constUtf8 start, int byteCount) 1716 { 1717 utf8 end = (utf8) (start + byteCount); 1718 1719 return genxAddBoundedText(w, start, end); 1720 } 1721 1722 genxStatus genxAddCharacter(genxWriter w, int c) 1723 { 1724 unsigned char cUTF8[10]; 1725 utf8 lasts, breaker, next; 1726 1727 if (w->sequence == SEQUENCE_START_TAG || 1728 w->sequence == SEQUENCE_ATTRIBUTES) 1729 { 1730 if ((w->status = writeStartTag(w)) != GENX_SUCCESS) 1731 return w->status; 1732 w->sequence = SEQUENCE_CONTENT; 1733 } 1734 1735 if (w->sequence != SEQUENCE_CONTENT) 1736 return w->status = GENX_SEQUENCE_ERROR; 1737 1738 if (!isXMLChar(w, c)) 1739 return w->status = GENX_NON_XML_CHARACTER; 1740 1741 /* make UTF8 representation of character */ 1742 lasts = breaker = next = cUTF8; 1743 1744 if (c < 0x80) 1745 *next++ = c; 1746 else if (c < 0x800) 1747 { 1748 *next++ = 0xc0 | (c >> 6); 1749 *next++ = 0x80 | (c & 0x3f); 1750 } 1751 else if (c < 0x10000) 1752 { 1753 *next++ = 0xe0 | (c >> 12); 1754 *next++ = 0x80 | ((c & 0xfc0) >> 6); 1755 *next++ = 0x80 | (c & 0x3f); 1756 } 1757 else 1758 { 1759 *next++ = 0xf0 | (c >> 18); 1760 *next++ = 0x80 | ((c & 0x3f000) >> 12); 1761 *next++ = 0x80 | ((c & 0xfc0) >> 6); 1762 *next++ = 0x80 | (c & 0x3f); 1763 } 1764 *next = 0; 1765 1766 w->status = 1767 addChar(w, c, next, (constUtf8 *) &lasts, (constUtf8 *) &breaker); 1768 if (w->status != GENX_SUCCESS) 1769 return w->status; 1770 1771 return sendxBounded(w, breaker, next); 1772 } 1773 1774 genxStatus genxEndDocument(genxWriter w) 1775 { 1776 if (w->sequence != SEQUENCE_POST_DOC) 1777 return w->status = GENX_SEQUENCE_ERROR; 1778 1779 if (w->file) 1780 fflush(w->file); 1781 else 1782 if ((w->status = (*w->sender->flush)(w->userData)) != GENX_SUCCESS) 1783 return w->status; 1784 1785 w->sequence = SEQUENCE_NO_DOC; 1786 return GENX_SUCCESS; 1787 } 1788 1789 genxStatus genxComment(genxWriter w, constUtf8 text) 1790 { 1791 int i; 1792 1793 if (w->sequence == SEQUENCE_NO_DOC) 1794 return w->status = GENX_SEQUENCE_ERROR; 1795 1796 if ((w->status = genxCheckText(w, text)) != GENX_SUCCESS) 1797 return w->status; 1798 1799 /* no leading '-', no trailing '-', no '--' */ 1800 if (text[0] == '-') 1801 return w->status = GENX_MALFORMED_COMMENT; 1802 for (i = 0; text[i]; i++) 1803 if (text[i] == '-' && (text[i + 1] == '-' || text[i + 1] == 0)) 1804 return w->status = GENX_MALFORMED_COMMENT; 1805 1806 if (w->sequence == SEQUENCE_START_TAG || 1807 w->sequence == SEQUENCE_ATTRIBUTES) 1808 { 1809 if ((w->status = writeStartTag(w)) != GENX_SUCCESS) 1810 return w->status; 1811 w->sequence = SEQUENCE_CONTENT; 1812 } 1813 1814 else if (w->sequence == SEQUENCE_POST_DOC) 1815 if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) 1816 return w->status; 1817 1818 if ((w->status = sendx(w, (utf8) "<!--")) != GENX_SUCCESS) 1819 return w->status; 1820 if ((w->status = sendx(w, (utf8) text)) != GENX_SUCCESS) 1821 return w->status; 1822 if ((w->status = sendx(w, (utf8) "-->")) != GENX_SUCCESS) 1823 return w->status; 1824 1825 if (w->sequence == SEQUENCE_PRE_DOC) 1826 if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) 1827 return w->status; 1828 1829 return GENX_SUCCESS; 1830 } 1831 1832 genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text) 1833 { 1834 int i; 1835 1836 if (w->sequence == SEQUENCE_NO_DOC) 1837 return w->status = GENX_SEQUENCE_ERROR; 1838 1839 if ((w->status = genxCheckText(w, target)) != GENX_SUCCESS) 1840 return w->status; 1841 if ((w->status = checkNCName(w, target)) != GENX_SUCCESS) 1842 return w->status; 1843 if ((strlen((const char *) target) >= 3) && 1844 (target[0] == 'x' || target[0] == 'X') && 1845 (target[1] == 'm' || target[1] == 'M') && 1846 (target[2] == 'l' || target[2] == 'L') && 1847 (target[3] == 0)) 1848 return w->status = GENX_XML_PI_TARGET; 1849 1850 if ((w->status = genxCheckText(w, text)) != GENX_SUCCESS) 1851 return w->status; 1852 1853 /* no ?> within */ 1854 for (i = 1; text[i]; i++) 1855 if (text[i] == '>' && text[i - 1] == '?') 1856 return w->status = GENX_MALFORMED_PI; 1857 1858 if (w->sequence == SEQUENCE_START_TAG || 1859 w->sequence == SEQUENCE_ATTRIBUTES) 1860 { 1861 if ((w->status = writeStartTag(w)) != GENX_SUCCESS) 1862 return w->status; 1863 w->sequence = SEQUENCE_CONTENT; 1864 } 1865 1866 else if (w->sequence == SEQUENCE_POST_DOC) 1867 if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) 1868 return w->status; 1869 1870 if ((w->status = sendx(w, (utf8) "<?")) != GENX_SUCCESS) 1871 return w->status; 1872 if ((w->status = sendx(w, target)) != GENX_SUCCESS) 1873 return w->status; 1874 if (text[0]) 1875 { 1876 if ((w->status = sendx(w, (utf8) " ")) != GENX_SUCCESS) 1877 return w->status; 1878 if ((w->status = sendx(w, text)) != GENX_SUCCESS) 1879 return w->status; 1880 } 1881 if ((w->status = sendx(w, (utf8) "?>")) != GENX_SUCCESS) 1882 return w->status; 1883 1884 if (w->sequence == SEQUENCE_PRE_DOC) 1885 if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS) 1886 return w->status; 1887 1888 return GENX_SUCCESS; 1889 } 1890 1891 /******************************* 1892 * Literal versions of the writing routines 1893 */ 1894 genxStatus genxStartElementLiteral(genxWriter w, 1895 constUtf8 xmlns, constUtf8 type) 1896 { 1897 genxNamespace ns = NULL; 1898 genxElement e; 1899 1900 if (xmlns) 1901 { 1902 ns = genxDeclareNamespace(w, xmlns, NULL, &w->status); 1903 if (ns == NULL || w->status != GENX_SUCCESS) 1904 return w->status; 1905 } 1906 e = genxDeclareElement(w, ns, type, &w->status); 1907 if (e == NULL || w->status != GENX_SUCCESS) 1908 return w->status; 1909 1910 return genxStartElement(e); 1911 } 1912 1913 genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns, 1914 constUtf8 name, constUtf8 value) 1915 { 1916 genxNamespace ns = NULL; 1917 genxAttribute a; 1918 1919 if (xmlns) 1920 { 1921 ns = genxDeclareNamespace(w, xmlns, NULL, &w->status); 1922 if (ns == NULL && w->status != GENX_SUCCESS) 1923 return w->status; 1924 } 1925 1926 a = genxDeclareAttribute(w, ns, name, &w->status); 1927 if (a == NULL || w->status != GENX_SUCCESS) 1928 return w->status; 1929 1930 return genxAddAttribute(a, value); 1931 } 1932 1933 /* 1934 * return version 1935 */ 1936 char * genxGetVersion() 1937 { 1938 return GENX_VERSION; 1939 } 1940