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