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
vCheckTagTable(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
__vStackTrace(int iLine)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
vPushStack(UCHAR ucTag)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
ucPopStack(void)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
ucReadStack(void)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
vPrintLevel(FILE * pOutFile)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
vPrintFootnote(diagram_type * pDiag,UINT uiFootnoteIndex)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
vPrintChar(diagram_type * pDiag,char cChar)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
vPrintSpecialChar(diagram_type * pDiag,USHORT usChar)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
vPrintSpecialString(diagram_type * pDiag,const char * szString)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
vAddStartTag(diagram_type * pDiag,UCHAR ucTag,const char * szAttribute)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
vAddEndTag(diagram_type * pDiag,UCHAR ucTag)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
vAddEndTagOptional(diagram_type * pDiag,UCHAR ucTag)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
vAddCombinedTag(diagram_type * pDiag,UCHAR ucTag,const char * szAttribute)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
vAddEndTagsUntil2(diagram_type * pDiag,UCHAR ucTag1,UCHAR ucTag2)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
vCreateBookIntro(diagram_type * pDiag,int iVersion)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
vPrologueXML(diagram_type * pDiag,const options_type * pOptions)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
vEpilogueXML(diagram_type * pDiag)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
vPrintXML(diagram_type * pDiag,const char * szString,size_t tStringLength,USHORT usFontstyle)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
vMove2NextLineXML(diagram_type * pDiag)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
vSubstringXML(diagram_type * pDiag,const char * szString,size_t tStringLength,long lStringWidth,USHORT usFontstyle)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
vStartOfParagraphXML(diagram_type * pDiag,UINT uiMaxLevel)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
vEndOfParagraphXML(diagram_type * pDiag,UINT uiMaxLevel)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
vEndOfPageXML(diagram_type * pDiag)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
vCloseHeaderLevels(diagram_type * pDiag,USHORT usIstd)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
vSetHeadersXML(diagram_type * pDiag,USHORT usIstd)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
vStartOfListXML(diagram_type * pDiag,UCHAR ucNFC,BOOL bIsEndOfTable)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
vEndOfListXML(diagram_type * pDiag)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
vStartOfListItemXML(diagram_type * pDiag,BOOL bNoMarks)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
vStartOfTable(diagram_type * pDiag,UCHAR ucBorderInfo)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
vStartOfTableGroup(diagram_type * pDiag,int iNbrOfColumns,const short * asColumnWidth)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
vEndOfTableXML(diagram_type * pDiag)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
vAddTableRowXML(diagram_type * pDiag,char ** aszColTxt,int iNbrOfColumns,const short * asColumnWidth,UCHAR ucBorderInfo)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