1 /* 2 * xml.c 3 * Copyright (C) 2002,2003 A.J. van Os; Released under GNU GPL 4 * 5 * Description: 6 * Functions to deal with the XML/DocBook format 7 * 8 */ 9 10 #include <string.h> 11 #include "antiword.h" 12 13 14 #define vAddEndTagsUntil1(p,t) vAddEndTagsUntil2(p,t,TAG_NOTAG) 15 16 #if defined(DEBUG) 17 #define vStackTrace() __vStackTrace(__LINE__) 18 #else 19 #define vStackTrace() /* EMPTY */ 20 #endif /* DEBUG */ 21 22 /* Text is emphasised */ 23 static BOOL bEmphasisOpen = FALSE; 24 /* Text is superscript */ 25 static BOOL bSuperscriptOpen = FALSE; 26 /* Text is subscript */ 27 static BOOL bSubscriptOpen = FALSE; 28 /* Title is open */ 29 static BOOL bTitleOpen = FALSE; 30 /* Table is open */ 31 static BOOL bTableOpen = FALSE; 32 /* Current paragraph level */ 33 static UINT uiParagraphLevel = 0; 34 /* Current list level */ 35 static UINT uiListLevel = 0; 36 /* Current list level is still empty */ 37 static BOOL bEmptyListLevel = TRUE; 38 /* Current header level */ 39 static USHORT usHeaderLevelCurrent = 0; 40 /* Current header level is still empty */ 41 static BOOL bEmptyHeaderLevel = TRUE; 42 /* Number of columns in the current table */ 43 static int iTableColumnsCurrent = 0; 44 45 /* Constants for the stack */ 46 #define INITIAL_STACK_SIZE 10 47 #if defined(DEBUG) 48 #define EXTENSION_STACK_SIZE 2 49 #else 50 #define EXTENSION_STACK_SIZE 10 51 #endif /* DEBUG */ 52 53 /* Variables for the stack */ 54 static UCHAR *aucStack = NULL; 55 static size_t tStacksize = 0; 56 static size_t tStackNextFree = 0; 57 58 /* Constants for the tags */ 59 #define TAG_NOTAG (UCHAR)0 60 #define TAG_AUTHOR (UCHAR)1 61 #define TAG_BEGINPAGE (UCHAR)2 62 #define TAG_BOOK (UCHAR)3 63 #define TAG_BOOKINFO (UCHAR)4 64 #define TAG_CHAPTER (UCHAR)5 65 #define TAG_COLSPEC (UCHAR)6 66 #define TAG_CORPNAME (UCHAR)7 67 #define TAG_DATE (UCHAR)8 68 #define TAG_EMPHASIS (UCHAR)9 69 #define TAG_ENTRY (UCHAR)10 70 #define TAG_FILENAME (UCHAR)11 71 #define TAG_INFORMALTABLE (UCHAR)12 72 #define TAG_ITEMIZEDLIST (UCHAR)13 73 #define TAG_LISTITEM (UCHAR)14 74 #define TAG_ORDEREDLIST (UCHAR)15 75 #define TAG_PARA (UCHAR)16 76 #define TAG_ROW (UCHAR)17 77 #define TAG_SECT1 (UCHAR)18 78 #define TAG_SECT2 (UCHAR)19 79 #define TAG_SECT3 (UCHAR)20 80 #define TAG_SECT4 (UCHAR)21 81 #define TAG_SECT5 (UCHAR)22 82 #define TAG_SUBSCRIPT (UCHAR)23 83 #define TAG_SUBTITLE (UCHAR)24 84 #define TAG_SUPERSCRIPT (UCHAR)25 85 #define TAG_SURNAME (UCHAR)26 86 #define TAG_TBODY (UCHAR)27 87 #define TAG_TGROUP (UCHAR)28 88 #define TAG_TITLE (UCHAR)29 89 90 typedef struct docbooktags_tag { 91 UCHAR ucTagnumber; 92 char szTagname[15]; 93 BOOL bAddNewline; 94 } docbooktags_type; 95 96 static const docbooktags_type atDocBookTags[] = { 97 { TAG_NOTAG, "!ERROR!", TRUE }, 98 { TAG_AUTHOR, "author", TRUE }, 99 { TAG_BEGINPAGE, "beginpage", TRUE }, 100 { TAG_BOOK, "book", TRUE }, 101 { TAG_BOOKINFO, "bookinfo", TRUE }, 102 { TAG_CHAPTER, "chapter", TRUE }, 103 { TAG_COLSPEC, "colspec", TRUE }, 104 { TAG_CORPNAME, "corpname", FALSE }, 105 { TAG_DATE, "date", FALSE }, 106 { TAG_EMPHASIS, "emphasis", FALSE }, 107 { TAG_ENTRY, "entry", TRUE }, 108 { TAG_FILENAME, "filename", FALSE }, 109 { TAG_INFORMALTABLE, "informaltable",TRUE }, 110 { TAG_ITEMIZEDLIST, "itemizedlist", TRUE }, 111 { TAG_LISTITEM, "listitem", TRUE }, 112 { TAG_ORDEREDLIST, "orderedlist", TRUE }, 113 { TAG_PARA, "para", TRUE }, 114 { TAG_ROW, "row", TRUE }, 115 { TAG_SECT1, "sect1", TRUE }, 116 { TAG_SECT2, "sect2", TRUE }, 117 { TAG_SECT3, "sect3", TRUE }, 118 { TAG_SECT4, "sect4", TRUE }, 119 { TAG_SECT5, "sect5", TRUE }, 120 { TAG_SUBSCRIPT, "subscript", FALSE }, 121 { TAG_SUBTITLE, "subtitle", FALSE }, 122 { TAG_SUPERSCRIPT, "superscript", FALSE }, 123 { TAG_SURNAME, "surname", FALSE }, 124 { TAG_TBODY, "tbody", TRUE }, 125 { TAG_TGROUP, "tgroup", TRUE }, 126 { TAG_TITLE, "title", FALSE }, 127 }; 128 129 130 #if defined(DEBUG) 131 /* 132 * vCheckTagTable - check the tag table 133 */ 134 static void 135 vCheckTagTable(void) 136 { 137 size_t tIndex; 138 139 for (tIndex = 0; tIndex < elementsof(atDocBookTags); tIndex++) { 140 if (tIndex != (size_t)atDocBookTags[tIndex].ucTagnumber) { 141 DBG_DEC(tIndex); 142 werr(1, "Array atDocBookTags is broken"); 143 } 144 } 145 } /* end of vCheckTagTable */ 146 147 /* 148 * __vStackTrace - show a stack trace 149 */ 150 static void 151 __vStackTrace(int iLine) 152 { 153 int iIndex; 154 155 fprintf(stderr, "%s[%3d]:\n", __FILE__, iLine); 156 157 if (tStackNextFree == 0) { 158 fprintf(stderr, "The stack is empty\n"); 159 return; 160 } 161 for (iIndex = (int)tStackNextFree - 1; iIndex >= 0; iIndex--) { 162 fprintf(stderr, "%2d: %2d: '%s'\n", 163 iIndex, 164 (int)atDocBookTags[(UINT)aucStack[iIndex]].ucTagnumber, 165 atDocBookTags[(UINT)aucStack[iIndex]].szTagname); 166 } 167 } /* end of __vStackTrace */ 168 #endif /* DEBUG */ 169 170 /* 171 * vPushStack - push a tag onto the stack 172 */ 173 static void 174 vPushStack(UCHAR ucTag) 175 { 176 fail(tStackNextFree > tStacksize); 177 178 if (tStackNextFree == tStacksize) { 179 /* The stack is full; enlarge the stack */ 180 tStacksize += EXTENSION_STACK_SIZE; 181 aucStack = xrealloc(aucStack, tStacksize * sizeof(UCHAR)); 182 DBG_DEC(tStacksize); 183 } 184 185 fail(tStackNextFree >= tStacksize); 186 187 aucStack[tStackNextFree++] = ucTag; 188 } /* end of vPushStack */ 189 190 /* 191 * vPopStack - pop a tag from the stack 192 */ 193 static UCHAR 194 ucPopStack(void) 195 { 196 DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree); 197 DBG_DEC_C(tStackNextFree > tStacksize, tStacksize); 198 fail(tStackNextFree > tStacksize); 199 fail(tStackNextFree == 0); 200 201 if (tStackNextFree == 0) { 202 werr(1, "The stack is empty, unable to continue"); 203 return TAG_NOTAG; 204 } 205 return aucStack[--tStackNextFree]; 206 } /* end of ucPopStack */ 207 208 /* 209 * vReadStack - read a tag from the top of the stack 210 */ 211 static UCHAR 212 ucReadStack(void) 213 { 214 DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree); 215 DBG_DEC_C(tStackNextFree > tStacksize, tStacksize); 216 fail(tStackNextFree > tStacksize); 217 218 if (tStackNextFree == 0) { 219 /* The stack is empty */ 220 return TAG_NOTAG; 221 } 222 return aucStack[tStackNextFree - 1]; 223 } /* end of ucReadStack */ 224 225 /* 226 * vPrintLevel - print the tag level 227 */ 228 static void 229 vPrintLevel(FILE *pOutFile) 230 { 231 size_t tIndex; 232 233 fail(pOutFile == NULL); 234 235 for (tIndex = 0; tIndex < tStackNextFree; tIndex++) { 236 (void)putc(' ', pOutFile); 237 } 238 } /* end of vPrintLevel */ 239 240 /* 241 * vPrintChar - print a character with XML encoding 242 */ 243 static void 244 vPrintChar(FILE *pOutFile, char cChar) 245 { 246 switch (cChar) { 247 case '<': 248 fprintf(pOutFile, "%s", "<"); 249 break; 250 case '>': 251 fprintf(pOutFile, "%s", ">"); 252 break; 253 case '&': 254 fprintf(pOutFile, "%s", "&"); 255 break; 256 default: 257 (void)putc(cChar, pOutFile); 258 break; 259 } 260 } /* end of vPrintChar */ 261 262 /* 263 * vPrintSpecial 264 */ 265 static void 266 vPrintSpecial(FILE *pOutFile, const char *szString, 267 int iWordVersion, encoding_type eEncoding) 268 { 269 ULONG ulChar; 270 size_t tLen, tIndex; 271 int iIndex; 272 BOOL bOldMacFile; 273 USHORT usChar; 274 char szResult[4]; 275 276 fail(pOutFile == NULL); 277 fail(szString == NULL); 278 279 bOldMacFile = bIsOldMacFile(); 280 281 for (iIndex = 0; szString[iIndex] != '\0'; iIndex++) { 282 usChar = (USHORT)(UCHAR)szString[iIndex]; 283 ulChar = ulTranslateCharacters(usChar, 0, iWordVersion, 284 conversion_xml, eEncoding, bOldMacFile); 285 tLen = tUcs2Utf8(ulChar, szResult, sizeof(szResult)); 286 if (tLen == 1) { 287 vPrintChar(pOutFile, szResult[0]); 288 } else { 289 for (tIndex = 0; tIndex < tLen; tIndex++) { 290 (void)putc(szResult[tIndex], pOutFile); 291 } 292 } 293 } 294 } /* end of vPrintSpecial */ 295 296 /* 297 * vAddStartTag - add the specified start tag to the file 298 */ 299 static void 300 vAddStartTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute) 301 { 302 fail(pDiag == NULL); 303 fail(pDiag->pOutFile == NULL); 304 fail((size_t)ucTag >= elementsof(atDocBookTags)); 305 306 if (atDocBookTags[(UINT)ucTag].bAddNewline) { 307 fprintf(pDiag->pOutFile, "\n"); 308 vPrintLevel(pDiag->pOutFile); 309 } 310 311 if (szAttribute == NULL || szAttribute[0] == '\0') { 312 fprintf(pDiag->pOutFile, "<%s>", 313 atDocBookTags[(UINT)ucTag].szTagname); 314 } else { 315 fprintf(pDiag->pOutFile, "<%s %s>", 316 atDocBookTags[(UINT)ucTag].szTagname, szAttribute); 317 } 318 319 if (atDocBookTags[(UINT)ucTag].bAddNewline) { 320 fprintf(pDiag->pOutFile, "\n"); 321 pDiag->lXleft = 0; 322 } 323 324 vPushStack(ucTag); 325 326 /* Set global variables */ 327 switch (ucTag) { 328 case TAG_CHAPTER: 329 usHeaderLevelCurrent = 1; 330 bEmptyHeaderLevel = TRUE; 331 break; 332 case TAG_SECT1: 333 usHeaderLevelCurrent = 2; 334 bEmptyHeaderLevel = TRUE; 335 break; 336 case TAG_SECT2: 337 usHeaderLevelCurrent = 3; 338 bEmptyHeaderLevel = TRUE; 339 break; 340 case TAG_SECT3: 341 usHeaderLevelCurrent = 4; 342 bEmptyHeaderLevel = TRUE; 343 break; 344 case TAG_SECT4: 345 usHeaderLevelCurrent = 5; 346 bEmptyHeaderLevel = TRUE; 347 break; 348 case TAG_SECT5: 349 usHeaderLevelCurrent = 6; 350 bEmptyHeaderLevel = TRUE; 351 break; 352 case TAG_TITLE: 353 fail(uiParagraphLevel != 0); 354 bTitleOpen = TRUE; 355 break; 356 case TAG_PARA: 357 fail(bTitleOpen); 358 uiParagraphLevel++; 359 bEmptyHeaderLevel = FALSE; 360 break; 361 case TAG_EMPHASIS: 362 bEmphasisOpen = TRUE; 363 break; 364 case TAG_ITEMIZEDLIST: 365 case TAG_ORDEREDLIST: 366 uiListLevel++; 367 bEmptyListLevel = TRUE; 368 bEmptyHeaderLevel = FALSE; 369 break; 370 case TAG_LISTITEM: 371 bEmptyListLevel = FALSE; 372 break; 373 case TAG_SUPERSCRIPT: 374 bSuperscriptOpen = TRUE; 375 break; 376 case TAG_SUBSCRIPT: 377 bSubscriptOpen = TRUE; 378 break; 379 case TAG_INFORMALTABLE: 380 bTableOpen = TRUE; 381 bEmptyHeaderLevel = FALSE; 382 break; 383 default: 384 break; 385 } 386 } /* end of vAddStartTag */ 387 388 /* 389 * vAddEndTag - add the specified end tag to the file 390 */ 391 static void 392 vAddEndTag(diagram_type *pDiag, UCHAR ucTag) 393 { 394 UCHAR ucTopTag; 395 396 fail(pDiag == NULL); 397 fail(pDiag->pOutFile == NULL); 398 fail((size_t)ucTag >= elementsof(atDocBookTags)); 399 400 #if defined(DEBUG) 401 ucTopTag = ucReadStack(); 402 if (ucTag != ucTopTag) { 403 DBG_DEC(ucTag); 404 DBG_MSG(atDocBookTags[(UINT)ucTag].szTagname); 405 vStackTrace(); 406 } 407 #endif /* DEBUG */ 408 409 ucTopTag = ucPopStack(); 410 fail((size_t)ucTopTag >= elementsof(atDocBookTags)); 411 if (ucTag != ucTopTag) { 412 DBG_DEC(ucTag); 413 DBG_DEC(ucTopTag); 414 DBG_FIXME(); 415 werr(1, "Impossible tag sequence, unable to continue"); 416 } 417 418 if (atDocBookTags[(UINT)ucTag].bAddNewline) { 419 fprintf(pDiag->pOutFile, "\n"); 420 vPrintLevel(pDiag->pOutFile); 421 } 422 423 fprintf(pDiag->pOutFile, "</%s>", atDocBookTags[(UINT)ucTag].szTagname); 424 425 if (atDocBookTags[(UINT)ucTag].bAddNewline) { 426 fprintf(pDiag->pOutFile, "\n"); 427 pDiag->lXleft = 0; 428 } 429 430 /* Set global variables */ 431 switch (ucTag) { 432 case TAG_CHAPTER: 433 usHeaderLevelCurrent = 0; 434 break; 435 case TAG_SECT1: 436 usHeaderLevelCurrent = 1; 437 break; 438 case TAG_SECT2: 439 usHeaderLevelCurrent = 2; 440 break; 441 case TAG_SECT3: 442 usHeaderLevelCurrent = 3; 443 break; 444 case TAG_SECT4: 445 usHeaderLevelCurrent = 4; 446 break; 447 case TAG_SECT5: 448 usHeaderLevelCurrent = 5; 449 break; 450 case TAG_TITLE: 451 bTitleOpen = FALSE; 452 break; 453 case TAG_PARA: 454 uiParagraphLevel--; 455 break; 456 case TAG_EMPHASIS: 457 bEmphasisOpen = FALSE; 458 break; 459 case TAG_SUPERSCRIPT: 460 bSuperscriptOpen = FALSE; 461 break; 462 case TAG_ITEMIZEDLIST: 463 case TAG_ORDEREDLIST: 464 uiListLevel--; 465 break; 466 case TAG_SUBSCRIPT: 467 bSubscriptOpen = FALSE; 468 break; 469 case TAG_INFORMALTABLE: 470 bTableOpen = FALSE; 471 iTableColumnsCurrent = 0; 472 break; 473 default: 474 break; 475 } 476 } /* end of vAddEndTag */ 477 478 /* 479 * vAddEndTagOptional - add the specified end tag to the file if needed 480 */ 481 static void 482 vAddEndTagOptional(diagram_type *pDiag, UCHAR ucTag) 483 { 484 UCHAR ucTopTag; 485 486 ucTopTag = ucReadStack(); 487 if (ucTag == ucTopTag) { 488 vAddEndTag(pDiag, ucTag); 489 } 490 } /* end of vAddEndTagOptional */ 491 492 /* 493 * vAddCombinedTag - add the specified start and end tag to the file 494 */ 495 static void 496 vAddCombinedTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute) 497 { 498 fail(pDiag == NULL); 499 fail(pDiag->pOutFile == NULL); 500 fail((size_t)ucTag >= elementsof(atDocBookTags)); 501 502 if (atDocBookTags[(UINT)ucTag].bAddNewline) { 503 fprintf(pDiag->pOutFile, "\n"); 504 vPrintLevel(pDiag->pOutFile); 505 } 506 507 if (szAttribute == NULL || szAttribute[0] == '\0') { 508 fprintf(pDiag->pOutFile, "<%s/>", 509 atDocBookTags[(UINT)ucTag].szTagname); 510 } else { 511 fprintf(pDiag->pOutFile, "<%s %s/>", 512 atDocBookTags[(UINT)ucTag].szTagname, szAttribute); 513 } 514 515 if (atDocBookTags[(UINT)ucTag].bAddNewline) { 516 fprintf(pDiag->pOutFile, "\n"); 517 pDiag->lXleft = 0; 518 } 519 } /* end of vAddCombinedTag */ 520 521 /* 522 * vAddEndTagsUntil2 - add end tags until one the specified tags is seen 523 */ 524 static void 525 vAddEndTagsUntil2(diagram_type *pDiag, UCHAR ucTag1, UCHAR ucTag2) 526 { 527 UCHAR ucTopTag; 528 529 do { 530 ucTopTag = ucReadStack(); 531 switch (ucTopTag) { 532 case TAG_CHAPTER: 533 case TAG_SECT1: 534 case TAG_SECT2: 535 case TAG_SECT3: 536 case TAG_SECT4: 537 case TAG_SECT5: 538 if (bEmptyHeaderLevel) { 539 /* 540 * An empty chapter is legal in Word, 541 * but not in DocBook. 542 */ 543 vAddCombinedTag(pDiag, TAG_PARA, NULL); 544 bEmptyHeaderLevel = FALSE; 545 } 546 break; 547 case TAG_ITEMIZEDLIST: 548 case TAG_ORDEREDLIST: 549 if (bEmptyListLevel) { 550 /* 551 * A list without items is legal in Word, 552 * but not in DocBook. (Nor are empty items) 553 */ 554 vAddStartTag(pDiag, TAG_LISTITEM, NULL); 555 vAddCombinedTag(pDiag, TAG_PARA, NULL); 556 vAddEndTag(pDiag, TAG_LISTITEM); 557 bEmptyListLevel = FALSE; 558 } 559 break; 560 default: 561 break; 562 } 563 vAddEndTag(pDiag, ucTopTag); 564 } while (ucTopTag != ucTag1 && ucTopTag != ucTag2); 565 } /* end of vAddEndTagsUntil2 */ 566 567 /* 568 * vCreateBookIntro - create title and bookinfo 569 */ 570 void 571 vCreateBookIntro(diagram_type *pDiag, int iWordVersion, encoding_type eEncoding) 572 { 573 const char *szTitle, *szSubject, *szAuthor; 574 const char *szLastSaveDtm, *szCompany; 575 const char *szLanguage; 576 char szTmp[13]; 577 578 fail(pDiag == NULL); 579 fail(pDiag->pOutFile == NULL); 580 fail(iWordVersion < 0); 581 fail(eEncoding == encoding_neutral); 582 583 szTitle = szGetTitle(); 584 szSubject = szGetSubject(); 585 szAuthor = szGetAuthor(); 586 szLastSaveDtm = szGetLastSaveDtm(); 587 szCompany = szGetCompany(); 588 589 /* Start Book */ 590 szLanguage = szGetLanguage(); 591 if (szLanguage != NULL) { 592 DBG_MSG(szLanguage); 593 sprintf(szTmp, "lang='%.5s'", szLanguage); 594 szLanguage = szTmp; 595 } 596 vAddStartTag(pDiag, TAG_BOOK, szLanguage); 597 598 /* Book title */ 599 if (szTitle != NULL && szTitle[0] != '\0') { 600 vAddStartTag(pDiag, TAG_TITLE, NULL); 601 vPrintSpecial(pDiag->pOutFile, 602 szTitle, iWordVersion, eEncoding); 603 vAddEndTag(pDiag, TAG_TITLE); 604 } 605 /* Bookinfo */ 606 if ((szTitle != NULL && szTitle[0] != '\0') || 607 (szSubject != NULL && szSubject[0] != '\0') || 608 (szAuthor != NULL && szAuthor[0] != '\0') || 609 (szLastSaveDtm != NULL && szLastSaveDtm[0] != '\0') || 610 (szCompany != NULL && szCompany[0] != '\0')) { 611 vAddStartTag(pDiag, TAG_BOOKINFO, NULL); 612 if (szTitle != NULL && szTitle[0] != '\0') { 613 vAddStartTag(pDiag, TAG_TITLE, NULL); 614 vPrintSpecial(pDiag->pOutFile, 615 szTitle, iWordVersion, eEncoding); 616 vAddEndTag(pDiag, TAG_TITLE); 617 } 618 if (szSubject != NULL && szSubject[0] != '\0') { 619 vAddStartTag(pDiag, TAG_SUBTITLE, NULL); 620 vPrintSpecial(pDiag->pOutFile, 621 szSubject, iWordVersion, eEncoding); 622 vAddEndTag(pDiag, TAG_SUBTITLE); 623 } 624 if (szAuthor != NULL && szAuthor[0] != '\0') { 625 vAddStartTag(pDiag, TAG_AUTHOR, NULL); 626 vAddStartTag(pDiag, TAG_SURNAME, NULL); 627 vPrintSpecial(pDiag->pOutFile, 628 szAuthor, iWordVersion, eEncoding); 629 vAddEndTag(pDiag, TAG_SURNAME); 630 vAddEndTag(pDiag, TAG_AUTHOR); 631 } 632 if (szLastSaveDtm != NULL && szLastSaveDtm[0] != '\0') { 633 vAddStartTag(pDiag, TAG_DATE, NULL); 634 vPrintSpecial(pDiag->pOutFile, 635 szLastSaveDtm, iWordVersion, eEncoding); 636 vAddEndTag(pDiag, TAG_DATE); 637 } 638 if (szCompany != NULL && szCompany[0] != '\0') { 639 vAddStartTag(pDiag, TAG_CORPNAME, NULL); 640 vPrintSpecial(pDiag->pOutFile, 641 szCompany, iWordVersion, eEncoding); 642 vAddEndTag(pDiag, TAG_CORPNAME); 643 } 644 vAddEndTag(pDiag, TAG_BOOKINFO); 645 } 646 } /* end of vCreateBookIntro */ 647 648 /* 649 * vPrologueXML - perform the XML initialization 650 */ 651 void 652 vPrologueXML(diagram_type *pDiag) 653 { 654 655 fail(pDiag == NULL); 656 fail(pDiag->pOutFile == NULL); 657 658 #if defined(DEBUG) 659 vCheckTagTable(); 660 #endif /* DEBUG */ 661 662 /* Set global variables to their start values */ 663 bEmphasisOpen = FALSE; 664 bSuperscriptOpen = FALSE; 665 bSubscriptOpen = FALSE; 666 bTitleOpen = FALSE; 667 bTableOpen = FALSE; 668 uiParagraphLevel = 0; 669 uiListLevel = 0; 670 bEmptyListLevel = TRUE; 671 usHeaderLevelCurrent = 0; 672 bEmptyHeaderLevel = TRUE; 673 iTableColumnsCurrent = 0; 674 675 pDiag->lXleft = 0; 676 pDiag->lYtop = 0; 677 678 /* Create an empty stack */ 679 tStacksize = INITIAL_STACK_SIZE; 680 aucStack = xcalloc(tStacksize, sizeof(UCHAR)); 681 tStackNextFree = 0; 682 } /* end of vPrologueXML */ 683 684 /* 685 * vEpilogueXML - clean up after everything is done 686 */ 687 void 688 vEpilogueXML(diagram_type *pDiag) 689 { 690 vStackTrace(); 691 692 vAddEndTagsUntil1(pDiag, TAG_BOOK); 693 694 vStackTrace(); 695 696 /* Destroy the stack */ 697 fail(tStackNextFree != 0); 698 tStacksize = 0; 699 aucStack = xfree(aucStack); 700 tStackNextFree = 0; 701 } /* end of vEpilogueXML */ 702 703 /* 704 * vPrintXML - print a XML string 705 */ 706 static void 707 vPrintXML(diagram_type *pDiag, const char *szString, size_t tStringLength, 708 USHORT usFontstyle) 709 { 710 int iCount; 711 size_t tNextFree; 712 BOOL bNotReady, bEmphasisNew, bSuperscriptNew, bSubscriptNew; 713 UCHAR ucTopTag, aucStorage[3]; 714 715 fail(szString == NULL); 716 717 if (szString == NULL || szString[0] == '\0' || tStringLength == 0) { 718 return; 719 } 720 721 bEmphasisNew = bIsBold(usFontstyle) || 722 bIsItalic(usFontstyle) || 723 bIsUnderline(usFontstyle) || 724 bIsStrike(usFontstyle); 725 bSuperscriptNew = bIsSuperscript(usFontstyle); 726 bSubscriptNew = bIsSubscript(usFontstyle); 727 728 /* End what has to be ended (or more to keep the stack happy) */ 729 tNextFree = 0; 730 bNotReady = TRUE; 731 do { 732 ucTopTag = ucReadStack(); 733 switch (ucTopTag) { 734 case TAG_EMPHASIS: 735 fail(!bEmphasisOpen); 736 if (bEmphasisNew) { 737 aucStorage[tNextFree++] = ucTopTag; 738 } 739 vAddEndTag(pDiag, ucTopTag); 740 break; 741 case TAG_SUPERSCRIPT: 742 fail(!bSuperscriptOpen); 743 if (bSuperscriptNew) { 744 aucStorage[tNextFree++] = ucTopTag; 745 } 746 vAddEndTag(pDiag, ucTopTag); 747 break; 748 case TAG_SUBSCRIPT: 749 fail(!bSubscriptOpen); 750 if (bSubscriptNew) { 751 aucStorage[tNextFree++] = ucTopTag; 752 } 753 vAddEndTag(pDiag, ucTopTag); 754 break; 755 default: 756 bNotReady = FALSE; 757 break; 758 } 759 fail(tNextFree > elementsof(aucStorage)); 760 fail(bNotReady && tNextFree == elementsof(aucStorage)); 761 } while (bNotReady); 762 763 /* Just te make sure */ 764 vStartOfParagraphXML(pDiag, 1); 765 766 /* Restart to keep the stack happy */ 767 for (iCount = (int)tNextFree - 1; iCount > 0; iCount--) { 768 vAddStartTag(pDiag, aucStorage[iCount], NULL); 769 } 770 771 /* Start what has to be started */ 772 if (bEmphasisNew && !bEmphasisOpen) { 773 vAddStartTag(pDiag, TAG_EMPHASIS, NULL); 774 } 775 if (bSuperscriptNew && !bSuperscriptOpen) { 776 vAddStartTag(pDiag, TAG_SUPERSCRIPT, NULL); 777 } 778 if (bSubscriptNew && !bSubscriptOpen) { 779 vAddStartTag(pDiag, TAG_SUBSCRIPT, NULL); 780 } 781 782 /* The print the string */ 783 for (iCount = 0; iCount < (int)tStringLength; iCount++) { 784 vPrintChar(pDiag->pOutFile, szString[iCount]); 785 } 786 } /* end of vPrintXML */ 787 788 /* 789 * vMove2NextLineXML - move to the next line 790 */ 791 void 792 vMove2NextLineXML(diagram_type *pDiag) 793 { 794 fail(pDiag == NULL); 795 796 if (uiParagraphLevel != 0) { 797 vEndOfParagraphXML(pDiag, INT_MAX); 798 vStartOfParagraphXML(pDiag, INT_MAX); 799 } 800 } /* end of vMove2NextLineXML */ 801 802 /* 803 * vSubstringXML - put a sub string into a diagram 804 */ 805 void 806 vSubstringXML(diagram_type *pDiag, 807 const char *szString, size_t tStringLength, long lStringWidth, 808 USHORT usFontstyle) 809 { 810 fail(pDiag == NULL || szString == NULL); 811 fail(pDiag->pOutFile == NULL); 812 fail(pDiag->lXleft < 0); 813 fail(tStringLength != strlen(szString)); 814 815 if (szString[0] == '\0' || tStringLength == 0) { 816 return; 817 } 818 819 vPrintXML(pDiag, szString, tStringLength, usFontstyle); 820 pDiag->lXleft += lStringWidth; 821 } /* end of vSubstringXML */ 822 823 /* 824 * Create an start of a paragraph 825 * Only works on paragraph level one, because Word doesn't allow paragraphs 826 * in paragraphs. Other paragraph levels result from DocBooks special needs. 827 */ 828 void 829 vStartOfParagraphXML(diagram_type *pDiag, int iMaxLevel) 830 { 831 fail(pDiag == NULL); 832 833 if (uiParagraphLevel >= (UINT)iMaxLevel || bTitleOpen) { 834 /* To Word titles are just paragraphs */ 835 return; 836 } 837 if (uiListLevel != 0 && bEmptyListLevel) { 838 /* No paragraphs in a list before the first listitem */ 839 return; 840 } 841 if (usHeaderLevelCurrent == 0) { 842 /* No paragraphs without an open header */ 843 vAddStartTag(pDiag, TAG_CHAPTER, NULL); 844 /* Dummy title */ 845 vAddCombinedTag(pDiag, TAG_TITLE, NULL); 846 } 847 vAddStartTag(pDiag, TAG_PARA, NULL); 848 } /* end of vStartOfParagraphXML */ 849 850 /* 851 * Create an end of a paragraph 852 * Only for paragraph level one and for titles 853 */ 854 void 855 vEndOfParagraphXML(diagram_type *pDiag, int iMaxLevel) 856 { 857 UCHAR ucTopTag; 858 859 fail(pDiag == NULL); 860 861 if (uiParagraphLevel > (UINT)iMaxLevel) { 862 DBG_DEC(uiParagraphLevel); 863 return; 864 } 865 866 for(;;) { 867 ucTopTag = ucReadStack(); 868 switch (ucTopTag) { 869 case TAG_EMPHASIS: 870 fail(!bEmphasisOpen); 871 vAddEndTag(pDiag, TAG_EMPHASIS); 872 break; 873 case TAG_SUPERSCRIPT: 874 fail(!bSuperscriptOpen); 875 vAddEndTag(pDiag, TAG_SUPERSCRIPT); 876 break; 877 case TAG_SUBSCRIPT: 878 fail(!bSubscriptOpen); 879 vAddEndTag(pDiag, TAG_SUBSCRIPT); 880 break; 881 case TAG_TITLE: 882 fail(!bTitleOpen); 883 vAddEndTag(pDiag, TAG_TITLE); 884 return; 885 case TAG_PARA: 886 fail(uiParagraphLevel == 0); 887 vAddEndTag(pDiag, TAG_PARA); 888 return; 889 case TAG_TBODY: 890 case TAG_TGROUP: 891 case TAG_INFORMALTABLE: 892 fail(!bTableOpen); 893 vAddEndTag(pDiag, ucTopTag); 894 break; 895 case TAG_NOTAG: 896 DBG_FIXME(); 897 werr(1, "Impossible tag sequence, unable to continue"); 898 break; 899 default: 900 DBG_DEC(ucTopTag); 901 DBG_MSG_C((size_t)ucTopTag < elementsof(atDocBookTags), 902 atDocBookTags[(UINT)ucTopTag].szTagname); 903 return; 904 } 905 } 906 } /* end of vEndOfParagraphXML */ 907 908 /* 909 * Create an end of a page 910 */ 911 void 912 vEndOfPageXML(diagram_type *pDiag) 913 { 914 if (bTableOpen || usHeaderLevelCurrent == 0) { 915 /* No beginpage in a table or outside a chapter */ 916 return; 917 } 918 if (bTitleOpen) { 919 /* A beginpage is not allowed when in a title */ 920 /* So start a new paragraph */ 921 vEndOfParagraphXML(pDiag, INT_MAX); 922 vStartOfParagraphXML(pDiag, INT_MAX); 923 return; 924 } 925 vAddCombinedTag(pDiag, TAG_BEGINPAGE, NULL); 926 } /* end of vEndOfPageXML */ 927 928 /* 929 * vCloseHeaderLevels - close the specified header levels 930 */ 931 static void 932 vCloseHeaderLevels(diagram_type *pDiag, USHORT usIstd) 933 { 934 BOOL bNotReady; 935 UCHAR ucTopTag; 936 937 DBG_MSG("vCloseHeaderLevels"); 938 DBG_DEC(usIstd); 939 DBG_DEC(usHeaderLevelCurrent); 940 941 vStackTrace(); 942 943 bNotReady = TRUE; 944 do { 945 ucTopTag = ucReadStack(); 946 switch (ucTopTag) { 947 case TAG_TITLE: 948 case TAG_PARA: 949 vAddEndTag(pDiag, ucTopTag); 950 break; 951 default: 952 bNotReady = FALSE; 953 break; 954 } 955 } while (bNotReady); 956 957 vStackTrace(); 958 959 while (usHeaderLevelCurrent >= usIstd) { 960 if (bEmptyHeaderLevel) { 961 vAddCombinedTag(pDiag, TAG_PARA, NULL); 962 bEmptyHeaderLevel = FALSE; 963 } 964 switch (usHeaderLevelCurrent) { 965 case 1: vAddEndTag(pDiag, TAG_CHAPTER); break; 966 case 2: vAddEndTag(pDiag, TAG_SECT1); break; 967 case 3: vAddEndTag(pDiag, TAG_SECT2); break; 968 case 4: vAddEndTag(pDiag, TAG_SECT3); break; 969 case 5: vAddEndTag(pDiag, TAG_SECT4); break; 970 case 6: vAddEndTag(pDiag, TAG_SECT5); break; 971 default: 972 DBG_DEC(usHeaderLevelCurrent); 973 DBG_FIXME(); 974 return; 975 } 976 } 977 978 DBG_DEC(usHeaderLevelCurrent); 979 980 vStackTrace(); 981 } /* end of vCloseHeaderLevels */ 982 983 /* 984 * vSetHeadersXML - set the headers 985 */ 986 void 987 vSetHeadersXML(diagram_type *pDiag, USHORT usIstd) 988 { 989 fail(pDiag == NULL); 990 991 if (usIstd == 0 || usIstd > 6) { 992 DBG_DEC_C(usIstd != 0 && usIstd <= 9, usIstd); 993 return; 994 } 995 DBG_DEC(usIstd); 996 997 if (bTableOpen || uiListLevel != 0) { 998 /* No headers when you're in a table or in a list */ 999 return; 1000 } 1001 1002 /* Close levels */ 1003 vCloseHeaderLevels(pDiag, usIstd); 1004 1005 DBG_DEC(usHeaderLevelCurrent); 1006 1007 /* Open levels */ 1008 while (usHeaderLevelCurrent < usIstd) { 1009 switch (usHeaderLevelCurrent) { 1010 case 0: vAddStartTag(pDiag, TAG_CHAPTER, NULL); break; 1011 case 1: vAddStartTag(pDiag, TAG_SECT1, NULL); break; 1012 case 2: vAddStartTag(pDiag, TAG_SECT2, NULL); break; 1013 case 3: vAddStartTag(pDiag, TAG_SECT3, NULL); break; 1014 case 4: vAddStartTag(pDiag, TAG_SECT4, NULL); break; 1015 case 5: vAddStartTag(pDiag, TAG_SECT5, NULL); break; 1016 default: 1017 DBG_DEC(usHeaderLevelCurrent); 1018 DBG_FIXME(); 1019 return; 1020 } 1021 fail(usIstd == 0); 1022 /* The next paragraph should be a title */ 1023 if (usHeaderLevelCurrent < usIstd) { 1024 /* This chapter level is not in the Word document */ 1025 vAddCombinedTag(pDiag, TAG_TITLE, NULL); 1026 } else { 1027 vAddStartTag(pDiag, TAG_TITLE, NULL); 1028 } 1029 } 1030 } /* end of vSetHeadersXML */ 1031 1032 /* 1033 * Create a start of a list 1034 */ 1035 void 1036 vStartOfListXML(diagram_type *pDiag, UCHAR ucNFC, BOOL bIsEndOfTable) 1037 { 1038 const char *szAttr; 1039 UCHAR ucTag; 1040 1041 fail(pDiag == NULL); 1042 1043 if (bIsEndOfTable) { 1044 /* FIXME: until a list in a table is allowed */ 1045 vEndOfTableXML(pDiag); 1046 } 1047 1048 if (bTableOpen) { 1049 /* FIXME: a list in a table should be allowed */ 1050 return; 1051 } 1052 1053 if (usHeaderLevelCurrent == 0) { 1054 /* No list without an open header */ 1055 vAddStartTag(pDiag, TAG_CHAPTER, NULL); 1056 /* Dummy title */ 1057 vAddCombinedTag(pDiag, TAG_TITLE, NULL); 1058 } 1059 1060 switch (ucNFC) { 1061 case LIST_ARABIC_NUM: 1062 case LIST_ORDINAL_NUM: 1063 ucTag = TAG_ORDEREDLIST; 1064 szAttr = "numeration='arabic'"; 1065 break; 1066 case LIST_UPPER_ROMAN: 1067 ucTag = TAG_ORDEREDLIST; 1068 szAttr = "numeration='upperroman'"; 1069 break; 1070 case LIST_LOWER_ROMAN: 1071 ucTag = TAG_ORDEREDLIST; 1072 szAttr = "numeration='lowerroman'"; 1073 break; 1074 case LIST_UPPER_ALPHA: 1075 ucTag = TAG_ORDEREDLIST; 1076 szAttr = "numeration='upperalpha'"; 1077 break; 1078 case LIST_LOWER_ALPHA: 1079 ucTag = TAG_ORDEREDLIST; 1080 szAttr = "numeration='loweralpha'"; 1081 break; 1082 case LIST_SPECIAL: 1083 case LIST_BULLETS: 1084 ucTag = TAG_ITEMIZEDLIST; 1085 szAttr = "mark='bullet'"; 1086 break; 1087 default: 1088 ucTag = TAG_ORDEREDLIST; 1089 szAttr = "numeration='arabic'"; 1090 DBG_DEC(ucNFC); 1091 DBG_FIXME(); 1092 break; 1093 } 1094 vAddStartTag(pDiag, ucTag, szAttr); 1095 } /* end of vStartOfListXML */ 1096 1097 /* 1098 * Create an end of a list 1099 */ 1100 void 1101 vEndOfListXML(diagram_type *pDiag) 1102 { 1103 fail(pDiag == NULL); 1104 1105 if (bTableOpen) { 1106 /* FIXME: a list in a table should be allowed */ 1107 return; 1108 } 1109 1110 if (uiListLevel != 0) { 1111 vStackTrace(); 1112 vAddEndTagsUntil2(pDiag, TAG_ITEMIZEDLIST, TAG_ORDEREDLIST); 1113 vStackTrace(); 1114 } 1115 } /* end of vEndOfListXML */ 1116 1117 /* 1118 * Create a start of a list item 1119 */ 1120 void 1121 vStartOfListItemXML(diagram_type *pDiag, BOOL bNoMarks) 1122 { 1123 const char *szAttr; 1124 UCHAR ucTopTag; 1125 1126 fail(pDiag == NULL); 1127 1128 if (bTableOpen) { 1129 /* FIXME: a list in a table should be allowed */ 1130 return; 1131 } 1132 1133 ucTopTag = ucReadStack(); 1134 if (ucTopTag != TAG_ITEMIZEDLIST && ucTopTag != TAG_ORDEREDLIST) { 1135 /* Must end a previous list item first */ 1136 vAddEndTagsUntil1(pDiag, TAG_LISTITEM); 1137 } 1138 1139 DBG_DEC_C(ucReadStack() != TAG_ITEMIZEDLIST && 1140 ucReadStack() != TAG_ORDEREDLIST, ucReadStack()); 1141 1142 /* Start a new list item */ 1143 szAttr = bNoMarks ? "override='none'" : NULL; 1144 vAddStartTag(pDiag, TAG_LISTITEM, szAttr); 1145 /* Start a new paragraph (independant of level) */ 1146 vAddStartTag(pDiag, TAG_PARA, NULL); 1147 } /* end of vStartOfListItemXML */ 1148 1149 /* 1150 * Create a start of a table 1151 */ 1152 static void 1153 vStartOfTable(diagram_type *pDiag, UCHAR ucBorderInfo) 1154 { 1155 const char *szFrame; 1156 BOOL bNotReady; 1157 UCHAR ucTopTag; 1158 char cColSep, cRowSep; 1159 char szAttr[40]; 1160 1161 fail(pDiag == NULL); 1162 1163 /* Close elements that cannot contain a table */ 1164 bNotReady = TRUE; 1165 do { 1166 ucTopTag = ucReadStack(); 1167 switch (ucTopTag) { 1168 case TAG_TITLE: 1169 fail(!bTitleOpen); 1170 vAddEndTag(pDiag, TAG_TITLE); 1171 break; 1172 case TAG_EMPHASIS: 1173 fail(!bEmphasisOpen); 1174 vAddEndTag(pDiag, TAG_EMPHASIS); 1175 break; 1176 case TAG_SUPERSCRIPT: 1177 fail(!bSuperscriptOpen); 1178 vAddEndTag(pDiag, TAG_SUPERSCRIPT); 1179 break; 1180 case TAG_SUBSCRIPT: 1181 fail(!bSubscriptOpen); 1182 vAddEndTag(pDiag, TAG_SUBSCRIPT); 1183 break; 1184 default: 1185 bNotReady = FALSE; 1186 break; 1187 } 1188 } while (bNotReady); 1189 1190 /* Create table attributes */ 1191 switch (ucBorderInfo) { 1192 case TABLE_BORDER_TOP: 1193 szFrame = "top"; 1194 break; 1195 case TABLE_BORDER_LEFT|TABLE_BORDER_RIGHT: 1196 szFrame = "sides"; 1197 break; 1198 case TABLE_BORDER_TOP|TABLE_BORDER_BOTTOM: 1199 szFrame = "topbot"; 1200 break; 1201 case TABLE_BORDER_BOTTOM: 1202 szFrame = "bottom"; 1203 break; 1204 case TABLE_BORDER_TOP|TABLE_BORDER_LEFT| 1205 TABLE_BORDER_BOTTOM|TABLE_BORDER_RIGHT: 1206 szFrame = "all"; 1207 break; 1208 default: 1209 szFrame = "none"; 1210 break; 1211 } 1212 cColSep = bIsTableBorderLeft(ucBorderInfo) || 1213 bIsTableBorderRight(ucBorderInfo) ? '1' : '0'; 1214 cRowSep = bIsTableBorderTop(ucBorderInfo) || 1215 bIsTableBorderBottom(ucBorderInfo) ? '1' : '0'; 1216 1217 sprintf(szAttr, "frame='%.6s' colsep='%c' rowsep='%c'", 1218 szFrame, cColSep, cRowSep); 1219 1220 if (usHeaderLevelCurrent == 0) { 1221 /* No table without an open header */ 1222 vAddStartTag(pDiag, TAG_CHAPTER, NULL); 1223 /* Dummy title */ 1224 vAddCombinedTag(pDiag, TAG_TITLE, NULL); 1225 } 1226 vAddStartTag(pDiag, TAG_INFORMALTABLE, szAttr); 1227 } /* end of vStartOfTable */ 1228 1229 /* 1230 * Create a start of a table group 1231 */ 1232 static void 1233 vStartOfTableGroup(diagram_type *pDiag, 1234 int iNbrOfColumns, const short *asColumnWidth) 1235 { 1236 double dWidth; 1237 int iIndex; 1238 char szCols[6 + 3 * sizeof(int) + 1 + 1]; 1239 char szColWidth[10 + 3 * sizeof(short) + 3 + 3 + 1]; 1240 1241 fail(iNbrOfColumns < 1); 1242 fail(asColumnWidth == NULL); 1243 1244 sprintf(szCols, "cols='%d'", iNbrOfColumns); 1245 vAddStartTag(pDiag, TAG_TGROUP, szCols); 1246 1247 for (iIndex= 0; iIndex < iNbrOfColumns; iIndex++) { 1248 fail(asColumnWidth[iIndex] < 0); 1249 dWidth = dTwips2Points(asColumnWidth[iIndex]); 1250 if (dWidth <= 1.0) { 1251 strcpy(szColWidth, "colwidth='1.00pt'"); 1252 } else { 1253 sprintf(szColWidth, "colwidth='%.2fpt'", dWidth); 1254 } 1255 vAddCombinedTag(pDiag, TAG_COLSPEC, szColWidth); 1256 } 1257 } /* end of vStartOfTableGroup */ 1258 1259 /* 1260 * Create an end of a table 1261 */ 1262 void 1263 vEndOfTableXML(diagram_type *pDiag) 1264 { 1265 fail(pDiag == NULL); 1266 1267 if (bTableOpen) { 1268 vAddEndTag(pDiag, TAG_TBODY); 1269 vAddEndTag(pDiag, TAG_TGROUP); 1270 vAddEndTag(pDiag, TAG_INFORMALTABLE); 1271 } 1272 } /* end of vEndOfTableXML */ 1273 1274 /* 1275 * Add a table row 1276 */ 1277 void 1278 vAddTableRowXML(diagram_type *pDiag, char **aszColTxt, 1279 int iNbrOfColumns, const short *asColumnWidth, UCHAR ucBorderInfo) 1280 { 1281 size_t tCount, tStringLength; 1282 int iIndex; 1283 1284 fail(pDiag == NULL); 1285 fail(pDiag->pOutFile == NULL); 1286 fail(aszColTxt == NULL); 1287 fail(iNbrOfColumns < 1); 1288 fail(asColumnWidth == NULL); 1289 1290 if (iNbrOfColumns != iTableColumnsCurrent) { 1291 /* A new number of columns */ 1292 /* End the old table body and table group (if they exist) */ 1293 vAddEndTagOptional(pDiag, TAG_TBODY); 1294 vAddEndTagOptional(pDiag, TAG_TGROUP); 1295 if (!bTableOpen) { 1296 /* No table yet. Start a new table */ 1297 vStartOfTable(pDiag, ucBorderInfo); 1298 } 1299 /* Start a new table group and a new table body */ 1300 vStartOfTableGroup(pDiag, iNbrOfColumns, asColumnWidth); 1301 vAddStartTag(pDiag, TAG_TBODY, NULL); 1302 iTableColumnsCurrent = iNbrOfColumns; 1303 } 1304 1305 /* Add the table row */ 1306 vAddStartTag(pDiag, TAG_ROW, NULL); 1307 for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) { 1308 /* Add a table cell */ 1309 fail(aszColTxt[iIndex] == NULL); 1310 vAddStartTag(pDiag, TAG_ENTRY, NULL); 1311 tStringLength = strlen(aszColTxt[iIndex]); 1312 for (tCount = 0; tCount < tStringLength; tCount++) { 1313 vPrintChar(pDiag->pOutFile, aszColTxt[iIndex][tCount]); 1314 } 1315 vAddEndTag(pDiag, TAG_ENTRY); 1316 } 1317 vAddEndTag(pDiag, TAG_ROW); 1318 } /* end of vAddTableRowXML */ 1319