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