- Unknown destinations are now correctly skipped (so loading an RTF
[wine] / dlls / riched20 / reader.c
1 /*
2  * WINE RTF file reader
3  *
4  * Portions Copyright 2004 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 /*
22  * Derived from RTF Tools by Paul DuBois (dubois@primate.wisc.edu)
23  * Homepage: http://www.snake.net/software/RTF/
24  * Original license follows:
25  */
26
27 /*
28  * reader.c - RTF file reader.  Release 1.10.
29  *
30  * ....
31  *
32  * Author: Paul DuBois  dubois@primate.wisc.edu
33  *
34  * This software may be redistributed without restriction and used for
35  * any purpose whatsoever.
36  */
37
38 #include <stdio.h>
39 #include <ctype.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <assert.h>
44
45 #include "rtf.h"
46
47 #include "windef.h"
48 #include "winbase.h"
49 #include "wine/debug.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
52
53 extern HANDLE me_heap;
54
55 static int      _RTFGetChar(RTF_Info *);
56 static void     _RTFGetToken (RTF_Info *);
57 static void     _RTFGetToken2 (RTF_Info *);
58 static int      GetChar (RTF_Info *);
59 static void     ReadFontTbl (RTF_Info *);
60 static void     ReadColorTbl (RTF_Info *);
61 static void     ReadStyleSheet (RTF_Info *);
62 static void     ReadInfoGroup (RTF_Info *);
63 static void     ReadPictGroup (RTF_Info *);
64 static void     ReadObjGroup (RTF_Info *);
65 static void     LookupInit (void);
66 static void     Lookup (RTF_Info *, char *);
67 static int      Hash (char*);
68
69 static void     CharSetInit (RTF_Info *);
70 static void     ReadCharSetMaps (RTF_Info *);
71
72
73 /*
74  RTF ANSI character set (\ansi) general map
75  These are taken from the ISO-Latin-1 (ISO-8859-1) encodings, with
76  a few additions
77
78  Field 1 is the standard character name which the character value in
79  field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
80  use the value in field 2.)
81
82  The character value may be given either as a single character (which will be
83  converted to the ASCII value of the character), or in numeric format, either
84  in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
85  characters.*/
86
87 int ansi_gen[] =
88 {
89   rtfSC_formula          ,0x06,
90   rtfSC_nobrkhyphen      ,0x1e,
91   rtfSC_opthyphen        ,0x1f,
92   rtfSC_space            ,' ',
93   rtfSC_exclam           ,'!',
94   rtfSC_quotedbl         ,'"',
95   rtfSC_numbersign       ,'#',
96   rtfSC_dollar           ,'$',
97   rtfSC_percent          ,'%',
98   rtfSC_ampersand        ,'&',
99   rtfSC_quoteright       ,'\'',
100   rtfSC_parenleft        ,'(',
101   rtfSC_parenright       ,')',
102   rtfSC_asterisk         ,'*',
103   rtfSC_plus             ,'+',
104   rtfSC_comma            ,',',
105   rtfSC_hyphen           ,'-',
106   rtfSC_period           ,'.',
107   rtfSC_slash            ,'/',
108   rtfSC_zero             ,'0',
109   rtfSC_one              ,'1',
110   rtfSC_two              ,'2',
111   rtfSC_three            ,'3',
112   rtfSC_four             ,'4',
113   rtfSC_five             ,'5',
114   rtfSC_six              ,'6',
115   rtfSC_seven            ,'7',
116   rtfSC_eight            ,'8',
117   rtfSC_nine             ,'9',
118   rtfSC_colon            ,':',
119   rtfSC_semicolon        ,';',
120   rtfSC_less             ,'<',
121   rtfSC_equal            ,'=',
122   rtfSC_greater          ,'>',
123   rtfSC_question         ,'?',
124   rtfSC_at               ,'@',
125   rtfSC_A                ,'A',
126   rtfSC_B                ,'B',
127   rtfSC_C                ,'C',
128   rtfSC_D                ,'D',
129   rtfSC_E                ,'E',
130   rtfSC_F                ,'F',
131   rtfSC_G                ,'G',
132   rtfSC_H                ,'H',
133   rtfSC_I                ,'I',
134   rtfSC_J                ,'J',
135   rtfSC_K                ,'K',
136   rtfSC_L                ,'L',
137   rtfSC_M                ,'M',
138   rtfSC_N                ,'N',
139   rtfSC_O                ,'O',
140   rtfSC_P                ,'P',
141   rtfSC_Q                ,'Q',
142   rtfSC_R                ,'R',
143   rtfSC_S                ,'S',
144   rtfSC_T                ,'T',
145   rtfSC_U                ,'U',
146   rtfSC_V                ,'V',
147   rtfSC_W                ,'W',
148   rtfSC_X                ,'X',
149   rtfSC_Y                ,'Y',
150   rtfSC_Z                ,'Z',
151   rtfSC_bracketleft      ,'[',
152   rtfSC_backslash        ,'\\',
153   rtfSC_bracketright     ,']',
154   rtfSC_asciicircum      ,'^',
155   rtfSC_underscore       ,'_',
156   rtfSC_quoteleft        ,'`',
157   rtfSC_a                ,'a',
158   rtfSC_b                ,'b',
159   rtfSC_c                ,'c',
160   rtfSC_d                ,'d',
161   rtfSC_e                ,'e',
162   rtfSC_f                ,'f',
163   rtfSC_g                ,'g',
164   rtfSC_h                ,'h',
165   rtfSC_i                ,'i',
166   rtfSC_j                ,'j',
167   rtfSC_k                ,'k',
168   rtfSC_l                ,'l',
169   rtfSC_m                ,'m',
170   rtfSC_n                ,'n',
171   rtfSC_o                ,'o',
172   rtfSC_p                ,'p',
173   rtfSC_q                ,'q',
174   rtfSC_r                ,'r',
175   rtfSC_s                ,'s',
176   rtfSC_t                ,'t',
177   rtfSC_u                ,'u',
178   rtfSC_v                ,'v',
179   rtfSC_w                ,'w',
180   rtfSC_x                ,'x',
181   rtfSC_y                ,'y',
182   rtfSC_z                ,'z',
183   rtfSC_braceleft        ,'{',
184   rtfSC_bar              ,'|',
185   rtfSC_braceright       ,'}',
186   rtfSC_asciitilde       ,'~',
187   rtfSC_nobrkspace       ,0xa0,
188   rtfSC_exclamdown       ,0xa1,
189   rtfSC_cent             ,0xa2,
190   rtfSC_sterling         ,0xa3,
191   rtfSC_currency         ,0xa4,
192   rtfSC_yen              ,0xa5,
193   rtfSC_brokenbar        ,0xa6,
194   rtfSC_section          ,0xa7,
195   rtfSC_dieresis         ,0xa8,
196   rtfSC_copyright        ,0xa9,
197   rtfSC_ordfeminine      ,0xaa,
198   rtfSC_guillemotleft    ,0xab,
199   rtfSC_logicalnot       ,0xac,
200   rtfSC_opthyphen        ,0xad,
201   rtfSC_registered       ,0xae,
202   rtfSC_macron           ,0xaf,
203   rtfSC_degree           ,0xb0,
204   rtfSC_plusminus        ,0xb1,
205   rtfSC_twosuperior      ,0xb2,
206   rtfSC_threesuperior    ,0xb3,
207   rtfSC_acute            ,0xb4,
208   rtfSC_mu               ,0xb5,
209   rtfSC_paragraph        ,0xb6,
210   rtfSC_periodcentered   ,0xb7,
211   rtfSC_cedilla          ,0xb8,
212   rtfSC_onesuperior      ,0xb9,
213   rtfSC_ordmasculine     ,0xba,
214   rtfSC_guillemotright   ,0xbb,
215   rtfSC_onequarter       ,0xbc,
216   rtfSC_onehalf          ,0xbd,
217   rtfSC_threequarters    ,0xbe,
218   rtfSC_questiondown     ,0xbf,
219   rtfSC_Agrave           ,0xc0,
220   rtfSC_Aacute           ,0xc1,
221   rtfSC_Acircumflex      ,0xc2,
222   rtfSC_Atilde           ,0xc3,
223   rtfSC_Adieresis        ,0xc4,
224   rtfSC_Aring            ,0xc5,
225   rtfSC_AE               ,0xc6,
226   rtfSC_Ccedilla         ,0xc7,
227   rtfSC_Egrave           ,0xc8,
228   rtfSC_Eacute           ,0xc9,
229   rtfSC_Ecircumflex      ,0xca,
230   rtfSC_Edieresis        ,0xcb,
231   rtfSC_Igrave           ,0xcc,
232   rtfSC_Iacute           ,0xcd,
233   rtfSC_Icircumflex      ,0xce,
234   rtfSC_Idieresis        ,0xcf,
235   rtfSC_Eth              ,0xd0,
236   rtfSC_Ntilde           ,0xd1,
237   rtfSC_Ograve           ,0xd2,
238   rtfSC_Oacute           ,0xd3,
239   rtfSC_Ocircumflex      ,0xd4,
240   rtfSC_Otilde           ,0xd5,
241   rtfSC_Odieresis        ,0xd6,
242   rtfSC_multiply         ,0xd7,
243   rtfSC_Oslash           ,0xd8,
244   rtfSC_Ugrave           ,0xd9,
245   rtfSC_Uacute           ,0xda,
246   rtfSC_Ucircumflex      ,0xdb,
247   rtfSC_Udieresis        ,0xdc,
248   rtfSC_Yacute           ,0xdd,
249   rtfSC_Thorn            ,0xde,
250   rtfSC_germandbls       ,0xdf,
251   rtfSC_agrave           ,0xe0,
252   rtfSC_aacute           ,0xe1,
253   rtfSC_acircumflex      ,0xe2,
254   rtfSC_atilde           ,0xe3,
255   rtfSC_adieresis        ,0xe4,
256   rtfSC_aring            ,0xe5,
257   rtfSC_ae               ,0xe6,
258   rtfSC_ccedilla         ,0xe7,
259   rtfSC_egrave           ,0xe8,
260   rtfSC_eacute           ,0xe9,
261   rtfSC_ecircumflex      ,0xea,
262   rtfSC_edieresis        ,0xeb,
263   rtfSC_igrave           ,0xec,
264   rtfSC_iacute           ,0xed,
265   rtfSC_icircumflex      ,0xee,
266   rtfSC_idieresis        ,0xef,
267   rtfSC_eth              ,0xf0,
268   rtfSC_ntilde           ,0xf1,
269   rtfSC_ograve           ,0xf2,
270   rtfSC_oacute           ,0xf3,
271   rtfSC_ocircumflex      ,0xf4,
272   rtfSC_otilde           ,0xf5,
273   rtfSC_odieresis        ,0xf6,
274   rtfSC_divide           ,0xf7,
275   rtfSC_oslash           ,0xf8,
276   rtfSC_ugrave           ,0xf9,
277   rtfSC_uacute           ,0xfa,
278   rtfSC_ucircumflex      ,0xfb,
279   rtfSC_udieresis        ,0xfc,
280   rtfSC_yacute           ,0xfd,
281   rtfSC_thorn            ,0xfe,
282   rtfSC_ydieresis        ,0xff
283 };
284
285 /*
286  * RTF ANSI character set (\ansi) Symbol font map
287  *
288  * Field 1 is the standard character name which the character value in
289  * field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
290  * use the value in field 2.)
291  *
292  * The character value may be given either as a single character (which will be
293  * converted to the ASCII value of the character), or in numeric format, either
294  * in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
295  * characters.
296  *
297  */
298
299 int ansi_sym[] =
300 {
301   rtfSC_formula        ,0x06,
302   rtfSC_nobrkhyphen    ,0x1e,
303   rtfSC_opthyphen      ,0x1f,
304   rtfSC_space          ,' ',
305   rtfSC_exclam         ,'!',
306   rtfSC_universal      ,'"',
307   rtfSC_mathnumbersign ,'#',
308   rtfSC_existential    ,'$',
309   rtfSC_percent        ,'%',
310   rtfSC_ampersand      ,'&',
311   rtfSC_suchthat       ,'\\',
312   rtfSC_parenleft      ,'(',
313   rtfSC_parenright     ,')',
314   rtfSC_mathasterisk   ,'*',
315   rtfSC_mathplus       ,'+',
316   rtfSC_comma          ,',',
317   rtfSC_mathminus      ,'-',
318   rtfSC_period         ,'.',
319   rtfSC_slash          ,'/',
320   rtfSC_zero           ,'0',
321   rtfSC_one            ,'1',
322   rtfSC_two            ,'2',
323   rtfSC_three          ,'3',
324   rtfSC_four           ,'4',
325   rtfSC_five           ,'5',
326   rtfSC_six            ,'6',
327   rtfSC_seven          ,'7',
328   rtfSC_eight          ,'8',
329   rtfSC_nine           ,'9',
330   rtfSC_colon          ,':',
331   rtfSC_semicolon      ,';',
332   rtfSC_less           ,'<',
333   rtfSC_mathequal      ,'=',
334   rtfSC_greater        ,'>',
335   rtfSC_question       ,'?',
336   rtfSC_congruent      ,'@',
337   rtfSC_Alpha          ,'A',
338   rtfSC_Beta           ,'B',
339   rtfSC_Chi            ,'C',
340   rtfSC_Delta          ,'D',
341   rtfSC_Epsilon        ,'E',
342   rtfSC_Phi            ,'F',
343   rtfSC_Gamma          ,'G',
344   rtfSC_Eta            ,'H',
345   rtfSC_Iota           ,'I',
346   rtfSC_Kappa          ,'K',
347   rtfSC_Lambda         ,'L',
348   rtfSC_Mu             ,'M',
349   rtfSC_Nu             ,'N',
350   rtfSC_Omicron        ,'O',
351   rtfSC_Pi             ,'P',
352   rtfSC_Theta          ,'Q',
353   rtfSC_Rho            ,'R',
354   rtfSC_Sigma          ,'S',
355   rtfSC_Tau            ,'T',
356   rtfSC_Upsilon        ,'U',
357   rtfSC_varsigma       ,'V',
358   rtfSC_Omega          ,'W',
359   rtfSC_Xi             ,'X',
360   rtfSC_Psi            ,'Y',
361   rtfSC_Zeta           ,'Z',
362   rtfSC_bracketleft    ,'[',
363   rtfSC_backslash      ,'\\',
364   rtfSC_bracketright   ,']',
365   rtfSC_asciicircum    ,'^',
366   rtfSC_underscore     ,'_',
367   rtfSC_quoteleft      ,'`',
368   rtfSC_alpha          ,'a',
369   rtfSC_beta           ,'b',
370   rtfSC_chi            ,'c',
371   rtfSC_delta          ,'d',
372   rtfSC_epsilon        ,'e',
373   rtfSC_phi            ,'f',
374   rtfSC_gamma          ,'g',
375   rtfSC_eta            ,'h',
376   rtfSC_iota           ,'i',
377   rtfSC_kappa          ,'k',
378   rtfSC_lambda         ,'l',
379   rtfSC_mu             ,'m',
380   rtfSC_nu             ,'n',
381   rtfSC_omicron        ,'o',
382   rtfSC_pi             ,'p',
383   rtfSC_theta          ,'q',
384   rtfSC_rho            ,'r',
385   rtfSC_sigma          ,'s',
386   rtfSC_tau            ,'t',
387   rtfSC_upsilon        ,'u',
388   rtfSC_omega          ,'w',
389   rtfSC_xi             ,'x',
390   rtfSC_psi            ,'y',
391   rtfSC_zeta           ,'z',
392   rtfSC_braceleft      ,'{',
393   rtfSC_bar            ,'|',
394   rtfSC_braceright     ,'}',
395   rtfSC_mathtilde      ,'~'
396 };
397
398 /*
399  *  Output sequence map for rtf2text
400  *
401  *  Field 1 is the standard character name.  Field 2 is the output sequence
402  *  to produce for that character.
403  *
404  *  The output sequence is simply a string of characters.  If it contains
405  *  whitespace, it may be quoted.  If it contains quotes, it may be quoted
406  *  with a different quote character.
407  *
408  *  characters in ASCII range (32-127
409  */
410
411 const char *text_map[] = {
412   "space"             ," ",
413   "exclam"            ,"!",
414   "quotedbl"          ,"\"",
415   "numbersign"        ,"#",
416   "dollar"            ,"$",
417   "percent"           ,"%",
418   "ampersand"         ,"&",
419   "quoteright"        ,"'",
420   "parenleft"         ,"(",
421   "parenright"        ,")",
422   "asterisk"          ,"*",
423   "plus"              ,"+",
424   "comma"             ,",",
425   "hyphen"            ,"-",
426   "period"            ,".",
427   "slash"             ,"/",
428   "zero"              ,"0",
429   "one"               ,"1",
430   "two"               ,"2",
431   "three"             ,"3",
432   "four"              ,"4",
433   "five"              ,"5",
434   "six"               ,"6",
435   "seven"             ,"7",
436   "eight"             ,"8",
437   "nine"              ,"9",
438   "colon"             ,":",
439   "semicolon"         ,";",
440   "less"              ,"<",
441   "equal"             ,"=",
442   "greater"           ,">",
443   "question"          ,"?",
444   "at"                ,"@",
445   "A"                 ,"A",
446   "B"                 ,"B",
447   "C"                 ,"C",
448   "D"                 ,"D",
449   "E"                 ,"E",
450   "F"                 ,"F",
451   "G"                 ,"G",
452   "H"                 ,"H",
453   "I"                 ,"I",
454   "J"                 ,"J",
455   "K"                 ,"K",
456   "L"                 ,"L",
457   "M"                 ,"M",
458   "N"                 ,"N",
459   "O"                 ,"O",
460   "P"                 ,"P",
461   "Q"                 ,"Q",
462   "R"                 ,"R",
463   "S"                 ,"S",
464   "T"                 ,"T",
465   "U"                 ,"U",
466   "V"                 ,"V",
467   "W"                 ,"W",
468   "X"                 ,"X",
469   "Y"                 ,"Y",
470   "Z"                 ,"Z",
471   "bracketleft"       ,"[",
472   "backslash"         ,"\\",
473   "bracketright"      ,"]",
474   "asciicircum"       ,"^",
475   "underscore"        ,"_",
476   "quoteleft"         ,"`",
477   "a"                 ,"a",
478   "b"                 ,"b",
479   "c"                 ,"c",
480   "d"                 ,"d",
481   "e"                 ,"e",
482   "f"                 ,"f",
483   "g"                 ,"g",
484   "h"                 ,"h",
485   "i"                 ,"i",
486   "j"                 ,"j",
487   "k"                 ,"k",
488   "l"                 ,"l",
489   "m"                 ,"m",
490   "n"                 ,"n",
491   "o"                 ,"o",
492   "p"                 ,"p",
493   "q"                 ,"q",
494   "r"                 ,"r",
495   "s"                 ,"s",
496   "t"                 ,"t",
497   "u"                 ,"u",
498   "v"                 ,"v",
499   "w"                 ,"w",
500   "x"                 ,"x",
501   "y"                 ,"y",
502   "z"                 ,"z",
503   "braceleft"         ,"{",
504   "bar"               ,"|",
505   "braceright"        ,"}",
506   "asciitilde"        ,"~",
507   "AE"                ,"AE",
508   "OE"                ,"OE",
509   "acute"             ,"'",
510   "ae"                ,"ae",
511   "angleleft"         ,"<",
512   "angleright"        ,">",
513   "arrowboth"         ,"<->",
514   "arrowdblboth"      ,"<=>",
515   "arrowdblleft"      ,"<=",
516   "arrowdblright"     ,"=>",
517   "arrowleft"         ,"<-",
518   "arrowright"        ,"->",
519   "bullet"            ,"o",
520   "cent"              ,"cent",
521   "circumflex"        ,"^",
522   "copyright"         ,"(c)",
523   "copyrightsans"     ,"(c)",
524   "degree"            ,"deg.",
525   "divide"            ,"/",
526   "dotlessi"          ,"i",
527   "ellipsis"          ,"...",
528   "emdash"            ,"--",
529   "endash"            ,"-",
530   "fi"                ,"fi",
531   "fl"                ,"fl",
532   "fraction"          ,"/",
533   "germandbls"        ,"ss",
534   "grave"             ,"`",
535   "greaterequal"      ,">=",
536   "guillemotleft"     ,"<<",
537   "guillemotright"    ,">>",
538   "guilsinglleft"     ,"<",
539   "guilsinglright"    ,">",
540   "lessequal"         ,"<=",
541   "logicalnot"        ,"~",
542   "mathasterisk"      ,"*",
543   "mathequal"         ,"=",
544   "mathminus"         ,"-",
545   "mathnumbersign"    ,"#",
546   "mathplus"          ,"+",
547   "mathtilde"         ,"~",
548   "minus"             ,"-",
549   "mu"                ,"u",
550   "multiply"          ,"x",
551   "nobrkhyphen"       ,"-",
552   "nobrkspace"        ," ",
553   "notequal"          ,"!=",
554   "oe"                ,"oe",
555   "onehalf"           ,"1/2",
556   "onequarter"        ,"1/4",
557   "periodcentered"    ,".",
558   "plusminus"         ,"+/-",
559   "quotedblbase"      ,",,",
560   "quotedblleft"      ,"\"",
561   "quotedblright"     ,"\"",
562   "quotesinglbase"    ,",",
563   "registered"        ,"reg.",
564   "registersans"      ,"reg.",
565   "threequarters"     ,"3/4",
566   "tilde"             ,"~",
567   "trademark"         ,"(TM)",
568   "trademarksans"     ,"(TM)"
569 };
570
571 /*
572  * This array is used to map standard character names onto their numeric codes.
573  * The position of the name within the array is the code.
574  * stdcharnames.h is generated in the ../h directory.
575  */
576
577 const char *stdCharName[] =
578 {
579         "nothing",
580         "space",
581         "exclam",
582         "quotedbl",
583         "numbersign",
584         "dollar",
585         "percent",
586         "ampersand",
587         "quoteright",
588         "parenleft",
589         "parenright",
590         "asterisk",
591         "plus",
592         "comma",
593         "hyphen",
594         "period",
595         "slash",
596         "zero",
597         "one",
598         "two",
599         "three",
600         "four",
601         "five",
602         "six",
603         "seven",
604         "eight",
605         "nine",
606         "colon",
607         "semicolon",
608         "less",
609         "equal",
610         "greater",
611         "question",
612         "at",
613         "A",
614         "B",
615         "C",
616         "D",
617         "E",
618         "F",
619         "G",
620         "H",
621         "I",
622         "J",
623         "K",
624         "L",
625         "M",
626         "N",
627         "O",
628         "P",
629         "Q",
630         "R",
631         "S",
632         "T",
633         "U",
634         "V",
635         "W",
636         "X",
637         "Y",
638         "Z",
639         "bracketleft",
640         "backslash",
641         "bracketright",
642         "asciicircum",
643         "underscore",
644         "quoteleft",
645         "a",
646         "b",
647         "c",
648         "d",
649         "e",
650         "f",
651         "g",
652         "h",
653         "i",
654         "j",
655         "k",
656         "l",
657         "m",
658         "n",
659         "o",
660         "p",
661         "q",
662         "r",
663         "s",
664         "t",
665         "u",
666         "v",
667         "w",
668         "x",
669         "y",
670         "z",
671         "braceleft",
672         "bar",
673         "braceright",
674         "asciitilde",
675         "exclamdown",
676         "cent",
677         "sterling",
678         "fraction",
679         "yen",
680         "florin",
681         "section",
682         "currency",
683         "quotedblleft",
684         "guillemotleft",
685         "guilsinglleft",
686         "guilsinglright",
687         "fi",
688         "fl",
689         "endash",
690         "dagger",
691         "daggerdbl",
692         "periodcentered",
693         "paragraph",
694         "bullet",
695         "quotesinglbase",
696         "quotedblbase",
697         "quotedblright",
698         "guillemotright",
699         "ellipsis",
700         "perthousand",
701         "questiondown",
702         "grave",
703         "acute",
704         "circumflex",
705         "tilde",
706         "macron",
707         "breve",
708         "dotaccent",
709         "dieresis",
710         "ring",
711         "cedilla",
712         "hungarumlaut",
713         "ogonek",
714         "caron",
715         "emdash",
716         "AE",
717         "ordfeminine",
718         "Lslash",
719         "Oslash",
720         "OE",
721         "ordmasculine",
722         "ae",
723         "dotlessi",
724         "lslash",
725         "oslash",
726         "oe",
727         "germandbls",
728         "Aacute",
729         "Acircumflex",
730         "Adieresis",
731         "Agrave",
732         "Aring",
733         "Atilde",
734         "Ccedilla",
735         "Eacute",
736         "Ecircumflex",
737         "Edieresis",
738         "Egrave",
739         "Eth",
740         "Iacute",
741         "Icircumflex",
742         "Idieresis",
743         "Igrave",
744         "Ntilde",
745         "Oacute",
746         "Ocircumflex",
747         "Odieresis",
748         "Ograve",
749         "Otilde",
750         "Scaron",
751         "Thorn",
752         "Uacute",
753         "Ucircumflex",
754         "Udieresis",
755         "Ugrave",
756         "Yacute",
757         "Ydieresis",
758         "aacute",
759         "acircumflex",
760         "adieresis",
761         "agrave",
762         "aring",
763         "atilde",
764         "brokenbar",
765         "ccedilla",
766         "copyright",
767         "degree",
768         "divide",
769         "eacute",
770         "ecircumflex",
771         "edieresis",
772         "egrave",
773         "eth",
774         "iacute",
775         "icircumflex",
776         "idieresis",
777         "igrave",
778         "logicalnot",
779         "minus",
780         "multiply",
781         "ntilde",
782         "oacute",
783         "ocircumflex",
784         "odieresis",
785         "ograve",
786         "onehalf",
787         "onequarter",
788         "onesuperior",
789         "otilde",
790         "plusminus",
791         "registered",
792         "thorn",
793         "threequarters",
794         "threesuperior",
795         "trademark",
796         "twosuperior",
797         "uacute",
798         "ucircumflex",
799         "udieresis",
800         "ugrave",
801         "yacute",
802         "ydieresis",
803         "Alpha",
804         "Beta",
805         "Chi",
806         "Delta",
807         "Epsilon",
808         "Phi",
809         "Gamma",
810         "Eta",
811         "Iota",
812         "Kappa",
813         "Lambda",
814         "Mu",
815         "Nu",
816         "Omicron",
817         "Pi",
818         "Theta",
819         "Rho",
820         "Sigma",
821         "Tau",
822         "Upsilon",
823         "varUpsilon",
824         "Omega",
825         "Xi",
826         "Psi",
827         "Zeta",
828         "alpha",
829         "beta",
830         "chi",
831         "delta",
832         "epsilon",
833         "phi",
834         "varphi",
835         "gamma",
836         "eta",
837         "iota",
838         "kappa",
839         "lambda",
840         "mu",
841         "nu",
842         "omicron",
843         "pi",
844         "varpi",
845         "theta",
846         "vartheta",
847         "rho",
848         "sigma",
849         "varsigma",
850         "tau",
851         "upsilon",
852         "omega",
853         "xi",
854         "psi",
855         "zeta",
856         "nobrkspace",
857         "nobrkhyphen",
858         "lessequal",
859         "greaterequal",
860         "infinity",
861         "integral",
862         "notequal",
863         "radical",
864         "radicalex",
865         "approxequal",
866         "apple",
867         "partialdiff",
868         "opthyphen",
869         "formula",
870         "lozenge",
871         "universal",
872         "existential",
873         "suchthat",
874         "congruent",
875         "therefore",
876         "perpendicular",
877         "minute",
878         "club",
879         "diamond",
880         "heart",
881         "spade",
882         "arrowboth",
883         "arrowleft",
884         "arrowup",
885         "arrowright",
886         "arrowdown",
887         "second",
888         "proportional",
889         "equivalence",
890         "arrowvertex",
891         "arrowhorizex",
892         "carriagereturn",
893         "aleph",
894         "Ifraktur",
895         "Rfraktur",
896         "weierstrass",
897         "circlemultiply",
898         "circleplus",
899         "emptyset",
900         "intersection",
901         "union",
902         "propersuperset",
903         "reflexsuperset",
904         "notsubset",
905         "propersubset",
906         "reflexsubset",
907         "element",
908         "notelement",
909         "angle",
910         "gradient",
911         "product",
912         "logicaland",
913         "logicalor",
914         "arrowdblboth",
915         "arrowdblleft",
916         "arrowdblup",
917         "arrowdblright",
918         "arrowdbldown",
919         "angleleft",
920         "registersans",
921         "copyrightsans",
922         "trademarksans",
923         "angleright",
924         "mathplus",
925         "mathminus",
926         "mathasterisk",
927         "mathnumbersign",
928         "dotmath",
929         "mathequal",
930         "mathtilde",
931         (char *) NULL
932 };
933
934 int _RTFGetChar(RTF_Info *info)
935 {
936         int ch;
937
938         TRACE("\n");
939
940         /* if the last buffer wasn't full, it's EOF */
941   if (info->dwInputSize > 0 &&
942     info->dwInputSize == info->dwInputUsed && info->dwInputSize < sizeof(info->InputBuffer))
943     return EOF;
944   if (info->dwInputSize <= info->dwInputUsed)
945         {
946                 long count = 0;
947                 info->editstream.dwError = info->editstream.pfnCallback(info->editstream.dwCookie, 
948                         info->InputBuffer, sizeof(info->InputBuffer), &count);
949         /* if error, it's EOF */
950                 if (info->editstream.dwError)
951                   return EOF;
952         /* if no bytes read, it's EOF */
953                 if(count == 0)
954                         return EOF;
955                 info->dwInputSize = count;
956                 info->dwInputUsed = 0;
957         }
958         ch = info->InputBuffer[info->dwInputUsed++];
959         if (!ch)
960                  return EOF;
961         return ch;
962 }
963
964 void RTFSetEditStream(RTF_Info *info, EDITSTREAM *es)
965 {
966         TRACE("\n");
967
968         info->editstream.dwCookie = es->dwCookie;
969         info->editstream.dwError  = es->dwError;
970         info->editstream.pfnCallback = es->pfnCallback;
971 }
972
973 /*
974  * Initialize the reader.  This may be called multiple times,
975  * to read multiple files.  The only thing not reset is the input
976  * stream; that must be done with RTFSetStream().
977  */
978
979 void RTFInit(RTF_Info *info)
980 {
981         int     i;
982         RTFColor        *cp;
983         RTFFont         *fp;
984         RTFStyle        *sp;
985         RTFStyleElt     *eltList, *ep;
986
987         TRACE("\n");
988
989         if (info->rtfTextBuf == (char *) NULL)  /* initialize the text buffers */
990         {
991                 info->rtfTextBuf = RTFAlloc (rtfBufSiz);
992                 info->pushedTextBuf = RTFAlloc (rtfBufSiz);
993                 if (info->rtfTextBuf == (char *) NULL
994                         || info->pushedTextBuf == (char *) NULL)
995                         RTFPanic (info,"Cannot allocate text buffers.");
996                 info->rtfTextBuf[0] = info->pushedTextBuf[0] = '\0';
997         }
998
999         RTFFree (info->inputName);
1000         RTFFree (info->outputName);
1001         info->inputName = info->outputName = (char *) NULL;
1002
1003         /* initialize lookup table */
1004         LookupInit ();
1005
1006         for (i = 0; i < rtfMaxClass; i++)
1007                 RTFSetClassCallback (info, i, (RTFFuncPtr) NULL);
1008         for (i = 0; i < rtfMaxDestination; i++)
1009                 RTFSetDestinationCallback (info, i, (RTFFuncPtr) NULL);
1010
1011         /* install built-in destination readers */
1012         RTFSetDestinationCallback (info, rtfFontTbl, ReadFontTbl);
1013         RTFSetDestinationCallback (info, rtfColorTbl, ReadColorTbl);
1014         RTFSetDestinationCallback (info, rtfStyleSheet, ReadStyleSheet);
1015         RTFSetDestinationCallback (info, rtfInfo, ReadInfoGroup);
1016         RTFSetDestinationCallback (info, rtfPict, ReadPictGroup);
1017         RTFSetDestinationCallback (info, rtfObject, ReadObjGroup);
1018
1019
1020         RTFSetReadHook (info, (RTFFuncPtr) NULL);
1021
1022         /* dump old lists if necessary */
1023
1024         while (info->fontList != (RTFFont *) NULL)
1025         {
1026                 fp = info->fontList->rtfNextFont;
1027                 RTFFree (info->fontList->rtfFName);
1028                 RTFFree ((char *) info->fontList);
1029                 info->fontList = fp;
1030         }
1031         while (info->colorList != (RTFColor *) NULL)
1032         {
1033                 cp = info->colorList->rtfNextColor;
1034                 RTFFree ((char *) info->colorList);
1035                 info->colorList = cp;
1036         }
1037         while (info->styleList != (RTFStyle *) NULL)
1038         {
1039                 sp = info->styleList->rtfNextStyle;
1040                 eltList = info->styleList->rtfSSEList;
1041                 while (eltList != (RTFStyleElt *) NULL)
1042                 {
1043                         ep = eltList->rtfNextSE;
1044                         RTFFree (eltList->rtfSEText);
1045                         RTFFree ((char *) eltList);
1046                         eltList = ep;
1047                 }
1048                 RTFFree (info->styleList->rtfSName);
1049                 RTFFree ((char *) info->styleList);
1050                 info->styleList = sp;
1051         }
1052
1053         info->rtfClass = -1;
1054         info->pushedClass = -1;
1055         info->pushedChar = EOF;
1056
1057         info->rtfLineNum = 0;
1058         info->rtfLinePos = 0;
1059         info->prevChar = EOF;
1060         info->bumpLine = 0;
1061
1062         CharSetInit (info);
1063         info->csTop = 0;
1064 }
1065
1066 /*
1067  * Set or get the input or output file name.  These are never guaranteed
1068  * to be accurate, only insofar as the calling program makes them so.
1069  */
1070
1071 void RTFSetInputName(RTF_Info *info, char *name)
1072 {
1073         TRACE("\n");
1074
1075         if ((info->inputName = RTFStrSave (name)) == (char *) NULL)
1076                 RTFPanic (info,"RTFSetInputName: out of memory");
1077 }
1078
1079
1080 char *RTFGetInputName(RTF_Info *info)
1081 {
1082         return (info->inputName);
1083 }
1084
1085
1086 void RTFSetOutputName(RTF_Info *info, char *name)
1087 {
1088         TRACE("\n");
1089
1090         if ((info->outputName = RTFStrSave (name)) == (char *) NULL)
1091                 RTFPanic (info, "RTFSetOutputName: out of memory");
1092 }
1093
1094
1095 char *RTFGetOutputName(RTF_Info *info)
1096 {
1097         return (info->outputName);
1098 }
1099
1100
1101
1102 /* ---------------------------------------------------------------------- */
1103
1104 /*
1105  * Callback table manipulation routines
1106  */
1107
1108
1109 /*
1110  * Install or return a writer callback for a token class
1111  */
1112
1113 void RTFSetClassCallback(RTF_Info *info, int class, RTFFuncPtr callback)
1114 {
1115         if (class >= 0 && class < rtfMaxClass)
1116                 info->ccb[class] = callback;
1117 }
1118
1119
1120 RTFFuncPtr RTFGetClassCallback(RTF_Info *info, int class)
1121 {
1122         if (class >= 0 && class < rtfMaxClass)
1123                 return (info->ccb[class]);
1124         return ((RTFFuncPtr) NULL);
1125 }
1126
1127
1128 /*
1129  * Install or return a writer callback for a destination type
1130  */
1131
1132 void RTFSetDestinationCallback(RTF_Info *info, int dest, RTFFuncPtr callback)
1133 {
1134         if (dest >= 0 && dest < rtfMaxDestination)
1135                 info->dcb[dest] = callback;
1136 }
1137
1138
1139 RTFFuncPtr RTFGetDestinationCallback(RTF_Info *info, int dest)
1140 {
1141         if (dest >= 0 && dest < rtfMaxDestination)
1142                 return (info->dcb[dest]);
1143         return ((RTFFuncPtr) NULL);
1144 }
1145
1146
1147 /* ---------------------------------------------------------------------- */
1148
1149 /*
1150  * Token reading routines
1151  */
1152
1153
1154 /*
1155  * Read the input stream, invoking the writer's callbacks
1156  * where appropriate.
1157  */
1158
1159 void RTFRead(RTF_Info *info)
1160 {
1161         while (RTFGetToken (info) != rtfEOF)
1162                 RTFRouteToken (info);
1163 }
1164
1165
1166 /*
1167  * Route a token.  If it's a destination for which a reader is
1168  * installed, process the destination internally, otherwise
1169  * pass the token to the writer's class callback.
1170  */
1171
1172 void RTFRouteToken(RTF_Info *info)
1173 {
1174         RTFFuncPtr      p;
1175
1176         TRACE("\n");
1177
1178         if (info->rtfClass < 0 || info->rtfClass >= rtfMaxClass)        /* watchdog */
1179         {
1180                 RTFPanic (info,"Unknown class %d: %s (reader malfunction)",
1181                                                         info->rtfClass, info->rtfTextBuf);
1182         }
1183         if (RTFCheckCM (info, rtfControl, rtfDestination))
1184         {
1185                 /* invoke destination-specific callback if there is one */
1186                 if ((p = RTFGetDestinationCallback (info, info->rtfMinor))
1187                                                         != (RTFFuncPtr) NULL)
1188                 {
1189                         (*p) (info);
1190                         return;
1191                 }
1192         }
1193         /* invoke class callback if there is one */
1194         if ((p = RTFGetClassCallback (info, info->rtfClass)) != (RTFFuncPtr) NULL)
1195                 (*p) (info);
1196 }
1197
1198
1199 /*
1200  * Skip to the end of the current group.  When this returns,
1201  * writers that maintain a state stack may want to call their
1202  * state unstacker; global vars will still be set to the group's
1203  * closing brace.
1204  */
1205
1206 void RTFSkipGroup(RTF_Info *info)
1207 {
1208         int     level = 1;
1209
1210         TRACE("\n");
1211
1212         while (RTFGetToken (info) != rtfEOF)
1213         {
1214                 if (info->rtfClass == rtfGroup)
1215                 {
1216                         if (info->rtfMajor == rtfBeginGroup)
1217                                 ++level;
1218                         else if (info->rtfMajor == rtfEndGroup)
1219                         {
1220                                 if (--level < 1)
1221                                         break;  /* end of initial group */
1222                         }
1223                 }
1224         }
1225 }
1226
1227
1228 /*
1229  * Read one token.  Call the read hook if there is one.  The
1230  * token class is the return value.  Returns rtfEOF when there
1231  * are no more tokens.
1232  */
1233
1234 int RTFGetToken(RTF_Info *info)
1235 {
1236         RTFFuncPtr      p;
1237
1238         TRACE("\n");
1239
1240         for (;;)
1241         {
1242                 _RTFGetToken (info);
1243                 if ((p = RTFGetReadHook (info)) != (RTFFuncPtr) NULL)
1244                         (*p) (info);    /* give read hook a look at token */
1245
1246                 /* Silently discard newlines, carriage returns, nulls.  */
1247                 if (!(info->rtfClass == rtfText && info->rtfFormat != SF_TEXT
1248                         && (info->rtfMajor == '\r' || info->rtfMajor == '\n' || info->rtfMajor == '\0')))
1249                         break;
1250         }
1251         return (info->rtfClass);
1252 }
1253
1254
1255 /*
1256  * Install or return a token reader hook.
1257  */
1258
1259 void RTFSetReadHook(RTF_Info *info, RTFFuncPtr f)
1260 {
1261         info->readHook = f;
1262 }
1263
1264
1265 RTFFuncPtr RTFGetReadHook(RTF_Info *info)
1266 {
1267         return (info->readHook);
1268 }
1269
1270
1271 void RTFUngetToken(RTF_Info *info)
1272 {
1273         TRACE("\n");
1274
1275         if (info->pushedClass >= 0)     /* there's already an ungotten token */
1276                 RTFPanic (info,"cannot unget two tokens");
1277         if (info->rtfClass < 0)
1278                 RTFPanic (info,"no token to unget");
1279         info->pushedClass = info->rtfClass;
1280         info->pushedMajor = info->rtfMajor;
1281         info->pushedMinor = info->rtfMinor;
1282         info->pushedParam = info->rtfParam;
1283         (void) strcpy (info->pushedTextBuf, info->rtfTextBuf);
1284 }
1285
1286
1287 int RTFPeekToken(RTF_Info *info)
1288 {
1289         _RTFGetToken (info);
1290         RTFUngetToken (info);
1291         return (info->rtfClass);
1292 }
1293
1294
1295 static void _RTFGetToken(RTF_Info *info)
1296 {
1297         RTFFont *fp;
1298
1299         TRACE("\n");
1300
1301         if (info->rtfFormat == SF_TEXT) {
1302             info->rtfMajor = GetChar (info);
1303             info->rtfMinor = rtfSC_nothing;
1304             info->rtfParam = rtfNoParam;
1305             info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
1306             if (info->rtfMajor == EOF)
1307                 info->rtfClass = rtfEOF;
1308             else
1309                 info->rtfClass = rtfText;
1310             return;
1311         }
1312
1313         /* first check for pushed token from RTFUngetToken() */
1314
1315         if (info->pushedClass >= 0)
1316         {
1317                 info->rtfClass = info->pushedClass;
1318                 info->rtfMajor = info->pushedMajor;
1319                 info->rtfMinor = info->pushedMinor;
1320                 info->rtfParam = info->pushedParam;
1321                 (void) strcpy (info->rtfTextBuf, info->pushedTextBuf);
1322                 info->rtfTextLen = strlen (info->rtfTextBuf);
1323                 info->pushedClass = -1;
1324                 return;
1325         }
1326
1327         /*
1328          * Beyond this point, no token is ever seen twice, which is
1329          * important, e.g., for making sure no "}" pops the font stack twice.
1330          */
1331
1332         _RTFGetToken2 (info);
1333         if (info->rtfClass == rtfText)  /* map RTF char to standard code */
1334                 info->rtfMinor = RTFMapChar (info, info->rtfMajor);
1335
1336         /*
1337          * If auto-charset stuff is activated, see if anything needs doing,
1338          * like reading the charset maps or switching between them.
1339          */
1340
1341         if (info->autoCharSetFlags == 0)
1342                 return;
1343
1344         if ((info->autoCharSetFlags & rtfReadCharSet)
1345                 && RTFCheckCM (info, rtfControl, rtfCharSet))
1346         {
1347                 ReadCharSetMaps (info);
1348         }
1349         else if ((info->autoCharSetFlags & rtfSwitchCharSet)
1350                 && RTFCheckCMM (info, rtfControl, rtfCharAttr, rtfFontNum))
1351         {
1352                 if ((fp = RTFGetFont (info, info->rtfParam)) != (RTFFont *) NULL)
1353                 {
1354                         if (strncmp (fp->rtfFName, "Symbol", 6) == 0)
1355                                 info->curCharSet = rtfCSSymbol;
1356                         else
1357                                 info->curCharSet = rtfCSGeneral;
1358                         RTFSetCharSet (info, info->curCharSet);
1359                 }
1360         }
1361         else if ((info->autoCharSetFlags & rtfSwitchCharSet) && info->rtfClass == rtfGroup)
1362         {
1363                 switch (info->rtfMajor)
1364                 {
1365                 case rtfBeginGroup:
1366                         if (info->csTop >= maxCSStack)
1367                                 RTFPanic (info, "_RTFGetToken: stack overflow");
1368                         info->csStack[info->csTop++] = info->curCharSet;
1369                         break;
1370                 case rtfEndGroup:
1371                         /*
1372                          * If stack top is 1 at this point, we are ending the
1373                          * group started by the initial {, which ends the
1374                          * RTF stream
1375                          */
1376                         if (info->csTop <= 0)
1377                                 RTFPanic (info,"_RTFGetToken: stack underflow");
1378                         else if (info->csTop == 1)
1379                                 info->rtfClass = rtfEOF;
1380                         else
1381                         {
1382                                 info->curCharSet = info->csStack[--info->csTop];
1383                                 RTFSetCharSet (info, info->curCharSet);
1384                         }
1385                         break;
1386                 }
1387         }
1388 }
1389
1390
1391 /* this shouldn't be called anywhere but from _RTFGetToken() */
1392
1393 static void _RTFGetToken2(RTF_Info *info)
1394 {
1395         int     sign;
1396         int     c;
1397
1398         TRACE("\n");
1399
1400         /* initialize token vars */
1401
1402         info->rtfClass = rtfUnknown;
1403         info->rtfParam = rtfNoParam;
1404         info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
1405
1406         /* get first character, which may be a pushback from previous token */
1407
1408         if (info->pushedChar != EOF)
1409         {
1410                 c = info->pushedChar;
1411                 info->rtfTextBuf[info->rtfTextLen++] = c;
1412                 info->rtfTextBuf[info->rtfTextLen] = '\0';
1413                 info->pushedChar = EOF;
1414         }
1415         else if ((c = GetChar (info)) == EOF)
1416         {
1417                 info->rtfClass = rtfEOF;
1418                 return;
1419         }
1420
1421         if (c == '{')
1422         {
1423                 info->rtfClass = rtfGroup;
1424                 info->rtfMajor = rtfBeginGroup;
1425                 return;
1426         }
1427         if (c == '}')
1428         {
1429                 info->rtfClass = rtfGroup;
1430                 info->rtfMajor = rtfEndGroup;
1431                 return;
1432         }
1433         if (c != '\\')
1434         {
1435                 /*
1436                  * Two possibilities here:
1437                  * 1) ASCII 9, effectively like \tab control symbol
1438                  * 2) literal text char
1439                  */
1440                 if (c == '\t')                  /* ASCII 9 */
1441                 {
1442                         info->rtfClass = rtfControl;
1443                         info->rtfMajor = rtfSpecialChar;
1444                         info->rtfMinor = rtfTab;
1445                 }
1446                 else
1447                 {
1448                         info->rtfClass = rtfText;
1449                         info->rtfMajor = c;
1450                 }
1451                 return;
1452         }
1453         if ((c = GetChar (info)) == EOF)
1454         {
1455                 /* early eof, whoops (class is rtfUnknown) */
1456                 return;
1457         }
1458         if (!isalpha (c))
1459         {
1460                 /*
1461                  * Three possibilities here:
1462                  * 1) hex encoded text char, e.g., \'d5, \'d3
1463                  * 2) special escaped text char, e.g., \{, \}
1464                  * 3) control symbol, e.g., \_, \-, \|, \<10>
1465                  */
1466                 if (c == '\'')                          /* hex char */
1467                 {
1468                 int     c2;
1469
1470                         if ((c = GetChar (info)) != EOF && (c2 = GetChar (info)) != EOF)
1471                         {
1472                                 /* should do isxdigit check! */
1473                                 info->rtfClass = rtfText;
1474                                 info->rtfMajor = RTFCharToHex (c) * 16
1475                                                 + RTFCharToHex (c2);
1476                                 return;
1477                         }
1478                         /* early eof, whoops (class is rtfUnknown) */
1479                         return;
1480                 }
1481
1482                 /* escaped char */
1483                 /*if (index (":{}\\", c) != (char *) NULL)*/ /* escaped char */
1484                 if (c == ':' || c == '{' || c == '}' || c == '\\')
1485                 {
1486                         info->rtfClass = rtfText;
1487                         info->rtfMajor = c;
1488                         return;
1489                 }
1490
1491                 /* control symbol */
1492                 Lookup (info, info->rtfTextBuf);        /* sets class, major, minor */
1493                 return;
1494         }
1495         /* control word */
1496         while (isalpha (c))
1497         {
1498                 if ((c = GetChar (info)) == EOF)
1499                         break;
1500         }
1501
1502         /*
1503          * At this point, the control word is all collected, so the
1504          * major/minor numbers are determined before the parameter
1505          * (if any) is scanned.  There will be one too many characters
1506          * in the buffer, though, so fix up before and restore after
1507          * looking up.
1508          */
1509
1510         if (c != EOF)
1511                 info->rtfTextBuf[info->rtfTextLen-1] = '\0';
1512         Lookup (info, info->rtfTextBuf);        /* sets class, major, minor */
1513         if (c != EOF)
1514                 info->rtfTextBuf[info->rtfTextLen-1] = c;
1515
1516         /*
1517          * Should be looking at first digit of parameter if there
1518          * is one, unless it's negative.  In that case, next char
1519          * is '-', so need to gobble next char, and remember sign.
1520          */
1521
1522         sign = 1;
1523         if (c == '-')
1524         {
1525                 sign = -1;
1526                 c = GetChar (info);
1527         }
1528         if (c != EOF && isdigit (c))
1529         {
1530                 info->rtfParam = 0;
1531                 while (isdigit (c))     /* gobble parameter */
1532                 {
1533                         info->rtfParam = info->rtfParam * 10 + c - '0';
1534                         if ((c = GetChar (info)) == EOF)
1535                                 break;
1536                 }
1537                 info->rtfParam *= sign;
1538         }
1539         /*
1540          * If control symbol delimiter was a blank, gobble it.
1541          * Otherwise the character is first char of next token, so
1542          * push it back for next call.  In either case, delete the
1543          * delimiter from the token buffer.
1544          */
1545         if (c != EOF)
1546         {
1547                 if (c != ' ')
1548                         info->pushedChar = c;
1549                 info->rtfTextBuf[--info->rtfTextLen] = '\0';
1550         }
1551 }
1552
1553
1554 /*
1555  * Read the next character from the input.  This handles setting the
1556  * current line and position-within-line variables.  Those variable are
1557  * set correctly whether lines end with CR, LF, or CRLF (the last being
1558  * the tricky case).
1559  *
1560  * bumpLine indicates whether the line number should be incremented on
1561  * the *next* input character.
1562  */
1563
1564
1565 static int GetChar(RTF_Info *info)
1566 {
1567         int     c;
1568         int     oldBumpLine;
1569
1570         TRACE("\n");
1571
1572         if ((c = _RTFGetChar(info)) != EOF)
1573         {
1574                 info->rtfTextBuf[info->rtfTextLen++] = c;
1575                 info->rtfTextBuf[info->rtfTextLen] = '\0';
1576         }
1577         if (info->prevChar == EOF)
1578                 info->bumpLine = 1;
1579         oldBumpLine = info->bumpLine;   /* non-zero if prev char was line ending */
1580         info->bumpLine = 0;
1581         if (c == '\r')
1582                 info->bumpLine = 1;
1583         else if (c == '\n')
1584         {
1585                 info->bumpLine = 1;
1586                 if (info->prevChar == '\r')             /* oops, previous \r wasn't */
1587                         oldBumpLine = 0;        /* really a line ending */
1588         }
1589         ++info->rtfLinePos;
1590         if (oldBumpLine)        /* were we supposed to increment the */
1591         {                       /* line count on this char? */
1592                 ++info->rtfLineNum;
1593                 info->rtfLinePos = 1;
1594         }
1595         info->prevChar = c;
1596         return (c);
1597 }
1598
1599
1600 /*
1601  * Synthesize a token by setting the global variables to the
1602  * values supplied.  Typically this is followed with a call
1603  * to RTFRouteToken().
1604  *
1605  * If a param value other than rtfNoParam is passed, it becomes
1606  * part of the token text.
1607  */
1608
1609 void RTFSetToken(RTF_Info *info, int class, int major, int minor, int param, const char *text)
1610 {
1611         TRACE("\n");
1612
1613         info->rtfClass = class;
1614         info->rtfMajor = major;
1615         info->rtfMinor = minor;
1616         info->rtfParam = param;
1617         if (param == rtfNoParam)
1618                 (void) strcpy (info->rtfTextBuf, text);
1619         else
1620                 sprintf (info->rtfTextBuf, "%s%d", text, param);
1621         info->rtfTextLen = strlen (info->rtfTextBuf);
1622 }
1623
1624
1625 /* ---------------------------------------------------------------------- */
1626
1627 /*
1628  * Routines to handle mapping of RTF character sets
1629  * onto standard characters.
1630  *
1631  * RTFStdCharCode(name) given char name, produce numeric code
1632  * RTFStdCharName(code) given char code, return name
1633  * RTFMapChar(c)        map input (RTF) char code to std code
1634  * RTFSetCharSet(id)    select given charset map
1635  * RTFGetCharSet()      get current charset map
1636  *
1637  * See ../h/README for more information about charset names and codes.
1638  */
1639
1640
1641 /*
1642  * Initialize charset stuff.
1643  */
1644
1645 static void CharSetInit(RTF_Info *info)
1646 {
1647         TRACE("\n");
1648
1649         info->autoCharSetFlags = (rtfReadCharSet | rtfSwitchCharSet);
1650         RTFFree (info->genCharSetFile);
1651         info->genCharSetFile = (char *) NULL;
1652         info->haveGenCharSet = 0;
1653         RTFFree (info->symCharSetFile);
1654         info->symCharSetFile = (char *) NULL;
1655         info->haveSymCharSet = 0;
1656         info->curCharSet = rtfCSGeneral;
1657         info->curCharCode = info->genCharCode;
1658 }
1659
1660
1661 /*
1662  * Specify the name of a file to be read when auto-charset-file reading is
1663  * done.
1664  */
1665
1666 void RTFSetCharSetMap (RTF_Info *info, char *name, int csId)
1667 {
1668         TRACE("\n");
1669
1670         if ((name = RTFStrSave (name)) == (char *) NULL)        /* make copy */
1671                 RTFPanic (info,"RTFSetCharSetMap: out of memory");
1672         switch (csId)
1673         {
1674         case rtfCSGeneral:
1675                 RTFFree (info->genCharSetFile); /* free any previous value */
1676                 info->genCharSetFile = name;
1677                 break;
1678         case rtfCSSymbol:
1679                 RTFFree (info->symCharSetFile); /* free any previous value */
1680                 info->symCharSetFile = name;
1681                 break;
1682         }
1683 }
1684
1685
1686 /*
1687  * Do auto-charset-file reading.
1688  * will always use the ansi charset no mater what the value
1689  * of the rtfTextBuf is.
1690  *
1691  * TODO: add support for other charset in the future.
1692  *
1693  */
1694
1695 static void ReadCharSetMaps(RTF_Info *info)
1696 {
1697         char    buf[rtfBufSiz];
1698
1699         TRACE("\n");
1700
1701         if (info->genCharSetFile != (char *) NULL)
1702                 (void) strcpy (buf, info->genCharSetFile);
1703         else
1704                 sprintf (buf, "%s-gen", &info->rtfTextBuf[1]);
1705         if (RTFReadCharSetMap (info, rtfCSGeneral) == 0)
1706                 RTFPanic (info,"ReadCharSetMaps: Cannot read charset map %s", buf);
1707         if (info->symCharSetFile != (char *) NULL)
1708             (void) strcpy (buf, info->symCharSetFile);
1709         else
1710                 sprintf (buf, "%s-sym", &info->rtfTextBuf[1]);
1711         if (RTFReadCharSetMap (info, rtfCSSymbol) == 0)
1712                 RTFPanic (info,"ReadCharSetMaps: Cannot read charset map %s", buf);
1713 }
1714
1715
1716
1717 /*
1718  * Convert a CharSetMap (character_name, character) into
1719  * this form : array[character_ident] = character;
1720  */
1721
1722 int RTFReadCharSetMap(RTF_Info *info, int csId)
1723 {
1724         int     *stdCodeArray;
1725         unsigned int i;
1726
1727         TRACE("\n");
1728
1729         switch (csId)
1730         {
1731         default:
1732                 return (0);     /* illegal charset id */
1733         case rtfCSGeneral:
1734
1735                 info->haveGenCharSet = 1;
1736                 stdCodeArray = info->genCharCode;
1737                 for (i = 0; i < charSetSize; i++)
1738                 {
1739                     stdCodeArray[i] = rtfSC_nothing;
1740                 }
1741
1742                 for ( i = 0 ; i< sizeof(ansi_gen)/(sizeof(int));i+=2)
1743                 {
1744                     stdCodeArray[ ansi_gen[i+1] ] = ansi_gen[i];
1745                 }
1746                 break;
1747
1748         case rtfCSSymbol:
1749
1750                 info->haveSymCharSet = 1;
1751                 stdCodeArray = info->symCharCode;
1752                 for (i = 0; i < charSetSize; i++)
1753                 {
1754                     stdCodeArray[i] = rtfSC_nothing;
1755                 }
1756
1757                 for ( i = 0 ; i< sizeof(ansi_sym)/(sizeof(int));i+=2)
1758                 {
1759                     stdCodeArray[ ansi_sym[i+1] ] = ansi_sym[i];
1760                 }
1761                 break;
1762         }
1763
1764         return (1);
1765 }
1766
1767
1768 /*
1769  * Given a standard character name (a string), find its code (a number).
1770  * Return -1 if name is unknown.
1771  */
1772
1773 int RTFStdCharCode(RTF_Info *info, const char *name)
1774 {
1775         int     i;
1776
1777         TRACE("\n");
1778
1779         for (i = 0; i < rtfSC_MaxChar; i++)
1780         {
1781                 if (strcmp (name, stdCharName[i]) == 0)
1782                         return (i);
1783         }
1784         return (-1);
1785 }
1786
1787
1788 /*
1789  * Given a standard character code (a number), find its name (a string).
1790  * Return NULL if code is unknown.
1791  */
1792
1793 const char *RTFStdCharName(RTF_Info *info, int code)
1794 {
1795         if (code < 0 || code >= rtfSC_MaxChar)
1796                 return ((char *) NULL);
1797         return (stdCharName[code]);
1798 }
1799
1800
1801 /*
1802  * Given an RTF input character code, find standard character code.
1803  * The translator should read the appropriate charset maps when it finds a
1804  * charset control.  However, the file might not contain one.  In this
1805  * case, no map will be available.  When the first attempt is made to
1806  * map a character under these circumstances, RTFMapChar() assumes ANSI
1807  * and reads the map as necessary.
1808  */
1809
1810 int RTFMapChar(RTF_Info *info, int c)
1811 {
1812         TRACE("\n");
1813
1814         switch (info->curCharSet)
1815         {
1816         case rtfCSGeneral:
1817                 if (!info->haveGenCharSet)
1818                 {
1819                         if (RTFReadCharSetMap (info, rtfCSGeneral) == 0)
1820                                 RTFPanic (info,"RTFMapChar: cannot read ansi-gen");
1821                 }
1822                 break;
1823         case rtfCSSymbol:
1824                 if (!info->haveSymCharSet)
1825                 {
1826                         if (RTFReadCharSetMap (info, rtfCSSymbol) == 0)
1827                                 RTFPanic (info,"RTFMapChar: cannot read ansi-sym");
1828                 }
1829                 break;
1830         }
1831         if (c < 0 || c >= charSetSize)
1832                 return (rtfSC_nothing);
1833         return (info->curCharCode[c]);
1834 }
1835
1836
1837 /*
1838  * Set the current character set.  If csId is illegal, uses general charset.
1839  */
1840
1841 void RTFSetCharSet(RTF_Info *info, int csId)
1842 {
1843         TRACE("\n");
1844
1845         switch (csId)
1846         {
1847         default:                /* use general if csId unknown */
1848         case rtfCSGeneral:
1849                 info->curCharCode = info->genCharCode;
1850                 info->curCharSet = csId;
1851                 break;
1852         case rtfCSSymbol:
1853                 info->curCharCode = info->symCharCode;
1854                 info->curCharSet = csId;
1855                 break;
1856         }
1857 }
1858
1859
1860 int RTFGetCharSet(RTF_Info *info)
1861 {
1862         return (info->curCharSet);
1863 }
1864
1865
1866 /* ---------------------------------------------------------------------- */
1867
1868 /*
1869  * Special destination readers.  They gobble the destination so the
1870  * writer doesn't have to deal with them.  That's wrong for any
1871  * translator that wants to process any of these itself.  In that
1872  * case, these readers should be overridden by installing a different
1873  * destination callback.
1874  *
1875  * NOTE: The last token read by each of these reader will be the
1876  * destination's terminating '}', which will then be the current token.
1877  * That '}' token is passed to RTFRouteToken() - the writer has already
1878  * seen the '{' that began the destination group, and may have pushed a
1879  * state; it also needs to know at the end of the group that a state
1880  * should be popped.
1881  *
1882  * It's important that rtf.h and the control token lookup table list
1883  * as many symbols as possible, because these destination readers
1884  * unfortunately make strict assumptions about the input they expect,
1885  * and a token of class rtfUnknown will throw them off easily.
1886  */
1887
1888
1889 /*
1890  * Read { \fonttbl ... } destination.  Old font tables don't have
1891  * braces around each table entry; try to adjust for that.
1892  */
1893
1894 static void ReadFontTbl(RTF_Info *info)
1895 {
1896         RTFFont         *fp = NULL;
1897         char            buf[rtfBufSiz], *bp;
1898         int             old = -1;
1899         const char      *fn = "ReadFontTbl";
1900
1901         TRACE("\n");
1902
1903         for (;;)
1904         {
1905                 (void) RTFGetToken (info);
1906                 if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
1907                         break;
1908                 if (old < 0)            /* first entry - determine tbl type */
1909                 {
1910                         if (RTFCheckCMM (info, rtfControl, rtfCharAttr, rtfFontNum))
1911                                 old = 1;        /* no brace */
1912                         else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))
1913                                 old = 0;        /* brace */
1914                         else                    /* can't tell! */
1915                                 RTFPanic (info, "%s: Cannot determine format", fn);
1916                 }
1917                 if (old == 0)           /* need to find "{" here */
1918                 {
1919                         if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
1920                                 RTFPanic (info, "%s: missing \"{\"", fn);
1921                         (void) RTFGetToken (info);      /* yes, skip to next token */
1922                 }
1923                 if ((fp = New (RTFFont)) == (RTFFont *) NULL)
1924                         RTFPanic (info, "%s: cannot allocate font entry", fn);
1925
1926                 fp->rtfNextFont = info->fontList;
1927                 info->fontList = fp;
1928
1929                 fp->rtfFName = (char *) NULL;
1930                 fp->rtfFAltName = (char *) NULL;
1931                 fp->rtfFNum = -1;
1932                 fp->rtfFFamily = 0;
1933                 fp->rtfFCharSet = 0;
1934                 fp->rtfFPitch = 0;
1935                 fp->rtfFType = 0;
1936                 fp->rtfFCodePage = 0;
1937
1938                 while (info->rtfClass != rtfEOF
1939                        && !RTFCheckCM (info, rtfText, ';')
1940                        && !RTFCheckCM (info, rtfGroup, rtfEndGroup))
1941                 {
1942                         if (info->rtfClass == rtfControl)
1943                         {
1944                                 switch (info->rtfMajor)
1945                                 {
1946                                 default:
1947                                         /* ignore token but announce it */
1948                                         RTFMsg (info,"%s: unknown token \"%s\"\n",
1949                                                         fn, info->rtfTextBuf);
1950                                         break;
1951                                 case rtfFontFamily:
1952                                         fp->rtfFFamily = info->rtfMinor;
1953                                         break;
1954                                 case rtfCharAttr:
1955                                         switch (info->rtfMinor)
1956                                         {
1957                                         default:
1958                                                 break;  /* ignore unknown? */
1959                                         case rtfFontNum:
1960                                                 fp->rtfFNum = info->rtfParam;
1961                                                 break;
1962                                         }
1963                                         break;
1964                                 case rtfFontAttr:
1965                                         switch (info->rtfMinor)
1966                                         {
1967                                         default:
1968                                                 break;  /* ignore unknown? */
1969                                         case rtfFontCharSet:
1970                                                 fp->rtfFCharSet = info->rtfParam;
1971                                                 break;
1972                                         case rtfFontPitch:
1973                                                 fp->rtfFPitch = info->rtfParam;
1974                                                 break;
1975                                         case rtfFontCodePage:
1976                                                 fp->rtfFCodePage = info->rtfParam;
1977                                                 break;
1978                                         case rtfFTypeNil:
1979                                         case rtfFTypeTrueType:
1980                                                 fp->rtfFType = info->rtfParam;
1981                                                 break;
1982                                         }
1983                                         break;
1984                                 }
1985                         }
1986                         else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))    /* dest */
1987                         {
1988                                 RTFSkipGroup (info);    /* ignore for now */
1989                         }
1990                         else if (info->rtfClass == rtfText)     /* font name */
1991                         {
1992                                 bp = buf;
1993                                 while (info->rtfClass == rtfText
1994                                         && !RTFCheckCM (info, rtfText, ';'))
1995                                 {
1996                                         *bp++ = info->rtfMajor;
1997                                         (void) RTFGetToken (info);
1998                                 }
1999
2000                                 /* FIX: in some cases the <fontinfo> isn't finished with a semi-column */
2001                                 if(RTFCheckCM (info, rtfGroup, rtfEndGroup))
2002                                 {
2003                                   RTFUngetToken (info);
2004                                 }
2005                                 *bp = '\0';
2006                                 fp->rtfFName = RTFStrSave (buf);
2007                                 if (fp->rtfFName == (char *) NULL)
2008                                         RTFPanic (info, "%s: cannot allocate font name", fn);
2009                                 /* already have next token; don't read one */
2010                                 /* at bottom of loop */
2011                                 continue;
2012                         }
2013                         else
2014                         {
2015                                 /* ignore token but announce it */
2016                                 RTFMsg (info, "%s: unknown token \"%s\"\n",
2017                                                         fn,info->rtfTextBuf);
2018                         }
2019                         (void) RTFGetToken (info);
2020                 }
2021                 if (old == 0)   /* need to see "}" here */
2022                 {
2023                         (void) RTFGetToken (info);
2024                         if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
2025                                 RTFPanic (info, "%s: missing \"}\"", fn);
2026                 }
2027         }
2028         if (fp->rtfFNum == -1)
2029                 RTFPanic (info,"%s: missing font number", fn);
2030 /*
2031  * Could check other pieces of structure here, too, I suppose.
2032  */
2033         RTFRouteToken (info);   /* feed "}" back to router */
2034 }
2035
2036
2037 /*
2038  * The color table entries have color values of -1 if
2039  * the default color should be used for the entry (only
2040  * a semi-colon is given in the definition, no color values).
2041  * There will be a problem if a partial entry (1 or 2 but
2042  * not 3 color values) is given.  The possibility is ignored
2043  * here.
2044  */
2045
2046 static void ReadColorTbl(RTF_Info *info)
2047 {
2048         RTFColor        *cp;
2049         int             cnum = 0;
2050         const char      *fn = "ReadColorTbl";
2051
2052         TRACE("\n");
2053
2054         for (;;)
2055         {
2056                 (void) RTFGetToken (info);
2057                 if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
2058                         break;
2059                 if ((cp = New (RTFColor)) == (RTFColor *) NULL)
2060                         RTFPanic (info,"%s: cannot allocate color entry", fn);
2061                 cp->rtfCNum = cnum++;
2062                 cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
2063                 cp->rtfNextColor = info->colorList;
2064                 info->colorList = cp;
2065                 while (RTFCheckCM (info, rtfControl, rtfColorName))
2066                 {
2067                         switch (info->rtfMinor)
2068                         {
2069                         case rtfRed:    cp->rtfCRed = info->rtfParam; break;
2070                         case rtfGreen:  cp->rtfCGreen = info->rtfParam; break;
2071                         case rtfBlue:   cp->rtfCBlue = info->rtfParam; break;
2072                         }
2073                         RTFGetToken (info);
2074                 }
2075                 if (!RTFCheckCM (info, rtfText, (int) ';'))
2076                         RTFPanic (info,"%s: malformed entry", fn);
2077         }
2078         RTFRouteToken (info);   /* feed "}" back to router */
2079 }
2080
2081
2082 /*
2083  * The "Normal" style definition doesn't contain any style number,
2084  * all others do.  Normal style is given style rtfNormalStyleNum.
2085  */
2086
2087 static void ReadStyleSheet(RTF_Info *info)
2088 {
2089         RTFStyle        *sp;
2090         RTFStyleElt     *sep, *sepLast;
2091         char            buf[rtfBufSiz], *bp;
2092         const char      *fn = "ReadStyleSheet";
2093
2094         TRACE("\n");
2095
2096         for (;;)
2097         {
2098                 (void) RTFGetToken (info);
2099                 if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
2100                         break;
2101                 if ((sp = New (RTFStyle)) == (RTFStyle *) NULL)
2102                         RTFPanic (info,"%s: cannot allocate stylesheet entry", fn);
2103                 sp->rtfSName = (char *) NULL;
2104                 sp->rtfSNum = -1;
2105                 sp->rtfSType = rtfParStyle;
2106                 sp->rtfSAdditive = 0;
2107                 sp->rtfSBasedOn = rtfNoStyleNum;
2108                 sp->rtfSNextPar = -1;
2109                 sp->rtfSSEList = sepLast = (RTFStyleElt *) NULL;
2110                 sp->rtfNextStyle = info->styleList;
2111                 sp->rtfExpanding = 0;
2112                 info->styleList = sp;
2113                 if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
2114                         RTFPanic (info,"%s: missing \"{\"", fn);
2115                 for (;;)
2116                 {
2117                         (void) RTFGetToken (info);
2118                         if (info->rtfClass == rtfEOF
2119                                 || RTFCheckCM (info, rtfText, ';'))
2120                                 break;
2121                         if (info->rtfClass == rtfControl)
2122                         {
2123                                 if (RTFCheckMM (info, rtfSpecialChar, rtfOptDest))
2124                                         continue;       /* ignore "\*" */
2125                                 if (RTFCheckMM (info, rtfParAttr, rtfStyleNum))
2126                                 {
2127                                         sp->rtfSNum = info->rtfParam;
2128                                         sp->rtfSType = rtfParStyle;
2129                                         continue;
2130                                 }
2131                                 if (RTFCheckMM (info, rtfCharAttr, rtfCharStyleNum))
2132                                 {
2133                                         sp->rtfSNum = info->rtfParam;
2134                                         sp->rtfSType = rtfCharStyle;
2135                                         continue;
2136                                 }
2137                                 if (RTFCheckMM (info, rtfSectAttr, rtfSectStyleNum))
2138                                 {
2139                                         sp->rtfSNum = info->rtfParam;
2140                                         sp->rtfSType = rtfSectStyle;
2141                                         continue;
2142                                 }
2143                                 if (RTFCheckMM (info, rtfStyleAttr, rtfBasedOn))
2144                                 {
2145                                         sp->rtfSBasedOn = info->rtfParam;
2146                                         continue;
2147                                 }
2148                                 if (RTFCheckMM (info, rtfStyleAttr, rtfAdditive))
2149                                 {
2150                                         sp->rtfSAdditive = 1;
2151                                         continue;
2152                                 }
2153                                 if (RTFCheckMM (info, rtfStyleAttr, rtfNext))
2154                                 {
2155                                         sp->rtfSNextPar = info->rtfParam;
2156                                         continue;
2157                                 }
2158                                 if ((sep = New (RTFStyleElt)) == (RTFStyleElt *) NULL)
2159                                         RTFPanic (info,"%s: cannot allocate style element", fn);
2160                                 sep->rtfSEClass = info->rtfClass;
2161                                 sep->rtfSEMajor = info->rtfMajor;
2162                                 sep->rtfSEMinor = info->rtfMinor;
2163                                 sep->rtfSEParam = info->rtfParam;
2164                                 if ((sep->rtfSEText = RTFStrSave (info->rtfTextBuf))
2165                                                                 == (char *) NULL)
2166                                         RTFPanic (info,"%s: cannot allocate style element text", fn);
2167                                 if (sepLast == (RTFStyleElt *) NULL)
2168                                         sp->rtfSSEList = sep;   /* first element */
2169                                 else                            /* add to end */
2170                                         sepLast->rtfNextSE = sep;
2171                                 sep->rtfNextSE = (RTFStyleElt *) NULL;
2172                                 sepLast = sep;
2173                         }
2174                         else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))
2175                         {
2176                                 /*
2177                                  * This passes over "{\*\keycode ... }, among
2178                                  * other things. A temporary (perhaps) hack.
2179                                  */
2180                                 RTFSkipGroup (info);
2181                                 continue;
2182                         }
2183                         else if (info->rtfClass == rtfText)     /* style name */
2184                         {
2185                                 bp = buf;
2186                                 while (info->rtfClass == rtfText)
2187                                 {
2188                                         if (info->rtfMajor == ';')
2189                                         {
2190                                                 /* put back for "for" loop */
2191                                                 (void) RTFUngetToken (info);
2192                                                 break;
2193                                         }
2194                                         *bp++ = info->rtfMajor;
2195                                         (void) RTFGetToken (info);
2196                                 }
2197                                 *bp = '\0';
2198                                 if ((sp->rtfSName = RTFStrSave (buf)) == (char *) NULL)
2199                                         RTFPanic (info, "%s: cannot allocate style name", fn);
2200                         }
2201                         else            /* unrecognized */
2202                         {
2203                                 /* ignore token but announce it */
2204                                 RTFMsg (info, "%s: unknown token \"%s\"\n",
2205                                                         fn, info->rtfTextBuf);
2206                         }
2207                 }
2208                 (void) RTFGetToken (info);
2209                 if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
2210                         RTFPanic (info, "%s: missing \"}\"", fn);
2211
2212                 /*
2213                  * Check over the style structure.  A name is a must.
2214                  * If no style number was specified, check whether it's the
2215                  * Normal style (in which case it's given style number
2216                  * rtfNormalStyleNum).  Note that some "normal" style names
2217                  * just begin with "Normal" and can have other stuff following,
2218                  * e.g., "Normal,Times 10 point".  Ugh.
2219                  *
2220                  * Some German RTF writers use "Standard" instead of "Normal".
2221                  */
2222                 if (sp->rtfSName == (char *) NULL)
2223                         RTFPanic (info,"%s: missing style name", fn);
2224                 if (sp->rtfSNum < 0)
2225                 {
2226                         if (strncmp (buf, "Normal", 6) != 0
2227                                 && strncmp (buf, "Standard", 8) != 0)
2228                                 RTFPanic (info,"%s: missing style number", fn);
2229                         sp->rtfSNum = rtfNormalStyleNum;
2230                 }
2231                 if (sp->rtfSNextPar == -1)      /* if \snext not given, */
2232                         sp->rtfSNextPar = sp->rtfSNum;  /* next is itself */
2233         }
2234         RTFRouteToken (info);   /* feed "}" back to router */
2235 }
2236
2237
2238 static void ReadInfoGroup(RTF_Info *info)
2239 {
2240         RTFSkipGroup (info);
2241         RTFRouteToken (info);   /* feed "}" back to router */
2242 }
2243
2244
2245 static void ReadPictGroup(RTF_Info *info)
2246 {
2247         RTFSkipGroup (info);
2248         RTFRouteToken (info);   /* feed "}" back to router */
2249 }
2250
2251
2252 static void ReadObjGroup(RTF_Info *info)
2253 {
2254         RTFSkipGroup (info);
2255         RTFRouteToken (info);   /* feed "}" back to router */
2256 }
2257
2258
2259 /* ---------------------------------------------------------------------- */
2260
2261 /*
2262  * Routines to return pieces of stylesheet, or font or color tables.
2263  * References to style 0 are mapped onto the Normal style.
2264  */
2265
2266
2267 RTFStyle *RTFGetStyle(RTF_Info *info, int num)
2268 {
2269         RTFStyle        *s;
2270
2271         if (num == -1)
2272                 return (info->styleList);
2273         for (s = info->styleList; s != (RTFStyle *) NULL; s = s->rtfNextStyle)
2274         {
2275                 if (s->rtfSNum == num)
2276                         break;
2277         }
2278         return (s);             /* NULL if not found */
2279 }
2280
2281
2282 RTFFont *RTFGetFont(RTF_Info *info, int num)
2283 {
2284         RTFFont *f;
2285
2286         if (num == -1)
2287                 return (info->fontList);
2288         for (f = info->fontList; f != (RTFFont *) NULL; f = f->rtfNextFont)
2289         {
2290                 if (f->rtfFNum == num)
2291                         break;
2292         }
2293         return (f);             /* NULL if not found */
2294 }
2295
2296
2297 RTFColor *RTFGetColor(RTF_Info *info, int num)
2298 {
2299         RTFColor        *c;
2300
2301         if (num == -1)
2302                 return (info->colorList);
2303         for (c = info->colorList; c != (RTFColor *) NULL; c = c->rtfNextColor)
2304         {
2305                 if (c->rtfCNum == num)
2306                         break;
2307         }
2308         return (c);             /* NULL if not found */
2309 }
2310
2311
2312 /* ---------------------------------------------------------------------- */
2313
2314
2315 /*
2316  * Expand style n, if there is such a style.
2317  */
2318
2319 void RTFExpandStyle(RTF_Info *info, int n)
2320 {
2321         RTFStyle        *s;
2322         RTFStyleElt     *se;
2323
2324         TRACE("\n");
2325
2326         if (n == -1 || (s = RTFGetStyle (info, n)) == (RTFStyle *) NULL)
2327                 return;
2328         if (s->rtfExpanding != 0)
2329                 RTFPanic (info,"Style expansion loop, style %d", n);
2330         s->rtfExpanding = 1;    /* set expansion flag for loop detection */
2331         /*
2332          * Expand "based-on" style (unless it's the same as the current
2333          * style -- Normal style usually gives itself as its own based-on
2334          * style).  Based-on style expansion is done by synthesizing
2335          * the token that the writer needs to see in order to trigger
2336          * another style expansion, and feeding to token back through
2337          * the router so the writer sees it.
2338          */
2339         if (n != s->rtfSBasedOn)
2340         {
2341                 RTFSetToken (info, rtfControl, rtfParAttr, rtfStyleNum,
2342                                                         s->rtfSBasedOn, "\\s");
2343                 RTFRouteToken (info);
2344         }
2345         /*
2346          * Now route the tokens unique to this style.  RTFSetToken()
2347          * isn't used because it would add the param value to the end
2348          * of the token text, which already has it in.
2349          */
2350         for (se = s->rtfSSEList; se != (RTFStyleElt *) NULL; se = se->rtfNextSE)
2351         {
2352                 info->rtfClass = se->rtfSEClass;
2353                 info->rtfMajor = se->rtfSEMajor;
2354                 info->rtfMinor = se->rtfSEMinor;
2355                 info->rtfParam = se->rtfSEParam;
2356                 (void) strcpy (info->rtfTextBuf, se->rtfSEText);
2357                 info->rtfTextLen = strlen (info->rtfTextBuf);
2358                 RTFRouteToken (info);
2359         }
2360         s->rtfExpanding = 0;    /* done - clear expansion flag */
2361 }
2362
2363
2364 /* ---------------------------------------------------------------------- */
2365
2366 /*
2367  * Control symbol lookup routines
2368  */
2369
2370
2371 typedef struct RTFKey   RTFKey;
2372
2373 struct RTFKey
2374 {
2375         int        rtfKMajor;   /* major number */
2376         int        rtfKMinor;   /* minor number */
2377         const char *rtfKStr;    /* symbol name */
2378         int        rtfKHash;    /* symbol name hash value */
2379 };
2380
2381 /*
2382  * A minor number of -1 means the token has no minor number
2383  * (all valid minor numbers are >= 0).
2384  */
2385
2386 static RTFKey   rtfKey[] =
2387 {
2388         /*
2389          * Special characters
2390          */
2391
2392         { rtfSpecialChar,       rtfIIntVersion,         "vern",         0 },
2393         { rtfSpecialChar,       rtfICreateTime,         "creatim",      0 },
2394         { rtfSpecialChar,       rtfIRevisionTime,       "revtim",       0 },
2395         { rtfSpecialChar,       rtfIPrintTime,          "printim",      0 },
2396         { rtfSpecialChar,       rtfIBackupTime,         "buptim",       0 },
2397         { rtfSpecialChar,       rtfIEditTime,           "edmins",       0 },
2398         { rtfSpecialChar,       rtfIYear,               "yr",           0 },
2399         { rtfSpecialChar,       rtfIMonth,              "mo",           0 },
2400         { rtfSpecialChar,       rtfIDay,                "dy",           0 },
2401         { rtfSpecialChar,       rtfIHour,               "hr",           0 },
2402         { rtfSpecialChar,       rtfIMinute,             "min",          0 },
2403         { rtfSpecialChar,       rtfISecond,             "sec",          0 },
2404         { rtfSpecialChar,       rtfINPages,             "nofpages",     0 },
2405         { rtfSpecialChar,       rtfINWords,             "nofwords",     0 },
2406         { rtfSpecialChar,       rtfINChars,             "nofchars",     0 },
2407         { rtfSpecialChar,       rtfIIntID,              "id",           0 },
2408
2409         { rtfSpecialChar,       rtfCurHeadDate,         "chdate",       0 },
2410         { rtfSpecialChar,       rtfCurHeadDateLong,     "chdpl",        0 },
2411         { rtfSpecialChar,       rtfCurHeadDateAbbrev,   "chdpa",        0 },
2412         { rtfSpecialChar,       rtfCurHeadTime,         "chtime",       0 },
2413         { rtfSpecialChar,       rtfCurHeadPage,         "chpgn",        0 },
2414         { rtfSpecialChar,       rtfSectNum,             "sectnum",      0 },
2415         { rtfSpecialChar,       rtfCurFNote,            "chftn",        0 },
2416         { rtfSpecialChar,       rtfCurAnnotRef,         "chatn",        0 },
2417         { rtfSpecialChar,       rtfFNoteSep,            "chftnsep",     0 },
2418         { rtfSpecialChar,       rtfFNoteCont,           "chftnsepc",    0 },
2419         { rtfSpecialChar,       rtfCell,                "cell",         0 },
2420         { rtfSpecialChar,       rtfRow,                 "row",          0 },
2421         { rtfSpecialChar,       rtfPar,                 "par",          0 },
2422         /* newline and carriage return are synonyms for */
2423         /* \par when they are preceded by a \ character */
2424         { rtfSpecialChar,       rtfPar,                 "\n",           0 },
2425         { rtfSpecialChar,       rtfPar,                 "\r",           0 },
2426         { rtfSpecialChar,       rtfSect,                "sect",         0 },
2427         { rtfSpecialChar,       rtfPage,                "page",         0 },
2428         { rtfSpecialChar,       rtfColumn,              "column",       0 },
2429         { rtfSpecialChar,       rtfLine,                "line",         0 },
2430         { rtfSpecialChar,       rtfSoftPage,            "softpage",     0 },
2431         { rtfSpecialChar,       rtfSoftColumn,          "softcol",      0 },
2432         { rtfSpecialChar,       rtfSoftLine,            "softline",     0 },
2433         { rtfSpecialChar,       rtfSoftLineHt,          "softlheight",  0 },
2434         { rtfSpecialChar,       rtfTab,                 "tab",          0 },
2435         { rtfSpecialChar,       rtfEmDash,              "emdash",       0 },
2436         { rtfSpecialChar,       rtfEnDash,              "endash",       0 },
2437         { rtfSpecialChar,       rtfEmSpace,             "emspace",      0 },
2438         { rtfSpecialChar,       rtfEnSpace,             "enspace",      0 },
2439         { rtfSpecialChar,       rtfBullet,              "bullet",       0 },
2440         { rtfSpecialChar,       rtfLQuote,              "lquote",       0 },
2441         { rtfSpecialChar,       rtfRQuote,              "rquote",       0 },
2442         { rtfSpecialChar,       rtfLDblQuote,           "ldblquote",    0 },
2443         { rtfSpecialChar,       rtfRDblQuote,           "rdblquote",    0 },
2444         { rtfSpecialChar,       rtfFormula,             "|",            0 },
2445         { rtfSpecialChar,       rtfNoBrkSpace,          "~",            0 },
2446         { rtfSpecialChar,       rtfNoReqHyphen,         "-",            0 },
2447         { rtfSpecialChar,       rtfNoBrkHyphen,         "_",            0 },
2448         { rtfSpecialChar,       rtfOptDest,             "*",            0 },
2449         { rtfSpecialChar,       rtfLTRMark,             "ltrmark",      0 },
2450         { rtfSpecialChar,       rtfRTLMark,             "rtlmark",      0 },
2451         { rtfSpecialChar,       rtfNoWidthJoiner,       "zwj",          0 },
2452         { rtfSpecialChar,       rtfNoWidthNonJoiner,    "zwnj",         0 },
2453         /* is this valid? */
2454         { rtfSpecialChar,       rtfCurHeadPict,         "chpict",       0 },
2455
2456         /*
2457          * Character formatting attributes
2458          */
2459
2460         { rtfCharAttr,  rtfPlain,               "plain",        0 },
2461         { rtfCharAttr,  rtfBold,                "b",            0 },
2462         { rtfCharAttr,  rtfAllCaps,             "caps",         0 },
2463         { rtfCharAttr,  rtfDeleted,             "deleted",      0 },
2464         { rtfCharAttr,  rtfSubScript,           "dn",           0 },
2465         { rtfCharAttr,  rtfSubScrShrink,        "sub",          0 },
2466         { rtfCharAttr,  rtfNoSuperSub,          "nosupersub",   0 },
2467         { rtfCharAttr,  rtfExpand,              "expnd",        0 },
2468         { rtfCharAttr,  rtfExpandTwips,         "expndtw",      0 },
2469         { rtfCharAttr,  rtfKerning,             "kerning",      0 },
2470         { rtfCharAttr,  rtfFontNum,             "f",            0 },
2471         { rtfCharAttr,  rtfFontSize,            "fs",           0 },
2472         { rtfCharAttr,  rtfItalic,              "i",            0 },
2473         { rtfCharAttr,  rtfOutline,             "outl",         0 },
2474         { rtfCharAttr,  rtfRevised,             "revised",      0 },
2475         { rtfCharAttr,  rtfRevAuthor,           "revauth",      0 },
2476         { rtfCharAttr,  rtfRevDTTM,             "revdttm",      0 },
2477         { rtfCharAttr,  rtfSmallCaps,           "scaps",        0 },
2478         { rtfCharAttr,  rtfShadow,              "shad",         0 },
2479         { rtfCharAttr,  rtfStrikeThru,          "strike",       0 },
2480         { rtfCharAttr,  rtfUnderline,           "ul",           0 },
2481         { rtfCharAttr,  rtfDotUnderline,        "uld",          0 },
2482         { rtfCharAttr,  rtfDbUnderline,         "uldb",         0 },
2483         { rtfCharAttr,  rtfNoUnderline,         "ulnone",       0 },
2484         { rtfCharAttr,  rtfWordUnderline,       "ulw",          0 },
2485         { rtfCharAttr,  rtfSuperScript,         "up",           0 },
2486         { rtfCharAttr,  rtfSuperScrShrink,      "super",        0 },
2487         { rtfCharAttr,  rtfInvisible,           "v",            0 },
2488         { rtfCharAttr,  rtfForeColor,           "cf",           0 },
2489         { rtfCharAttr,  rtfBackColor,           "cb",           0 },
2490         { rtfCharAttr,  rtfRTLChar,             "rtlch",        0 },
2491         { rtfCharAttr,  rtfLTRChar,             "ltrch",        0 },
2492         { rtfCharAttr,  rtfCharStyleNum,        "cs",           0 },
2493         { rtfCharAttr,  rtfCharCharSet,         "cchs",         0 },
2494         { rtfCharAttr,  rtfLanguage,            "lang",         0 },
2495         /* this has disappeared from spec 1.2 */
2496         { rtfCharAttr,  rtfGray,                "gray",         0 },
2497
2498         /*
2499          * Paragraph formatting attributes
2500          */
2501
2502         { rtfParAttr,   rtfParDef,              "pard",         0 },
2503         { rtfParAttr,   rtfStyleNum,            "s",            0 },
2504         { rtfParAttr,   rtfHyphenate,           "hyphpar",      0 },
2505         { rtfParAttr,   rtfInTable,             "intbl",        0 },
2506         { rtfParAttr,   rtfKeep,                "keep",         0 },
2507         { rtfParAttr,   rtfNoWidowControl,      "nowidctlpar",  0 },
2508         { rtfParAttr,   rtfKeepNext,            "keepn",        0 },
2509         { rtfParAttr,   rtfOutlineLevel,        "level",        0 },
2510         { rtfParAttr,   rtfNoLineNum,           "noline",       0 },
2511         { rtfParAttr,   rtfPBBefore,            "pagebb",       0 },
2512         { rtfParAttr,   rtfSideBySide,          "sbys",         0 },
2513         { rtfParAttr,   rtfQuadLeft,            "ql",           0 },
2514         { rtfParAttr,   rtfQuadRight,           "qr",           0 },
2515         { rtfParAttr,   rtfQuadJust,            "qj",           0 },
2516         { rtfParAttr,   rtfQuadCenter,          "qc",           0 },
2517         { rtfParAttr,   rtfFirstIndent,         "fi",           0 },
2518         { rtfParAttr,   rtfLeftIndent,          "li",           0 },
2519         { rtfParAttr,   rtfRightIndent,         "ri",           0 },
2520         { rtfParAttr,   rtfSpaceBefore,         "sb",           0 },
2521         { rtfParAttr,   rtfSpaceAfter,          "sa",           0 },
2522         { rtfParAttr,   rtfSpaceBetween,        "sl",           0 },
2523         { rtfParAttr,   rtfSpaceMultiply,       "slmult",       0 },
2524
2525         { rtfParAttr,   rtfSubDocument,         "subdocument",  0 },
2526
2527         { rtfParAttr,   rtfRTLPar,              "rtlpar",       0 },
2528         { rtfParAttr,   rtfLTRPar,              "ltrpar",       0 },
2529
2530         { rtfParAttr,   rtfTabPos,              "tx",           0 },
2531         /*
2532          * FrameMaker writes \tql (to mean left-justified tab, apparently)
2533          * although it's not in the spec.  It's also redundant, since lj
2534          * tabs are the default.
2535          */
2536         { rtfParAttr,   rtfTabLeft,             "tql",          0 },
2537         { rtfParAttr,   rtfTabRight,            "tqr",          0 },
2538         { rtfParAttr,   rtfTabCenter,           "tqc",          0 },
2539         { rtfParAttr,   rtfTabDecimal,          "tqdec",        0 },
2540         { rtfParAttr,   rtfTabBar,              "tb",           0 },
2541         { rtfParAttr,   rtfLeaderDot,           "tldot",        0 },
2542         { rtfParAttr,   rtfLeaderHyphen,        "tlhyph",       0 },
2543         { rtfParAttr,   rtfLeaderUnder,         "tlul",         0 },
2544         { rtfParAttr,   rtfLeaderThick,         "tlth",         0 },
2545         { rtfParAttr,   rtfLeaderEqual,         "tleq",         0 },
2546
2547         { rtfParAttr,   rtfParLevel,            "pnlvl",        0 },
2548         { rtfParAttr,   rtfParBullet,           "pnlvlblt",     0 },
2549         { rtfParAttr,   rtfParSimple,           "pnlvlbody",    0 },
2550         { rtfParAttr,   rtfParNumCont,          "pnlvlcont",    0 },
2551         { rtfParAttr,   rtfParNumOnce,          "pnnumonce",    0 },
2552         { rtfParAttr,   rtfParNumAcross,        "pnacross",     0 },
2553         { rtfParAttr,   rtfParHangIndent,       "pnhang",       0 },
2554         { rtfParAttr,   rtfParNumRestart,       "pnrestart",    0 },
2555         { rtfParAttr,   rtfParNumCardinal,      "pncard",       0 },
2556         { rtfParAttr,   rtfParNumDecimal,       "pndec",        0 },
2557         { rtfParAttr,   rtfParNumULetter,       "pnucltr",      0 },
2558         { rtfParAttr,   rtfParNumURoman,        "pnucrm",       0 },
2559         { rtfParAttr,   rtfParNumLLetter,       "pnlcltr",      0 },
2560         { rtfParAttr,   rtfParNumLRoman,        "pnlcrm",       0 },
2561         { rtfParAttr,   rtfParNumOrdinal,       "pnord",        0 },
2562         { rtfParAttr,   rtfParNumOrdinalText,   "pnordt",       0 },
2563         { rtfParAttr,   rtfParNumBold,          "pnb",          0 },
2564         { rtfParAttr,   rtfParNumItalic,        "pni",          0 },
2565         { rtfParAttr,   rtfParNumAllCaps,       "pncaps",       0 },
2566         { rtfParAttr,   rtfParNumSmallCaps,     "pnscaps",      0 },
2567         { rtfParAttr,   rtfParNumUnder,         "pnul",         0 },
2568         { rtfParAttr,   rtfParNumDotUnder,      "pnuld",        0 },
2569         { rtfParAttr,   rtfParNumDbUnder,       "pnuldb",       0 },
2570         { rtfParAttr,   rtfParNumNoUnder,       "pnulnone",     0 },
2571         { rtfParAttr,   rtfParNumWordUnder,     "pnulw",        0 },
2572         { rtfParAttr,   rtfParNumStrikethru,    "pnstrike",     0 },
2573         { rtfParAttr,   rtfParNumForeColor,     "pncf",         0 },
2574         { rtfParAttr,   rtfParNumFont,          "pnf",          0 },
2575         { rtfParAttr,   rtfParNumFontSize,      "pnfs",         0 },
2576         { rtfParAttr,   rtfParNumIndent,        "pnindent",     0 },
2577         { rtfParAttr,   rtfParNumSpacing,       "pnsp",         0 },
2578         { rtfParAttr,   rtfParNumInclPrev,      "pnprev",       0 },
2579         { rtfParAttr,   rtfParNumCenter,        "pnqc",         0 },
2580         { rtfParAttr,   rtfParNumLeft,          "pnql",         0 },
2581         { rtfParAttr,   rtfParNumRight,         "pnqr",         0 },
2582         { rtfParAttr,   rtfParNumStartAt,       "pnstart",      0 },
2583
2584         { rtfParAttr,   rtfBorderTop,           "brdrt",        0 },
2585         { rtfParAttr,   rtfBorderBottom,        "brdrb",        0 },
2586         { rtfParAttr,   rtfBorderLeft,          "brdrl",        0 },
2587         { rtfParAttr,   rtfBorderRight,         "brdrr",        0 },
2588         { rtfParAttr,   rtfBorderBetween,       "brdrbtw",      0 },
2589         { rtfParAttr,   rtfBorderBar,           "brdrbar",      0 },
2590         { rtfParAttr,   rtfBorderBox,           "box",          0 },
2591         { rtfParAttr,   rtfBorderSingle,        "brdrs",        0 },
2592         { rtfParAttr,   rtfBorderThick,         "brdrth",       0 },
2593         { rtfParAttr,   rtfBorderShadow,        "brdrsh",       0 },
2594         { rtfParAttr,   rtfBorderDouble,        "brdrdb",       0 },
2595         { rtfParAttr,   rtfBorderDot,           "brdrdot",      0 },
2596         { rtfParAttr,   rtfBorderDot,           "brdrdash",     0 },
2597         { rtfParAttr,   rtfBorderHair,          "brdrhair",     0 },
2598         { rtfParAttr,   rtfBorderWidth,         "brdrw",        0 },
2599         { rtfParAttr,   rtfBorderColor,         "brdrcf",       0 },
2600         { rtfParAttr,   rtfBorderSpace,         "brsp",         0 },
2601
2602         { rtfParAttr,   rtfShading,             "shading",      0 },
2603         { rtfParAttr,   rtfBgPatH,              "bghoriz",      0 },
2604         { rtfParAttr,   rtfBgPatV,              "bgvert",       0 },
2605         { rtfParAttr,   rtfFwdDiagBgPat,        "bgfdiag",      0 },
2606         { rtfParAttr,   rtfBwdDiagBgPat,        "bgbdiag",      0 },
2607         { rtfParAttr,   rtfHatchBgPat,          "bgcross",      0 },
2608         { rtfParAttr,   rtfDiagHatchBgPat,      "bgdcross",     0 },
2609         { rtfParAttr,   rtfDarkBgPatH,          "bgdkhoriz",    0 },
2610         { rtfParAttr,   rtfDarkBgPatV,          "bgdkvert",     0 },
2611         { rtfParAttr,   rtfFwdDarkBgPat,        "bgdkfdiag",    0 },
2612         { rtfParAttr,   rtfBwdDarkBgPat,        "bgdkbdiag",    0 },
2613         { rtfParAttr,   rtfDarkHatchBgPat,      "bgdkcross",    0 },
2614         { rtfParAttr,   rtfDarkDiagHatchBgPat,  "bgdkdcross",   0 },
2615         { rtfParAttr,   rtfBgPatLineColor,      "cfpat",        0 },
2616         { rtfParAttr,   rtfBgPatColor,          "cbpat",        0 },
2617
2618         /*
2619          * Section formatting attributes
2620          */
2621
2622         { rtfSectAttr,  rtfSectDef,             "sectd",        0 },
2623         { rtfSectAttr,  rtfENoteHere,           "endnhere",     0 },
2624         { rtfSectAttr,  rtfPrtBinFirst,         "binfsxn",      0 },
2625         { rtfSectAttr,  rtfPrtBin,              "binsxn",       0 },
2626         { rtfSectAttr,  rtfSectStyleNum,        "ds",           0 },
2627
2628         { rtfSectAttr,  rtfNoBreak,             "sbknone",      0 },
2629         { rtfSectAttr,  rtfColBreak,            "sbkcol",       0 },
2630         { rtfSectAttr,  rtfPageBreak,           "sbkpage",      0 },
2631         { rtfSectAttr,  rtfEvenBreak,           "sbkeven",      0 },
2632         { rtfSectAttr,  rtfOddBreak,            "sbkodd",       0 },
2633
2634         { rtfSectAttr,  rtfColumns,             "cols",         0 },
2635         { rtfSectAttr,  rtfColumnSpace,         "colsx",        0 },
2636         { rtfSectAttr,  rtfColumnNumber,        "colno",        0 },
2637         { rtfSectAttr,  rtfColumnSpRight,       "colsr",        0 },
2638         { rtfSectAttr,  rtfColumnWidth,         "colw",         0 },
2639         { rtfSectAttr,  rtfColumnLine,          "linebetcol",   0 },
2640
2641         { rtfSectAttr,  rtfLineModulus,         "linemod",      0 },
2642         { rtfSectAttr,  rtfLineDist,            "linex",        0 },
2643         { rtfSectAttr,  rtfLineStarts,          "linestarts",   0 },
2644         { rtfSectAttr,  rtfLineRestart,         "linerestart",  0 },
2645         { rtfSectAttr,  rtfLineRestartPg,       "lineppage",    0 },
2646         { rtfSectAttr,  rtfLineCont,            "linecont",     0 },
2647
2648         { rtfSectAttr,  rtfSectPageWid,         "pgwsxn",       0 },
2649         { rtfSectAttr,  rtfSectPageHt,          "pghsxn",       0 },
2650         { rtfSectAttr,  rtfSectMarginLeft,      "marglsxn",     0 },
2651         { rtfSectAttr,  rtfSectMarginRight,     "margrsxn",     0 },
2652         { rtfSectAttr,  rtfSectMarginTop,       "margtsxn",     0 },
2653         { rtfSectAttr,  rtfSectMarginBottom,    "margbsxn",     0 },
2654         { rtfSectAttr,  rtfSectMarginGutter,    "guttersxn",    0 },
2655         { rtfSectAttr,  rtfSectLandscape,       "lndscpsxn",    0 },
2656         { rtfSectAttr,  rtfTitleSpecial,        "titlepg",      0 },
2657         { rtfSectAttr,  rtfHeaderY,             "headery",      0 },
2658         { rtfSectAttr,  rtfFooterY,             "footery",      0 },
2659
2660         { rtfSectAttr,  rtfPageStarts,          "pgnstarts",    0 },
2661         { rtfSectAttr,  rtfPageCont,            "pgncont",      0 },
2662         { rtfSectAttr,  rtfPageRestart,         "pgnrestart",   0 },
2663         { rtfSectAttr,  rtfPageNumRight,        "pgnx",         0 },
2664         { rtfSectAttr,  rtfPageNumTop,          "pgny",         0 },
2665         { rtfSectAttr,  rtfPageDecimal,         "pgndec",       0 },
2666         { rtfSectAttr,  rtfPageURoman,          "pgnucrm",      0 },
2667         { rtfSectAttr,  rtfPageLRoman,          "pgnlcrm",      0 },
2668         { rtfSectAttr,  rtfPageULetter,         "pgnucltr",     0 },
2669         { rtfSectAttr,  rtfPageLLetter,         "pgnlcltr",     0 },
2670         { rtfSectAttr,  rtfPageNumHyphSep,      "pgnhnsh",      0 },
2671         { rtfSectAttr,  rtfPageNumSpaceSep,     "pgnhnsp",      0 },
2672         { rtfSectAttr,  rtfPageNumColonSep,     "pgnhnsc",      0 },
2673         { rtfSectAttr,  rtfPageNumEmdashSep,    "pgnhnsm",      0 },
2674         { rtfSectAttr,  rtfPageNumEndashSep,    "pgnhnsn",      0 },
2675
2676         { rtfSectAttr,  rtfTopVAlign,           "vertalt",      0 },
2677         /* misspelled as "vertal" in specification 1.0 */
2678         { rtfSectAttr,  rtfBottomVAlign,        "vertalb",      0 },
2679         { rtfSectAttr,  rtfCenterVAlign,        "vertalc",      0 },
2680         { rtfSectAttr,  rtfJustVAlign,          "vertalj",      0 },
2681
2682         { rtfSectAttr,  rtfRTLSect,             "rtlsect",      0 },
2683         { rtfSectAttr,  rtfLTRSect,             "ltrsect",      0 },
2684
2685         /* I've seen these in an old spec, but not in real files... */
2686         /*rtfSectAttr,  rtfNoBreak,             "nobreak",      0,*/
2687         /*rtfSectAttr,  rtfColBreak,            "colbreak",     0,*/
2688         /*rtfSectAttr,  rtfPageBreak,           "pagebreak",    0,*/
2689         /*rtfSectAttr,  rtfEvenBreak,           "evenbreak",    0,*/
2690         /*rtfSectAttr,  rtfOddBreak,            "oddbreak",     0,*/
2691
2692         /*
2693          * Document formatting attributes
2694          */
2695
2696         { rtfDocAttr,   rtfDefTab,              "deftab",       0 },
2697         { rtfDocAttr,   rtfHyphHotZone,         "hyphhotz",     0 },
2698         { rtfDocAttr,   rtfHyphConsecLines,     "hyphconsec",   0 },
2699         { rtfDocAttr,   rtfHyphCaps,            "hyphcaps",     0 },
2700         { rtfDocAttr,   rtfHyphAuto,            "hyphauto",     0 },
2701         { rtfDocAttr,   rtfLineStart,           "linestart",    0 },
2702         { rtfDocAttr,   rtfFracWidth,           "fracwidth",    0 },
2703         /* \makeback was given in old version of spec, it's now */
2704         /* listed as \makebackup */
2705         { rtfDocAttr,   rtfMakeBackup,          "makeback",     0 },
2706         { rtfDocAttr,   rtfMakeBackup,          "makebackup",   0 },
2707         { rtfDocAttr,   rtfRTFDefault,          "defformat",    0 },
2708         { rtfDocAttr,   rtfPSOverlay,           "psover",       0 },
2709         { rtfDocAttr,   rtfDocTemplate,         "doctemp",      0 },
2710         { rtfDocAttr,   rtfDefLanguage,         "deflang",      0 },
2711
2712         { rtfDocAttr,   rtfFENoteType,          "fet",          0 },
2713         { rtfDocAttr,   rtfFNoteEndSect,        "endnotes",     0 },
2714         { rtfDocAttr,   rtfFNoteEndDoc,         "enddoc",       0 },
2715         { rtfDocAttr,   rtfFNoteText,           "ftntj",        0 },
2716         { rtfDocAttr,   rtfFNoteBottom,         "ftnbj",        0 },
2717         { rtfDocAttr,   rtfENoteEndSect,        "aendnotes",    0 },
2718         { rtfDocAttr,   rtfENoteEndDoc,         "aenddoc",      0 },
2719         { rtfDocAttr,   rtfENoteText,           "aftntj",       0 },
2720         { rtfDocAttr,   rtfENoteBottom,         "aftnbj",       0 },
2721         { rtfDocAttr,   rtfFNoteStart,          "ftnstart",     0 },
2722         { rtfDocAttr,   rtfENoteStart,          "aftnstart",    0 },
2723         { rtfDocAttr,   rtfFNoteRestartPage,    "ftnrstpg",     0 },
2724         { rtfDocAttr,   rtfFNoteRestart,        "ftnrestart",   0 },
2725         { rtfDocAttr,   rtfFNoteRestartCont,    "ftnrstcont",   0 },
2726         { rtfDocAttr,   rtfENoteRestart,        "aftnrestart",  0 },
2727         { rtfDocAttr,   rtfENoteRestartCont,    "aftnrstcont",  0 },
2728         { rtfDocAttr,   rtfFNoteNumArabic,      "ftnnar",       0 },
2729         { rtfDocAttr,   rtfFNoteNumLLetter,     "ftnnalc",      0 },
2730         { rtfDocAttr,   rtfFNoteNumULetter,     "ftnnauc",      0 },
2731         { rtfDocAttr,   rtfFNoteNumLRoman,      "ftnnrlc",      0 },
2732         { rtfDocAttr,   rtfFNoteNumURoman,      "ftnnruc",      0 },
2733         { rtfDocAttr,   rtfFNoteNumChicago,     "ftnnchi",      0 },
2734         { rtfDocAttr,   rtfENoteNumArabic,      "aftnnar",      0 },
2735         { rtfDocAttr,   rtfENoteNumLLetter,     "aftnnalc",     0 },
2736         { rtfDocAttr,   rtfENoteNumULetter,     "aftnnauc",     0 },
2737         { rtfDocAttr,   rtfENoteNumLRoman,      "aftnnrlc",     0 },
2738         { rtfDocAttr,   rtfENoteNumURoman,      "aftnnruc",     0 },
2739         { rtfDocAttr,   rtfENoteNumChicago,     "aftnnchi",     0 },
2740
2741         { rtfDocAttr,   rtfPaperWidth,          "paperw",       0 },
2742         { rtfDocAttr,   rtfPaperHeight,         "paperh",       0 },
2743         { rtfDocAttr,   rtfPaperSize,           "psz",          0 },
2744         { rtfDocAttr,   rtfLeftMargin,          "margl",        0 },
2745         { rtfDocAttr,   rtfRightMargin,         "margr",        0 },
2746         { rtfDocAttr,   rtfTopMargin,           "margt",        0 },
2747         { rtfDocAttr,   rtfBottomMargin,        "margb",        0 },
2748         { rtfDocAttr,   rtfFacingPage,          "facingp",      0 },
2749         { rtfDocAttr,   rtfGutterWid,           "gutter",       0 },
2750         { rtfDocAttr,   rtfMirrorMargin,        "margmirror",   0 },
2751         { rtfDocAttr,   rtfLandscape,           "landscape",    0 },
2752         { rtfDocAttr,   rtfPageStart,           "pgnstart",     0 },
2753         { rtfDocAttr,   rtfWidowCtrl,           "widowctrl",    0 },
2754
2755         { rtfDocAttr,   rtfLinkStyles,          "linkstyles",   0 },
2756
2757         { rtfDocAttr,   rtfNoAutoTabIndent,     "notabind",     0 },
2758         { rtfDocAttr,   rtfWrapSpaces,          "wraptrsp",     0 },
2759         { rtfDocAttr,   rtfPrintColorsBlack,    "prcolbl",      0 },
2760         { rtfDocAttr,   rtfNoExtraSpaceRL,      "noextrasprl",  0 },
2761         { rtfDocAttr,   rtfNoColumnBalance,     "nocolbal",     0 },
2762         { rtfDocAttr,   rtfCvtMailMergeQuote,   "cvmme",        0 },
2763         { rtfDocAttr,   rtfSuppressTopSpace,    "sprstsp",      0 },
2764         { rtfDocAttr,   rtfSuppressPreParSpace, "sprsspbf",     0 },
2765         { rtfDocAttr,   rtfCombineTblBorders,   "otblrul",      0 },
2766         { rtfDocAttr,   rtfTranspMetafiles,     "transmf",      0 },
2767         { rtfDocAttr,   rtfSwapBorders,         "swpbdr",       0 },
2768         { rtfDocAttr,   rtfShowHardBreaks,      "brkfrm",       0 },
2769
2770         { rtfDocAttr,   rtfFormProtected,       "formprot",     0 },
2771         { rtfDocAttr,   rtfAllProtected,        "allprot",      0 },
2772         { rtfDocAttr,   rtfFormShading,         "formshade",    0 },
2773         { rtfDocAttr,   rtfFormDisplay,         "formdisp",     0 },
2774         { rtfDocAttr,   rtfPrintData,           "printdata",    0 },
2775
2776         { rtfDocAttr,   rtfRevProtected,        "revprot",      0 },
2777         { rtfDocAttr,   rtfRevisions,           "revisions",    0 },
2778         { rtfDocAttr,   rtfRevDisplay,          "revprop",      0 },
2779         { rtfDocAttr,   rtfRevBar,              "revbar",       0 },
2780
2781         { rtfDocAttr,   rtfAnnotProtected,      "annotprot",    0 },
2782
2783         { rtfDocAttr,   rtfRTLDoc,              "rtldoc",       0 },
2784         { rtfDocAttr,   rtfLTRDoc,              "ltrdoc",       0 },
2785
2786         /*
2787          * Style attributes
2788          */
2789
2790         { rtfStyleAttr, rtfAdditive,            "additive",     0 },
2791         { rtfStyleAttr, rtfBasedOn,             "sbasedon",     0 },
2792         { rtfStyleAttr, rtfNext,                "snext",        0 },
2793
2794         /*
2795          * Picture attributes
2796          */
2797
2798         { rtfPictAttr,  rtfMacQD,               "macpict",      0 },
2799         { rtfPictAttr,  rtfPMMetafile,          "pmmetafile",   0 },
2800         { rtfPictAttr,  rtfWinMetafile,         "wmetafile",    0 },
2801         { rtfPictAttr,  rtfDevIndBitmap,        "dibitmap",     0 },
2802         { rtfPictAttr,  rtfWinBitmap,           "wbitmap",      0 },
2803         { rtfPictAttr,  rtfPixelBits,           "wbmbitspixel", 0 },
2804         { rtfPictAttr,  rtfBitmapPlanes,        "wbmplanes",    0 },
2805         { rtfPictAttr,  rtfBitmapWid,           "wbmwidthbytes", 0 },
2806
2807         { rtfPictAttr,  rtfPicWid,              "picw",         0 },
2808         { rtfPictAttr,  rtfPicHt,               "pich",         0 },
2809         { rtfPictAttr,  rtfPicGoalWid,          "picwgoal",     0 },
2810         { rtfPictAttr,  rtfPicGoalHt,           "pichgoal",     0 },
2811         /* these two aren't in the spec, but some writers emit them */
2812         { rtfPictAttr,  rtfPicGoalWid,          "picwGoal",     0 },
2813         { rtfPictAttr,  rtfPicGoalHt,           "pichGoal",     0 },
2814         { rtfPictAttr,  rtfPicScaleX,           "picscalex",    0 },
2815         { rtfPictAttr,  rtfPicScaleY,           "picscaley",    0 },
2816         { rtfPictAttr,  rtfPicScaled,           "picscaled",    0 },
2817         { rtfPictAttr,  rtfPicCropTop,          "piccropt",     0 },
2818         { rtfPictAttr,  rtfPicCropBottom,       "piccropb",     0 },
2819         { rtfPictAttr,  rtfPicCropLeft,         "piccropl",     0 },
2820         { rtfPictAttr,  rtfPicCropRight,        "piccropr",     0 },
2821
2822         { rtfPictAttr,  rtfPicMFHasBitmap,      "picbmp",       0 },
2823         { rtfPictAttr,  rtfPicMFBitsPerPixel,   "picbpp",       0 },
2824
2825         { rtfPictAttr,  rtfPicBinary,           "bin",          0 },
2826
2827         /*
2828          * NeXT graphic attributes
2829          */
2830
2831         { rtfNeXTGrAttr,        rtfNeXTGWidth,          "width",        0 },
2832         { rtfNeXTGrAttr,        rtfNeXTGHeight,         "height",       0 },
2833
2834         /*
2835          * Destinations
2836          */
2837
2838         { rtfDestination,       rtfFontTbl,             "fonttbl",      0 },
2839         { rtfDestination,       rtfFontAltName,         "falt",         0 },
2840         { rtfDestination,       rtfEmbeddedFont,        "fonteb",       0 },
2841         { rtfDestination,       rtfFontFile,            "fontfile",     0 },
2842         { rtfDestination,       rtfFileTbl,             "filetbl",      0 },
2843         { rtfDestination,       rtfFileInfo,            "file",         0 },
2844         { rtfDestination,       rtfColorTbl,            "colortbl",     0 },
2845         { rtfDestination,       rtfStyleSheet,          "stylesheet",   0 },
2846         { rtfDestination,       rtfKeyCode,             "keycode",      0 },
2847         { rtfDestination,       rtfRevisionTbl,         "revtbl",       0 },
2848         { rtfDestination,       rtfGenerator,           "generator",    0 },
2849         { rtfDestination,       rtfInfo,                "info",         0 },
2850         { rtfDestination,       rtfITitle,              "title",        0 },
2851         { rtfDestination,       rtfISubject,            "subject",      0 },
2852         { rtfDestination,       rtfIAuthor,             "author",       0 },
2853         { rtfDestination,       rtfIOperator,           "operator",     0 },
2854         { rtfDestination,       rtfIKeywords,           "keywords",     0 },
2855         { rtfDestination,       rtfIComment,            "comment",      0 },
2856         { rtfDestination,       rtfIVersion,            "version",      0 },
2857         { rtfDestination,       rtfIDoccomm,            "doccomm",      0 },
2858         /* \verscomm may not exist -- was seen in earlier spec version */
2859         { rtfDestination,       rtfIVerscomm,           "verscomm",     0 },
2860         { rtfDestination,       rtfNextFile,            "nextfile",     0 },
2861         { rtfDestination,       rtfTemplate,            "template",     0 },
2862         { rtfDestination,       rtfFNSep,               "ftnsep",       0 },
2863         { rtfDestination,       rtfFNContSep,           "ftnsepc",      0 },
2864         { rtfDestination,       rtfFNContNotice,        "ftncn",        0 },
2865         { rtfDestination,       rtfENSep,               "aftnsep",      0 },
2866         { rtfDestination,       rtfENContSep,           "aftnsepc",     0 },
2867         { rtfDestination,       rtfENContNotice,        "aftncn",       0 },
2868         { rtfDestination,       rtfPageNumLevel,        "pgnhn",        0 },
2869         { rtfDestination,       rtfParNumLevelStyle,    "pnseclvl",     0 },
2870         { rtfDestination,       rtfHeader,              "header",       0 },
2871         { rtfDestination,       rtfFooter,              "footer",       0 },
2872         { rtfDestination,       rtfHeaderLeft,          "headerl",      0 },
2873         { rtfDestination,       rtfHeaderRight,         "headerr",      0 },
2874         { rtfDestination,       rtfHeaderFirst,         "headerf",      0 },
2875         { rtfDestination,       rtfFooterLeft,          "footerl",      0 },
2876         { rtfDestination,       rtfFooterRight,         "footerr",      0 },
2877         { rtfDestination,       rtfFooterFirst,         "footerf",      0 },
2878         { rtfDestination,       rtfParNumText,          "pntext",       0 },
2879         { rtfDestination,       rtfParNumbering,        "pn",           0 },
2880         { rtfDestination,       rtfParNumTextAfter,     "pntexta",      0 },
2881         { rtfDestination,       rtfParNumTextBefore,    "pntextb",      0 },
2882         { rtfDestination,       rtfBookmarkStart,       "bkmkstart",    0 },
2883         { rtfDestination,       rtfBookmarkEnd,         "bkmkend",      0 },
2884         { rtfDestination,       rtfPict,                "pict",         0 },
2885         { rtfDestination,       rtfObject,              "object",       0 },
2886         { rtfDestination,       rtfObjClass,            "objclass",     0 },
2887         { rtfDestination,       rtfObjName,             "objname",      0 },
2888         { rtfObjAttr,   rtfObjTime,             "objtime",      0 },
2889         { rtfDestination,       rtfObjData,             "objdata",      0 },
2890         { rtfDestination,       rtfObjAlias,            "objalias",     0 },
2891         { rtfDestination,       rtfObjSection,          "objsect",      0 },
2892         /* objitem and objtopic aren't documented in the spec! */
2893         { rtfDestination,       rtfObjItem,             "objitem",      0 },
2894         { rtfDestination,       rtfObjTopic,            "objtopic",     0 },
2895         { rtfDestination,       rtfObjResult,           "result",       0 },
2896         { rtfDestination,       rtfDrawObject,          "do",           0 },
2897         { rtfDestination,       rtfFootnote,            "footnote",     0 },
2898         { rtfDestination,       rtfAnnotRefStart,       "atrfstart",    0 },
2899         { rtfDestination,       rtfAnnotRefEnd,         "atrfend",      0 },
2900         { rtfDestination,       rtfAnnotID,             "atnid",        0 },
2901         { rtfDestination,       rtfAnnotAuthor,         "atnauthor",    0 },
2902         { rtfDestination,       rtfAnnotation,          "annotation",   0 },
2903         { rtfDestination,       rtfAnnotRef,            "atnref",       0 },
2904         { rtfDestination,       rtfAnnotTime,           "atntime",      0 },
2905         { rtfDestination,       rtfAnnotIcon,           "atnicn",       0 },
2906         { rtfDestination,       rtfField,               "field",        0 },
2907         { rtfDestination,       rtfFieldInst,           "fldinst",      0 },
2908         { rtfDestination,       rtfFieldResult,         "fldrslt",      0 },
2909         { rtfDestination,       rtfDataField,           "datafield",    0 },
2910         { rtfDestination,       rtfIndex,               "xe",           0 },
2911         { rtfDestination,       rtfIndexText,           "txe",          0 },
2912         { rtfDestination,       rtfIndexRange,          "rxe",          0 },
2913         { rtfDestination,       rtfTOC,                 "tc",           0 },
2914         { rtfDestination,       rtfNeXTGraphic,         "NeXTGraphic",  0 },
2915
2916         /*
2917          * Font families
2918          */
2919
2920         { rtfFontFamily,        rtfFFNil,               "fnil",         0 },
2921         { rtfFontFamily,        rtfFFRoman,             "froman",       0 },
2922         { rtfFontFamily,        rtfFFSwiss,             "fswiss",       0 },
2923         { rtfFontFamily,        rtfFFModern,            "fmodern",      0 },
2924         { rtfFontFamily,        rtfFFScript,            "fscript",      0 },
2925         { rtfFontFamily,        rtfFFDecor,             "fdecor",       0 },
2926         { rtfFontFamily,        rtfFFTech,              "ftech",        0 },
2927         { rtfFontFamily,        rtfFFBidirectional,     "fbidi",        0 },
2928
2929         /*
2930          * Font attributes
2931          */
2932
2933         { rtfFontAttr,  rtfFontCharSet,         "fcharset",     0 },
2934         { rtfFontAttr,  rtfFontPitch,           "fprq",         0 },
2935         { rtfFontAttr,  rtfFontCodePage,        "cpg",          0 },
2936         { rtfFontAttr,  rtfFTypeNil,            "ftnil",        0 },
2937         { rtfFontAttr,  rtfFTypeTrueType,       "fttruetype",   0 },
2938
2939         /*
2940          * File table attributes
2941          */
2942
2943         { rtfFileAttr,  rtfFileNum,             "fid",          0 },
2944         { rtfFileAttr,  rtfFileRelPath,         "frelative",    0 },
2945         { rtfFileAttr,  rtfFileOSNum,           "fosnum",       0 },
2946
2947         /*
2948          * File sources
2949          */
2950
2951         { rtfFileSource,        rtfSrcMacintosh,        "fvalidmac",    0 },
2952         { rtfFileSource,        rtfSrcDOS,              "fvaliddos",    0 },
2953         { rtfFileSource,        rtfSrcNTFS,             "fvalidntfs",   0 },
2954         { rtfFileSource,        rtfSrcHPFS,             "fvalidhpfs",   0 },
2955         { rtfFileSource,        rtfSrcNetwork,          "fnetwork",     0 },
2956
2957         /*
2958          * Color names
2959          */
2960
2961         { rtfColorName, rtfRed,                 "red",          0 },
2962         { rtfColorName, rtfGreen,               "green",        0 },
2963         { rtfColorName, rtfBlue,                "blue",         0 },
2964
2965         /*
2966          * Charset names
2967          */
2968
2969         { rtfCharSet,   rtfMacCharSet,          "mac",          0 },
2970         { rtfCharSet,   rtfAnsiCharSet,         "ansi",         0 },
2971         { rtfCharSet,   rtfPcCharSet,           "pc",           0 },
2972         { rtfCharSet,   rtfPcaCharSet,          "pca",          0 },
2973
2974         /*
2975          * Table attributes
2976          */
2977
2978         { rtfTblAttr,   rtfRowDef,              "trowd",        0 },
2979         { rtfTblAttr,   rtfRowGapH,             "trgaph",       0 },
2980         { rtfTblAttr,   rtfCellPos,             "cellx",        0 },
2981         { rtfTblAttr,   rtfMergeRngFirst,       "clmgf",        0 },
2982         { rtfTblAttr,   rtfMergePrevious,       "clmrg",        0 },
2983
2984         { rtfTblAttr,   rtfRowLeft,             "trql",         0 },
2985         { rtfTblAttr,   rtfRowRight,            "trqr",         0 },
2986         { rtfTblAttr,   rtfRowCenter,           "trqc",         0 },
2987         { rtfTblAttr,   rtfRowLeftEdge,         "trleft",       0 },
2988         { rtfTblAttr,   rtfRowHt,               "trrh",         0 },
2989         { rtfTblAttr,   rtfRowHeader,           "trhdr",        0 },
2990         { rtfTblAttr,   rtfRowKeep,             "trkeep",       0 },
2991
2992         { rtfTblAttr,   rtfRTLRow,              "rtlrow",       0 },
2993         { rtfTblAttr,   rtfLTRRow,              "ltrrow",       0 },
2994
2995         { rtfTblAttr,   rtfRowBordTop,          "trbrdrt",      0 },
2996         { rtfTblAttr,   rtfRowBordLeft,         "trbrdrl",      0 },
2997         { rtfTblAttr,   rtfRowBordBottom,       "trbrdrb",      0 },
2998         { rtfTblAttr,   rtfRowBordRight,        "trbrdrr",      0 },
2999         { rtfTblAttr,   rtfRowBordHoriz,        "trbrdrh",      0 },
3000         { rtfTblAttr,   rtfRowBordVert,         "trbrdrv",      0 },
3001
3002         { rtfTblAttr,   rtfCellBordBottom,      "clbrdrb",      0 },
3003         { rtfTblAttr,   rtfCellBordTop,         "clbrdrt",      0 },
3004         { rtfTblAttr,   rtfCellBordLeft,        "clbrdrl",      0 },
3005         { rtfTblAttr,   rtfCellBordRight,       "clbrdrr",      0 },
3006
3007         { rtfTblAttr,   rtfCellShading,         "clshdng",      0 },
3008         { rtfTblAttr,   rtfCellBgPatH,          "clbghoriz",    0 },
3009         { rtfTblAttr,   rtfCellBgPatV,          "clbgvert",     0 },
3010         { rtfTblAttr,   rtfCellFwdDiagBgPat,    "clbgfdiag",    0 },
3011         { rtfTblAttr,   rtfCellBwdDiagBgPat,    "clbgbdiag",    0 },
3012         { rtfTblAttr,   rtfCellHatchBgPat,      "clbgcross",    0 },
3013         { rtfTblAttr,   rtfCellDiagHatchBgPat,  "clbgdcross",   0 },
3014         /*
3015          * The spec lists "clbgdkhor", but the corresponding non-cell
3016          * control is "bgdkhoriz".  At any rate Macintosh Word seems
3017          * to accept both "clbgdkhor" and "clbgdkhoriz".
3018          */
3019         { rtfTblAttr,   rtfCellDarkBgPatH,      "clbgdkhoriz",  0 },
3020         { rtfTblAttr,   rtfCellDarkBgPatH,      "clbgdkhor",    0 },
3021         { rtfTblAttr,   rtfCellDarkBgPatV,      "clbgdkvert",   0 },
3022         { rtfTblAttr,   rtfCellFwdDarkBgPat,    "clbgdkfdiag",  0 },
3023         { rtfTblAttr,   rtfCellBwdDarkBgPat,    "clbgdkbdiag",  0 },
3024         { rtfTblAttr,   rtfCellDarkHatchBgPat,  "clbgdkcross",  0 },
3025         { rtfTblAttr,   rtfCellDarkDiagHatchBgPat, "clbgdkdcross",      0 },
3026         { rtfTblAttr,   rtfCellBgPatLineColor, "clcfpat",       0 },
3027         { rtfTblAttr,   rtfCellBgPatColor,      "clcbpat",      0 },
3028
3029         /*
3030          * Field attributes
3031          */
3032
3033         { rtfFieldAttr, rtfFieldDirty,          "flddirty",     0 },
3034         { rtfFieldAttr, rtfFieldEdited,         "fldedit",      0 },
3035         { rtfFieldAttr, rtfFieldLocked,         "fldlock",      0 },
3036         { rtfFieldAttr, rtfFieldPrivate,        "fldpriv",      0 },
3037         { rtfFieldAttr, rtfFieldAlt,            "fldalt",       0 },
3038
3039         /*
3040          * Positioning attributes
3041          */
3042
3043         { rtfPosAttr,   rtfAbsWid,              "absw",         0 },
3044         { rtfPosAttr,   rtfAbsHt,               "absh",         0 },
3045
3046         { rtfPosAttr,   rtfRPosMargH,           "phmrg",        0 },
3047         { rtfPosAttr,   rtfRPosPageH,           "phpg",         0 },
3048         { rtfPosAttr,   rtfRPosColH,            "phcol",        0 },
3049         { rtfPosAttr,   rtfPosX,                "posx",         0 },
3050         { rtfPosAttr,   rtfPosNegX,             "posnegx",      0 },
3051         { rtfPosAttr,   rtfPosXCenter,          "posxc",        0 },
3052         { rtfPosAttr,   rtfPosXInside,          "posxi",        0 },
3053         { rtfPosAttr,   rtfPosXOutSide,         "posxo",        0 },
3054         { rtfPosAttr,   rtfPosXRight,           "posxr",        0 },
3055         { rtfPosAttr,   rtfPosXLeft,            "posxl",        0 },
3056
3057         { rtfPosAttr,   rtfRPosMargV,           "pvmrg",        0 },
3058         { rtfPosAttr,   rtfRPosPageV,           "pvpg",         0 },
3059         { rtfPosAttr,   rtfRPosParaV,           "pvpara",       0 },
3060         { rtfPosAttr,   rtfPosY,                "posy",         0 },
3061         { rtfPosAttr,   rtfPosNegY,             "posnegy",      0 },
3062         { rtfPosAttr,   rtfPosYInline,          "posyil",       0 },
3063         { rtfPosAttr,   rtfPosYTop,             "posyt",        0 },
3064         { rtfPosAttr,   rtfPosYCenter,          "posyc",        0 },
3065         { rtfPosAttr,   rtfPosYBottom,          "posyb",        0 },
3066
3067         { rtfPosAttr,   rtfNoWrap,              "nowrap",       0 },
3068         { rtfPosAttr,   rtfDistFromTextAll,     "dxfrtext",     0 },
3069         { rtfPosAttr,   rtfDistFromTextX,       "dfrmtxtx",     0 },
3070         { rtfPosAttr,   rtfDistFromTextY,       "dfrmtxty",     0 },
3071         /* \dyfrtext no longer exists in spec 1.2, apparently */
3072         /* replaced by \dfrmtextx and \dfrmtexty. */
3073         { rtfPosAttr,   rtfTextDistY,           "dyfrtext",     0 },
3074
3075         { rtfPosAttr,   rtfDropCapLines,        "dropcapli",    0 },
3076         { rtfPosAttr,   rtfDropCapType,         "dropcapt",     0 },
3077
3078         /*
3079          * Object controls
3080          */
3081
3082         { rtfObjAttr,   rtfObjEmb,              "objemb",       0 },
3083         { rtfObjAttr,   rtfObjLink,             "objlink",      0 },
3084         { rtfObjAttr,   rtfObjAutoLink,         "objautlink",   0 },
3085         { rtfObjAttr,   rtfObjSubscriber,       "objsub",       0 },
3086         { rtfObjAttr,   rtfObjPublisher,        "objpub",       0 },
3087         { rtfObjAttr,   rtfObjICEmb,            "objicemb",     0 },
3088
3089         { rtfObjAttr,   rtfObjLinkSelf,         "linkself",     0 },
3090         { rtfObjAttr,   rtfObjLock,             "objupdate",    0 },
3091         { rtfObjAttr,   rtfObjUpdate,           "objlock",      0 },
3092
3093         { rtfObjAttr,   rtfObjHt,               "objh",         0 },
3094         { rtfObjAttr,   rtfObjWid,              "objw",         0 },
3095         { rtfObjAttr,   rtfObjSetSize,          "objsetsize",   0 },
3096         { rtfObjAttr,   rtfObjAlign,            "objalign",     0 },
3097         { rtfObjAttr,   rtfObjTransposeY,       "objtransy",    0 },
3098         { rtfObjAttr,   rtfObjCropTop,          "objcropt",     0 },
3099         { rtfObjAttr,   rtfObjCropBottom,       "objcropb",     0 },
3100         { rtfObjAttr,   rtfObjCropLeft,         "objcropl",     0 },
3101         { rtfObjAttr,   rtfObjCropRight,        "objcropr",     0 },
3102         { rtfObjAttr,   rtfObjScaleX,           "objscalex",    0 },
3103         { rtfObjAttr,   rtfObjScaleY,           "objscaley",    0 },
3104
3105         { rtfObjAttr,   rtfObjResRTF,           "rsltrtf",      0 },
3106         { rtfObjAttr,   rtfObjResPict,          "rsltpict",     0 },
3107         { rtfObjAttr,   rtfObjResBitmap,        "rsltbmp",      0 },
3108         { rtfObjAttr,   rtfObjResText,          "rslttxt",      0 },
3109         { rtfObjAttr,   rtfObjResMerge,         "rsltmerge",    0 },
3110
3111         { rtfObjAttr,   rtfObjBookmarkPubObj,   "bkmkpub",      0 },
3112         { rtfObjAttr,   rtfObjPubAutoUpdate,    "pubauto",      0 },
3113
3114         /*
3115          * Associated character formatting attributes
3116          */
3117
3118         { rtfACharAttr, rtfACBold,              "ab",           0 },
3119         { rtfACharAttr, rtfACAllCaps,           "caps",         0 },
3120         { rtfACharAttr, rtfACForeColor,         "acf",          0 },
3121         { rtfACharAttr, rtfACSubScript,         "adn",          0 },
3122         { rtfACharAttr, rtfACExpand,            "aexpnd",       0 },
3123         { rtfACharAttr, rtfACFontNum,           "af",           0 },
3124         { rtfACharAttr, rtfACFontSize,          "afs",          0 },
3125         { rtfACharAttr, rtfACItalic,            "ai",           0 },
3126         { rtfACharAttr, rtfACLanguage,          "alang",        0 },
3127         { rtfACharAttr, rtfACOutline,           "aoutl",        0 },
3128         { rtfACharAttr, rtfACSmallCaps,         "ascaps",       0 },
3129         { rtfACharAttr, rtfACShadow,            "ashad",        0 },
3130         { rtfACharAttr, rtfACStrikeThru,        "astrike",      0 },
3131         { rtfACharAttr, rtfACUnderline,         "aul",          0 },
3132         { rtfACharAttr, rtfACDotUnderline,      "auld",         0 },
3133         { rtfACharAttr, rtfACDbUnderline,       "auldb",        0 },
3134         { rtfACharAttr, rtfACNoUnderline,       "aulnone",      0 },
3135         { rtfACharAttr, rtfACWordUnderline,     "aulw",         0 },
3136         { rtfACharAttr, rtfACSuperScript,       "aup",          0 },
3137
3138         /*
3139          * Footnote attributes
3140          */
3141
3142         { rtfFNoteAttr, rtfFNAlt,               "ftnalt",       0 },
3143
3144         /*
3145          * Key code attributes
3146          */
3147
3148         { rtfKeyCodeAttr,       rtfAltKey,              "alt",          0 },
3149         { rtfKeyCodeAttr,       rtfShiftKey,            "shift",        0 },
3150         { rtfKeyCodeAttr,       rtfControlKey,          "ctrl",         0 },
3151         { rtfKeyCodeAttr,       rtfFunctionKey,         "fn",           0 },
3152
3153         /*
3154          * Bookmark attributes
3155          */
3156
3157         { rtfBookmarkAttr, rtfBookmarkFirstCol, "bkmkcolf",     0 },
3158         { rtfBookmarkAttr, rtfBookmarkLastCol,  "bkmkcoll",     0 },
3159
3160         /*
3161          * Index entry attributes
3162          */
3163
3164         { rtfIndexAttr, rtfIndexNumber,         "xef",          0 },
3165         { rtfIndexAttr, rtfIndexBold,           "bxe",          0 },
3166         { rtfIndexAttr, rtfIndexItalic,         "ixe",          0 },
3167
3168         /*
3169          * Table of contents attributes
3170          */
3171
3172         { rtfTOCAttr,   rtfTOCType,             "tcf",          0 },
3173         { rtfTOCAttr,   rtfTOCLevel,            "tcl",          0 },
3174
3175         /*
3176          * Drawing object attributes
3177          */
3178
3179         { rtfDrawAttr,  rtfDrawLock,            "dolock",       0 },
3180         { rtfDrawAttr,  rtfDrawPageRelX,        "doxpage",      0 },
3181         { rtfDrawAttr,  rtfDrawColumnRelX,      "dobxcolumn",   0 },
3182         { rtfDrawAttr,  rtfDrawMarginRelX,      "dobxmargin",   0 },
3183         { rtfDrawAttr,  rtfDrawPageRelY,        "dobypage",     0 },
3184         { rtfDrawAttr,  rtfDrawColumnRelY,      "dobycolumn",   0 },
3185         { rtfDrawAttr,  rtfDrawMarginRelY,      "dobymargin",   0 },
3186         { rtfDrawAttr,  rtfDrawHeight,          "dobhgt",       0 },
3187
3188         { rtfDrawAttr,  rtfDrawBeginGroup,      "dpgroup",      0 },
3189         { rtfDrawAttr,  rtfDrawGroupCount,      "dpcount",      0 },
3190         { rtfDrawAttr,  rtfDrawEndGroup,        "dpendgroup",   0 },
3191         { rtfDrawAttr,  rtfDrawArc,             "dparc",        0 },
3192         { rtfDrawAttr,  rtfDrawCallout,         "dpcallout",    0 },
3193         { rtfDrawAttr,  rtfDrawEllipse,         "dpellipse",    0 },
3194         { rtfDrawAttr,  rtfDrawLine,            "dpline",       0 },
3195         { rtfDrawAttr,  rtfDrawPolygon,         "dppolygon",    0 },
3196         { rtfDrawAttr,  rtfDrawPolyLine,        "dppolyline",   0 },
3197         { rtfDrawAttr,  rtfDrawRect,            "dprect",       0 },
3198         { rtfDrawAttr,  rtfDrawTextBox,         "dptxbx",       0 },
3199
3200         { rtfDrawAttr,  rtfDrawOffsetX,         "dpx",          0 },
3201         { rtfDrawAttr,  rtfDrawSizeX,           "dpxsize",      0 },
3202         { rtfDrawAttr,  rtfDrawOffsetY,         "dpy",          0 },
3203         { rtfDrawAttr,  rtfDrawSizeY,           "dpysize",      0 },
3204
3205         { rtfDrawAttr,  rtfCOAngle,             "dpcoa",        0 },
3206         { rtfDrawAttr,  rtfCOAccentBar,         "dpcoaccent",   0 },
3207         { rtfDrawAttr,  rtfCOBestFit,           "dpcobestfit",  0 },
3208         { rtfDrawAttr,  rtfCOBorder,            "dpcoborder",   0 },
3209         { rtfDrawAttr,  rtfCOAttachAbsDist,     "dpcodabs",     0 },
3210         { rtfDrawAttr,  rtfCOAttachBottom,      "dpcodbottom",  0 },
3211         { rtfDrawAttr,  rtfCOAttachCenter,      "dpcodcenter",  0 },
3212         { rtfDrawAttr,  rtfCOAttachTop,         "dpcodtop",     0 },
3213         { rtfDrawAttr,  rtfCOLength,            "dpcolength",   0 },
3214         { rtfDrawAttr,  rtfCONegXQuadrant,      "dpcominusx",   0 },
3215         { rtfDrawAttr,  rtfCONegYQuadrant,      "dpcominusy",   0 },
3216         { rtfDrawAttr,  rtfCOOffset,            "dpcooffset",   0 },
3217         { rtfDrawAttr,  rtfCOAttachSmart,       "dpcosmarta",   0 },
3218         { rtfDrawAttr,  rtfCODoubleLine,        "dpcotdouble",  0 },
3219         { rtfDrawAttr,  rtfCORightAngle,        "dpcotright",   0 },
3220         { rtfDrawAttr,  rtfCOSingleLine,        "dpcotsingle",  0 },
3221         { rtfDrawAttr,  rtfCOTripleLine,        "dpcottriple",  0 },
3222
3223         { rtfDrawAttr,  rtfDrawTextBoxMargin,   "dptxbxmar",    0 },
3224         { rtfDrawAttr,  rtfDrawTextBoxText,     "dptxbxtext",   0 },
3225         { rtfDrawAttr,  rtfDrawRoundRect,       "dproundr",     0 },
3226
3227         { rtfDrawAttr,  rtfDrawPointX,          "dpptx",        0 },
3228         { rtfDrawAttr,  rtfDrawPointY,          "dppty",        0 },
3229         { rtfDrawAttr,  rtfDrawPolyCount,       "dppolycount",  0 },
3230
3231         { rtfDrawAttr,  rtfDrawArcFlipX,        "dparcflipx",   0 },
3232         { rtfDrawAttr,  rtfDrawArcFlipY,        "dparcflipy",   0 },
3233
3234         { rtfDrawAttr,  rtfDrawLineBlue,        "dplinecob",    0 },
3235         { rtfDrawAttr,  rtfDrawLineGreen,       "dplinecog",    0 },
3236         { rtfDrawAttr,  rtfDrawLineRed,         "dplinecor",    0 },
3237         { rtfDrawAttr,  rtfDrawLinePalette,     "dplinepal",    0 },
3238         { rtfDrawAttr,  rtfDrawLineDashDot,     "dplinedado",   0 },
3239         { rtfDrawAttr,  rtfDrawLineDashDotDot,  "dplinedadodo", 0 },
3240         { rtfDrawAttr,  rtfDrawLineDash,        "dplinedash",   0 },
3241         { rtfDrawAttr,  rtfDrawLineDot,         "dplinedot",    0 },
3242         { rtfDrawAttr,  rtfDrawLineGray,        "dplinegray",   0 },
3243         { rtfDrawAttr,  rtfDrawLineHollow,      "dplinehollow", 0 },
3244         { rtfDrawAttr,  rtfDrawLineSolid,       "dplinesolid",  0 },
3245         { rtfDrawAttr,  rtfDrawLineWidth,       "dplinew",      0 },
3246
3247         { rtfDrawAttr,  rtfDrawHollowEndArrow,  "dpaendhol",    0 },
3248         { rtfDrawAttr,  rtfDrawEndArrowLength,  "dpaendl",      0 },
3249         { rtfDrawAttr,  rtfDrawSolidEndArrow,   "dpaendsol",    0 },
3250         { rtfDrawAttr,  rtfDrawEndArrowWidth,   "dpaendw",      0 },
3251         { rtfDrawAttr,  rtfDrawHollowStartArrow,"dpastarthol",  0 },
3252         { rtfDrawAttr,  rtfDrawStartArrowLength,"dpastartl",    0 },
3253         { rtfDrawAttr,  rtfDrawSolidStartArrow, "dpastartsol",  0 },
3254         { rtfDrawAttr,  rtfDrawStartArrowWidth, "dpastartw",    0 },
3255
3256         { rtfDrawAttr,  rtfDrawBgFillBlue,      "dpfillbgcb",   0 },
3257         { rtfDrawAttr,  rtfDrawBgFillGreen,     "dpfillbgcg",   0 },
3258         { rtfDrawAttr,  rtfDrawBgFillRed,       "dpfillbgcr",   0 },
3259         { rtfDrawAttr,  rtfDrawBgFillPalette,   "dpfillbgpal",  0 },
3260         { rtfDrawAttr,  rtfDrawBgFillGray,      "dpfillbggray", 0 },
3261         { rtfDrawAttr,  rtfDrawFgFillBlue,      "dpfillfgcb",   0 },
3262         { rtfDrawAttr,  rtfDrawFgFillGreen,     "dpfillfgcg",   0 },
3263         { rtfDrawAttr,  rtfDrawFgFillRed,       "dpfillfgcr",   0 },
3264         { rtfDrawAttr,  rtfDrawFgFillPalette,   "dpfillfgpal",  0 },
3265         { rtfDrawAttr,  rtfDrawFgFillGray,      "dpfillfggray", 0 },
3266         { rtfDrawAttr,  rtfDrawFillPatIndex,    "dpfillpat",    0 },
3267
3268         { rtfDrawAttr,  rtfDrawShadow,          "dpshadow",     0 },
3269         { rtfDrawAttr,  rtfDrawShadowXOffset,   "dpshadx",      0 },
3270         { rtfDrawAttr,  rtfDrawShadowYOffset,   "dpshady",      0 },
3271
3272         { rtfVersion,   -1,                     "rtf",          0 },
3273         { rtfDefFont,   -1,                     "deff",         0 },
3274
3275         { 0,            -1,                     (char *) NULL,  0 }
3276 };
3277 #define RTF_KEY_COUNT (sizeof(rtfKey) / sizeof(RTFKey))
3278
3279 typedef struct tagRTFHashTableEntry {
3280   int count;
3281   RTFKey **value;
3282 } RTFHashTableEntry;
3283
3284 static RTFHashTableEntry rtfHashTable[RTF_KEY_COUNT];
3285
3286
3287 /*
3288  * Initialize lookup table hash values.  Only need to do this once.
3289  */
3290
3291 static void LookupInit(void)
3292 {
3293         static int      inited = 0;
3294         RTFKey  *rp;
3295
3296         if (inited == 0)
3297         {
3298                 memset(rtfHashTable, 0, RTF_KEY_COUNT * sizeof(*rtfHashTable));
3299                 for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++) {
3300                         int index;
3301                         
3302                         rp->rtfKHash = Hash ((char*)rp->rtfKStr);
3303                         index = rp->rtfKHash % RTF_KEY_COUNT;
3304                         if (!rtfHashTable[index].count)
3305                                 rtfHashTable[index].value = (void *)RTFAlloc(sizeof(RTFKey *));
3306                         else
3307                                 rtfHashTable[index].value = (void *)RTFReAlloc((void *)rtfHashTable[index].value, sizeof(RTFKey *) * (rtfHashTable[index].count + 1));
3308                         rtfHashTable[index].value[rtfHashTable[index].count++] = rp;
3309                 }
3310                 ++inited;
3311         }
3312 }
3313
3314
3315 /*
3316  * Determine major and minor number of control token.  If it's
3317  * not found, the class turns into rtfUnknown.
3318  */
3319
3320 static void Lookup(RTF_Info *info, char *s)
3321 {
3322         RTFKey  *rp;
3323         int     hash;
3324         RTFHashTableEntry *entry;
3325         int i;
3326
3327         TRACE("\n");
3328         ++s;                    /* skip over the leading \ character */
3329         hash = Hash (s);
3330         entry = &rtfHashTable[hash % RTF_KEY_COUNT];
3331         for (i = 0; i < entry->count; i++)
3332         {
3333                 rp = entry->value[i];
3334                 if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0)
3335                 {
3336                         info->rtfClass = rtfControl;
3337                         info->rtfMajor = rp->rtfKMajor;
3338                         info->rtfMinor = rp->rtfKMinor;
3339                         return;
3340                 }
3341         }
3342         info->rtfClass = rtfUnknown;
3343 }
3344
3345
3346 /*
3347  * Compute hash value of symbol
3348  */
3349
3350 static int Hash(char *s)
3351 {
3352         char    c;
3353         int     val = 0;
3354
3355         while ((c = *s++) != '\0')
3356                 val += (int) c;
3357         return (val);
3358 }
3359
3360
3361 /* ---------------------------------------------------------------------- */
3362
3363 /*
3364  * Memory allocation routines
3365  */
3366
3367
3368 /*
3369  * Return pointer to block of size bytes, or NULL if there's
3370  * not enough memory available.
3371  *
3372  * This is called through RTFAlloc(), a define which coerces the
3373  * argument to int.  This avoids the persistent problem of allocation
3374  * failing under THINK C when a long is passed.
3375  */
3376
3377 char *_RTFAlloc(int size)
3378 {
3379         return HeapAlloc(me_heap, 0, size);
3380 }
3381
3382
3383 char *
3384 RTFReAlloc(char *ptr, int size)
3385 {
3386         return HeapReAlloc(me_heap, 0, ptr, size);
3387 }
3388
3389
3390 /*
3391  * Saves a string on the heap and returns a pointer to it.
3392  */
3393
3394
3395 char *RTFStrSave(char *s)
3396 {
3397         char    *p;
3398
3399         if ((p = RTFAlloc ((int) (strlen (s) + 1))) == (char *) NULL)
3400                 return ((char *) NULL);
3401         return (strcpy (p, s));
3402 }
3403
3404
3405 void RTFFree(char *p)
3406 {
3407         HeapFree(me_heap, 0, p);
3408 }
3409
3410
3411 /* ---------------------------------------------------------------------- */
3412
3413
3414 /*
3415  * Token comparison routines
3416  */
3417
3418 int RTFCheckCM(RTF_Info *info, int class, int major)
3419 {
3420         return (info->rtfClass == class && info->rtfMajor == major);
3421 }
3422
3423
3424 int RTFCheckCMM(RTF_Info *info, int class, int major, int minor)
3425 {
3426         return (info->rtfClass == class && info->rtfMajor == major && info->rtfMinor == minor);
3427 }
3428
3429
3430 int RTFCheckMM(RTF_Info *info, int major, int minor)
3431 {
3432         return (info->rtfMajor == major && info->rtfMinor == minor);
3433 }
3434
3435
3436 /* ---------------------------------------------------------------------- */
3437
3438
3439 int RTFCharToHex(char c)
3440 {
3441         if (isupper (c))
3442                 c = tolower (c);
3443         if (isdigit (c))
3444                 return (c - '0');       /* '0'..'9' */
3445         return (c - 'a' + 10);          /* 'a'..'f' */
3446 }
3447
3448
3449 int RTFHexToChar(int i)
3450 {
3451         if (i < 10)
3452                 return (i + '0');
3453         return (i - 10 + 'a');
3454 }
3455
3456
3457 /* ---------------------------------------------------------------------- */
3458
3459 /*
3460  * RTFReadOutputMap() -- Read output translation map
3461  */
3462
3463 /*
3464  * Read in an array describing the relation between the standard character set
3465  * and an RTF translator's corresponding output sequences.  Each line consists
3466  * of a standard character name and the output sequence for that character.
3467  *
3468  * outMap is an array of strings into which the sequences should be placed.
3469  * It should be declared like this in the calling program:
3470  *
3471  *      char *outMap[rtfSC_MaxChar];
3472  *
3473  * reinit should be non-zero if outMap should be initialized
3474  * zero otherwise.
3475  *
3476  */
3477
3478 int RTFReadOutputMap(RTF_Info *info, char *outMap[], int reinit)
3479 {
3480         unsigned int  i;
3481         int  stdCode;
3482
3483         if (reinit)
3484         {
3485                 for (i = 0; i < rtfSC_MaxChar; i++)
3486                 {
3487                         outMap[i] = (char *) NULL;
3488                 }
3489         }
3490
3491         for (i=0 ;i< sizeof(text_map)/sizeof(char*); i+=2)
3492         {
3493                 const char *name = text_map[i];
3494                 const char *seq  = text_map[i+1];
3495                 stdCode = RTFStdCharCode( info, name );
3496                 outMap[stdCode] = (char*)seq;
3497         }
3498
3499         return (1);
3500 }
3501
3502 /* ---------------------------------------------------------------------- */
3503
3504 /*
3505  * Open a library file.
3506  */
3507
3508
3509 void RTFSetOpenLibFileProc(RTF_Info *info, FILE *(*proc)())
3510 {
3511         info->libFileOpen = proc;
3512 }
3513
3514
3515 FILE *RTFOpenLibFile (RTF_Info *info, char *file, char *mode)
3516 {
3517         if (info->libFileOpen == NULL)
3518                 return ((FILE *) NULL);
3519         return ((*info->libFileOpen) (file, mode));
3520 }
3521
3522
3523 /* ---------------------------------------------------------------------- */
3524
3525 /*
3526  * Print message.  Default is to send message to stderr
3527  * but this may be overridden with RTFSetMsgProc().
3528  *
3529  * Message should include linefeeds as necessary.  If the default
3530  * function is overridden, the overriding function may want to
3531  * map linefeeds to another line ending character or sequence if
3532  * the host system doesn't use linefeeds.
3533  */
3534
3535
3536 void RTFMsg (RTF_Info *info, const char *fmt, ...)
3537 {
3538         char    buf[rtfBufSiz];
3539
3540         va_list args;
3541         va_start (args,fmt);
3542         vsprintf (buf, fmt, args);
3543         va_end (args);
3544         MESSAGE( "%s", buf);
3545 }
3546
3547
3548 /* ---------------------------------------------------------------------- */
3549
3550
3551 /*
3552  * Process termination.  Print error message and exit.  Also prints
3553  * current token, and current input line number and position within
3554  * line if any input has been read from the current file.  (No input
3555  * has been read if prevChar is EOF).
3556  */
3557
3558 static void DefaultPanicProc(RTF_Info *info, char *s)
3559 {
3560         MESSAGE( "%s", s);
3561         /*exit (1);*/
3562 }
3563
3564
3565
3566 void RTFPanic(RTF_Info *info, const char *fmt, ...)
3567 {
3568         char    buf[rtfBufSiz];
3569
3570         va_list args;
3571         va_start (args,fmt);
3572         vsprintf (buf, fmt, args);
3573         va_end (args);
3574         (void) strcat (buf, "\n");
3575         if (info->prevChar != EOF && info->rtfTextBuf != (char *) NULL)
3576         {
3577                 sprintf (buf + strlen (buf),
3578                         "Last token read was \"%s\" near line %ld, position %d.\n",
3579                         info->rtfTextBuf, info->rtfLineNum, info->rtfLinePos);
3580         }
3581         DefaultPanicProc(info, buf);
3582 }
3583
3584 /* ---------------------------------------------------------------------- */
3585
3586 /*
3587  * originally from RTF tools' text-writer.c
3588  *
3589  * text-writer -- RTF-to-text translation writer code.
3590  *
3591  * Read RTF input, write text of document (text extraction).
3592  */
3593
3594 static void     TextClass (RTF_Info *info);
3595 static void     ControlClass (RTF_Info *info);
3596 static void     Destination (RTF_Info *info);
3597 static void     SpecialChar (RTF_Info *info);
3598 static void     PutStdChar (RTF_Info *info, int stdCode);
3599 static void     PutLitChar (RTF_Info *info, int c);
3600 static void     PutLitStr (RTF_Info *info, char *s);
3601
3602 /*
3603  * Initialize the writer.
3604  */
3605
3606 void
3607 WriterInit (RTF_Info *info )
3608 {
3609         RTFReadOutputMap (info, info->outMap,1);
3610 }
3611
3612
3613 int
3614 BeginFile (RTF_Info *info )
3615 {
3616         /* install class callbacks */
3617
3618         RTFSetClassCallback (info, rtfText, TextClass);
3619         RTFSetClassCallback (info, rtfControl, ControlClass);
3620
3621         return (1);
3622 }
3623
3624 /*
3625  * Write out a character. Seems to work for the default ANSI codepage,
3626  * contrary to TextClass_orig. 
3627  */
3628
3629 static void
3630 TextClass (RTF_Info *info)
3631 {
3632         PutLitChar (info, info->rtfMajor);
3633 }
3634
3635 /*
3636  * Write out a character.  rtfMajor contains the input character, rtfMinor
3637  * contains the corresponding standard character code.
3638  *
3639  * If the input character isn't in the charset map, try to print some
3640  * representation of it.
3641  * 
3642  * I'm not removing it, because it may be helpful if someone else decides
3643  * to rewrite the character handler in a i18n-friendly way 
3644  */
3645 #if 0
3646 static void
3647 TextClass_orig (RTF_Info *info)
3648 {
3649         char    buf[rtfBufSiz];
3650
3651         TRACE("\n");
3652
3653         if (info->rtfFormat == SF_TEXT)
3654                 PutLitChar (info, info->rtfMajor);
3655         else if (info->rtfMinor != rtfSC_nothing)
3656                 PutStdChar (info, info->rtfMinor);
3657         else
3658         {
3659                 if (info->rtfMajor < 256)       /* in ASCII range */
3660                         PutLitChar(info, info->rtfMajor);
3661                 else {
3662                         sprintf (buf, "[[\\'%02x]]", info->rtfMajor);
3663                         PutLitStr (info, buf);
3664                 }
3665         }
3666 }
3667 #endif
3668
3669
3670 static void
3671 ControlClass (RTF_Info *info)
3672 {
3673         TRACE("\n");
3674
3675         switch (info->rtfMajor)
3676         {
3677         case rtfDestination:
3678                 Destination (info);
3679                 break;
3680         case rtfSpecialChar:
3681                 SpecialChar (info);
3682                 break;
3683         }
3684 }
3685
3686
3687 /*
3688  * This function notices destinations that aren't explicitly handled
3689  * and skips to their ends.  This keeps, for instance, picture
3690  * data from being considered as plain text.
3691  */
3692
3693 static void
3694 Destination (RTF_Info *info)
3695 {
3696         TRACE("\n");
3697         if (!RTFGetDestinationCallback(info, info->rtfMinor))
3698                 RTFSkipGroup (info);    
3699 }
3700
3701
3702 /*
3703  * The reason these use the rtfSC_xxx thingies instead of just writing
3704  * out ' ', '-', '"', etc., is so that the mapping for these characters
3705  * can be controlled by the text-map file.
3706  */
3707
3708 void SpecialChar (RTF_Info *info)
3709 {
3710
3711         TRACE("\n");
3712
3713         switch (info->rtfMinor)
3714         {
3715         case rtfOptDest:
3716                 /* the next token determines destination, if it's unknown, skip the group */
3717                 /* this way we filter out the garbage coming from unknown destinations */ 
3718                 RTFGetToken(info); 
3719                 if (info->rtfClass != rtfDestination)
3720                         RTFSkipGroup(info);
3721                 else
3722                         RTFRouteToken(info); /* "\*" is ignored with known destinations */
3723                 break;
3724         case rtfPage:
3725         case rtfSect:
3726         case rtfRow:
3727         case rtfLine:
3728         case rtfPar:
3729                 PutLitChar (info, '\n');
3730                 break;
3731         case rtfCell:
3732                 PutStdChar (info, rtfSC_space); /* make sure cells are separated */
3733                 break;
3734         case rtfNoBrkSpace:
3735                 PutStdChar (info, rtfSC_nobrkspace);
3736                 break;
3737         case rtfTab:
3738                 PutLitChar (info, '\t');
3739                 break;
3740         case rtfNoBrkHyphen:
3741                 PutStdChar (info, rtfSC_nobrkhyphen);
3742                 break;
3743         case rtfBullet:
3744                 PutStdChar (info, rtfSC_bullet);
3745                 break;
3746         case rtfEmDash:
3747                 PutStdChar (info, rtfSC_emdash);
3748                 break;
3749         case rtfEnDash:
3750                 PutStdChar (info, rtfSC_endash);
3751                 break;
3752         case rtfLQuote:
3753                 PutStdChar (info, rtfSC_quoteleft);
3754                 break;
3755         case rtfRQuote:
3756                 PutStdChar (info, rtfSC_quoteright);
3757                 break;
3758         case rtfLDblQuote:
3759                 PutStdChar (info, rtfSC_quotedblleft);
3760                 break;
3761         case rtfRDblQuote:
3762                 PutStdChar (info, rtfSC_quotedblright);
3763                 break;
3764         }
3765 }
3766
3767
3768 /*
3769  * Eventually this should keep track of the destination of the
3770  * current state and only write text when in the initial state.
3771  *
3772  * If the output sequence is unspecified in the output map, write
3773  * the character's standard name instead.  This makes map deficiencies
3774  * obvious and provides incentive to fix it. :-)
3775  */
3776
3777 void PutStdChar (RTF_Info *info, int stdCode)
3778 {
3779
3780         char    *oStr = (char *) NULL;
3781         char    buf[rtfBufSiz];
3782
3783 /*      if (stdCode == rtfSC_nothing)
3784                 RTFPanic ("Unknown character code, logic error\n");
3785 */
3786         TRACE("\n");
3787
3788         oStr = info->outMap[stdCode];
3789         if (oStr == (char *) NULL)      /* no output sequence in map */
3790         {
3791                 sprintf (buf, "[[%s]]", RTFStdCharName (info, stdCode));
3792                 oStr = buf;
3793         }
3794         PutLitStr (info, oStr);
3795 }
3796
3797 void PutLitChar (RTF_Info *info, int c)
3798 {
3799         if( info->dwOutputCount >= ( sizeof info->OutputBuffer - 1 ) )
3800                 RTFFlushOutputBuffer( info );
3801         info->OutputBuffer[info->dwOutputCount++] = c;
3802 }
3803
3804 void RTFOutputANSIString( RTF_Info *info, char *str, int len )
3805 {
3806         assert(str[len] == '\0');
3807         if (len) SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str);
3808 }
3809
3810 void RTFFlushOutputBuffer( RTF_Info *info )
3811 {
3812         info->OutputBuffer[info->dwOutputCount] = 0;
3813         RTFOutputANSIString(info, info->OutputBuffer, info->dwOutputCount);
3814         info->dwOutputCount = 0;
3815 }
3816
3817 static void PutLitStr (RTF_Info *info, char *str )
3818 {
3819         int len = strlen( str );
3820
3821         if( ( len + info->dwOutputCount + 1 ) > sizeof info->OutputBuffer )
3822                 RTFFlushOutputBuffer( info );
3823         if( ( len + 1 ) >= sizeof info->OutputBuffer )
3824         {
3825                 RTFOutputANSIString(info, str, len);
3826                 return;
3827         }
3828         strcpy( &info->OutputBuffer[info->dwOutputCount], str );
3829         info->dwOutputCount += len;
3830 }