1 /*
2  * RTF-to-LaTeX2e translation writer code.
3  * (c) 1999 Ujwal S. Sathyam
4  * (c) 2011, 2012 Scott Prahl
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  */
20 
21 # include <stdint.h>
22 # include <stdio.h>
23 # include <string.h>
24 # include <stdlib.h>
25 # include <ctype.h>
26 # include <unistd.h>
27 # include <math.h>
28 
29 # include "rtf.h"
30 # include "tokenscan.h"
31 # include "cole.h"
32 # include "rtf2latex2e.h"
33 # include "eqn.h"
34 # include "init.h"
35 
36 void __cole_dump(void *_m, void *_start, uint32_t length, char *msg);
37 void ExamineToken(char * tag);
38 boolean ConvertRawEquationFile(char *rawFileName);
39 
40 # define  MAX_BLANK_LINES       2
41 # define  MATH_NONE_MODE        0
42 # define  MATH_INLINE_MODE      1
43 # define  MATH_DISPLAY_MODE     2
44 
45 # define  UNDEFINED_COLUMN_VALUE -10000
46 # define  ROUNDF(f) ((int)(f + 0.5))
47 
48 extern FILE *ifp, *ofp;
49 
50 # define EQUATION_OFFSET 35
51 # define MTEF_HEADER_SIZE 28
52 
53 int UsedColor[256];
54 const char *objectClassList[] = {
55     "Unknown",
56     "Equation",
57     "Word.Picture",
58     "MSGraph.Chart",
59     NULL
60 };
61 
62 const char *justificationList[] = {
63     "\\raggedright",
64     "\\centering",
65     "\\raggedleft"
66 };
67 
68 const char *environmentList[] = {
69     "flushleft",
70     "center",
71     "flushright"
72 };
73 
74 const char *fontSizeList[] = {
75     "\\tiny",
76     "\\scriptsize",
77     "\\footnotesize",
78     "\\small",
79     "\\normalsize",
80     "\\large",
81     "\\Large",
82     "\\LARGE",
83     "\\huge",
84     "\\Huge"
85 };
86 
87 static struct {
88     int cols;
89     int writtenCols;
90     boolean newSection;  /* true when \sect token has been seen */
91     boolean newPage;
92 } section;
93 
94 static struct {
95     int class;
96     char className[rtfBufSiz];
97     int shape;
98 } object;
99 
100 int wrapCount = 0;
101 int shapeObjectType;
102 boolean nowBetweenParagraphs;
103 boolean nowBetweenCells;
104 boolean suppressLineBreak;
105 boolean suppressSpaceBetweenParagraphs;
106 boolean requireSetspacePackage;
107 boolean requireTablePackage;
108 boolean requireMultirowPackage;
109 boolean requireGraphicxPackage;
110 boolean requireAmsSymbPackage;
111 boolean requireMultiColPackage;
112 boolean requireUlemPackage;
113 boolean requireFixLtx2ePackage;
114 boolean requireHyperrefPackage;
115 boolean requireAmsMathPackage;
116 boolean requireFancyHdrPackage;
117 boolean requireAMSSymbolPackage;
118 size_t packagePos;
119 size_t beginDocumentPos;
120 boolean insideTable;
121 boolean insideFootnote;
122 boolean insideHyperlink;
123 boolean insideHeaderFooter;
124 boolean insideShapeGroup;
125 int insideEquation;
126 int blackColor;
127 
128 char *preambleFancyHeader;
129 char *preambleFancyHeaderFirst;
130 
131 char *outMap[rtfSC_MaxChar];
132 
133 FILE *ostream;
134 parStyleStruct paragraph, paragraphWritten;
135 textStyleStruct textStyle, textStyleWritten;
136 int current_vspace;
137 pictureStruct picture;
138 equationStruct oleEquation;
139 tableStruct table;
140 shapeStruct shape;
141 
142 int g_debug_par_start       = 0;
143 int g_debug_table_prescan   = 0;
144 int g_debug_table_writing   = 0;
145 int g_debug_char_style      = 0;
146 int textWidth               = 345*20; /* \textwidth for 10pt article size in twips*/
147 int latexColumnSeparation   = 12 *20;  /*default intercolumn separation of tabular in twips */
148 char *UnicodeSymbolFontToLatex[];
149 char *UnicodeGreekToLatex[];
150 
151 /*
152  * a useful diagnostic (debugging) function to examine the token just read.
153  */
ExamineToken(char * tag)154 void ExamineToken(char * tag)
155 {
156     printf("********** %s **********\n", tag);
157     printf("* Token is %s\n", rtfTextBuf);
158     printf("* Class is %3d", rtfClass);
159     switch (rtfClass) {
160     case rtfUnknown: printf(" (rtfUnknown)\n"); break;
161     case rtfGroup: printf(" (rtfGroup)\n"); break;
162     case rtfText: printf(" (rtfText)\n"); break;
163     case rtfControl: printf(" (rtfControl)\n"); break;
164     case rtfEOF: printf(" (rtfEOF)\n"); break;
165     default: printf(" (not one of the basic five)\n"); break;
166     }
167 
168     printf("* Major is %3d", rtfMajor);
169     if (rtfClass == rtfText) {
170         if (rtfMajor == 0x0A)
171             printf(" raw=LF \n");
172         else if (rtfMajor == 0x0D)
173             printf(" raw= CR \n");
174         else
175             printf(" raw='%c' \n", rtfMajor);
176     } else if (rtfClass == rtfGroup) {
177         printf(" (%s)\n", rtfMajor? "rtfEndGroup" : "rtfBeginGroup");
178     } else {
179         switch (rtfMajor) {
180             case rtfVersion: printf(" (rtfVersion)\n"); break;
181             case rtfDefFont: printf(" (rtfDefFont)\n"); break;
182             case rtfCharSet: printf(" (rtfCharSet)\n"); break;
183             case rtfDestination: printf(" (rtfDestination)\n"); break;
184             case rtfFontFamily: printf(" (rtfFontFamily)\n"); break;
185             case rtfFontAttr: printf(" (rtfFontAttr)\n"); break;
186             case rtfColorName: printf(" (rtfColorName)\n"); break;
187             case rtfFileAttr: printf(" (rtfFileAttr)\n"); break;
188             case rtfFileSource: printf(" (rtfFileSource)\n"); break;
189             case rtfStyleAttr: printf(" (rtfStyleAttr)\n"); break;
190             case rtfKeyCodeAttr: printf(" (rtfKeyCodeAttr)\n"); break;
191             case rtfDocAttr: printf(" (rtfDocAttr)\n"); break;
192             case rtfSectAttr: printf(" (rtfSectAttr)\n"); break;
193             case rtfParAttr: printf(" (rtfParAttr)\n"); break;
194             case rtfPosAttr: printf(" (rtfPosAttr)\n"); break;
195             case rtfTblAttr: printf(" (rtfTblAttr)\n"); break;
196             case rtfCharAttr: printf(" (rtfCharAttr)\n"); break;
197             case rtfACharAttr: printf(" (rtfACharAttr)\n"); break;
198             case rtfSpecialChar: printf(" (rtfSpecialChar)\n"); break;
199             case rtfBookmarkAttr: printf(" (rtfBookmarkAttr)\n"); break;
200             case rtfPictAttr: printf(" (rtfPictAttr)\n"); break;
201             case rtfObjAttr: printf(" (rtfObjAttr)\n"); break;
202             case rtfDrawAttr: printf(" (rtfDrawAttr)\n"); break;
203             case rtfFNoteAttr: printf(" (rtfFNoteAttr)\n"); break;
204             case rtfFieldAttr: printf(" (rtfFieldAttr)\n"); break;
205             case rtfIndexAttr: printf(" (rtfIndexAttr)\n"); break;
206             case rtfTOCAttr: printf(" (rtfTOCAttr)\n"); break;
207             case rtfNeXTGrAttr: printf(" (rtfNeXTGrAttr)\n"); break;
208             case rtfShapeAttr: printf(" (rtfShapeAttr)\n"); break;
209             case rtfAnsiCharAttr: printf(" (rtfAnsiCharAttr)\n"); break;
210             case rtfEquationFieldCmd: printf(" (rtfEquationFieldCmd)\n"); break;
211             default: printf(" (unknown)\n"); break;
212         }
213     }
214 
215     printf("* Minor is %3d", rtfMinor);
216     if (rtfClass == rtfText) {
217         printf(" std=0x%2x\n", rtfMinor);
218     } else {
219         printf("\n");
220     }
221     printf("* Param is %3d\n\n", (int) rtfParam);
222 }
223 
224 char lastCharWritten;
225 
PutIntAsUtf8(int x)226 static void PutIntAsUtf8(int x)
227 {
228     x &= 0x0000FFFF;
229     if (x < 0x80){
230         fputc((char) x, ostream);
231         wrapCount++;
232         lastCharWritten = (char) x;
233         return;
234     }
235 
236     lastCharWritten = 0x80;;
237 
238     if (x < 0xA0) {
239         fprintf(stderr, "there should be no such character c='%c'=0x%02x\n",(char) x,x);
240         return;
241     }
242 
243     if (x<0x07FF) {
244         unsigned char d, e;
245         d = 0xC0 + (x & 0x07C0)/64;
246         e = 0x80 + (x & 0x003F);
247         fputc(d, ostream);
248         fputc(e, ostream);
249         wrapCount+=2;
250         return;
251     }
252 
253     if (x<0xFFFF) {
254         unsigned char c, d, e;
255         c = 0xE0 + (x & 0xF000)/4096;
256         d = 0x80 + (x & 0x0FC0)/64;
257         e = 0x80 + (x & 0x003F);
258         fputc(c, ostream);
259         fputc(d, ostream);
260         fputc(e, ostream);
261         wrapCount+=3;
262         return;
263     }
264 
265 }
266 
267 /*
268  * Some environments fail if there is a blank line in
269  * the argument ... e.g., \section{} will set suppressLineBreak
270  * so, in this case, make sure that there is at least one char
271  * on each line before writing a '\n' to the latex file.
272  * We can't use wrapCount for this purpose because an "empty"
273  * line of spaces will also cause these environments grief.
274  *
275  * Furthermore, make sure that at most two '\n' are output
276  * to the latex file at a time just for esthetic reasons.
277  *
278  * Finally, reset wrapCount to zero every time a '\n' is
279  * written to the LaTeX file so that WrapText() below can
280  * work properly
281  */
PutLitChar(int c)282 static void PutLitChar(int c)
283 {
284     static int lf_in_succession = 0;
285     static int no_chars_in_row = true;
286 
287     if (c != '\n') {
288         lf_in_succession = 0;
289         if (c != ' ') no_chars_in_row=false;
290         PutIntAsUtf8(c & 0x00ff);
291         return;
292     }
293 
294     if (suppressLineBreak && no_chars_in_row) {
295         lf_in_succession = 0;
296         PutIntAsUtf8((int) ' ');
297         return;
298     }
299 
300     lf_in_succession++;
301     no_chars_in_row = true;
302     if (lf_in_succession > 2)
303         return;
304 
305     wrapCount = 0;
306 
307     PutIntAsUtf8(c & 0x00ff);
308 }
309 
310 /* copy a sequence of bytes to the ostream, avoiding all the encoding machinery */
PutLitByteStr(char * s)311 static void PutLitByteStr(char *s)
312 {
313     char *p = s;
314     if (!s) return;
315     while (*p) {
316         fputc(*p, ostream);
317         p++;
318     }
319 }
320 
PutLitStr(char * s)321 static void PutLitStr(char *s)
322 {
323     char *p = s;
324     if (!s) return;
325     while (*p) {
326         PutLitChar(*p);
327         p++;
328     }
329 }
330 
PutMathLitStr(char * s)331 static void PutMathLitStr(char *s)
332 {
333     if (s && *s) {
334         if (!insideEquation) PutLitStr("$");
335         PutLitStr(s);
336         if (!insideEquation) PutLitStr("$");
337     }
338 }
339 
InsertNewLine(void)340 static void InsertNewLine(void)
341 {
342     PutLitChar('\n');
343 }
344 
345 /* useful for just printing filenames in latex doc */
PutEscapedLitStr(char * s)346 static void PutEscapedLitStr(char *s)
347 {
348     int i=0;
349     while (s[i]) {
350         switch (s[i]) {
351         case '_':
352             PutLitStr("\\_");
353             break;
354         case '%':
355             PutLitStr("\\%");
356             break;
357         case '\\':
358             PutLitStr("\\textbackslash{}");
359             break;
360         default:
361             PutLitChar(s[i]);
362         }
363         i++;
364     }
365 }
366 
367 /*
368  * This function reads colors from the color table and defines them in
369  * LaTeX format to be included in the preamble.
370  * This is done after the color table has been read (see above).
371  */
DefineColors(int ignoreUsedColors)372 static void DefineColors(int ignoreUsedColors)
373 {
374     RTFColor *rtfColorPtr;
375     int i = 1;
376     float Red, Blue, Green;
377     char buf[rtfBufSiz];
378 
379     while ((rtfColorPtr = RTFGetColor(i)) != NULL) {
380         Red = rtfColorPtr->rtfCRed / 255.0;
381         Green = rtfColorPtr->rtfCGreen / 255.0;
382         Blue = rtfColorPtr->rtfCBlue / 255.0;
383 
384         if (Red==0 && Green==0 && Blue==0)
385             blackColor = i;
386 
387         if (ignoreUsedColors || (!ignoreUsedColors && UsedColor[i])) {
388             snprintf(buf, rtfBufSiz, "\\definecolor{color%02d}{rgb}",i);
389             PutLitStr(buf);
390             snprintf(buf, rtfBufSiz, "{%1.2f,%1.2f,%1.2f}\n", Red, Green, Blue);
391             PutLitStr(buf);
392         }
393 
394         i++;
395     }
396 }
397 
WriteColors(void)398 static void WriteColors(void)
399 {
400     ReadColorTbl();
401 
402     if (!prefs[pConvertTextColor]) return;
403     DefineColors(true);
404 }
405 
406 /*
407  * Eventually this should keep track of the destination of the
408  * current state and only write text when in the initial state.
409  *
410  * If the output sequence is unspecified in the output map, write
411  * the character's standard name instead.  This makes map deficiencies
412  * obvious and provides incentive to fix it. :-)
413  */
414 
PutStdChar(int stdCode)415 static void PutStdChar(int stdCode)
416 {
417     char *oStr = NULL;
418     char buf[rtfBufSiz];
419 
420     if (stdCode == rtfSC_nothing) {
421         RTFMsg("* Unknown character %c (0x%x)!\n", rtfTextBuf[0], rtfTextBuf[0]);
422         ExamineToken("PutStdChar");
423         PutLitStr("(unknown char)");
424         return;
425     }
426     oStr = outMap[stdCode];
427     if (!oStr) {        /* no output sequence in map */
428         snprintf(buf, rtfBufSiz, "(%s)", RTFStdCharName(stdCode));
429         oStr = buf;
430         PutLitStr(oStr);
431         return;
432     }
433 
434     if (oStr[0] == '0' && (oStr[1] == 'x' || oStr[1] == 'X')) {
435         int x = RTFHexStrToInt(oStr);
436         /*fprintf(stderr,"hex string = '%s' = %d\n",oStr,x);*/
437         PutIntAsUtf8(x);
438         return;
439     }
440 
441     PutLitStr(oStr);
442 }
443 
444 /*
445  * make sure we write this all important stuff. This routine is called
446  * whenever something is written to the output file.
447  */
448 static int wroteBeginDocument = false;
CheckForBeginDocument(void)449 static int CheckForBeginDocument(void)
450 {
451     char buf[100];
452 
453     if (insideHeaderFooter) return 0;
454 
455     if (!wroteBeginDocument) {
456 
457         if (preambleOurDefs) free(preambleOurDefs);
458         preambleOurDefs = malloc(1000);
459         preambleOurDefs[0] = '\0';
460 
461         if (prefs[pConvertPageSize]) {
462             snprintf(buf, 100, "\\setlength{\\oddsidemargin}{%dpt}\n", 72 - prefs[pPageLeft]/20);
463             strcat(preambleOurDefs,buf);
464             snprintf(buf, 100, "\\setlength{\\evensidemargin}{%dpt}\n", 72 - prefs[pPageRight]/20);
465             strcat(preambleOurDefs,buf);
466             snprintf(buf, 100, "\\setlength{\\textwidth}{%dpt}\n", (prefs[pPageWidth] - prefs[pPageLeft] - prefs[pPageRight])/20);
467             strcat(preambleOurDefs,buf);
468         }
469 
470         if (!prefs[pConvertTextNoTab])
471             strcat(preambleOurDefs,"\\newcommand{\\tab}{\\hspace{5mm}}\n\n");
472         PutLitByteStr(preambleOurDefs);
473 
474         beginDocumentPos = ftell(ofp);
475         if (g_shouldIncludePreamble)
476             PutLitStr("\\begin{document}\n");
477         wroteBeginDocument = true;
478         return 1;
479     }
480     return 0;
481 }
482 
483 /*
484  * This function initializes the text style.
485  */
InitTextStyle(void)486 static void InitTextStyle(void)
487 {
488     textStyle.fontSize = normalSize;
489 
490     textStyle.bold = 0;
491     textStyle.italic = 0;
492     textStyle.underlined = 0;
493     textStyle.dbUnderlined = 0;
494     textStyle.smallCaps = 0;
495     textStyle.subScript = 0;
496     textStyle.superScript = 0;
497     textStyle.foreColor = 0; /* black */
498     textStyle.fontNumber = -1;
499     textStyle.charCode = genCharCode;
500     textStyle.mathRoman = 0;
501 
502     textStyle.allCaps = 0;
503     textStyle.backColor = 0;
504 }
505 
506 /*
507  * This function initializes the paragraph style.
508  */
InitParagraphStyle(void)509 static void InitParagraphStyle(void)
510 {
511     paragraph.firstIndent = 0;
512     paragraph.leftIndent = 0;
513     paragraph.rightIndent = 0;
514     paragraph.spaceBefore = 0;
515     paragraph.extraIndent = 0;
516     paragraph.styleIndex = -1;
517 }
518 
SameTextStyle(void)519 static int SameTextStyle(void)
520 {
521     if (prefs[pConvertTextSize] && textStyleWritten.fontSize != textStyle.fontSize) return false;
522 
523     if (prefs[pConvertTextColor] && textStyleWritten.foreColor != textStyle.foreColor) return false;
524 
525     if (textStyleWritten.superScript != textStyle.superScript) return false;
526 
527     if (textStyleWritten.subScript != textStyle.subScript) return false;
528 
529     if (!prefs[pConvertTextForm]) return true;
530 
531     if (textStyleWritten.italic != textStyle.italic) return false;
532 
533     if (textStyleWritten.bold != textStyle.bold)  return false;
534 
535     if (textStyleWritten.underlined != textStyle.underlined) return false;
536 
537     if (textStyleWritten.smallCaps != textStyle.smallCaps) return false;
538 
539     if (textStyleWritten.dbUnderlined != textStyle.dbUnderlined) return false;
540 
541     if (textStyleWritten.charCode != textStyle.charCode) return false;
542 
543     if (textStyleWritten.mathRoman != textStyle.mathRoman) return false;
544 
545     return true;
546 }
547 
548 /*
549  * This function ends all text styles
550  */
StopTextStyle(void)551 static void StopTextStyle(void)
552 {
553     if (prefs[pConvertTextSize] && textStyleWritten.fontSize != normalSize) {
554         PutLitStr("}");
555         textStyleWritten.fontSize=normalSize;
556     }
557 
558     if (prefs[pConvertTextColor] && textStyleWritten.foreColor) {
559         PutLitStr("}");
560         textStyleWritten.foreColor=0; /* black */
561     }
562 
563     if (textStyleWritten.subScript) {
564         PutLitStr("}");
565         textStyleWritten.subScript=false;
566     }
567 
568     if (textStyleWritten.superScript) {
569         PutLitStr("}");
570         textStyleWritten.superScript=false;
571     }
572 
573     if (!prefs[pConvertTextForm]) return;
574 
575     if (textStyleWritten.italic) {
576         PutLitStr("}");
577         textStyleWritten.italic=false;
578     }
579 
580     if (textStyleWritten.bold) {
581         PutLitStr("}");
582         textStyleWritten.bold=false;
583     }
584 
585     if (textStyleWritten.smallCaps) {
586         PutLitStr("}");
587         textStyleWritten.smallCaps=false;
588     }
589 
590     if (textStyleWritten.underlined) {
591         PutLitStr("}");
592         textStyleWritten.underlined=false;
593     }
594 
595     if (textStyleWritten.dbUnderlined) {
596         PutLitStr("}");
597         textStyleWritten.dbUnderlined=false;
598     }
599 
600     if (textStyleWritten.mathRoman) {
601         PutLitStr("}");
602         textStyleWritten.mathRoman=false;
603     }
604 
605 }
606 
607 /*
608  * Alters the written latex style so it matches the current RTF style
609  * This should only be called right before emitting a character
610  */
WriteTextStyle(void)611 static void WriteTextStyle(void)
612 {
613     char buf[100];
614 
615     if (SameTextStyle()) return;
616 
617     if (wroteBeginDocument || !insideHeaderFooter) StopTextStyle();
618 
619     if (prefs[pConvertTextSize] && textStyleWritten.fontSize != textStyle.fontSize && !insideEquation) {
620         if (textStyle.fontSize != normalSize) {
621             snprintf(buf, 100, "{%s{}", fontSizeList[textStyle.fontSize]);
622             PutLitStr(buf);
623         }
624         textStyleWritten.fontSize=textStyle.fontSize;
625     }
626 
627     if (textStyleWritten.mathRoman != textStyle.mathRoman) {
628         if (textStyle.mathRoman)
629             PutLitStr("\\mathrm{");
630         textStyleWritten.mathRoman=textStyle.mathRoman;
631     }
632 
633     if (textStyleWritten.superScript != textStyle.superScript) {
634         if (textStyle.superScript) {
635         	if (insideEquation)
636             	PutLitStr("^{");
637         	else
638             	PutLitStr("\\textsuperscript{");
639         }
640         textStyleWritten.superScript=textStyle.superScript;
641     }
642 
643     if (textStyleWritten.subScript != textStyle.subScript) {
644         if (textStyle.subScript) {
645         	if (insideEquation)
646             	PutLitStr("_{");
647         	else
648             	PutLitStr("\\textsubscript{");
649         }
650         textStyleWritten.subScript=textStyle.subScript;
651         requireFixLtx2ePackage = true;
652     }
653 
654     if (prefs[pConvertTextColor] && textStyleWritten.foreColor != textStyle.foreColor && !insideEquation) {
655         if (textStyle.foreColor) {
656             snprintf(buf, 100, "{\\color{color%02d} ", textStyle.foreColor);
657             PutLitStr(buf);
658             UsedColor[textStyle.foreColor] = 1;
659         }
660         textStyleWritten.foreColor=textStyle.foreColor;
661     }
662 
663     if (!prefs[pConvertTextForm]) return;
664 
665     if (textStyleWritten.italic != textStyle.italic && !insideEquation) {
666         if (textStyle.italic)
667             PutLitStr("\\textit{");
668         textStyleWritten.italic=textStyle.italic;
669     }
670 
671     if (textStyleWritten.bold != textStyle.bold) {
672         if (textStyle.bold)
673         	if (insideEquation)
674             	PutLitStr("\\mathbf{");
675             else
676             	PutLitStr("\\textbf{");
677         textStyleWritten.bold=textStyle.bold;
678     }
679 
680     if (textStyleWritten.underlined != textStyle.underlined && !insideEquation) {
681         if (textStyle.underlined)
682             PutLitStr("\\emph{");
683         requireUlemPackage = true;
684         textStyleWritten.underlined=textStyle.underlined;
685     }
686 
687     if (textStyleWritten.smallCaps != textStyle.smallCaps && !insideEquation) {
688         if (textStyle.smallCaps)
689             PutLitStr("\\textsc{");
690         textStyleWritten.smallCaps=textStyle.smallCaps;
691     }
692 
693     if (textStyleWritten.dbUnderlined != textStyle.dbUnderlined && !insideEquation) {
694         if (textStyle.dbUnderlined)
695             PutLitStr("\\uuline{");
696         requireUlemPackage = true;
697         textStyleWritten.dbUnderlined=textStyle.dbUnderlined;
698     }
699 
700     if (textStyleWritten.charCode != textStyle.charCode) {
701         curCharCode = textStyle.charCode;
702         textStyleWritten.charCode=textStyle.charCode;
703     }
704 }
705 
706 /*
707  * This handles font changing
708  *
709  * When switching fonts like Times -> Helvetica
710  *
711  *   (1) the style might change from roman to sans serif
712  *   (2) the character code translation may change because
713  *       the font is encoded with a different codepage
714  */
SetFontStyle(void)715 static void SetFontStyle(void)
716 {
717     RTFFont *font;
718 
719     textStyle.fontNumber = rtfParam;
720     font = RTFGetFont(rtfParam);
721 //  fprintf(stderr, "Font %3d, cs=%3d, lookup=%p, name='%s'\n", font->rtfFNum, font->rtfFCharSet, font->rtfFCharCode, font->rtfFName);
722     textStyle.charCode = font->rtfFCharCode;
723     curCharCode = font->rtfFCharCode;
724 }
725 
726 /*
727  * This function stores the text style.
728  */
SetTextStyle(void)729 static void SetTextStyle(void)
730 {
731     if (insideHyperlink)
732         return;
733 
734 	if (insideEquation) {
735 		switch (rtfMinor) {
736 		case rtfPlain:
737 			InitTextStyle();
738 			textStyle.mathRoman = (rtfParam) ? true : false;
739 			break;
740 		case rtfBold:
741 			textStyle.bold = (rtfParam) ? true : false;
742 			break;
743 		case rtfSubScrShrink:
744 		case rtfSubScript:
745 			textStyle.subScript = (rtfParam) ? true : false;
746 			textStyle.superScript = false;
747 			break;
748 		case rtfSuperScrShrink:
749 		case rtfSuperScript:
750 			textStyle.superScript = (rtfParam) ? true : false;
751 			textStyle.subScript = false;
752 			break;
753 		}
754 		return;
755 	}
756 
757     switch (rtfMinor) {
758     case rtfPlain:
759         InitTextStyle();
760         break;
761     case rtfSmallCaps:
762         textStyle.smallCaps = (rtfParam) ? true : false;
763         break;
764     case rtfAllCaps:
765         textStyle.allCaps = (rtfParam) ? true : false;
766         break;
767     case rtfItalic:
768         textStyle.italic = (rtfParam) ? true : false;
769         break;
770     case rtfBold:
771         textStyle.bold = (rtfParam) ? true : false;
772         break;
773     case rtfUnderline:
774         textStyle.underlined = (rtfParam) ? true : false;
775         break;
776     case rtfNoUnderline:
777         textStyle.underlined = false;
778         break;
779     case rtfDbUnderline:
780         textStyle.dbUnderlined = (rtfParam) ? true : false;
781         break;
782     case rtfForeColor:
783         if (rtfParam == blackColor)
784             textStyle.foreColor = 0;
785         else
786             textStyle.foreColor = rtfParam;
787         break;
788     case rtfSubScrShrink:
789     case rtfSubScript:
790         textStyle.subScript = (rtfParam) ? true : false;
791         textStyle.superScript = false;
792         break;
793     case rtfSuperScrShrink:
794     case rtfSuperScript:
795         textStyle.superScript = (rtfParam) ? true : false;
796         textStyle.subScript = false;
797         break;
798     case rtfFontSize:
799         textStyle.fontSize = normalSize;
800         if (rtfParam <= 12)
801             textStyle.fontSize = scriptSize;
802         else if (rtfParam <= 14)
803             textStyle.fontSize = footNoteSize;
804         else if (rtfParam <= 18)
805             textStyle.fontSize = smallSize;
806         else if (rtfParam <= 24)
807             textStyle.fontSize = normalSize;
808         else if (rtfParam <= 28)
809             textStyle.fontSize = largeSize;
810         else if (rtfParam <= 32)
811             textStyle.fontSize = LargeSize;
812         else if (rtfParam <= 36)
813             textStyle.fontSize = LARGESize;
814         else if (rtfParam <= 48)
815             textStyle.fontSize = giganticSize;
816         else if (rtfParam <= 72)
817             textStyle.fontSize = GiganticSize;
818         break;
819     case rtfFontNum:
820         SetFontStyle();
821         break;
822     case rtfDeleted:
823         RTFSkipGroup();
824         break;
825     }
826 }
827 
setLineSpacing(void)828 static void setLineSpacing(void)
829 {
830     char buff[100];
831 
832     if (!prefs[pConvertLineSpacing]) return;
833 
834     if (paragraphWritten.lineSpacing == paragraph.lineSpacing)
835         return;
836 
837     snprintf(buff, 100, "\\baselineskip=%dpt\n", abs(paragraph.lineSpacing)/20);
838     PutLitStr(buff);
839 
840     if (g_debug_par_start) {
841         snprintf(buff, 100, "[ls=%d]", paragraph.lineSpacing);
842         PutLitStr(buff);
843     }
844 
845     paragraphWritten.lineSpacing = paragraph.lineSpacing;
846 }
847 
848 /*
849  * Allocate memory for new table cell
850  */
CellAllocate(void)851 static cellStruct * CellAllocate(void)
852 {
853     cellStruct *cell;
854 
855     cell = New(cellStruct);
856     if (!cell) {
857         RTFPanic("Cannot allocate memory for cell entry");
858         exit(1);
859     }
860 
861     return cell;
862 }
863 
864 /*
865  * This routine sets attributes for the detected cell and
866  * adds it to the table.theCell list. Memory for cells is
867  * allocated dynamically as each cell is encountered.
868  */
CellInitialize(cellStruct * cell)869 static void CellInitialize(cellStruct *cell)
870 {
871     /*fprintf(stderr,"initializing cell %d, (x,y)=(%d,%d)\n",
872               table.cellCount, table.rows, (table.cellsInRow)[table.rows]);*/
873     cell->nextCell         = table.theCell;
874     cell->row              = table.rows;
875     cell->col              = (table.cellsInRow)[table.rows];
876     if (table.cols == 0 || table.theCell == NULL)
877         cell->originalLeft = table.leftEdge;
878     else
879         cell->originalLeft = (table.theCell)->originalRight;
880     cell->originalRight    = rtfParam;
881     cell->index            = table.cellCount;
882     cell->verticalMerge    = table.cellMergePar;
883     cell->leftBorder       = table.limboCellLeftBorder;
884     cell->rightBorder      = table.limboCellRightBorder;
885     cell->topBorder        = table.limboCellTopBorder;
886     cell->bottomBorder     = table.limboCellBottomBorder;
887 }
888 
889 /*
890  * This function searches the cell list by cell index
891  * returns NULL if not found
892  */
CellGetByIndex(int cellNum)893 static cellStruct *CellGetByIndex(int cellNum)
894 {
895     cellStruct *cell;
896 
897     if (cellNum == -1)
898         return (table.theCell);
899 
900     for (cell = (table.theCell); cell != NULL; cell = cell->nextCell) {
901         if (cell->index == cellNum)
902             return cell;
903     }
904 
905     if (!cell)
906         RTFPanic("CellGetByIndex: Attempting to access invalid cell with index %d\n", cellNum);
907 
908     return NULL;
909 }
910 
911 /*
912  * This function returns the cell from the current table
913  * for the specified row and column
914  */
CellGetByPosition(int therow,int thecol)915 static cellStruct *CellGetByPosition(int therow, int thecol)
916 {
917     cellStruct *cell;
918 
919     if (!table.theCell)
920         RTFPanic("CellGetByPosition: Attempting to access invalid cell at row=%d, col=%d\n", therow, thecol);
921 
922     for (cell = table.theCell; cell != NULL; cell = cell->nextCell) {
923         if (cell->row == therow && cell->col == thecol)
924             return cell;
925     }
926 
927     return NULL;
928 }
929 
930 /* returns the width of the current cell in points*/
CellWidth(cellStruct * cell)931 static int CellWidth(cellStruct *cell)
932 {
933     int cleft = (table.rightColumnBorders)[cell->col];
934     int cright = (table.rightColumnBorders)[cell->col+cell->columnSpan];
935 
936     return (cright-cleft)/20;
937 }
938 
939 /*
940  * Given a cell in the first row of a multirow cell, count the number
941  * of cells below that should be merged vertically
942  *
943  * unused at the moment
944 
945 static int rowsInMultirow(cellStruct * cell)
946 {
947     int i;
948     for (i=cell->row+1; i < table.rows; i++) {
949         cellStruct *c = CellGetByPosition(i, cell->col);
950         if (c->verticalMerge != mergeAbove) break;
951     }
952     return i-cell->row;
953 }
954 
955  *
956  * Counts the number of rows to be merged vertically for the
957  * current column and writes the corresponding \multirow statement.
958  *
959  * not used at the moment ... still needs work
960  *
961 static void CellMultirow(cellStruct * cell)
962 {
963     int rows;
964     char buf[rtfBufSiz];
965 
966     rows = rowsInMultirow(cell);
967 
968     if (rows < 2) return;
969 
970     if (prefs[pConvertTableAlignment] && paragraph.alignment != left)
971         snprintf(buf, rtfBufSiz, "\\multirow{%d}{*}{%s{}", rows, justificationList[paragraph.alignment]);
972     else
973         snprintf(buf, rtfBufSiz, "\\multirow{%d}{*}{ ", rows);
974 
975     PutLitStr(buf);
976     table.multiRow = true;
977     requireMultirowPackage = true;
978 }
979 */
980 
NewSection(void)981 static void NewSection(void)
982 {
983     char buff[100];
984     if (section.cols > 1) {
985         snprintf(buff, 100, "\n\\begin{multicols}{%d}\n", section.cols);
986         PutLitStr(buff);
987         requireMultiColPackage = true;
988         section.writtenCols = section.cols;
989     }
990 
991     section.newSection = false;
992 }
993 
NewParagraph(void)994 static void NewParagraph(void)
995 {
996     char buff[100];
997 
998     (void) CheckForBeginDocument();
999 
1000     nowBetweenParagraphs = false;
1001 
1002     if (insideFootnote || insideHeaderFooter) return;
1003 
1004     if (prefs[pConvertInterParagraphSpace] && !insideTable) {
1005         if (!suppressSpaceBetweenParagraphs && (current_vspace || paragraph.spaceBefore) ) {
1006             snprintf(buff,100,"\\vspace{%dpt}\n", (current_vspace+paragraph.spaceBefore)/20);
1007             PutLitStr(buff);
1008             current_vspace = 0;
1009         }
1010     }
1011 
1012     if (section.newSection && !insideTable) NewSection();
1013 
1014     if (prefs[pConvertParagraphStyle] && paragraph.styleIndex != -1) {
1015         PutLitStr(Style2LatexOpen[paragraph.styleIndex]);
1016         paragraphWritten.styleIndex = paragraph.styleIndex;
1017         suppressLineBreak = true;
1018         return;
1019     }
1020 
1021 //    if ((!insideTable && prefs[pConvertParagraphAlignment]) ||
1022 //        ( insideTable && prefs[pConvertTableAlignment]    )) {
1023     if (!insideTable && prefs[pConvertParagraphAlignment]) {
1024         if (paragraphWritten.alignment != paragraph.alignment) {
1025 
1026             if (paragraph.alignment == right)
1027                 PutLitStr("\\begin{flushright}\n");
1028 
1029             if (paragraph.alignment == center)
1030                 PutLitStr("\\begin{center}\n");
1031 
1032             paragraphWritten.alignment = paragraph.alignment;
1033         }
1034     }
1035 
1036     if (insideTable) return;
1037 
1038     setLineSpacing();
1039 
1040     if (prefs[pConvertParagraphMargin]) {
1041         if (paragraphWritten.leftIndent != paragraph.leftIndent) {
1042             snprintf(buff, 100, "\\leftskip=%dpt\n", paragraph.leftIndent/20);
1043             if (paragraph.alignment != right && paragraph.alignment != center) {
1044                 PutLitStr(buff);
1045                 paragraphWritten.leftIndent = paragraph.leftIndent;
1046             }
1047         }
1048     }
1049 
1050     if (prefs[pConvertParagraphIndent]) {
1051         if (paragraphWritten.firstIndent != paragraph.firstIndent+paragraph.extraIndent) {
1052             snprintf(buff, 100, "\\parindent=%dpt\n", (paragraph.firstIndent+paragraph.extraIndent)/20);
1053             if (paragraph.alignment != right && paragraph.alignment != center) {
1054                 PutLitStr(buff);
1055                 paragraphWritten.firstIndent = paragraph.firstIndent+paragraph.extraIndent;
1056             }
1057             paragraph.extraIndent=0;
1058         }
1059     }
1060 
1061     suppressSpaceBetweenParagraphs = false;
1062 }
1063 
EndSection(void)1064 static void EndSection(void)
1065 {
1066     if (section.writtenCols > 1) {
1067         PutLitStr("\n\\end{multicols}\n");
1068         section.writtenCols = 1;
1069     }
1070 
1071     if (section.newPage)
1072         PutLitStr("\\newpage\n");
1073 }
1074 
1075 
1076 /*
1077  * This routine just closes the environments that have been written
1078  */
1079 
FinalizeParagraph(void)1080 static void FinalizeParagraph(void)
1081 {
1082     char buf[rtfBufSiz];
1083 
1084     if (insideHeaderFooter) return;
1085 
1086     if (CheckForBeginDocument()) return;
1087 
1088     StopTextStyle();
1089 
1090     if (prefs[pConvertParagraphStyle] && (paragraphWritten.styleIndex != -1)) {
1091         PutLitStr(Style2LatexClose[paragraphWritten.styleIndex]);
1092         suppressLineBreak = false;
1093         paragraphWritten.styleIndex=-1;
1094         return;
1095     }
1096 
1097 //    if ( (!insideTable && paragraphWritten.alignment != paragraph.alignment) ||
1098 //         (insideTable && prefs[pConvertTableAlignment] && nowBetweenCells)) {
1099 
1100     if (insideTable && prefs[pConvertTableAlignment] ) {
1101         if (paragraphWritten.alignment == right || paragraphWritten.alignment == center){
1102             paragraphWritten.alignment = -900;
1103             paragraphWritten.leftIndent = -900;
1104             paragraphWritten.lineSpacing = -900;
1105         }
1106     }
1107 
1108     if ( !insideTable && paragraphWritten.alignment != paragraph.alignment) {
1109 
1110         if (g_debug_par_start) {
1111             snprintf(buf, rtfBufSiz, "[oldalign=%d, newalign=%d]", paragraphWritten.alignment, paragraph.alignment);
1112             PutLitStr(buf);
1113         }
1114 
1115         if (paragraphWritten.alignment == right){
1116             PutLitStr("\n\\end{flushright}");
1117             paragraphWritten.alignment = -900;
1118             paragraphWritten.leftIndent = -900;
1119             paragraphWritten.lineSpacing = -900;
1120         }
1121 
1122         if (paragraphWritten.alignment == center){
1123             PutLitStr("\n\\end{center}");
1124             paragraphWritten.alignment = -900;
1125             paragraphWritten.leftIndent = -900;
1126             paragraphWritten.lineSpacing = -900;
1127         }
1128     }
1129 
1130     if (section.newSection) EndSection();
1131     insideEquation = false;
1132 }
1133 
1134 /*
1135  * Closes last paragraph and insert some line feeds.
1136  */
1137 
EndParagraph(void)1138 static void EndParagraph(void)
1139 {
1140     FinalizeParagraph();
1141 
1142     if (insideFootnote && !suppressSpaceBetweenParagraphs) {
1143         InsertNewLine();
1144         InsertNewLine();
1145         return;
1146     }
1147 
1148     if (insideTable) {
1149         PutLitStr("\\linebreak{}\n");
1150         return;
1151     }
1152 
1153     if (!suppressSpaceBetweenParagraphs) {
1154         InsertNewLine();
1155         InsertNewLine();
1156     }
1157 
1158     if (section.newSection) EndSection();
1159 }
1160 
1161 /*
1162  * Writes cell information for each cell. Similiar to NewParagraph()
1163  * Each cell is defined in a multicolumn
1164  * environment for maximum flexibility. Useful when we have merged rows and columns.
1165  */
NewCell(void)1166 static void NewCell(void)
1167 {
1168     char buf[rtfBufSiz];
1169     cellStruct *cell = CellGetByIndex(table.cellCount);
1170 
1171     if (cell->col != 0) PutLitStr(" & ");
1172 
1173     if (cell->columnSpan == 1) {
1174 
1175         if (prefs[pConvertTableAlignment] && paragraph.alignment != left) {
1176             snprintf(buf,rtfBufSiz, "%s ", justificationList[paragraph.alignment]);
1177             PutLitStr(buf);
1178         }
1179 
1180     } else {
1181 
1182         if (cell->col == 0)
1183             snprintf(buf, rtfBufSiz, "\\multicolumn{%d}{|p{%dpt}|}{", cell->columnSpan, CellWidth(cell));
1184         else
1185             snprintf(buf, rtfBufSiz, "\\multicolumn{%d}{p{%dpt}|}{",  cell->columnSpan, CellWidth(cell));
1186         PutLitStr(buf);
1187 
1188         if (prefs[pConvertTableAlignment]) {
1189             if (paragraph.alignment!=left){
1190                 snprintf(buf,rtfBufSiz, "%s ", justificationList[paragraph.alignment]);
1191                 PutLitStr(buf);
1192             }
1193             InsertNewLine();
1194         }
1195 
1196     }
1197 
1198 //    if (cell->verticalMerge == mergeTop)
1199 //        CellMultirow(cell);
1200 
1201     if (g_debug_table_writing)  {
1202         snprintf(buf, rtfBufSiz, "[cell \\#%d]", table.cellCount);
1203         PutLitStr(buf);
1204     }
1205     nowBetweenCells = false;
1206     NewParagraph();
1207 }
1208 
EndCell(void)1209 static void EndCell(void)
1210 {
1211     cellStruct *cell;
1212 
1213     if (g_debug_table_writing) fprintf(stderr,"* Ending cell #%d\n", table.cellCount);
1214 
1215     if (nowBetweenCells) {
1216         if (g_debug_table_writing) fprintf(stderr,"* cell #%d is empty\n", table.cellCount);
1217         NewCell();
1218     }
1219 
1220     nowBetweenCells = true;
1221     FinalizeParagraph();
1222 //  StopTextStyle();
1223     cell = CellGetByIndex(table.cellCount);
1224 
1225 //  if (cell->verticalMerge == mergeTop)
1226     //  PutLitChar('}');
1227 
1228 //    if (prefs[pConvertTableAlignment])
1229 //      PutLitStr("\\end{minipage}");
1230 
1231     if (cell->columnSpan > 1)
1232         PutLitChar('}');
1233 
1234     (table.cellCount)++;
1235     paragraph.alignment = left;
1236 }
1237 
1238 
1239 
setPreamblePackages(int ignoreUsedColor)1240 static void setPreamblePackages(int ignoreUsedColor)
1241 {
1242     if (!preamblePackages)
1243         preamblePackages = malloc(1024);
1244 
1245     preamblePackages[0] = '\0';
1246     if (requireSetspacePackage)
1247         strcat(preamblePackages,"\\usepackage{setspace}\n");
1248     if (requireGraphicxPackage)
1249         strcat(preamblePackages,"\\usepackage{graphicx}\n");
1250     if (requireTablePackage)
1251         strcat(preamblePackages,"\\usepackage{array}\n");
1252     if (requireMultirowPackage)
1253         strcat(preamblePackages,"\\usepackage{multirow}\n");
1254     if (requireAmsSymbPackage)
1255         strcat(preamblePackages,"\\usepackage{amssymb}\n");
1256     if (requireMultiColPackage)
1257         strcat(preamblePackages,"\\usepackage{multicol}\n");
1258     if (requireUlemPackage)
1259         strcat(preamblePackages,"\\usepackage{ulem}\n");
1260     if (requireFixLtx2ePackage)
1261         strcat(preamblePackages,"\\usepackage{fixltx2e}\n");
1262     if (requireAmsMathPackage)
1263         strcat(preamblePackages,"\\usepackage{amsmath}\n");
1264     if (requireHyperrefPackage)
1265         strcat(preamblePackages,"\\usepackage{hyperref}\n");
1266     if (requireAMSSymbolPackage)
1267         strcat(preamblePackages,"\\usepackage{amssymb}\n");
1268 
1269 
1270     /* almost certainly want these packages for russian */
1271     if (genCharCode == cp1251CharCode) {
1272         strcat(preamblePackages,"\\usepackage[T2A]{fontenc}\n");
1273         strcat(preamblePackages,"\\usepackage[russian]{babel}\n");
1274     }
1275 
1276     if (requireFancyHdrPackage) {
1277         strcat(preamblePackages,"\\usepackage{fancyhdr}\n");
1278         strcat(preamblePackages,"\\renewcommand{\\headrulewidth}{0pt}\n");
1279         strcat(preamblePackages,"\\renewcommand{\\footrulewidth}{0pt}\n");
1280     }
1281 
1282     if (prefs[pConvertTextColor]) {
1283         int i=0;
1284         int needPackage=false;
1285 
1286         for (i=0; i<256; i++)
1287             if (UsedColor[i]) needPackage = true;
1288 
1289         if (ignoreUsedColor || (!ignoreUsedColor && needPackage))
1290             strcat(preamblePackages,"\\usepackage{color}\n");
1291     }
1292 }
1293 
1294 /*
1295  * This function writes the LaTeX header and includes some basic packages.
1296  */
WriteLaTeXHeader(void)1297 static void WriteLaTeXHeader(void)
1298 {
1299     int i, j;
1300 
1301     PutLitStr(preambleFirstText);  /* from pref/r2l-pref     */
1302     InsertNewLine();
1303     PutLitStr(preambleSecondText); /* from pref/r2l-pref     */
1304     InsertNewLine();
1305     PutLitStr(preambleDocClass);   /* from pref/r2l-pref     */
1306     InsertNewLine();
1307 
1308     /* insert latex-encoding qualifier */
1309     PutLitStr(preambleUserText);
1310 
1311     /* insert latex-encoding qualifier */
1312     PutLitStr(preambleEncoding);
1313 
1314     /* to come back and write necessary \usepackage{...}
1315      * commands if necessary */
1316     packagePos = ftell(ofp);
1317 
1318     for (j = 0; j <= PACKAGES; j++) {
1319         for (i = 0; i < 100; i++)
1320             PutLitChar(' ');
1321         PutLitChar('\n');
1322     }
1323 }
1324 
1325 /* This function make sure that the output TeX file does not
1326  * contain one very, very long line of text.
1327  */
WrapText(void)1328 static void WrapText(void)
1329 {
1330     if (wrapCount < WRAP_LIMIT) return;
1331 
1332     if (rtfMinor == rtfSC_space)
1333         PutLitChar('\n');
1334 }
1335 
MicrosoftEQFieldLiteral(void)1336 static void MicrosoftEQFieldLiteral(void)
1337 {
1338 	PutLitChar(rtfMinor);
1339 }
1340 
1341 /*
1342  *  Convert Microsoft Equation Command to LaTeX.  The parser should call
1343  *  this routine when something like \\s is encountered within a EQ field.
1344  *
1345  *  Array switch: \\a()
1346  *  Bracket: \\b()
1347  *  Fraction: \\f(,)
1348  *  Integral: \\i(,,)
1349  *  Radical: \\r(,)
1350  *  Superscript or Subscript: \\s()
1351  *
1352  *  Displace: \\d()    not done
1353  *  List: \\l()        not done
1354  *  Overstrike: \\o()  not done
1355  *  Box: \\x()         not done
1356  */
1357 
MicrosoftEQFieldCommand(void)1358 static void MicrosoftEQFieldCommand(void)
1359 {
1360 	/* subscript/superscript  \\s\\up8(UB)\\s\\do8(2)  */
1361 	if (rtfMinor == 's' || rtfMinor == 'S') {
1362 //		ExamineToken("EQ Subscript");
1363 		RTFGetNonWhiteSpaceToken();
1364 		if (rtfMajor == rtfEquationFieldCmd) {
1365 			if (rtfMinor == 'u') PutLitStr("^{");
1366 			if (rtfMinor == 'd') PutLitStr("_{");
1367 		}
1368 		RTFSkipToToken(rtfText,'(',9);
1369 		RTFExecuteToToken(rtfText,')',10);
1370 		PutLitChar('}');
1371 		return;
1372 	}
1373 
1374 	/* integrals \\i \\su(1,5,3) */
1375 	if (rtfMinor == 'i' || rtfMinor == 'I') {
1376 //		ExamineToken("EQ Integral");
1377 		RTFGetNonWhiteSpaceToken();
1378 		if (rtfMajor == rtfEquationFieldCmd) {
1379 			if (rtfMinor == 's') PutLitStr("\\sum\\limits_{");
1380 			if (rtfMinor == 'p') PutLitStr("\\prod\\limits_{");
1381 			if (rtfMinor == 'i') PutLitStr("\\int\\limits_{");
1382 		}
1383 		RTFSkipToToken(rtfText,'(',9);
1384 		RTFExecuteToToken(rtfText,',',13);
1385 		RTFGetToken();
1386 		PutLitStr("}^{");
1387 		RTFExecuteToToken(rtfText,')',10);
1388 		PutLitChar('}');
1389 		return;
1390 	}
1391 
1392 	/* fractions \\f(2,RateChange) */
1393 	if (rtfMinor == 'f' || rtfMinor == 'F') {
1394 //		ExamineToken("EQ Fraction");
1395 		RTFSkipToToken(rtfText,'(',9);
1396 		PutLitStr("{");
1397 		RTFExecuteToToken(rtfText,',',13);
1398 		/* discard comma */
1399 		PutLitStr("\\over ");
1400 		RTFExecuteParentheses();
1401 		PutLitChar('}');
1402 		return;
1403 	}
1404 
1405 	/* roots \\r(3,x) */
1406 	if (rtfMinor == 'r' || rtfMinor == 'R') {
1407 //		ExamineToken("EQ Root");
1408 		RTFSkipToToken(rtfText,'(',9);
1409 		PutLitStr("\\sqrt[");
1410 		RTFExecuteToToken(rtfText,',',13);
1411 		/* discard comma */
1412 		PutLitStr("]{");
1413 		RTFExecuteParentheses();
1414 		PutLitChar('}');
1415 		return;
1416 	}
1417 
1418 	/* braces \\b \\bc\\{ (\\r(3,x))  */
1419 	if (rtfMinor == 'b' || rtfMinor == 'B') {
1420 		char open = '(';
1421 		char close = ')';
1422 
1423 //		ExamineToken("EQ Brace");
1424 		RTFGetNonWhiteSpaceToken();
1425 
1426 		/* handle \\bc\\X \\lc\\X \\rc\\X */
1427 		while (rtfMajor == rtfEquationFieldCmd) {
1428 			char type = rtfMinor;
1429 			RTFGetToken(); /* get and discard 'c' */
1430 			RTFGetToken();
1431 
1432 			if (type == 'l') open = rtfMinor;
1433 			if (type == 'r') close = rtfMinor;
1434 			if (type == 'b') {
1435 				open = rtfMinor;
1436 				switch (open) {
1437 				case '<': close = '>'; break;
1438 				case '[': close = ']'; break;
1439 				case '{': close = '}'; break;
1440 				case '(': close = ')'; break;
1441 				default: close = open;
1442 				}
1443 			}
1444 			RTFGetNonWhiteSpaceToken();
1445 		}
1446 
1447 		if (rtfMajor != '(') RTFSkipToToken(rtfText,'(',9);
1448 		PutLitStr("\\left");
1449 		if (open=='{') PutLitChar('\\');
1450 		PutLitChar(open);
1451 
1452 		RTFExecuteParentheses();
1453 
1454 		PutLitStr("\\right");
1455 		if (close=='}') PutLitChar('\\');
1456 		PutLitChar(close);
1457 		return;
1458 	}
1459 
1460 	/* arrays { EQ \\a \\al \\co2 \\vs3 \\hs3(Axy,Bxy,A,B) } */
1461 	if (rtfMinor == 'a' || rtfMinor == 'A') {
1462 		int columns = 1;
1463 		int align = 'l';
1464 		int elements = '1';
1465 		int i;
1466 
1467 //		ExamineToken("EQ Array");
1468 		/* handle \\al \\co2 \\vs3 \\hs3 */
1469 		while (rtfMajor == rtfEquationFieldCmd) {
1470 			if (rtfMinor == 'c') {
1471 				RTFGetToken(); /*discard 'o' */
1472 				RTFGetToken();
1473 				columns = rtfMajor - '0';
1474 			}
1475 			if (rtfMinor == 'a') {
1476 				RTFGetToken();
1477 				align = rtfMajor;
1478 			}
1479 			RTFGetNonWhiteSpaceToken();
1480 		}
1481 
1482 		PutLitStr("\\begin{array}{");
1483 		for (i=0; i<columns; i++) {PutLitChar(align);}
1484 		PutLitStr("}\n");
1485 
1486 		RTFGetToken();
1487 		while (rtfMajor != ')') {
1488 			if (rtfMajor != ',')
1489 				RTFRouteToken();
1490 			else {
1491 				elements++;
1492 				if (elements % columns == 0)
1493 					PutLitStr("\\\\\n");
1494 				else
1495 					PutLitStr(" & ");
1496 			}
1497 			RTFGetToken();
1498 		}
1499 		PutLitStr("\n\\end{array}");
1500 		return;
1501 	}
1502 
1503 }
1504 
PrepareForChar(void)1505 static void PrepareForChar(void)
1506 {
1507     if (insideTable && nowBetweenCells) {
1508         NewCell();
1509         return;
1510     }
1511 
1512     if (nowBetweenParagraphs) {
1513 
1514         if (rtfMinor == rtfSC_space) {
1515             paragraph.extraIndent += 72;
1516             return;
1517         }
1518 
1519         EndParagraph();
1520         NewParagraph();
1521     }
1522 
1523     if (insideHyperlink) {
1524         switch (rtfMinor) {
1525         case rtfSC_underscore:
1526             PutLitChar('H');
1527             return;
1528         case rtfSC_backslash:
1529             RTFGetToken();  /* ignore backslash */
1530             RTFGetToken();  /* and next character */
1531             return;
1532         }
1533     }
1534 
1535     if (insideEquation && rtfMinor == rtfSC_backslash) {
1536     	RTFGetToken();
1537 		MicrosoftEQFieldCommand();
1538 	}
1539 
1540     if (rtfMinor >= rtfSC_therefore && rtfMinor < rtfSC_currency)
1541         requireAmsSymbPackage = true;
1542 
1543     WriteTextStyle();
1544 }
1545 
1546 /*
1547  * Write out a character.  rtfMajor contains the input character, rtfMinor
1548  * contains the corresponding standard character code.
1549  *
1550  * If the input character isn't in the charset map, try to print some
1551  * representation of it.
1552  */
1553 
TextClass(void)1554 static void TextClass(void)
1555 {
1556     PrepareForChar();
1557     PutStdChar(rtfMinor);
1558     WrapText();
1559 }
1560 
1561 /*
1562  * Put a footnote wrapper around whatever is inside the footnote.
1563  */
ReadFootnote(void)1564 static void ReadFootnote(void)
1565 {
1566     int footnoteGL;
1567 
1568 	CheckForBeginDocument();
1569     StopTextStyle();
1570     footnoteGL = RTFGetBraceLevel();
1571     PutLitStr("\\footnote{");
1572     insideFootnote = true;
1573     nowBetweenParagraphs = false;  /*no need to end last paragraph */
1574     while (RTFGetBraceLevel() >= footnoteGL) {
1575         RTFGetToken();
1576         RTFRouteToken();
1577     }
1578     PutLitStr("}");
1579     insideFootnote = false;
1580 }
1581 
1582 /* <celldef> = (\clmgf? & \clmrg? & \clvmgf? & \clvmrg? <celldgu>? & <celldgl>? &
1583                <cellalign>? & <celltop>? & <cellleft>? & <cellbot>? & <cellright>? &
1584                <cellshad>? & <cellflow>? & clFitText? & clNoWrap? & <cellwidth>? <cellrev>? &
1585                <cellins>? & <celldel>? & <cellpad>? & <cellsp>?) \cellxN
1586 */
1587 
DoTableAttr(void)1588 static void DoTableAttr(void)
1589 {
1590 cellStruct *cell;
1591 
1592     switch (rtfMinor) {
1593     case rtfRowLeftEdge:
1594         table.leftEdge = rtfParam;
1595         break;
1596     case rtfCellPos:  /* only \cellx is a required cell token */
1597         cell = CellAllocate();
1598         CellInitialize(cell);
1599 
1600         table.theCell = cell;
1601         table.cellMergePar = mergeNone;  /* reset */
1602         table.cellCount++;
1603         ((table.cellsInRow)[table.rows])++;
1604         (table.cols)++;
1605         table.limboCellLeftBorder   = false;
1606         table.limboCellRightBorder  = false;
1607         table.limboCellTopBorder    = false;
1608         table.limboCellBottomBorder = false;
1609         break;
1610     case rtfVertMergeRngFirst:
1611         table.cellMergePar = mergeTop;
1612         break;
1613     case rtfVertMergeRngPrevious:
1614         table.cellMergePar = mergeAbove;
1615         break;
1616     case rtfCellBordTop:
1617         table.limboCellTopBorder = true;
1618         break;
1619     case rtfCellBordBottom:
1620         table.limboCellBottomBorder = true;
1621         break;
1622     case rtfCellBordRight:
1623         table.limboCellRightBorder = true;
1624         break;
1625     case rtfCellBordLeft:
1626         table.limboCellLeftBorder = true;
1627         break;
1628     }
1629 }
1630 
1631 
1632 /*
1633  * In RTF, each table row need not start with a table row definition.
1634  * The next row may decide to use the row definition of the previous
1635  * row. In that case, I need to call this InheritTableRowSettings function
1636  */
InheritTableRowSettings(void)1637 static void InheritTableRowSettings(void)
1638 {
1639     int prevRow;
1640     int cellsInPrevRow;
1641     cellStruct *cell, *newCell;
1642     int i;
1643 
1644     prevRow = table.rows-1;
1645     cellsInPrevRow = (table.cellsInRow)[prevRow];
1646 
1647     (table.cellsInRow)[prevRow + 1] = (table.cellsInRow)[prevRow];
1648 
1649     for (i = 0; i < cellsInPrevRow; i++) {
1650         cell = CellGetByPosition(prevRow, i);
1651         newCell = CellAllocate();
1652         newCell->nextCell = table.theCell;
1653         newCell->row   = prevRow + 1;
1654         newCell->col   = cell->col;
1655         newCell->originalLeft  = cell->originalLeft;
1656         newCell->originalRight = cell->originalRight;
1657         newCell->index = table.cellCount;
1658         newCell->verticalMerge = cell->verticalMerge;
1659         table.cellMergePar = mergeNone;
1660         table.theCell = newCell;
1661         table.cellCount++;
1662     }
1663 }
1664 
1665 /*
1666  * This function counts the number of columns a cell spans.
1667  * This is done by comparing the cell's left and right edges
1668  * to the sorted column border array. If the left and right
1669  * edges of the cell are not consecutive entries in the array,
1670  * the cell spans multiple columns.
1671  */
GetColumnSpan(cellStruct * cell)1672 static int GetColumnSpan(cellStruct * cell)
1673 {
1674     int i, j;
1675 
1676     /* index of border that equals the left side of the cell */
1677     for (i = 0; i < table.cols; i++) {
1678         if ((table.rightColumnBorders)[i] == cell->originalLeft)
1679             break;
1680     }
1681 
1682     /* index of border that equals the right side of the cell */
1683     for (j = i; j < table.cols + 1; j++){
1684         if ((table.rightColumnBorders)[j] == cell->originalRight)
1685             break;
1686     }
1687 
1688 //  fprintf(stderr, "sought (%5d,%5d), found (%5d,%5d), for (%d,%d)\n",
1689     //        cell->originalLeft, cell->originalRight,
1690       //      (table.rightColumnBorders)[i],
1691         //    (table.rightColumnBorders)[j],
1692           //  i,j);
1693 
1694     return (j - i);
1695 }
1696 
1697 
1698 /*
1699  * This routine prescans the table.
1700  *
1701  * This is needed because RTF does not have a table construct.  Instead, each
1702  * row is laid out as a series of cells with markup for each.  So, this routine
1703  * counts how many rows there are in the table and the number of cells in each row.
1704  * In addition, it calculates the cell widths and builds an array of column borders.
1705  * The latter is useful in figuring out whether a cell spans
1706  * multiple columns.
1707  *
1708  * Finally, it turns out that to support vertically merged cells, the
1709  * contents of each cell need to also be collected.  This has yet to be
1710  * implemented.
1711  */
PrescanTable(void)1712 static void PrescanTable(void)
1713 {
1714     int i, j, *rightBorders, maxCol;
1715     cellStruct *cell, *previousCell;
1716     boolean gatherCellInfo, foundRow, lastRow;
1717 
1718     RTFParserState(SAVE_PARSER);
1719 
1720     table.rows = 0;
1721     table.cellCount = 0;
1722     table.theCell = NULL;
1723 
1724     /* Prescan each row until end of the table. */
1725     foundRow = true;
1726     lastRow = false;
1727 
1728     /*
1729      * Scan the whole table.  First, gather the cell layout information and then
1730      * check to see if another row of the table exists.  repeat until no more rows
1731      * are found.  The overall structure is
1732      *
1733      * <row>     = (<tbldef> <cell>+ <tbldef> \row) | (<tbldef> <cell>+ \row) | (<cell>+ <tbldef> \row)
1734      * <cell>    = (<nestrow>? <tbldef>?) & <textpar>+ \cell
1735      * <tbldef>  = \trowd \irowN  ... <celldef>+
1736      * <celldef> = ... \cellxN
1737      */
1738 
1739     while (foundRow) {
1740         table.cols = 0;
1741 
1742         if (0 && g_debug_table_prescan) fprintf(stderr,"*********** starting row %d\n", table.rows);
1743 
1744         /* Gather cell layout information ... the three possible token streams are:
1745          *
1746          *  1) \trowd .... \cellxN ... \cellxM ... \trowd ... \cellxN ... \cellxM ...\row
1747          *  2) \trowd .... \cellxN ... \cellxM ...\row
1748          *  3)        .... \cellxN ... \cellxM ...\row
1749          */
1750 
1751         if (RTFCheckMM(rtfTblAttr, rtfRowDef)) {
1752             gatherCellInfo = true;
1753             (table.cellsInRow)[table.rows] = 0;
1754         } else {
1755             InheritTableRowSettings();
1756             gatherCellInfo = false;
1757         }
1758 
1759         while (RTFGetToken() != rtfEOF) {
1760 
1761             if (RTFCheckMM(rtfSpecialChar, rtfRow))
1762                 break;
1763 
1764             if (RTFCheckMM(rtfTblAttr, rtfRowDef)) {
1765                 gatherCellInfo=false;
1766                 continue;
1767             }
1768 
1769             if (RTFCheckMM(rtfSpecialChar, rtfLastRow)) {
1770                 lastRow = true;
1771                 continue;
1772             }
1773 
1774             if (RTFCheckCM(rtfControl, rtfTblAttr)) {
1775                 if (gatherCellInfo) RTFRouteToken();
1776             }
1777 
1778             if (RTFCheckMM(rtfSpecialChar, rtfOptDest))
1779                 RTFSkipGroup();
1780         }
1781 
1782         if (0 && g_debug_table_prescan) fprintf(stderr,"* reached end of row %d\n", table.rows);
1783 
1784         (table.rows)++;
1785         if (lastRow) break;
1786 
1787         /* Look for another row, indicated by either \trowd or \intbl
1788          * \intbl should always follow \widctrpar
1789          */
1790 
1791         foundRow = false;
1792 
1793         while (RTFGetToken() != rtfEOF) {
1794 
1795             if (RTFCheckMM(rtfTblAttr, rtfRowDef)) {
1796                 foundRow = true;
1797                 break;
1798             }
1799 
1800             /* \intbl must follow \widctlpar or the next paragraph is not part of the table */
1801             if (RTFCheckMM(rtfParAttr, rtfNoWidowControl) || RTFCheckMM(rtfParAttr, rtfWidowCtlPar)) {
1802                 RTFGetToken();
1803                 if (!RTFCheckMM(rtfParAttr, rtfInTable)) break;
1804             }
1805 
1806             if (RTFCheckMM(rtfParAttr, rtfInTable)) {
1807                 foundRow = true;
1808                 break;
1809             }
1810 
1811             if (rtfClass == rtfText)
1812                 break;
1813 
1814             if (RTFCheckCM(rtfControl, rtfSpecialChar))
1815                 break;
1816 
1817             if (RTFCheckMM(rtfSpecialChar, rtfOptDest))
1818                 RTFSkipGroup();
1819         }
1820     }
1821 
1822     /*************************************************************************
1823      * Determine the number of columns and positions in the table by creating
1824      * a list containing one entry for each unique right border
1825      * This list is retained as table.rightColumnBorders
1826      * The number of columns is table.cols
1827      */
1828 
1829     /* largest possible list */
1830     rightBorders = (int *) RTFAlloc((table.cellCount) * sizeof(int));
1831     rightBorders[0] = 0;
1832 
1833     table.cols = 0;
1834     for (cell = table.theCell; cell != NULL; cell = cell->nextCell) {
1835         boolean cellBorderExistsAlready = false;
1836 
1837         for (i = 0; i < table.cols; i++) {
1838             if (rightBorders[i] == cell->originalRight) {
1839                 cellBorderExistsAlready=true;
1840                 break;
1841             }
1842         }
1843 
1844         if (!cellBorderExistsAlready) {
1845             rightBorders[table.cols] = cell->originalRight;
1846             (table.cols)++;
1847         }
1848 
1849         if (cell->col == 0)
1850             cell->originalLeft = table.leftEdge;
1851     }
1852 
1853     /* since rightBorders is too large, allocate correct size array for column border entries. */
1854     table.rightColumnBorders = (int *) RTFAlloc(((table.cols) + 1) * sizeof(int));
1855 
1856     (table.rightColumnBorders)[0] = table.leftEdge;
1857     for (i = 0; i < table.cols; i++)
1858         (table.rightColumnBorders)[i + 1] = rightBorders[i];
1859 
1860     RTFFree((char *)rightBorders);
1861 
1862     if (0 && g_debug_table_prescan) fprintf(stderr,"* table has %d rows and %d cols \n", table.rows, table.cols);
1863 
1864     /*
1865      * sort rightColumnBorders into ascending order.
1866      */
1867 
1868     for (i = 0; i < (table.cols); i++)
1869         for (j = i + 1; j < (table.cols + 1); j++)
1870             if ((table.rightColumnBorders)[i] > (table.rightColumnBorders)[j])
1871                 Swap((table.rightColumnBorders)[i], (table.rightColumnBorders)[j]);
1872 
1873     /*
1874      * fill in column spans for each cell.  GetColumnSpan uses table.rightColumnBorders
1875      * to decide if a cell spans multiple columns.
1876      */
1877     maxCol = 0;
1878 
1879     for (i = 0; i < table.cellCount; i++) {
1880         cell = CellGetByIndex(i);
1881 
1882         cell->columnSpan = GetColumnSpan(cell);
1883 
1884         /* update the column to account for multicolumn cells */
1885         if (cell->col > 0)
1886             cell->col = previousCell->col + previousCell->columnSpan;
1887 
1888         previousCell = cell;
1889     }
1890 
1891     /* adjust spacing for extra intercolumn space added by latex */
1892     for (i = 1; i <= table.cols; i++)
1893         (table.rightColumnBorders)[i] -= i*latexColumnSeparation;
1894 
1895     /* if the table is wider than textWidth, scale it appropriately */
1896     if (prefs[pConvertTableWidths] && table.rightColumnBorders[table.cols]+latexColumnSeparation*table.cols > textWidth) {
1897         float scale = 1.0*(textWidth-latexColumnSeparation*table.cols)/table.rightColumnBorders[table.cols];
1898 
1899         for (i = 1; i <= table.cols; i++)
1900             table.rightColumnBorders[i] = (int) (table.rightColumnBorders[i]*scale+0.5);
1901     }
1902 
1903     if (g_debug_table_prescan) {
1904         for (cell = table.theCell; cell != NULL; cell = cell->nextCell) {
1905             fprintf(stderr,"* cell #%3d (%2d, %2d) ", cell->index, cell->row, cell->col);
1906             fprintf(stderr,"left=%3dpt right=%3dpt ", cell->originalLeft/20, cell->originalRight/20);
1907             fprintf(stderr,"width=%3dpt ", CellWidth(cell));
1908             fprintf(stderr,"and spans %d columns", cell->columnSpan);
1909             fprintf(stderr," [vertical merge = %d]\n", cell->verticalMerge);
1910         }
1911     }
1912 
1913     /* go back to beginning of the table */
1914     RTFParserState(RESTORE_PARSER);
1915 }
1916 
1917 /* This is where we translate each row to latex. */
TableWriteRow(void)1918 static void TableWriteRow(void)
1919 {
1920     nowBetweenCells = true;
1921 
1922     while (RTFGetToken() != rtfEOF) {
1923 
1924         /* these have already been processed during prescanning */
1925         if (RTFCheckCM(rtfControl, rtfTblAttr))
1926             continue;
1927 
1928         /* token that signals end of the row */
1929         if (RTFCheckCMM(rtfControl, rtfSpecialChar, rtfRow)) {
1930             if (g_debug_table_writing) fprintf(stderr,"* end of row\n");
1931             suppressLineBreak = false;
1932             return;
1933         }
1934 
1935         /* token that signals last row in table */
1936         if (RTFCheckCMM(rtfControl, rtfSpecialChar, rtfLastRow))
1937             continue;
1938 
1939         /* token that signals the end of the current cell */
1940         if (RTFCheckCMM(rtfControl, rtfSpecialChar, rtfCell)) {
1941             EndCell();
1942             continue;
1943         }
1944 
1945         RTFRouteToken();
1946     }
1947 }
1948 
1949 /*
1950  * This function draws horizontal lines within a table. It looks
1951  * for vertically merged rows that do not have any bottom border
1952  */
DrawTableRowLine(int rowNum)1953 static void DrawTableRowLine(int rowNum)
1954 {
1955     int i, cellPosition;
1956     cellStruct *theCell1, *theCell2;
1957     char buf[rtfBufSiz];
1958 
1959     /* if we are at the last row of the table, just draw a straight \hline. */
1960     if (rowNum == (table.rows) - 1 || !table.multiRow) {
1961         PutLitStr("\\hline");
1962         InsertNewLine();
1963         return;
1964     }
1965 
1966     /* otherwise use \cline for every cell */
1967     /* this is to count cell positions as if the table is a matrix. */
1968     cellPosition = 0;
1969     for (i = 0; i < (table.cellsInRow)[rowNum]; i++) {
1970 
1971         theCell1 = CellGetByPosition(rowNum, cellPosition);
1972         cellPosition += theCell1->columnSpan;
1973 
1974         if (theCell1->verticalMerge == mergeNone) {
1975             snprintf(buf, rtfBufSiz, "\\cline{%d-%d}", theCell1->col + 1, theCell1->col + theCell1->columnSpan);
1976             PutLitStr(buf);
1977             continue;
1978         }
1979 
1980         if (theCell1->verticalMerge == mergeAbove) {
1981             theCell2 = CellGetByPosition(rowNum + 1, i);
1982             if (theCell2->verticalMerge != mergeAbove) {
1983                 snprintf(buf, rtfBufSiz, "\\cline{%d-%d}", theCell1->col + 1, theCell1->col + theCell1->columnSpan);
1984                 PutLitStr(buf);
1985             }
1986         }
1987     }
1988 
1989     InsertNewLine();
1990 }
1991 
1992 /*
1993 \begin{tabular}{\textwidth}{|>{\raggedright}p{99pt}|>{\raggedright}p{99pt}|...}
1994 ...
1995 \end{tabular}
1996 */
DoTablePreamble(void)1997 static void DoTablePreamble(void)
1998 {
1999     char buf[200];
2000     int i, width;
2001 
2002     width = (table.rightColumnBorders[table.cols]-table.rightColumnBorders[0])/20;
2003 
2004     snprintf(buf, 200, "\\begin{tabular}{");
2005     PutLitStr(buf);
2006 
2007     for (i = 0; i < table.cols; i++) {
2008     	int width = (table.rightColumnBorders[i+1]-table.rightColumnBorders[i])/20;
2009         snprintf(buf, 200, "|>{\\raggedright}p{\%dpt}", width);
2010         PutLitStr(buf);
2011     }
2012 
2013     PutLitStr("|}\n\\hline\n");
2014 }
2015 
2016 /*
2017  * When we reach a table, we don't know anything about it.  Initially,
2018  * we need to know the number of columns and width of each column. Later,
2019  * we need to know if a cell spans multiple columns.  One day, the
2020  * borders on cells might be used ... but not now.
2021  *
2022  * Therefore, we prescan the data and collect information about every
2023  * cell into a linked list of cells.  The table structure is filled in
2024  * with information that describes the table as a whole and a pointer
2025  * to the linked list of cells.
2026  *
2027  * After prescanning the table, the entire table is reread, but this time
2028  * the contents of each cell are translated.
2029  */
DoTable(void)2030 static void DoTable(void)
2031 {
2032     int i;
2033     cellStruct *cell;
2034     int oldwritten, oldparagraph;
2035 
2036     EndParagraph();
2037     NewParagraph();
2038 
2039     oldwritten = paragraphWritten.alignment;
2040     oldparagraph = paragraph.alignment;
2041     paragraphWritten.alignment = left;
2042     paragraph.alignment = left;
2043 
2044     requireTablePackage = true;
2045 
2046     /* throw away old cell information lists */
2047     while (table.theCell) {
2048         cell = (table.theCell)->nextCell;
2049         RTFFree((char *) table.theCell);
2050         table.theCell = cell;
2051     }
2052 
2053     PrescanTable();
2054     table.cellCount = 0;
2055     insideTable = true;
2056 
2057     DoTablePreamble();
2058 
2059     for (i = 0; i < table.rows; i++) {
2060         if (g_debug_table_writing) fprintf(stderr,"* Starting row #%d\n",i+1);
2061         TableWriteRow();
2062 
2063 //        PutLitStr("\\\\\n");
2064         PutLitStr("\\tabularnewline\n");
2065 
2066         if (i < (table.rows - 1))
2067             DrawTableRowLine(i);
2068     }
2069 
2070     PutLitStr("\\hline\n");
2071     PutLitStr("\\end{tabular}");
2072 
2073     nowBetweenParagraphs = true;
2074 
2075     RTFFree((char *) table.rightColumnBorders);
2076     insideTable = false;       /* end of table */
2077     table.multiRow = false;
2078 
2079     paragraphWritten.alignment = oldwritten;
2080     paragraph.alignment = oldparagraph;
2081 }
2082 
2083 /* set paragraph attributes that might be useful */
ParAttr(void)2084 static void ParAttr(void)
2085 {
2086     if (insideFootnote || insideHyperlink || insideHeaderFooter)
2087         return;
2088 
2089     switch (rtfMinor) {
2090     case rtfSpaceBetween:
2091         paragraph.lineSpacing = rtfParam;
2092         break;
2093     case rtfQuadCenter:
2094         paragraph.alignment = center;
2095         break;
2096     case rtfQuadJust:
2097     case rtfQuadLeft:
2098         paragraph.alignment = left;
2099         break;
2100     case rtfQuadRight:
2101         paragraph.alignment = right;
2102         break;
2103 
2104     case rtfParDef:
2105         paragraph.firstIndent = 0;
2106         paragraph.leftIndent = 0;
2107         paragraph.extraIndent = 0;
2108         paragraph.alignment = left;
2109         paragraph.styleIndex = -1;
2110         break;
2111 
2112     case rtfStyleNum:
2113         if (prefs[pConvertParagraphStyle] && rtfParam < MAX_STYLE_MAPPINGS)
2114             paragraph.styleIndex = Style2LatexMapIndex[rtfParam];
2115         else
2116             paragraph.styleIndex = -1;
2117         break;
2118 
2119     case rtfFirstIndent:
2120         paragraph.firstIndent = rtfParam;
2121         break;
2122     case rtfLeftIndent:
2123         paragraph.leftIndent = rtfParam;
2124         break;
2125     case rtfRightIndent:
2126         paragraph.rightIndent = rtfParam;
2127         break;
2128     case rtfSpaceBefore:
2129         paragraph.spaceBefore = rtfParam;
2130         break;
2131     case rtfSpaceAfter:
2132         paragraph.spaceAfter = rtfParam;
2133         break;
2134     }
2135 
2136 }
2137 
SectAttr(void)2138 static void SectAttr(void)
2139 {
2140     if (insideHeaderFooter) return;
2141 
2142     switch (rtfMinor) {
2143     case rtfColumns:
2144         section.cols = rtfParam;
2145         break;
2146     case rtfSectDef:
2147         section.cols = 1;
2148         section.newPage = 1;
2149         break;
2150     default:
2151         break;
2152     }
2153 }
2154 
2155 /*
2156  * This function rewrites the LaTeX file with simpler header
2157  */
EndLaTeXFile(void)2158 void EndLaTeXFile(void)
2159 {
2160     FILE *nfp=NULL;
2161     int numr,len;
2162     char* newname;
2163     char* oldname;
2164     char buffer[512];
2165 
2166     /* last few bits */
2167     EndParagraph();
2168     EndSection();
2169     if (g_shouldIncludePreamble)
2170         PutLitStr("\n\n\\end{document}\n");
2171 
2172     /* open new file, changing name from file.ltx to file.tex*/
2173     oldname = RTFGetOutputName();
2174     newname = strdup(oldname);
2175     len = strlen(newname);
2176     newname[len-3]='t';
2177     newname[len-2]='e';
2178     nfp = fopen(newname, "wb");
2179     if (!nfp) return;
2180 
2181     /* prepare */
2182     RTFSetOutputStream(nfp);
2183     RTFSetOutputName(newname);
2184 
2185     if (g_shouldIncludePreamble) {
2186         /* write improved header */
2187         suppressLineBreak = false;
2188         PutLitStr(preambleFirstText);  /* from pref/r2l-pref     */
2189         InsertNewLine();
2190         PutLitStr(preambleSecondText); /* from pref/r2l-pref     */
2191         InsertNewLine();
2192         PutLitStr(preambleDocClass);   /* from pref/r2l-pref     */
2193         InsertNewLine();
2194         PutLitStr(preambleEncoding);   /* from pref/latex-encoding */
2195         InsertNewLine();
2196         InsertNewLine();
2197         setPreamblePackages(false);
2198         PutLitStr(preamblePackages);   /* as needed */
2199 
2200         PutLitStr(preambleUserText);   /* from pref/r2l-head      */
2201         InsertNewLine();
2202 
2203         if (preambleFancyHeader){
2204             PutLitByteStr("\\pagestyle{fancy}\n");
2205             PutLitByteStr("\\rhead{}\n\\rfoot{}\n\\chead{}\n\\cfoot{}\n");
2206             PutLitByteStr(preambleFancyHeader);
2207             InsertNewLine();
2208         }
2209 
2210         if (preambleFancyHeaderFirst){
2211             PutLitByteStr("\\fancypagestyle{plain}{\n");
2212             PutLitByteStr("  \\rhead{}\n  \\rfoot{}\n  \\chead{}\n  \\cfoot{}\n");
2213             PutLitByteStr(preambleFancyHeaderFirst);
2214             PutLitByteStr("}\n");
2215             PutLitByteStr("\\thispagestyle{plain}\n");
2216             InsertNewLine();
2217         }
2218     }
2219 
2220     InsertNewLine();
2221     DefineColors(false);
2222     InsertNewLine();
2223     PutLitByteStr(preambleOurDefs);    /* e.g., \tab */
2224     InsertNewLine();
2225 
2226     /* now copy the body of the document */
2227     fseek(ofp, beginDocumentPos, 0);
2228 
2229     while(!feof(ofp)){
2230         numr = fread(buffer,1,512,ofp);
2231         fwrite(buffer,1,numr,nfp);
2232     }
2233 
2234     /* close files and delete old one */
2235     free(newname);
2236     fclose(ofp);
2237     fclose(nfp);
2238     unlink(oldname);
2239 }
2240 
2241 /* sets the output stream */
RTFSetOutputStream(stream)2242 void RTFSetOutputStream(stream)
2243 FILE *stream;
2244 {
2245     ostream = stream;
2246 }
2247 
2248 /* This function looks for the beginning of the hex data in a \pict structure */
HexData(void)2249 static int HexData(void)
2250 {
2251     /* get the next token */
2252     RTFGetToken();
2253 
2254     /* if we fall into a group, skip the whole she-bang */
2255     if (RTFCheckCM(rtfGroup, rtfBeginGroup) != 0) {
2256         RTFPeekToken();
2257         while ((int) (rtfTextBuf[0]) == 0x0a || (int) (rtfTextBuf[0]) == 0x0d) {
2258             RTFGetToken();      /* skip any carriage returns */
2259             RTFPeekToken();     /* look at the next token to check if there is another row */
2260         }
2261 
2262         /*
2263          * there are some groups within the header that contain text data that should not
2264          * be confused with hex data
2265          */
2266         if (RTFCheckMM(rtfDestination, rtfShapeProperty) != 0 || strcmp(rtfTextBuf, "\\*") == 0)
2267         {
2268             RTFSkipGroup();
2269             return (0);
2270         }
2271     }
2272 
2273     /* paydirt, hex data starts */
2274     if (rtfClass == rtfText)
2275         return (1);
2276 
2277     /* no such luck, but set picture attributes when encountered */
2278     if (RTFCheckCM(rtfControl, rtfPictAttr)) {
2279         RTFRouteToken();
2280     }
2281     return (0);
2282 
2283 }
2284 
2285 /*
2286  * return true for upper or lower case hex character
2287  */
ishex(char c)2288 static int ishex(char c)
2289 {
2290     if ( '0' <= c && c <= '9' )
2291         return 1;
2292     if ('a' <= c && c <= 'f')
2293         return 1;
2294     if ('A' <= c && c <= 'F')
2295         return 1;
2296     return 0;
2297 }
2298 
2299 /*
2300  * Read two characters of hex-encoded object data as an unsigned char
2301  */
ReadHexPair(void)2302 static int ReadHexPair(void)
2303 {
2304     int hexNumber;
2305 
2306     do
2307         RTFGetToken();
2308     while (rtfTextBuf[0] == 0x0a || rtfTextBuf[0] == 0x0d);
2309 
2310     if (!ishex(rtfTextBuf[0])) {
2311         fprintf(stderr, "oddness encountered in hex data\n");
2312         return -1;
2313     }
2314 
2315     hexNumber = 16 * RTFCharToHex(rtfTextBuf[0]);
2316 
2317     do
2318         RTFGetToken();
2319     while (rtfTextBuf[0] == 0x0a || rtfTextBuf[0] == 0x0d);
2320 
2321     if (!ishex(rtfTextBuf[0])) {
2322         fprintf(stderr, "oddness encountered in hex data\n");
2323         return -1;
2324     }
2325 
2326     return hexNumber + RTFCharToHex(rtfTextBuf[0]);
2327 }
2328 
2329 /*
2330  * Here we create an Aldus Placeable Metafile by including a 22-byte header
2331  */
WriteWMFHeader(FILE * pictureFile)2332 static void WriteWMFHeader(FILE * pictureFile)
2333 {
2334     unsigned char wmfhead[22] = {
2335         /* Magic      = */ 0xd7, 0xcd, 0xc6, 0x9a,
2336         /* handle     = */ 0x00, 0x00,
2337         /* left       = */ 0x00, 0x00,
2338         /* top        = */ 0x00, 0x00,
2339         /* right      = */ 0xff, 0xff,
2340         /* bottom     = */ 0xff, 0xff,
2341         /* resolution = */ 0xA0, 0x05,
2342         /* reserved   = */ 0x00, 0x00, 0x00, 0x00,
2343         /* checksum   = */ 0x00, 0x00
2344     };
2345 
2346     int i;
2347     int height, width;
2348 
2349     if (picture.goalHeight) {
2350         height = (int)(picture.goalHeight * picture.scaleY * 96.0 / rtfTpi);
2351     } else {
2352         height = (int)(picture.height * picture.scaleY * 96.0 / rtfTpi);
2353     }
2354 
2355     if (picture.goalWidth) {
2356         width = (int)(picture.goalWidth * picture.scaleX * 96.0 / rtfTpi);
2357     } else {
2358         width = (int)(picture.width * picture.scaleX * 96.0 / rtfTpi);
2359     }
2360 
2361     height = picture.goalHeight;
2362     width = picture.goalWidth ;
2363     wmfhead[10] = (width) % 256;
2364     wmfhead[11] = (width) / 256;
2365     wmfhead[12] = (height) % 256;
2366     wmfhead[13] = (height) / 256;
2367 
2368     /* Normally, the resolution is 1440 twips per inch; however, this number may be changed
2369      * to scale the image. A value of 720 indicates that the image is double its
2370      * normal size, or scaled to a factor of 2:1. A value of 360 indicates a scale of
2371      * 4:1, while a value of 2880 indicates that the image is scaled down in size by
2372      * a factor of two. A value of 1440 indicates a 1:1 scale ratio.
2373      *
2374      * For now it is left as 1440 0x05A0
2375      */
2376 
2377     /* compute Checksum */
2378     wmfhead[20] = 0;
2379     wmfhead[21] = 0;
2380     for (i = 0; i < 20; i += 2) {
2381         wmfhead[20] ^= wmfhead[i];
2382         wmfhead[21] ^= wmfhead[i + 1];
2383     }
2384     fwrite(wmfhead, 22, 1, pictureFile);
2385 }
2386 
WritePICTHeader(FILE * pictureFile)2387 static void WritePICTHeader(FILE * pictureFile)
2388 {
2389     int i, h[12];
2390 
2391     /* check for possibility of pre-existing 512 byte header */
2392     for (i=0; i<12; i++)
2393         h[i]=ReadHexPair();
2394 
2395     /* magic numbers for version 1 and version 2 pict files */
2396     if ( (h[10]==0x11 && h[11]==0x01) || (h[10]==0x00 && h[11]==0x11) )  {
2397 	    for (i = 0; i < 512; i++)
2398 	        fputc(' ', pictureFile);
2399     }
2400 
2401     /* write out the header information */
2402     for (i=0; i<12; i++)
2403         fputc(h[i], pictureFile);
2404 }
2405 
NewFigureName(char * fileSuffix)2406 static char * NewFigureName(char *fileSuffix)
2407 {
2408     char dummyBuf[rtfBufSiz];
2409     char *name;
2410 
2411     if (fileSuffix && fileSuffix[0] == '.') fileSuffix++;
2412 
2413     /* get input file name and create corresponding picture file name */
2414     name = strdup(RTFGetOutputName());
2415     if (strlen(name) > 4)
2416         name[strlen(name)-4] = '\0';
2417 
2418     if (fileSuffix == NULL)
2419         snprintf(dummyBuf, rtfBufSiz, "%s-fig%03d.???", name, picture.count);
2420     else
2421         snprintf(dummyBuf, rtfBufSiz, "%s-fig%03d.%s", name, picture.count, fileSuffix);
2422 
2423     free(name);
2424     return strdup(dummyBuf);
2425 }
2426 
2427 /* start reading hex encoded picture */
ConvertHexPicture(char * fileSuffix)2428 static void ConvertHexPicture(char *fileSuffix)
2429 {
2430     FILE *pictureFile;
2431     char pictByte;
2432     int groupEnd = false;
2433     short hexNumber;
2434     short hexEvenOdd = 0;       /* check if we read in an even number of hex characters */
2435 
2436     /* increment the picture counter */
2437     (picture.count)++;
2438 
2439     if (picture.name) free(picture.name);
2440     picture.name=NewFigureName(fileSuffix);
2441 
2442     /* open picture file */
2443     if ((pictureFile = fopen(picture.name, "wb")) == NULL)
2444         RTFPanic("Cannot open input file %s\n", picture.name);
2445 
2446     /* write appropriate header */
2447     if (picture.type== pict)
2448         WritePICTHeader(pictureFile);
2449 
2450     if (picture.type== wmf)
2451         WriteWMFHeader(pictureFile);
2452 
2453     /* now we have to read the hex code in pairs of two
2454      * (1 byte total) such as ff, a1, 4c, etc...*/
2455     while (!groupEnd) {
2456 
2457         do
2458         	RTFGetToken();
2459         while (rtfTextBuf[0] == 0x0a || rtfTextBuf[0] == 0x0d);
2460 
2461         if (rtfClass == rtfGroup)
2462             break;
2463 
2464         if (!groupEnd) {
2465             hexNumber = 16 * RTFCharToHex(rtfTextBuf[0]);
2466             hexEvenOdd++;
2467         }
2468 
2469         do
2470         	RTFGetToken();
2471         while (rtfTextBuf[0] == 0x0a || rtfTextBuf[0] == 0x0d);
2472 
2473         if (rtfClass == rtfGroup)
2474             break;
2475 
2476         if (!groupEnd) {
2477             hexNumber += RTFCharToHex(rtfTextBuf[0]);   /* this is the the number */
2478             hexEvenOdd--;
2479             /* shove that number into a character of 1 byte */
2480             pictByte = hexNumber;
2481             fputc(pictByte, pictureFile);
2482         }
2483     }
2484 
2485     if (fclose(pictureFile) != 0)
2486         printf("* error closing picture file %s\n", picture.name);
2487     if (hexEvenOdd)
2488         printf("* Warning! Odd number of hex characters read for picture %s\n",
2489              picture.name);
2490 }
2491 
2492 /*
2493  * Write appropriate commands to include the picture
2494  */
IncludeGraphics(char * pictureType)2495 static void IncludeGraphics(char *pictureType)
2496 {
2497     char *filename;
2498     char dummyBuf[rtfBufSiz];
2499     float trueWidth, trueHeight;
2500     int finalWidth, finalHeight;
2501     int displayFigure = 0;
2502     int isOpenOfficePDF = 0;
2503     int pictConverted = 0;
2504     static pict2pdf_exists = -1;
2505     static unoconv_exists = -1;
2506 
2507     /* it seems that when cropping is -4319 or -6084 the picture is empty */
2508     if (picture.cropTop<-1000) {
2509         unlink(picture.name);
2510     	(picture.count)--;  /* decrement the picture counter to keep figures sequential*/
2511     	return;
2512     }
2513 
2514 #ifdef UNIX
2515 	if (pict2pdf_exists == -1 && strcmp(pictureType, "pict") == 0)
2516        pict2pdf_exists = system("command -v pict2pdf") ? 0 : 1;
2517 
2518 	if (unoconv_exists == -1 && (strcmp(pictureType, "wmf") == 0 || strcmp(pictureType, "emf") == 0))
2519        unoconv_exists = system("command -v unoconv") ? 0 : 1;
2520 
2521     if (strcmp(pictureType, "pict") == 0 && pict2pdf_exists == 1) {
2522 		snprintf(dummyBuf, rtfBufSiz, "pict2pdf '%s' ", picture.name);
2523 		fprintf(stderr, ">> %s\n", dummyBuf);
2524 		if (!system(dummyBuf)) {
2525 //                unlink(picture.name);
2526 			strcpy(strrchr(picture.name,'.')+1, "pdf");
2527 			pictConverted = 1;
2528 		}
2529     }
2530 
2531 	if (unoconv_exists == 1 && (strcmp(pictureType, "wmf") == 0 ||
2532 	                            strcmp(pictureType, "emf") == 0 ||
2533 	                            (!pictConverted && strcmp(pictureType, "pict") == 0))) {
2534 		snprintf(dummyBuf, rtfBufSiz, "unoconv -f pdf '%s' ", picture.name);
2535 		fprintf(stderr, ">> %s\n", dummyBuf);
2536 		if (!system(dummyBuf)) {
2537 //               unlink(picture.name);
2538 			isOpenOfficePDF = 1;
2539 			strcpy(strrchr(picture.name,'.')+1, "pdf");
2540 		}
2541 	}
2542 
2543 #endif
2544 #ifdef MSWIN
2545     if (strcmp(pictureType, "wmf") == 0 || strcmp(pictureType, "emf") == 0) {
2546         if (!system("which epstopdf > NUL")) {
2547             int err;
2548             char *pdfname = strdup(picture.name);
2549             strcpy(pdfname + strlen(pdfname) - 3, "pdf");
2550 
2551             snprintf(dummyBuf, rtfBufSiz, "emf2pdf.bat %s %s", picture.name, pdfname);
2552             err = system(dummyBuf);
2553 
2554             if (!err) {
2555                 unlink(picture.name);
2556                 free(picture.name);
2557                 picture.name = pdfname;
2558             } else
2559                 free(pdfname);
2560         }
2561         else {
2562             int err;
2563             char *epsname = strdup(picture.name);
2564             strcpy(epsname + strlen(epsname) - 3, "eps");
2565 
2566             snprintf(dummyBuf, rtfBufSiz, "emf2pdf.bat %s %s", picture.name, epsname);
2567             err = system(dummyBuf);
2568 
2569             if (!err) {
2570                 unlink(picture.name);
2571                 free(picture.name);
2572                 picture.name = epsname;
2573             } else
2574                 free(epsname);
2575         }
2576     }
2577 #endif
2578 
2579     /* prefer picwgoal over picw */
2580     if (picture.goalWidth)
2581         trueWidth = picture.goalWidth / 20.0;
2582     else
2583         trueWidth = picture.width;
2584 
2585     /* prefer pichgoal over pich */
2586     if (picture.goalHeight)
2587         trueHeight = picture.goalHeight / 20.0;
2588     else
2589         trueHeight = picture.height;
2590 
2591 	finalWidth  = ROUNDF(trueWidth  * picture.scaleX);
2592 	finalHeight = ROUNDF(trueHeight * picture.scaleY);
2593 
2594     filename = strrchr(picture.name, PATH_SEP);
2595     if (!filename)
2596         filename = picture.name;
2597     else
2598         filename++;
2599 
2600     if (nowBetweenParagraphs) {
2601         displayFigure = 1;
2602         EndParagraph();
2603         NewParagraph();
2604         PutLitStr("%%\\begin{figure}[htbp]");
2605     } else {
2606         displayFigure = 0;
2607         StopTextStyle();
2608     }
2609 
2610     if (0) {
2611         PutLitStr("\n\\fbox{");
2612         snprintf(dummyBuf,rtfBufSiz,"crop (t,b)=(%d,%d), scaled (w,h)=(%d,%d)\n",
2613         picture.cropTop,picture.cropBottom,finalWidth,finalHeight);
2614         PutLitStr(dummyBuf);
2615         PutLitStr("}\n\n");
2616     }
2617 
2618 	if (isOpenOfficePDF) {
2619 		int lm, tm, rm, bm;  /* left top right bottom margins*/
2620 		lm = ROUNDF((612-trueWidth)/2);
2621 		rm = ROUNDF(612-trueWidth-lm);
2622 		tm = ROUNDF((792-trueHeight)/2);
2623 		bm = ROUNDF(792-trueHeight-tm);
2624     	snprintf(dummyBuf, rtfBufSiz, "\n\\includegraphics[trim=%dpt %dpt %dpt %dpt, clip=true, width=%dpt, height=%dpt]{%s}\n",
2625              lm, tm, rm, bm, finalWidth, finalHeight, filename);
2626     } else {
2627         snprintf(dummyBuf, rtfBufSiz, "\n\\includegraphics[width=%dpt, height=%dpt, keepaspectratio=true]{%s}\n",
2628              finalWidth, finalHeight, filename);
2629 	}
2630 
2631     PutLitStr(dummyBuf);
2632 
2633     if (displayFigure) {
2634         PutLitStr("%%\\caption{This should be the caption for \\texttt{");
2635         PutEscapedLitStr(filename);
2636         PutLitStr("}.}\n");
2637         PutLitStr("%%\\end{figure}\n");
2638         EndParagraph();
2639         nowBetweenParagraphs = true;
2640     }
2641 }
2642 
2643 /* This function reads in a picture */
ReadPicture(void)2644 static void ReadPicture(void)
2645 {
2646     requireGraphicxPackage = true;
2647     picture.type = unknownPict;
2648     picture.width = 0;
2649     picture.height = 0;
2650     picture.goalWidth = 0;
2651     picture.goalHeight = 0;
2652     picture.scaleX = 1.00;
2653     picture.scaleY = 1.00;
2654 
2655 /*     RTFMsg("Starting ReadPicture ...\n"); */
2656 
2657     /* skip everything until we reach hex data */
2658     while (!HexData());
2659 
2660     /* Put back the first hex character into the stream (removed by HexData) */
2661     RTFUngetToken();
2662 
2663     /* Process picture */
2664     switch (picture.type) {
2665     case pict:
2666         RTFMsg("* Image %03d: Apple PICT format\n", picture.count+1);
2667         ConvertHexPicture("pict");
2668         IncludeGraphics("pict");
2669         break;
2670     case wmf:
2671         RTFMsg("* Image %03d: Microsoft WMF format\n", picture.count+1);
2672         ConvertHexPicture("wmf");
2673         IncludeGraphics("wmf");
2674         break;
2675     case emf:
2676         RTFMsg("* Image %03d: Microsoft EMF format\n", picture.count+1);
2677         ConvertHexPicture("emf");
2678         IncludeGraphics("emf");
2679         break;
2680     case png:
2681         RTFMsg("* Image %03d: PNG\n", picture.count+1);
2682         ConvertHexPicture("png");
2683         IncludeGraphics("png");
2684         break;
2685     case jpeg:
2686         RTFMsg("* Image %03d: JPEG\n", picture.count+1);
2687         ConvertHexPicture("jpg");
2688         IncludeGraphics("jpg");
2689         break;
2690     default:
2691         RTFMsg("* Image %03d: Unknown type\n", picture.count+1);
2692         ConvertHexPicture("???");
2693         IncludeGraphics("unknown");
2694         break;
2695     }
2696 
2697     /* feed "}" back to router */
2698     RTFRouteToken();
2699 
2700     /* reset picture type */
2701     picture.type = unknownPict;
2702     picture.width = 0;
2703     picture.height = 0;
2704     picture.goalWidth = 0;
2705     picture.goalHeight = 0;
2706     picture.scaleX = 1.00;
2707     picture.scaleY = 1.00;
2708     picture.name = NULL;
2709 }
2710 
FileDirectory(char * path)2711 static char * FileDirectory(char *path)
2712 {
2713     char *s, *dir;
2714 
2715     if (!path) return NULL;
2716 
2717     dir = strdup(path);
2718     s = strrchr(dir,PATH_SEP);
2719     if (s) {
2720         *s ='\0';
2721         return dir;
2722     }
2723 
2724     free(dir);
2725     return NULL;
2726 }
2727 
CopyFile(char * in_path,char * out_path)2728 static void CopyFile(char *in_path, char *out_path)
2729 {
2730     FILE *in, *out;
2731     char buffer[512];
2732     size_t numr;
2733 
2734     in = fopen(in_path,"rb");
2735     out = fopen(out_path,"wb");
2736 
2737     if (!in || !out) {
2738         fprintf(stderr, "failed to copy '%s' as '%s'\n", in_path, out_path);
2739         return;
2740     }
2741 
2742     while(!feof(in)){
2743         numr = fread(buffer,1,512,in);
2744         fwrite(buffer,1,numr,out);
2745     }
2746     fclose(in);
2747     fclose(out);
2748 }
2749 
2750 /*
2751  * This function reads in a picture
2752  *
2753  * {{\NeXTGraphic build.tiff \width740 \height740 \noorient}�}
2754  *
2755  */
ReadNextGraphic(void)2756 static void ReadNextGraphic(void)
2757 {
2758     char *filename, *rtf_path, *in_path, *in_dir, *out_path;
2759     char *out_name, *fileSuffix, buff[100];
2760     int width=0;
2761     int height=0;
2762 
2763     requireGraphicxPackage = true;
2764     if (nowBetweenParagraphs)
2765         NewParagraph();
2766 
2767     filename = RTFGetTextWord();
2768 
2769     if (!filename) {
2770         RTFSkipGroup();
2771         return;
2772     }
2773 
2774     /* determine the directory containing the rtf file */
2775     rtf_path = RTFGetInputName();
2776     in_dir  = FileDirectory(rtf_path);
2777 
2778     /* now establish the full path to the NextGraphic */
2779     in_path=append_file_to_path(in_dir,filename);
2780     if (in_dir) free(in_dir);
2781 
2782     /* create the path for the new graphic */
2783     (picture.count)++;
2784     fileSuffix=strrchr(filename,'.');
2785     out_path=NewFigureName(fileSuffix);
2786     free(filename);
2787 
2788     CopyFile(in_path,out_path);
2789 
2790     while (RTFGetToken() != rtfEOF) {
2791         if (RTFCheckCM(rtfGroup, rtfEndGroup)) break;
2792         if (rtfMinor == rtfNeXTGHeight) height = rtfParam/20;
2793         if (rtfMinor == rtfNeXTGWidth) width = rtfParam/20;
2794     }
2795 
2796     /* skip everything until outer brace */
2797     RTFSkipGroup();
2798 
2799     /* need the local name of the file */
2800     out_name = strrchr(out_path,PATH_SEP);
2801     if (out_name)
2802         out_name++;
2803     else
2804         out_name = out_path;
2805 
2806     PutLitStr("\\includegraphics");
2807     if (width || height) {
2808         PutLitStr("[");
2809         if (width) {
2810             snprintf(buff, 100, "width=%dpt, ", width);
2811             PutLitStr(buff);
2812         }
2813         if (height) {
2814             snprintf(buff, 100, "height=%dpt", height);
2815             PutLitStr(buff);
2816         }
2817         PutLitStr("]");
2818     }
2819     PutLitStr("{");
2820     PutLitStr(out_name);
2821     PutLitStr("}\n");
2822     if (in_path) free(in_path);
2823     if (out_path) free(out_path);
2824 }
2825 
2826 /*
2827  * slow simplistic reimplementation of strcasestr for systems that
2828  * don't include it in their library
2829  *
2830  * based on a GPL implementation in OpenTTD found under GPL v2
2831  */
2832 
my_strcasestr(const char * haystack,const char * needle)2833 static char *my_strcasestr(const char *haystack, const char *needle)
2834 {
2835     size_t hay_len = strlen(haystack);
2836     size_t needle_len = strlen(needle);
2837     while (hay_len >= needle_len) {
2838         if (strncasecmp(haystack, needle, needle_len) == 0)
2839             return (char *) haystack;
2840 
2841         haystack++;
2842         hay_len--;
2843     }
2844 
2845     return NULL;
2846 }
2847 
ReadObjWidth(void)2848 static void ReadObjWidth(void)
2849 {
2850     g_object_width = rtfParam;
2851 }
2852 
2853 /*
2854 * parses \objectclass and adds the class type to the global variable 'object'
2855 */
GetObjectClass(void)2856 static int GetObjectClass(void)
2857 {
2858     int i;
2859     char *s;
2860 
2861     object.class = unknownObjClass;
2862 
2863     if (!RTFSkipToToken(rtfControl, rtfDestination, rtfObjClass))
2864         return -1;
2865 
2866     s = RTFGetTextWord();
2867     if (s && s[0]) {
2868         strcpy(object.className, s);
2869         free(s);
2870     }
2871 
2872 /* do we recognize this object class? */
2873     for (i = 0; objectClassList[i] != NULL; i++) {
2874         if (my_strcasestr(object.className, objectClassList[i])) {
2875             return i;
2876         }
2877     }
2878     return -1;
2879 }
2880 
2881 
2882 /*
2883  * The result section of an \object usually contains a picture of the object
2884  */
ReachedResult(void)2885 static int ReachedResult(void)
2886 {
2887     RTFGetToken();
2888 
2889     if (RTFCheckMM(rtfDestination, rtfObjResult) != 0 ||
2890         RTFCheckMM(rtfShapeAttr, rtfShapeResult) != 0 ||
2891         RTFCheckMM(rtfDestination, rtfPict) != 0 ||
2892         RTFCheckMM(rtfShapeAttr, rtfShapeText) != 0) {
2893         if (RTFCheckMM(rtfDestination, rtfPict) != 0)
2894             shapeObjectType = shapePicture;
2895         else if (RTFCheckMM(rtfDestination, rtfObjResult) != 0)
2896             shapeObjectType = standardObject;
2897         else if (RTFCheckMM(rtfShapeAttr, rtfShapeResult) != 0)
2898             shapeObjectType = shapeObject;
2899         else if (RTFCheckMM(rtfShapeAttr, rtfShapeText) != 0)
2900             shapeObjectType = shapeObjText;
2901         return (1);
2902     }
2903 
2904     if (rtfClass == rtfEOF) {
2905         RTFPanic("* EOF reached!\n");
2906         exit(1);
2907     }
2908 
2909     return (0);
2910 }
2911 
2912 /*
2913  * Decodes the OLE and extract the specified stream type into a buffer.
2914  * This function uses the cole library
2915  */
2916 static int
DecodeOLE(char * objectFileName,char * streamType,unsigned char ** nativeStream,uint32_t * size)2917 DecodeOLE(char *objectFileName, char *streamType,
2918           unsigned char **nativeStream, uint32_t * size)
2919 {
2920     COLEFS *cfs;
2921     COLERRNO colerrno;
2922     COLEFILE *coleFile;
2923 
2924     cfs = cole_mount(objectFileName, &colerrno);
2925     if (cfs == NULL) {
2926         cole_perror("DecodeOLE cole_mount", colerrno, objectFileName);
2927         return (1);
2928     }
2929 
2930 #ifdef COLE_VERBOSE
2931     cole_print_tree (cfs, &colerrno);
2932 #endif
2933 
2934     if ((coleFile = cole_fopen(cfs, streamType, &colerrno)) == NULL) {
2935         cole_perror("DecodeOLE cole_fopen", colerrno, objectFileName);
2936         cole_umount(cfs, NULL);
2937         return 1;
2938     }
2939 
2940     *size = (uint32_t) cole_fsize(coleFile);
2941 
2942     *nativeStream = (unsigned char *) malloc(*size);
2943 
2944     if (*nativeStream == NULL) {
2945         RTFMsg("* DecodeOLE: memory allocation failed for native stream!\n");
2946         cole_fclose(coleFile, &colerrno);
2947         cole_umount(cfs, NULL);
2948         return 1;
2949     }
2950 
2951     if (cole_fread(coleFile, *nativeStream, *size, &colerrno) == 0) {
2952         cole_perror("DecodeOLE cole_fread", colerrno, objectFileName);
2953         cole_fclose(coleFile, &colerrno);
2954         cole_umount(cfs, NULL);
2955         free(nativeStream);
2956         return 1;
2957     }
2958 
2959     if (cole_fclose(coleFile, &colerrno) != 0) {
2960         cole_perror("DecodeOLE cole_fclose", colerrno, objectFileName);
2961         cole_umount(cfs, NULL);
2962         free(nativeStream);
2963         return 1;
2964     }
2965 
2966     if (cole_umount(cfs, &colerrno)) {
2967         cole_perror("DecodeOLE cole_umount", colerrno, objectFileName);
2968         free(nativeStream);
2969         return (1);
2970     }
2971     return 0;
2972 }
2973 
2974 /*
2975  * Save the hex-encoded object data and as binary bytes in objectFileName
2976  */
ReadObjectData(char * objectFileName,int type,int offset)2977 static void ReadObjectData(char *objectFileName, int type, int offset)
2978 {
2979     char dummyBuf[20];
2980     int m[4];
2981     FILE *objFile;
2982     int i, value;
2983     uint8_t hexNumber;
2984     uint8_t hexEvenOdd = 0;       /* should be even at the end */
2985 
2986     if (type == EquationClass) {
2987         (oleEquation.count)++;
2988         snprintf(dummyBuf, 20, "-eqn%03d.eqn", oleEquation.count);
2989     } else
2990         snprintf(dummyBuf, 20, ".obj");
2991 
2992     /* construct full path of file name (without .tex) */
2993     strcpy(objectFileName, RTFGetOutputName());
2994     objectFileName[strlen(objectFileName)-4]='\0';
2995     strcat(objectFileName, dummyBuf);
2996 
2997     /* open object file */
2998     objFile = fopen(objectFileName, "wb");
2999     if (!objFile)
3000         RTFPanic("Cannot open input file %s\n", objectFileName);
3001 
3002 /* OLE header
3003  * (uint) version  e.g. 01000100 = 4 hex pairs
3004  * (uint) format   e.g. 02000000 = 4 hex pairs
3005  * ( int) type name length (int) e.g. 0f000000 = 4 hex pairs
3006  * ( str) type name  e.g. 4571 7561 7469 6f6e 2e44 534d 5434 00
3007  * 00000000 00000000 000e0000 = 3 unknown ints = 12 hex pairs
3008  *
3009  * two examples with spaces added to clarify
3010  * 01050000 02000000 0b000000 4571756174696f6e2e3300         00000000 00000000 000e0000
3011  * 01000100 02000000 0f000000 4571756174696f6e2e44534d543400 00000000 00000000 000e0000
3012 */
3013     /* skip three ints of 4 hex pairs each */
3014     for (i=0; i<12; i++)  ReadHexPair();
3015 
3016     /* skip the 00 hex-terminated string */
3017     do {
3018         value = ReadHexPair();
3019 //      fprintf(stderr,"%c", value);
3020     } while (value>0);
3021 //  fprintf(stderr,"\n");
3022 
3023     if (value==-1) {
3024         RTFMsg("* OLE object does not have proper header\n");
3025         fclose(objFile);
3026         return;
3027     }
3028 
3029     /* skip three ints of 4 hex characters each */
3030     for (i=0; i<12; i++)  ReadHexPair();
3031 
3032     /* read the OLE marker next 8 chars should be d0cf11e0 */
3033     for (i=0; i<4; i++)
3034     	m[i]=ReadHexPair();
3035 
3036     if (m[0]!=0xd0 || m[1]!=0xcf || m[2]!=0x11 || m[3]!=0xe0) {
3037         fprintf(stderr, "* OLE marker 0x'%02x%02x%02x%02x' is not 0xd0cf11e0\n", m[0], m[1], m[2], m[3]);
3038         fclose(objFile);
3039         return;
3040     }
3041 
3042     for (i=0; i<4; i++)
3043     	fputc(m[i], objFile);
3044 
3045     /* each byte is encoded as two hex chars ... ff, a1, 4c, ...*/
3046     while (1) {
3047         RTFGetToken();
3048 
3049         /* CR or LF in the hex stream should be skipped */
3050         while (rtfTextBuf[0] == 0x0a || rtfTextBuf[0] == 0x0d)
3051             RTFGetToken();
3052 
3053         if (rtfClass == rtfGroup)
3054             break;
3055 
3056         hexNumber = 16 * RTFCharToHex(rtfTextBuf[0]);
3057         hexEvenOdd++;
3058 
3059         RTFGetToken();
3060 
3061         while (rtfTextBuf[0] == 0x0a || rtfTextBuf[0] == 0x0d)
3062             RTFGetToken();  /* should not happen */
3063 
3064         if (rtfClass == rtfGroup)
3065             break;
3066 
3067         hexNumber += RTFCharToHex(rtfTextBuf[0]);   /* this is the the number */
3068         hexEvenOdd--;
3069         fputc(hexNumber, objFile);
3070     }
3071 
3072     if (fclose(objFile) != 0)
3073         fprintf(stderr,"* error closing object file %s\n", objectFileName);
3074 
3075     if (hexEvenOdd)
3076         fprintf (stderr,"* Warning! Odd number of hex characters read for object!\n");
3077 }
3078 
3079 /*
3080  * After an equation look for an equation number
3081  */
EqnNumberString(void)3082 static char * EqnNumberString(void)
3083 {
3084     char theNumber[10], comma[2], *s, *t;
3085     int stringIndex=0;
3086 
3087     theNumber[0]='\0';
3088     comma[0]='\0';
3089     /* skip to text following equation, stop looking a \par or \pard  */
3090     do  {
3091         RTFGetToken();
3092 
3093         /* paragraph ended ==> no equation number */
3094         if (RTFCheckCMM(rtfControl, rtfSpecialChar, rtfPar)) {
3095             RTFUngetToken();
3096             return NULL;
3097         }
3098 
3099         /* don't emit any tabs */
3100         if (RTFCheckCMM(rtfControl, rtfSpecialChar, rtfTab))
3101             continue;
3102 
3103         /* don't emit pictures */
3104         if (RTFCheckCMM(rtfControl, rtfDestination, rtfPict)) {
3105             RTFSkipGroup();
3106             RTFRouteToken();
3107             continue;
3108         }
3109 
3110         if (rtfClass == rtfText) {
3111             /* don't stop for spaces */
3112             if (isspace(rtfTextBuf[0]))
3113                 continue;
3114 
3115             /* commas or periods are common punctuation following an equation
3116                so keep them but keep looking for a real equation number */
3117             if (rtfTextBuf[0] == ',' || rtfTextBuf[0] == '.') {
3118                 comma[0]=rtfTextBuf[0];
3119                 comma[1]='\0';
3120                 continue;
3121             }
3122 
3123             /* found a text character that might start an equation number*/
3124             break;
3125         }
3126 
3127         RTFRouteToken();
3128 
3129     } while (rtfClass != rtfEOF);
3130 
3131     /* collect the equation number */
3132     do {
3133         if (RTFCheckCMM(rtfControl, rtfSpecialChar, rtfPar)) {
3134             RTFUngetToken();
3135             break;;
3136         }
3137 
3138         if (rtfClass == rtfText) {
3139             char c=rtfTextBuf[0];
3140 
3141             /* eqn numbers must start with '(', '[', or a digit */
3142             if (stringIndex==0 && !(isdigit(c) || c == '(' || c == ']') ) break;
3143 
3144             theNumber[stringIndex]=c;
3145             stringIndex++;
3146             if (c==')' || c==']') break;
3147         }
3148 
3149         RTFGetToken();
3150     } while (rtfClass != rtfEOF && stringIndex<10);
3151 
3152     if (stringIndex == 0) {
3153         RTFUngetToken();
3154         return strdup(comma);
3155     }
3156 
3157     theNumber[stringIndex]='\0';
3158     s=strdup_together(comma,"\\eqno");
3159     t=strdup_together(s,theNumber);
3160     free(s);
3161 
3162     return t;
3163 }
3164 
3165 /*
3166  * Convert OLE file containing equation
3167  */
3168 
ConvertEquationFile(char * objectFileName)3169 boolean ConvertEquationFile(char *objectFileName)
3170 {
3171     unsigned char *nativeStream;
3172     char *EqNo;
3173     MTEquation *theEquation;
3174     uint32_t equationSize;
3175 
3176     nativeStream = NULL;
3177     theEquation = NULL;
3178 
3179     /* Decode the OLE and extract the equation stream into buffer nativeStream */
3180     if (DecodeOLE(objectFileName, "/Equation Native", &nativeStream, &equationSize)) {
3181         RTFMsg("* error decoding OLE equation object!\n");
3182         return (false);
3183     }
3184 
3185     theEquation = (MTEquation *) malloc(sizeof(MTEquation));
3186     if (theEquation == NULL) {
3187         RTFMsg("* error allocating memory for equation!\n");
3188         free(nativeStream);
3189         return (false);
3190     }
3191 
3192    /* __cole_dump(nativeStream+slop, nativeStream+slop, 64, NULL); */
3193     if (*(nativeStream) == 0x1c && *(nativeStream+1) == 0x00) {
3194         equationSize -= MTEF_HEADER_SIZE;
3195 
3196         if (!Eqn_Create(theEquation, nativeStream+MTEF_HEADER_SIZE, equationSize)) {
3197             RTFMsg("* could not create equation structure!\n");
3198             free(nativeStream);
3199             free(theEquation);
3200             return (false);
3201         }
3202 
3203         theEquation->m_inline = 1;
3204         EqNo=NULL;
3205 
3206         if (insideTable) {
3207             if (nowBetweenCells) NewCell();
3208         } else if (nowBetweenParagraphs) {
3209             theEquation->m_inline = 0;
3210             suppressSpaceBetweenParagraphs=true;
3211             EndParagraph();
3212             if (lastCharWritten != '\n')
3213                 PutLitChar('\n');
3214             current_vspace = 0;
3215             EqNo=EqnNumberString();
3216         }
3217 
3218         if (g_eqn_insert_name) {
3219             PutLitStr("\\fbox{file://");
3220             PutEscapedLitStr(objectFileName);
3221             PutLitStr("}");
3222             requireHyperrefPackage = true;
3223         }
3224 
3225         /* this returns the translated equation in m_latex record */
3226         Eqn_TranslateObjectList(theEquation, ostream, 0);
3227 
3228         if (theEquation->m_inline){
3229             /* Add a space unless the last character was punctuation */
3230             if (lastCharWritten != ' ' && lastCharWritten != '(' &&
3231                 lastCharWritten != '[' && lastCharWritten != '{' )
3232                    PutLitChar(' ');
3233         }
3234 
3235         PutLitStr(theEquation->m_latex_start);
3236         PutLitStr(theEquation->m_latex);
3237         PutLitStr(EqNo);
3238         PutLitStr(theEquation->m_latex_end);
3239 
3240         if (theEquation->m_inline) {
3241             /* Add a space unless the next character is punctuation */
3242             RTFPeekToken();
3243             if (rtfClass == rtfText) {
3244                 if (rtfTextBuf[0]!='.' &&
3245                     rtfTextBuf[0]!=',' &&
3246                     rtfTextBuf[0]!=':' &&
3247                     rtfTextBuf[0]!=';' &&
3248                     rtfTextBuf[0]!=']' &&
3249                     rtfTextBuf[0]!=')') PutLitChar(' ');
3250             } else
3251                 PutLitChar(' ');
3252         }
3253 
3254         Eqn_Destroy(theEquation);
3255     }
3256 
3257     if (theEquation != NULL)
3258         free(theEquation);
3259 
3260     if (nativeStream != NULL)
3261         free(nativeStream);
3262 
3263     requireAmsSymbPackage = true;
3264     requireAmsMathPackage = true;
3265     return true;
3266 }
3267 
3268 /*
3269  * Convert file containing just equation
3270  */
3271 
ConvertRawEquationFile(char * rawFileName)3272 boolean ConvertRawEquationFile(char *rawFileName)
3273 {
3274     FILE *fp;
3275     unsigned char *nativeStream;
3276     char *EqNo;
3277     MTEquation *theEquation;
3278     uint32_t equationSize;
3279     int x;
3280 
3281 	fp = fopen(rawFileName, "r");
3282 	x=fgetc(fp);
3283 //	fprintf(stderr, "%d == 0?\n", x);
3284 	x=fgetc(fp);
3285 //	fprintf(stderr, "%d == 1?\n", x);
3286 	equationSize = fgetc(fp);
3287 	equationSize = equationSize * 256 + fgetc(fp);
3288 //	fprintf(stderr, "equation size is %d\n", equationSize);
3289 
3290 	nativeStream = (unsigned char *) malloc(equationSize+10);
3291 	fread(nativeStream, 1, equationSize, fp);
3292 	fclose(fp);
3293 
3294     theEquation = (MTEquation *) malloc(sizeof(MTEquation));
3295     if (theEquation == NULL) {
3296         RTFMsg("* error allocating memory for equation!\n");
3297         free(nativeStream);
3298         return (false);
3299     }
3300 
3301 	if (!Eqn_Create(theEquation, nativeStream, equationSize)) {
3302 		RTFMsg("* could not create equation structure!\n");
3303 		free(nativeStream);
3304 		free(theEquation);
3305 		return (false);
3306 	}
3307 
3308 	theEquation->m_inline = 1;
3309 	theEquation->log_level = 2;
3310 	EqNo=NULL;
3311 
3312 	if (insideTable) {
3313 		if (nowBetweenCells) NewCell();
3314 	} else if (nowBetweenParagraphs) {
3315 		theEquation->m_inline = 0;
3316 		suppressSpaceBetweenParagraphs=true;
3317 		EndParagraph();
3318 		if (lastCharWritten != '\n')
3319 			PutLitChar('\n');
3320 		current_vspace = 0;
3321 		EqNo=EqnNumberString();
3322 	}
3323 
3324 	if (g_eqn_insert_name) {
3325 		PutLitStr("\\fbox{file://");
3326 		PutEscapedLitStr(rawFileName);
3327 		PutLitStr("}");
3328 		requireHyperrefPackage = true;
3329 	}
3330 
3331 	/* this returns the translated equation in m_latex record */
3332 	Eqn_TranslateObjectList(theEquation, ostream, 0);
3333 
3334 	if (theEquation->m_inline){
3335 		/* Add a space unless the last character was punctuation */
3336 		if (lastCharWritten != ' ' && lastCharWritten != '(' &&
3337 			lastCharWritten != '[' && lastCharWritten != '{' )
3338 			   PutLitChar(' ');
3339 	}
3340 
3341 	PutLitStr(theEquation->m_latex_start);
3342 	PutLitStr(theEquation->m_latex);
3343 	PutLitStr(EqNo);
3344 	PutLitStr(theEquation->m_latex_end);
3345 
3346 	if (theEquation->m_inline) {
3347 		/* Add a space unless the next character is punctuation */
3348 		RTFPeekToken();
3349 		if (rtfClass == rtfText) {
3350 			if (rtfTextBuf[0]!='.' &&
3351 				rtfTextBuf[0]!=',' &&
3352 				rtfTextBuf[0]!=':' &&
3353 				rtfTextBuf[0]!=';' &&
3354 				rtfTextBuf[0]!=']' &&
3355 				rtfTextBuf[0]!=')') PutLitChar(' ');
3356 		} else
3357 			PutLitChar(' ');
3358 	}
3359 
3360 	Eqn_Destroy(theEquation);
3361 
3362 
3363     if (theEquation != NULL)
3364         free(theEquation);
3365 
3366     if (nativeStream != NULL)
3367         free(nativeStream);
3368 
3369     requireAmsSymbPackage = true;
3370     requireAmsMathPackage = true;
3371     return true;
3372 }
3373 
3374 /*
3375  * Translate an object containing a MathType equation
3376  */
ReadEquation(void)3377 static boolean ReadEquation(void)
3378 {
3379     boolean result;
3380     char objectFileName[rtfBufSiz];
3381 
3382     if (!RTFSkipToToken(rtfControl, rtfDestination, rtfObjData)) {
3383         RTFMsg("* ReadEquation: objdata group not found!\n");
3384         return (false);
3385     }
3386 
3387     /* save hex-encoded object data as a binary objectFileName */
3388     ReadObjectData(objectFileName, EquationClass, EQUATION_OFFSET);
3389 
3390     result = ConvertEquationFile(objectFileName);
3391 
3392     if (!g_eqn_keep_file)
3393         remove(objectFileName);
3394 
3395     return result;
3396 }
3397 
3398 
3399 /*
3400  * Read and process \object token
3401  */
ReadObject(void)3402 static void ReadObject(void)
3403 {
3404     int level = RTFGetBraceLevel();
3405     boolean res = false;
3406 
3407     object.class = GetObjectClass();
3408 
3409     switch (object.class) {
3410     case unknownObjClass:
3411     default:
3412 //        RTFMsg("*** unsupported object '%s', skipping...\n", object.className);
3413         break;
3414 
3415     case EquationClass:
3416 
3417         if (prefs[pConvertEquation]) {
3418             res = ReadEquation();
3419             if (!res) fprintf(stderr, "failed to convert equation\n");
3420         }
3421 
3422         /* if unsuccessful, include the equation as a picture */
3423         if (!res || g_eqn_insert_image) {
3424             if (RTFSkipToToken(rtfControl,rtfDestination, rtfPict))
3425                 ReadPicture();
3426         }
3427         break;
3428 
3429     case WordPictureClass:
3430     case MSGraphChartClass:
3431         /*ExamineToken("WordPictureClass");*/
3432         while (!ReachedResult());
3433         ReadPicture();
3434         break;
3435     }
3436 
3437     object.class = 0;
3438     strcpy(object.className, "");
3439 
3440     RTFSkipToLevel(level);
3441 }
3442 
3443 
3444 /*
3445  * Word97 through Word 2002 pictures are different
3446  *
3447  *   {\*\shppict {\pict \emfblip ...}}{\nonshppict {\pict ...}}
3448  *
3449  * \shppict identifies a Word 97 through Word 2002 picture
3450  * \nonshppict indicates a {\pict} that Word not read on input and
3451  *             is for compatibility with other readers.
3452  */
ReadWord97Picture(void)3453 static void ReadWord97Picture(void)
3454 {
3455 //  ExamineToken("Word97Object");
3456     RTFGetToken();
3457     if (rtfClass != rtfGroup) {RTFSkipGroup(); return;}
3458 
3459     RTFGetToken();    /* should be pict */
3460     if (rtfMinor != rtfPict) {RTFSkipGroup(); return;}
3461 
3462     RTFRouteToken();  /* handle pict */
3463     RTFGetToken();    /* should be } */
3464     RTFRouteToken();  /* handle last brace from shppict */
3465     RTFGetToken();    /* should be { */
3466     if (rtfClass != rtfGroup) {RTFSkipGroup(); return;}
3467 
3468     RTFGetToken();    /* should be nonshppict */
3469     RTFSkipGroup();   /* because we don't want two pictures in latex file */
3470 }
3471 
3472 /* \sp{\sn PropertyName}{\sv PropertyValueInformation} */
ReadShapeProperty(void)3473 static void ReadShapeProperty(void)
3474 {
3475     char *name, *value;
3476 
3477     if (!RTFSkipToToken(rtfControl, rtfShapeAttr, rtfShapeName)) return;
3478 
3479     name = RTFGetTextWord();
3480 
3481     if (strcmp(name,"pib")==0) {
3482         RTFExecuteGroup();
3483         free(name);
3484         return;
3485     }
3486 
3487     if (!RTFSkipToToken(rtfControl, rtfShapeAttr, rtfShapeValue)) return;
3488 
3489     value = RTFGetTextWord();
3490 
3491     RTFSkipGroup();
3492 
3493 //    fprintf(stderr,"shape, name=%s, value=%s\n",name,value);
3494 
3495     if (strcasecmp(name,"relleft")==0)
3496         sscanf(value, "%d", &(shape.left));
3497     if (strcasecmp(name,"relright")==0)
3498         sscanf(value, "%d", &(shape.right));
3499     if (strcasecmp(name,"reltop")==0)
3500         sscanf(value, "%d", &(shape.top));
3501     if (strcasecmp(name,"relbottom")==0)
3502         sscanf(value, "%d", &(shape.bottom));
3503 
3504     free(name);
3505     free(value);
3506 }
3507 
ShapeAttr(void)3508 static void ShapeAttr(void)
3509 {
3510 //  ExamineToken("shapeattr");
3511     switch (rtfMinor) {
3512     case rtfShapeProperty:
3513         ReadShapeProperty();
3514         break;
3515     case rtfShapeText:
3516 //      ExamineToken("ShapeText");
3517         RTFExecuteGroup();
3518         break;
3519     case rtfShapeLeft:
3520         shape.left = rtfParam;
3521         break;
3522     case rtfShapeTop:
3523         shape.top = rtfParam;
3524         break;
3525     case rtfShapeBottom:
3526         shape.bottom = rtfParam;
3527         break;
3528     case rtfShapeRight:
3529         shape.right = rtfParam;
3530         break;
3531     case rtfShapeLid:
3532     case rtfShapeOrderZ:
3533     case rtfShapeHeader:
3534     case rtfShapeXPosPage:
3535     case rtfShapeXPosMargin:
3536     case rtfShapeXPosColumn:
3537     case rtfShapeXPosIgnore:
3538     case rtfShapeYPosPage:
3539     case rtfShapeYPosMargin:
3540     case rtfShapeYPosColumn:
3541     case rtfShapeYPosIgnore:
3542     case rtfShapeWrap:
3543     case rtfShapeWrapSides:
3544     case rtfShapeRelOrderZ:
3545     case rtfShapeAnchor:
3546     default:
3547         break;
3548     }
3549 }
3550 
3551 /*
3552  * The parameters following \shpgrp are the same as those following \shp.
3553  * The order of the shapes inside a group is from bottom to top in z-order.
3554  * Inside a \shpgrp, no {\shprslt ...} tokens are generated (that is, only
3555  * the root-level shape can have a \shprslt token (this token describes the
3556  * entire group). For example:
3557  *
3558  *  {\shpgrp ... {\shp ... } {\shp ... } {\shprslt ... }}
3559  *
3560  *  {\shpgrp ... } can be substituted for {\shp ... } to create groups inside groups.
3561  *
3562  *  We _nearly_ always want to process the \shprslt group
3563  *      {\shp\pict...\pngblip} {\shprslt\pict...} => opt for png
3564  *      {\shp\pict...} {\shprslt\object Equation ...} => opt for equation
3565  *  for now, we always opt for the result group
3566  */
ReadShapeGroup(void)3567 static void ReadShapeGroup(void)
3568 {
3569     insideShapeGroup = 1;
3570 //  ExamineToken("ShapeGroup");
3571     if (RTFExecuteToToken(rtfControl,rtfShapeAttr,rtfShapeResult)) {
3572         RTFSkipGroup();
3573     }
3574     insideShapeGroup = 0;
3575 }
3576 
3577 /*
3578  * Shape
3579  *
3580  * {\shp <shpinfo> {\*\shpinst ... } {\*\shprslt ... } }
3581  *
3582  */
ReadShape(void)3583 static void ReadShape(void)
3584 {
3585 //  ExamineToken("Shape");
3586     if (insideShapeGroup) {
3587         RTFExecuteGroup();
3588         return;
3589     }
3590 
3591     if (RTFSkipToToken(rtfControl,rtfShapeAttr,rtfShapeResult)) {
3592         RTFExecuteGroup();
3593     }
3594 }
3595 
ReadUnicodeSkipN(void)3596 static void ReadUnicodeSkipN(void)
3597 {
3598     textStyle.unicodeSkipN= rtfParam;
3599 }
3600 
ReadUnicode(void)3601 static void ReadUnicode(void)
3602 {
3603     int thechar,i;
3604 
3605     if (rtfParam<0)
3606         thechar = rtfParam + 65536;
3607     else
3608         thechar = rtfParam;
3609 
3610     if (rtfMinor == rtfUnicode) {
3611         /* \uNNNNY, drop Y as fallback char (assuming \uc1) */
3612         for (i=0; i<textStyle.unicodeSkipN; i++) {
3613             RTFGetToken();
3614         }
3615     }
3616 
3617     PrepareForChar();
3618 
3619 //  fprintf(stderr, "Unicode --- %d, 0x%04X\n", thechar, thechar);
3620     if (thechar == 8201) {
3621         PutLitStr("\\,");
3622         return;
3623     }
3624 
3625     if (thechar == 8212) {
3626         PutLitStr("---");
3627         return;
3628     }
3629 
3630     if (thechar == 8216) {
3631         PutLitStr("`");
3632         return;
3633     }
3634 
3635     if (thechar == 8217) {
3636         PutLitStr("'");
3637         return;
3638     }
3639 
3640     if (thechar == 8220) {
3641         PutLitStr("``");
3642         return;
3643     }
3644 
3645     if (thechar == 8221) {
3646         PutLitStr("''");
3647         return;
3648     }
3649 
3650     if (thechar == 8230) {
3651         PutLitStr("...");
3652         return;
3653     }
3654 
3655 	if (thechar == 64256) {
3656 		PutLitStr("ff");
3657 		return;
3658 	}
3659 
3660 	if (thechar == 64257) {
3661 		PutLitStr("fi");
3662 		return;
3663 	}
3664 
3665 	if (thechar == 64258) {
3666 		PutLitStr("fl");
3667 		return;
3668 	}
3669 
3670 	if (thechar == 64259) {
3671 		PutLitStr("ffi");
3672 		return;
3673 	}
3674 
3675 	if (thechar == 64260) {
3676 		PutLitStr("ffl");
3677 		return;
3678 	}
3679 
3680     if (0xC0 <= thechar && thechar <=0xFF) {
3681         PutLitChar(thechar);
3682         return;
3683     }
3684 
3685     /* directly translate greek */
3686     if ((913 <= thechar && thechar <= 937) || (945 <= thechar && thechar <= 969)) {
3687         PutMathLitStr(UnicodeGreekToLatex[thechar-913]);
3688         return;
3689     }
3690 
3691     /* directly translate special cursive greek */
3692     if (976 == thechar) {
3693         PutMathLitStr("\\beta");
3694         return;
3695     }
3696     if (977 == thechar) {
3697         PutMathLitStr("\\vartheta");
3698         return;
3699     }
3700     if (981 == thechar) {
3701         PutMathLitStr("\\varphi");
3702         return;
3703     }
3704     if (982 == thechar) {
3705         PutMathLitStr("\\varpi");
3706         return;
3707     }
3708 
3709 
3710     /* and also a bunch of wierd codepoints from the Symbol font
3711        that end up in a private code area of Unicode */
3712     if (61472 <= thechar && thechar <= 61632) {
3713         PutMathLitStr(UnicodeSymbolFontToLatex[thechar-61472]);
3714         return;
3715     }
3716 
3717     PutIntAsUtf8(thechar);
3718     /*snprintf(unitext,20,"\\unichar{%d}",(int)thechar);
3719     if (0) fprintf(stderr,"unicode --- %s!\n",unitext);
3720     PutLitStr(unitext);
3721     */
3722 }
3723 
SkipFieldResult(void)3724 static void SkipFieldResult(void)
3725 {
3726     /* skip over to the result group */
3727     while (!RTFCheckCMM(rtfControl, rtfDestination, rtfFieldResult))
3728         RTFGetToken();
3729 
3730     RTFSkipGroup();
3731     RTFRouteToken();
3732 }
3733 
ReadHyperlinkField(void)3734 static void ReadHyperlinkField(void)
3735 {
3736     int localGL;
3737 
3738     PutLitStr("\\href{");
3739 
3740     localGL = RTFGetBraceLevel();
3741 
3742     insideHyperlink = true;
3743 
3744     while (RTFGetBraceLevel() && RTFGetBraceLevel() >= localGL) {
3745         RTFGetToken();
3746         if (rtfClass == rtfText) {
3747             if (rtfTextBuf[0] != '"'
3748                 && !RTFCheckMM(rtfSpecialChar, rtfLDblQuote)
3749                 && !RTFCheckMM(rtfSpecialChar, rtfRDblQuote))
3750                     RTFRouteToken();
3751          } else
3752              RTFRouteToken();
3753     }
3754 
3755     PutLitStr("}{");
3756 
3757     /* skip over to the result group */
3758     while (!RTFCheckCMM(rtfControl, rtfDestination, rtfFieldResult))
3759         RTFGetToken();
3760 
3761     localGL = RTFGetBraceLevel();
3762     /* switch off hyperlink flag */
3763     insideHyperlink = false;
3764 
3765     while (RTFGetBraceLevel() && RTFGetBraceLevel() >= localGL) {
3766         RTFGetToken();
3767         RTFRouteToken();
3768     }
3769 
3770     PutLitStr("}");
3771     requireHyperrefPackage = true;
3772 }
3773 
ReadSymbolField(void)3774 static void ReadSymbolField(void)
3775 {
3776     char buf[100];
3777     short major, minor;
3778     short *currentCharCode = curCharCode;
3779 
3780     /* go to the start of the symbol representation */
3781     if (RTFGetToken() != rtfText) {
3782         if (RTFCheckCM(rtfGroup, rtfBeginGroup) != 0)
3783             RTFSkipGroup();
3784         RTFSkipGroup();
3785         RTFRouteToken();
3786         return;
3787     }
3788 
3789     /* read in the symbol token */
3790     strcpy(buf, rtfTextBuf);
3791     while (strcmp(rtfTextBuf, " ") != 0) {
3792         RTFGetToken();
3793         if (strcmp(rtfTextBuf, " ") != 0)
3794             strcat(buf, rtfTextBuf);
3795     }
3796 
3797     /* convert the text symbol token to an int */
3798     major = atoi(buf);
3799 
3800     /* do the mapping */
3801     curCharCode = symCharCode;
3802     minor = RTFMapChar(major);
3803     curCharCode = currentCharCode;
3804 
3805     /* set the rtf token to the new value */
3806     RTFSetToken(rtfText, major, minor, rtfNoParam, buf);
3807 
3808     if (minor >= rtfSC_therefore && minor < rtfSC_currency)
3809         requireAmsSymbPackage = true;
3810 
3811     /* call the handler for text */
3812     TextClass();
3813 
3814     RTFSkipGroup();
3815     RTFRouteToken();
3816 }
3817 
3818 /* the following streams should just emit ... HToc268803753
3819  *    PAGEREF _Toc268803753 \h
3820  *    HYPERLINK \l "_Toc268803753"
3821  *     _Toc268803753
3822  */
emitBookmark(void)3823 static void emitBookmark(void)
3824 {
3825     boolean started = false;
3826 
3827     while (RTFGetToken() == rtfText) {
3828         switch (rtfTextBuf[0]) {
3829         case ' ':
3830             if (started) {     /* assume that bookmarks optionally start and end with spaces */
3831                 RTFSkipGroup();
3832                 return;
3833             }
3834             break;
3835         case '"':
3836             break;
3837         case '\\':
3838             RTFGetToken(); /* drop backslash and the next letter */
3839             break;
3840         case '_':
3841             started = true;
3842             PutLitChar('H');
3843             break;
3844         default:
3845             started = true;
3846             PutLitChar(rtfTextBuf[0]);
3847             break;
3848         }
3849     }
3850 }
3851 
3852 /*
3853  *  Just emit \pageref{HToc268612944} for {\*\fldinst {...  PAGEREF _Toc268612944 \\h } ..}
3854 */
ReadPageRefField(void)3855 static void ReadPageRefField(void)
3856 {
3857     PutLitStr("\\pageref{");
3858     emitBookmark();
3859     PutLitStr("}");
3860     RTFRouteToken();
3861 
3862     SkipFieldResult();
3863 }
3864 
3865 
3866 /*
3867  *  Try to convert Microsoft Equation Field to latex.  The problem is that we
3868  *  now have rtf tokens mixed with the stupid field tokens.  I hacked the parser
3869  *  to handle read \\X in an equation and send it to MicrosoftEQFieldCommand.
3870  */
3871 
ReadEquationField(void)3872 static void ReadEquationField(void)
3873 {
3874     int parenCount = 0;
3875     int braceCount = 0;
3876 	int displayEquation = 0;
3877 	int oldSuppressLineBreak;
3878 
3879 	if (insideEquation == 0) {
3880 		if (nowBetweenParagraphs) {
3881 			EndParagraph();
3882 			NewParagraph();
3883 			PutLitStr("\n$$\n");
3884 			displayEquation=1;
3885 		} else {
3886 			StopTextStyle();
3887 			PutLitChar('$');
3888 		}
3889 		RTFPushStack();
3890 		InitTextStyle();
3891 		oldSuppressLineBreak = suppressLineBreak;
3892 		suppressLineBreak = 1;
3893 	}
3894 
3895 	insideEquation++;
3896     RTFExecuteGroup();
3897     SkipFieldResult();
3898 	insideEquation--;
3899 
3900 	if (insideEquation == 0) {
3901 		if (displayEquation) {
3902 			PutLitStr("\n$$\n");
3903 			EndParagraph();
3904 		} else {
3905 		    StopTextStyle();
3906 			PutLitChar('$');
3907 		}
3908 		suppressLineBreak = oldSuppressLineBreak;
3909 		RTFPopStack();
3910 	}
3911 
3912 }
3913 
3914 /*
3915  *  Just emit \pageref{HToc268612944} for {\*\fldinst {...  PAGEREF _Toc268612944 \\h } ..}
3916 */
ReadPageField(void)3917 static void ReadPageField(void)
3918 {
3919     PutLitStr("\\thepage{}");
3920     SkipFieldResult();
3921 }
3922 
3923 /*
3924  *  Three possible types of fields
3925  *     (1) supported ... translate and ignore FieldResult
3926  *     (2) tolerated ... ignore FieldInst and translate FieldResult
3927  *     (3) unknown   ... ignore both FieldInst and FieldResult
3928  */
ReadFieldInst(void)3929 static void ReadFieldInst(void)
3930 {
3931     char *fieldName;
3932     int level = RTFGetBraceLevel();
3933 
3934     fieldName = RTFGetTextWord();
3935     if (fieldName == NULL) return;
3936 
3937     if (strcasecmp(fieldName, "HYPERLINK") == 0 ) {
3938         if (prefs[pConvertHypertext])
3939             ReadHyperlinkField();
3940         else
3941             RTFSkipToLevel(level);
3942         free(fieldName);
3943         return;
3944     }
3945 
3946     if (strcasecmp(fieldName, "SYMBOL") == 0) {
3947         ReadSymbolField();
3948         free(fieldName);
3949         return;
3950     }
3951 
3952     if (strcasecmp(fieldName, "PAGEREF") == 0) {
3953         ReadPageRefField();
3954         free(fieldName);
3955         return;
3956     }
3957 
3958     if (strcasecmp(fieldName, "PAGE") == 0) {
3959         ReadPageField();
3960         free(fieldName);
3961         return;
3962     }
3963 
3964     if (strcasecmp(fieldName, "HYPERLINK") == 0) {
3965         ReadPageField();
3966         free(fieldName);
3967         return;
3968     }
3969 
3970     if (strcasecmp(fieldName, "EQ") == 0) {
3971         ReadEquationField();
3972         free(fieldName);
3973         return;
3974     }
3975 
3976 //    RTFMsg("FIELD type is '%s'\n",fieldName);
3977 
3978     /* Unsupported FIELD type ... the best we can do is bail from rtfFieldInst
3979        and hope rtfFieldResult can be processed  */
3980 
3981     RTFSkipToLevel(level);
3982     free(fieldName);
3983 }
3984 
3985 /*
3986  *  Just emit \label{HToc268612944} for {\*\bkmkstart _Toc268612944}
3987  */
ReadBookmarkStart(void)3988 static void ReadBookmarkStart(void)
3989 {
3990     PutLitStr("\\label{");
3991     emitBookmark();
3992     PutLitStr("}");
3993 }
3994 
HandleOptionalTokens(void)3995 static void HandleOptionalTokens(void)
3996 {
3997     RTFGetToken();
3998 
3999     switch (rtfMinor) {
4000     case rtfBookmarkStart:
4001         ReadBookmarkStart();
4002         break;
4003 
4004     case rtfFieldInst:
4005         ReadFieldInst();
4006         break;
4007 
4008     case rtfWord97Picture:
4009         ReadWord97Picture();
4010         break;
4011 
4012     case rtfDrawObject:
4013         break;
4014 
4015     case rtfShapeInst:
4016     case rtfShapeResult:
4017         break;
4018 
4019     default:
4020     //  ExamineToken("HandleOptionalTokesn");
4021         RTFSkipGroup();
4022         break;
4023     }
4024 }
4025 
4026 /*
4027  * The reason these use the rtfSC_xxx thingies instead of just writing
4028  * out ' ', '-', '"', etc., is so that the mapping for these characters
4029  * can be controlled by the latex-encoding file.
4030  */
SpecialChar(void)4031 static void SpecialChar(void)
4032 {
4033     switch (rtfMinor) {
4034     case rtfLine:
4035     case rtfPar:
4036         if (nowBetweenParagraphs && !suppressSpaceBetweenParagraphs)
4037             current_vspace += abs(paragraph.lineSpacing);
4038         nowBetweenParagraphs = true;
4039         break;
4040 
4041     case rtfSect:
4042         section.newSection = true;
4043         nowBetweenParagraphs = true;
4044         break;
4045 
4046     case rtfNoBrkSpace:
4047         if (nowBetweenParagraphs)
4048             paragraph.extraIndent += 0;
4049         else
4050             PutStdChar(rtfSC_nobrkspace);
4051         break;
4052     case rtfTab:
4053         if (nowBetweenParagraphs)
4054             paragraph.extraIndent += 360;
4055         else if (prefs[pConvertTextNoTab])
4056             PutLitChar(' ');
4057         else
4058             PutLitStr("\\tab ");
4059         break;
4060     case rtfNoBrkHyphen:
4061         PutStdChar(rtfSC_nobrkhyphen);
4062         break;
4063     case rtfBullet:
4064         PutStdChar(rtfSC_bullet);
4065         break;
4066     case rtfEmDash:
4067         PutLitStr("---");
4068         break;
4069     case rtfEnDash:
4070         PutLitStr("-");
4071         break;
4072     case rtfLQuote:
4073         PutLitStr("`");
4074         break;
4075     case rtfRQuote:
4076         PutLitStr("'");
4077         break;
4078     case rtfLDblQuote:
4079         PutLitStr("``");
4080         break;
4081     case rtfRDblQuote:
4082         PutLitStr("''");
4083         break;
4084     case rtfPage:
4085         if (!insideTable)
4086             PutLitStr("\\pagebreak{}");
4087         break;
4088     case rtfOptDest:
4089         HandleOptionalTokens();
4090         break;
4091     case rtfCurHeadPage:
4092         PutLitStr("\\thepage{}");
4093         break;
4094     case rtfCurFNote:
4095         break;
4096     default:
4097         ExamineToken("SpecialChar");  /* comment out before release */
4098     }
4099 }
4100 
DoHeaderFooter(void)4101 static void DoHeaderFooter(void)
4102 {
4103     char *buff, *s, *option;
4104     size_t hfStartPos, hfEndPos, len;
4105     int isHeader, isFirst;
4106     int level = RTFGetBraceLevel();
4107 
4108     if (insideHeaderFooter) return;
4109 
4110     insideHeaderFooter = true;
4111     suppressLineBreak = true;
4112     isHeader = (rtfMinor == rtfHeader) || (rtfMinor == rtfHeaderFirst) ;
4113     isFirst  = (rtfMinor == rtfHeaderFirst) || (rtfMinor == rtfFooterFirst) ;
4114 
4115     StopTextStyle();
4116 
4117     hfStartPos = ftell(ofp);
4118 
4119     switch (rtfMinor) {
4120     case rtfHeader:
4121         option = "\\lhead{";
4122         break;
4123     case rtfHeaderRight:
4124         option = "\\fancyhead[LO]{";
4125         break;
4126     case rtfHeaderLeft:
4127         option = "\\fancyhead[LE]{";
4128         break;
4129     case rtfHeaderFirst:
4130         option = "  \\lhead{";
4131         break;
4132     case rtfFooter:
4133         option = "\\lfoot{";
4134         break;
4135     case rtfFooterRight:
4136         option = "\\fancyfoot[LO]{";
4137         break;
4138     case rtfFooterLeft:
4139         option = "\\fancyfoot[LE]{";
4140         break;
4141     case rtfFooterFirst:
4142         option = "  \\lfoot{";
4143         break;
4144     }
4145 
4146     PutLitStr(option);
4147     while (RTFGetBraceLevel() && RTFGetBraceLevel() >= level) {
4148         RTFGetToken();
4149         RTFRouteToken();
4150     }
4151     StopTextStyle();
4152     PutLitStr("}\n");
4153 
4154     /* copy header/footer  */
4155     hfEndPos = ftell(ofp);
4156     len = hfEndPos - hfStartPos;
4157 
4158     /* Don't bother unless the header contains something */
4159     /* and we are still in the preamble */
4160 
4161     if (len<=strlen(option)+2) {
4162         /* erase empty command */
4163         fseek(ofp, hfStartPos, 0);
4164 
4165     } else {
4166 
4167         /* save only if still in preamble or it is a first page command */
4168         if (isFirst || !wroteBeginDocument) {
4169             requireFancyHdrPackage = true;
4170             buff = malloc(len+1);
4171             fseek(ofp, hfStartPos, 0);
4172             fread(buff,1,len,ofp);
4173             buff[len] = '\0';
4174 
4175             if (!isFirst) {
4176                 s = strdup_together(preambleFancyHeader,buff);
4177                 if (preambleFancyHeader) free(preambleFancyHeader);
4178                 preambleFancyHeader = s;
4179             } else {
4180                 s = strdup_together(preambleFancyHeaderFirst,buff);
4181                 if (preambleFancyHeaderFirst) free(preambleFancyHeaderFirst);
4182                 preambleFancyHeaderFirst = s;
4183             }
4184             fseek(ofp, hfStartPos, 0);
4185         }
4186     }
4187 
4188     suppressLineBreak = false;
4189     insideHeaderFooter = false;
4190 }
4191 
4192 /*
4193  * This function notices destinations that should be ignored
4194  * and skips to their ends.  This keeps, for instance, picture
4195  * data from being considered as plain text.
4196  */
4197 
Destination(void)4198 static void Destination(void)
4199 {
4200     switch (rtfMinor) {
4201     case rtfFNContSep:
4202     case rtfFNContNotice:
4203     case rtfInfo:
4204     case rtfIndexRange:
4205     case rtfITitle:
4206     case rtfISubject:
4207     case rtfIAuthor:
4208     case rtfIOperator:
4209     case rtfIKeywords:
4210     case rtfIComment:
4211     case rtfIVersion:
4212     case rtfIDoccomm:
4213     case rtfUserPropsGroup:
4214     case rtfWGRFmtFilter:
4215         RTFSkipGroup();
4216         break;
4217     case rtfNeXTGraphic:
4218         ReadNextGraphic();
4219         break;
4220     case rtfUnicodeSkipN:
4221         ReadUnicodeSkipN();
4222         break;
4223     case rtfUnicode:
4224     case rtfUnicodeFake:
4225         ReadUnicode();
4226         break;
4227     case rtfHeaderLeft:
4228     case rtfHeaderRight:
4229     case rtfFooterLeft:
4230     case rtfFooterRight:
4231     case rtfFooterFirst:
4232     case rtfHeaderFirst:
4233     case rtfHeader:
4234     case rtfFooter:
4235         DoHeaderFooter();
4236         break;
4237     case rtfShapeAttr:
4238         ShapeAttr();
4239         break;
4240     case rtfShapeGroup:
4241         ReadShapeGroup();
4242         break;
4243     case rtfShape:
4244         ReadShape();
4245         break;
4246     case rtfBlipTag:
4247 //      ExamineToken("BlipTag");
4248         break;
4249     }
4250 }
4251 
4252 /*
4253  * In RTF, the code page is specified in at least three different places
4254  *
4255  * (1) as the third token in the file, e.g., {\rtf1\ansi
4256  * (2) in the font table for each font e.g., \fcharset2
4257  * (3) by the code page token, e.g., \ansicpg1252
4258  *
4259  * A pragmatic approach is used here.  The third token is used to
4260  * set genCharCode.  If \aniscpg is found, then genCharCode will be
4261  * changed to that.  Here we just change if it is the symbol font.
4262  */
RTFSetGenCharSet(void)4263 static void RTFSetGenCharSet(void)
4264 {
4265     switch(rtfMinor) {
4266     case rtfAnsiCharSet:
4267         genCharCode = cp1252CharCode;
4268         break;
4269     case rtfMacCharSet:
4270         genCharCode = cpMacCharCode;
4271         break;
4272     case rtfPcCharSet:
4273         genCharCode = cp437CharCode;
4274         break;
4275     case rtfPcaCharSet:
4276         genCharCode = cp850CharCode;
4277         break;
4278     }
4279 
4280     /* check for the \ansicpg control word */
4281     RTFPeekToken();
4282     if (RTFCheckCMM(rtfControl, rtfFontAttr, rtfAnsiCodePage)) {  /* we will handle the token */
4283         RTFGetToken();
4284         switch (rtfParam) {
4285             case 437:
4286                 genCharCode=cp437CharCode;
4287                 break;
4288             case 850:
4289                 genCharCode=cp850CharCode;
4290                 break;
4291             case 1250:
4292                 genCharCode=cp1250CharCode;
4293                 break;
4294             case 1251:
4295                 genCharCode=cp1251CharCode;
4296                 break;
4297             case 1252:
4298                 genCharCode=cp1252CharCode;
4299                 break;
4300             case 1254:
4301                 genCharCode=cp1254CharCode;
4302                 break;
4303             case 10000:
4304                 genCharCode=cpMacCharCode;
4305                 break;
4306             case 10001:
4307                 genCharCode=cp932CharCode;
4308                 break;
4309             case 10008:
4310                 genCharCode=cp936CharCode;
4311                 break;
4312         }
4313     }
4314 
4315     curCharCode = genCharCode;
4316 }
4317 
PictureAttr(void)4318 static void PictureAttr(void)
4319 {
4320     switch (rtfMinor) {
4321     case rtfMacQD:
4322         picture.type = pict;
4323         break;
4324     case rtfWinMetafile:
4325         picture.type = wmf;
4326         break;
4327     case rtfEmf:
4328         picture.type = emf;
4329         break;
4330     case rtfPng:
4331         picture.type = png;
4332         break;
4333     case rtfJpeg:
4334         picture.type = jpeg;
4335         break;
4336     case rtfPicGoalWid:
4337         picture.goalWidth = rtfParam;
4338         break;
4339     case rtfPicGoalHt:
4340         picture.goalHeight = rtfParam;
4341         break;
4342     case rtfPicScaleX:
4343         picture.scaleX = rtfParam/100.0;
4344         break;
4345     case rtfPicWid:
4346         picture.width = rtfParam;
4347         break;
4348     case rtfPicHt:
4349         picture.height = rtfParam;
4350         break;
4351     case rtfPicScaleY:
4352         picture.scaleY = rtfParam/100.0;
4353         break;
4354     case rtfPicCropTop:
4355         picture.cropTop = rtfParam;
4356         break;
4357     case rtfPicCropBottom:
4358         picture.cropBottom = rtfParam;
4359         break;
4360     case rtfPicCropLeft:
4361         picture.cropLeft = rtfParam;
4362         break;
4363     case rtfPicCropRight:
4364         picture.cropRight = rtfParam;
4365         break;
4366     }
4367 }
4368 
4369 /* decides what to do when a control word is encountered */
ControlClass(void)4370 static void ControlClass(void)
4371 {
4372     switch (rtfMajor) {
4373     case rtfDefFont:
4374         RTFSetDefaultFont(rtfParam);
4375     case rtfFontAttr:
4376         switch (rtfMinor) {
4377         case rtfAnsiCodePage:
4378         case rtfFontCodePage:
4379             /* codePage = rtfParam;*/
4380             break;
4381         }
4382         break;
4383     case rtfDestination:
4384         Destination();
4385         break;
4386     case rtfSpecialChar:
4387         SpecialChar();
4388         break;
4389     case rtfCharAttr:
4390         SetTextStyle();
4391         break;
4392     case rtfListAttr:
4393         RTFSkipGroup();
4394         break;
4395     case rtfTblAttr:
4396         if (rtfMinor == rtfRowDef && !(insideTable))
4397             DoTable();          /* not inside a table, start one */
4398         else
4399             DoTableAttr();      /* currently inside a table, set table attribute */
4400         break;
4401     case rtfParAttr:
4402         ParAttr();
4403         break;
4404     case rtfSectAttr:
4405         SectAttr();
4406         break;
4407     case rtfCharSet:
4408         RTFSetGenCharSet();
4409         break;
4410     case rtfPictAttr:
4411         PictureAttr();
4412         break;
4413     case rtfShapeAttr:
4414         ShapeAttr();
4415         break;
4416     case rtfEquationFieldCmd:
4417         MicrosoftEQFieldCommand();
4418         break;
4419     case rtfEquationFieldLiteral:
4420         MicrosoftEQFieldLiteral();
4421         break;
4422     }
4423 
4424     /* handles {\*\keyword ...} */
4425 //  if (RTFCheckMM(rtfSpecialChar, rtfOptDest))
4426 //      RTFSkipGroup();
4427 
4428 }
4429 
4430 /* needed to handle groups in math environment */
GroupClass(void)4431 static void GroupClass(void)
4432 {
4433     if (!insideEquation) return;
4434 //    ExamineToken("Group");
4435     if (rtfMajor == rtfEndGroup)
4436     	StopTextStyle();
4437 }
4438 
4439 /*
4440  * Prepares output TeX file for each input RTF file.
4441  * Sets globals and installs callbacks.
4442  */
BeginLaTeXFile(void)4443 int BeginLaTeXFile(void)
4444 {
4445     int i;
4446 
4447     RTFSetDefaultFont(-1);
4448     insideFootnote = false;
4449     insideHyperlink = false;
4450     insideTable = false;
4451     insideHeaderFooter = false;
4452     section.newPage = 1;
4453     section.cols = 1;
4454     section.writtenCols = 1;
4455     section.newSection = false;
4456 
4457     requireSetspacePackage = false;
4458     requireTablePackage = false;
4459     requireGraphicxPackage = false;
4460     requireAmsSymbPackage = false;
4461     requireMultiColPackage = false;
4462     requireUlemPackage = false;
4463     requireFixLtx2ePackage = false;
4464     requireHyperrefPackage = false;
4465     requireMultirowPackage = false;
4466     requireAmsMathPackage = false;
4467     requireFancyHdrPackage = true;
4468     requireAMSSymbolPackage = true;
4469 
4470     preambleFancyHeader=NULL;
4471     preambleFancyHeaderFirst=NULL;
4472 
4473     picture.count = 0;
4474     picture.type = unknownPict;
4475     oleEquation.count = 0;
4476     object.class = unknownObjClass;
4477     object.shape = 0;
4478     table.cellCount = 0;
4479     table.theCell = NULL;
4480     table.cellMergePar = mergeNone;
4481     table.multiRow = false;
4482 
4483     InitTextStyle();
4484     textStyleWritten = textStyle;
4485 
4486     InitParagraphStyle();
4487     paragraphWritten = paragraph;
4488     nowBetweenParagraphs = true;
4489     suppressLineBreak = false;
4490     suppressSpaceBetweenParagraphs=false;
4491 
4492     /* install class callbacks */
4493     RTFSetClassCallback(rtfText, TextClass);
4494     RTFSetClassCallback(rtfControl, ControlClass);
4495     RTFSetClassCallback(rtfGroup, GroupClass);
4496 
4497     /* install destination callbacks */
4498     RTFSetDestinationCallback(rtfObjWid, ReadObjWidth);
4499     RTFSetDestinationCallback(rtfColorTbl, WriteColors);
4500     RTFSetDestinationCallback(rtfObject, ReadObject);
4501     RTFSetDestinationCallback(rtfPict, ReadPicture);
4502     RTFSetDestinationCallback(rtfFootnote, ReadFootnote);
4503 
4504     for (i=0; i<256; i++)
4505         UsedColor[i] = 0;
4506 
4507     WriteLaTeXHeader();
4508     return (1);
4509 }
4510 
4511 
4512 /* characters from the Symbol font get written to private areas
4513    of unicode that are not well supported by latex.  This is
4514    simple translation table. */
4515 char *UnicodeSymbolFontToLatex[] = {
4516     " ",  /* 61472 or U+F020 */
4517     "!",
4518     "\\forall",
4519     "\\#",
4520     "\\exists",
4521     "\\%",
4522     "\\&",
4523     " ",
4524     "(",
4525     ")",
4526     "*",
4527     "+",
4528     ",",
4529     "-",
4530     ".",
4531     "/",
4532     "0",
4533     "1",
4534     "2",
4535     "3",
4536     "4",
4537     "5",
4538     "6",
4539     "7",
4540     "8",
4541     "9",
4542     ":",
4543     ";",
4544     "<",
4545     "=",
4546     ">",
4547     "?",
4548     "\\congruent",
4549     "A",
4550     "B",
4551     "X",
4552     "\\Delta",
4553     "E",
4554     "\\Phi",
4555     "\\Gamma",
4556     "H",
4557     "I",
4558     "\\vartheta",
4559     "K",
4560     "\\Lambda",
4561     "",
4562     "N",
4563     "O",
4564     "\\Pi",
4565     "\\Theta",
4566     "P",
4567     "\\Sigma",
4568     "T",
4569     "Y",
4570     "\\zeta",
4571     "\\Omega",
4572     "\\Xi",
4573     "\\Psi",
4574     "Z",
4575     "[",
4576     "\\therefore",
4577     "]",
4578     "\\bot",
4579     "\\_",
4580     "-",  /* over bar?? */
4581     "\\alpha",
4582     "\\beta",
4583     "\\chi",
4584     "\\delta",
4585     "\\epsilon",
4586     "\\phi",
4587     "\\gamma",
4588     "\\eta",
4589     "\\iota",
4590     "\\varphi",
4591     "\\kappa",
4592     "\\lambda",
4593     "\\mu",
4594     "\\nu",
4595     "o",
4596     "\\pi",
4597     "\\theta",
4598     "\\rho",
4599     "\\sigma",
4600     "\\tau",
4601     "\\nu",
4602     "\\varpi",
4603     "\\omega",
4604     "\\xi",
4605     "\\psi",
4606     "\\zeta",
4607     "\\lbrace",
4608     "|",
4609     "\\rbrace",
4610     "\\sim",
4611     "Y",
4612     "\\prime",
4613     "\\le",
4614     "/",
4615     "\\infty",
4616     "\\int",
4617     "\\clubsuit",
4618     "\\diamondsuit",
4619     "\\heartsuit",
4620     "\\spadesuit",
4621     "\\rightleftarrow",
4622     "\\leftarrow",
4623     "\\uparrow",
4624     "\\rightarrow",
4625     "\\downarrow",
4626     "^\\circ",
4627     "\\pm",
4628     "\\prime\\prime",
4629     "\\ge",
4630     "\\times",
4631     "\\propto",
4632     "\\partial",
4633     "\\blackcircle",
4634     "\\division",
4635     "\\ne",
4636     "\\equiv",
4637     "\\approx",
4638     "...",
4639     "|",
4640     "\\_",
4641     "", /*corner arrow*/
4642     "\\Aleph",
4643     0
4644 };
4645 
4646 /* greek characters translated directly to avoid the textgreek.sty package
4647    positions 913-969  (0x0391-0x03C9)*/
4648 char *UnicodeGreekToLatex[] = {
4649     "A",
4650     "B",
4651     "\\Gamma", /*915*/
4652     "\\Delta",
4653     "E",
4654     "Z",
4655     "H",
4656     "\\Theta",/*920*/
4657     "I",
4658     "K",
4659     "\\Lambda",
4660     "M",
4661     "N",
4662     "\\Xi",
4663     "O",
4664     "\\Pi",
4665     "P",
4666     "", /* invalid character capital rho 930*/
4667     "\\Sigma",
4668     "T",
4669     "Y",
4670     "\\Phi",
4671     "X",
4672     "\\Psi",
4673     "\\Omega",
4674     "\\\"I",  /* these should not be in math mode 938*/
4675     "\\\"Y",
4676     "\\'\\alpha",
4677     "\\'\\epsilon",
4678     "\\'\\eta",
4679     "\\'\\iota",
4680     "\\\"u", /* 944 */
4681     "\\alpha",
4682     "\\beta",
4683     "\\gamma",
4684     "\\delta",
4685     "\\epsilon",
4686     "\\zeta",
4687     "\\eta",
4688     "\\theta",
4689     "\\iota",
4690     "\\kappa",
4691     "\\lambda",
4692     "\\mu",
4693     "\\nu",
4694     "\\xi",
4695     "o",
4696     "\\pi",
4697     "\\rho",
4698     "s",
4699     "\\sigma",
4700     "\\tau",
4701     "u",
4702     "\\phi",
4703     "\\chi",
4704     "\\psi",
4705     "\\omega",
4706     0
4707 };
4708