4 * Portions Copyright 2004 Mike McCormack for CodeWeavers
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.
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.
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
22 * Derived from RTF Tools by Paul DuBois (dubois@primate.wisc.edu)
23 * Homepage: http://www.snake.net/software/RTF/
24 * Original license follows:
28 * reader.c - RTF file reader. Release 1.10.
32 * Author: Paul DuBois dubois@primate.wisc.edu
34 * This software may be redistributed without restriction and used for
35 * any purpose whatsoever.
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(richedit
);
52 extern HANDLE me_heap
;
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*);
68 static void CharSetInit (RTF_Info
*);
69 static void ReadCharSetMaps (RTF_Info
*);
73 RTF ANSI character set (\ansi) general map
74 These are taken from the ISO-Latin-1 (ISO-8859-1) encodings, with
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.)
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
89 rtfSC_nobrkhyphen
,0x1e,
90 rtfSC_opthyphen
,0x1f,
94 rtfSC_numbersign
,'#',
98 rtfSC_quoteright
,'\'',
100 rtfSC_parenright
,')',
118 rtfSC_semicolon
,';',
150 rtfSC_bracketleft
,'[',
151 rtfSC_backslash
,'\\',
152 rtfSC_bracketright
,']',
153 rtfSC_asciicircum
,'^',
154 rtfSC_underscore
,'_',
155 rtfSC_quoteleft
,'`',
182 rtfSC_braceleft
,'{',
184 rtfSC_braceright
,'}',
185 rtfSC_asciitilde
,'~',
186 rtfSC_nobrkspace
,0xa0,
187 rtfSC_exclamdown
,0xa1,
189 rtfSC_sterling
,0xa3,
190 rtfSC_currency
,0xa4,
192 rtfSC_brokenbar
,0xa6,
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,
203 rtfSC_plusminus
,0xb1,
204 rtfSC_twosuperior
,0xb2,
205 rtfSC_threesuperior
,0xb3,
208 rtfSC_paragraph
,0xb6,
209 rtfSC_periodcentered
,0xb7,
211 rtfSC_onesuperior
,0xb9,
212 rtfSC_ordmasculine
,0xba,
213 rtfSC_guillemotright
,0xbb,
214 rtfSC_onequarter
,0xbc,
216 rtfSC_threequarters
,0xbe,
217 rtfSC_questiondown
,0xbf,
220 rtfSC_Acircumflex
,0xc2,
222 rtfSC_Adieresis
,0xc4,
225 rtfSC_Ccedilla
,0xc7,
228 rtfSC_Ecircumflex
,0xca,
229 rtfSC_Edieresis
,0xcb,
232 rtfSC_Icircumflex
,0xce,
233 rtfSC_Idieresis
,0xcf,
238 rtfSC_Ocircumflex
,0xd4,
240 rtfSC_Odieresis
,0xd6,
241 rtfSC_multiply
,0xd7,
245 rtfSC_Ucircumflex
,0xdb,
246 rtfSC_Udieresis
,0xdc,
249 rtfSC_germandbls
,0xdf,
252 rtfSC_acircumflex
,0xe2,
254 rtfSC_adieresis
,0xe4,
257 rtfSC_ccedilla
,0xe7,
260 rtfSC_ecircumflex
,0xea,
261 rtfSC_edieresis
,0xeb,
264 rtfSC_icircumflex
,0xee,
265 rtfSC_idieresis
,0xef,
270 rtfSC_ocircumflex
,0xf4,
272 rtfSC_odieresis
,0xf6,
277 rtfSC_ucircumflex
,0xfb,
278 rtfSC_udieresis
,0xfc,
281 rtfSC_ydieresis
,0xff
285 * RTF ANSI character set (\ansi) Symbol font map
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.)
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
301 rtfSC_nobrkhyphen
,0x1e,
302 rtfSC_opthyphen
,0x1f,
305 rtfSC_universal
,'"',
306 rtfSC_mathnumbersign
,'#',
307 rtfSC_existential
,'$',
309 rtfSC_ampersand
,'&',
310 rtfSC_suchthat
,'\\',
311 rtfSC_parenleft
,'(',
312 rtfSC_parenright
,')',
313 rtfSC_mathasterisk
,'*',
316 rtfSC_mathminus
,'-',
330 rtfSC_semicolon
,';',
332 rtfSC_mathequal
,'=',
335 rtfSC_congruent
,'@',
361 rtfSC_bracketleft
,'[',
362 rtfSC_backslash
,'\\',
363 rtfSC_bracketright
,']',
364 rtfSC_asciicircum
,'^',
365 rtfSC_underscore
,'_',
366 rtfSC_quoteleft
,'`',
391 rtfSC_braceleft
,'{',
393 rtfSC_braceright
,'}',
398 * Output sequence map for rtf2text
400 * Field 1 is the standard character name. Field 2 is the output sequence
401 * to produce for that character.
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.
407 * characters in ASCII range (32-127
410 const char *text_map
[] = {
513 "arrowdblboth" ,"<=>",
514 "arrowdblleft" ,"<=",
515 "arrowdblright" ,"=>",
522 "copyrightsans" ,"(c)",
534 "greaterequal" ,">=",
535 "guillemotleft" ,"<<",
536 "guillemotright" ,">>",
537 "guilsinglleft" ,"<",
538 "guilsinglright" ,">",
544 "mathnumbersign" ,"#",
556 "periodcentered" ,".",
558 "quotedblbase" ,",,",
559 "quotedblleft" ,"\"",
560 "quotedblright" ,"\"",
561 "quotesinglbase" ,",",
562 "registered" ,"reg.",
563 "registersans" ,"reg.",
564 "threequarters" ,"3/4",
567 "trademarksans" ,"(TM)"
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.
576 const char *stdCharName
[] =
933 int _RTFGetChar(RTF_Info
*info
)
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
))
943 if (info
->dwInputSize
<= info
->dwInputUsed
)
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
)
951 /* if no bytes read, it's EOF */
954 info
->dwInputSize
= count
;
955 info
->dwInputUsed
= 0;
957 ch
= info
->InputBuffer
[info
->dwInputUsed
++];
963 void RTFSetEditStream(RTF_Info
*info
, EDITSTREAM
*es
)
967 info
->editstream
.dwCookie
= es
->dwCookie
;
968 info
->editstream
.dwError
= es
->dwError
;
969 info
->editstream
.pfnCallback
= es
->pfnCallback
;
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().
978 void RTFInit(RTF_Info
*info
)
984 RTFStyleElt
*eltList
, *ep
;
988 if (info
->rtfTextBuf
== (char *) NULL
) /* initialize the text buffers */
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';
998 RTFFree (info
->inputName
);
999 RTFFree (info
->outputName
);
1000 info
->inputName
= info
->outputName
= (char *) NULL
;
1002 /* initialize lookup table */
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
);
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
);
1019 RTFSetReadHook (info
, (RTFFuncPtr
) NULL
);
1021 /* dump old lists if necessary */
1023 while (info
->fontList
!= (RTFFont
*) NULL
)
1025 fp
= info
->fontList
->rtfNextFont
;
1026 RTFFree (info
->fontList
->rtfFName
);
1027 RTFFree ((char *) info
->fontList
);
1028 info
->fontList
= fp
;
1030 while (info
->colorList
!= (RTFColor
*) NULL
)
1032 cp
= info
->colorList
->rtfNextColor
;
1033 RTFFree ((char *) info
->colorList
);
1034 info
->colorList
= cp
;
1036 while (info
->styleList
!= (RTFStyle
*) NULL
)
1038 sp
= info
->styleList
->rtfNextStyle
;
1039 eltList
= info
->styleList
->rtfSSEList
;
1040 while (eltList
!= (RTFStyleElt
*) NULL
)
1042 ep
= eltList
->rtfNextSE
;
1043 RTFFree (eltList
->rtfSEText
);
1044 RTFFree ((char *) eltList
);
1047 RTFFree (info
->styleList
->rtfSName
);
1048 RTFFree ((char *) info
->styleList
);
1049 info
->styleList
= sp
;
1052 info
->rtfClass
= -1;
1053 info
->pushedClass
= -1;
1054 info
->pushedChar
= EOF
;
1056 info
->rtfLineNum
= 0;
1057 info
->rtfLinePos
= 0;
1058 info
->prevChar
= EOF
;
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.
1070 void RTFSetInputName(RTF_Info
*info
, char *name
)
1074 if ((info
->inputName
= RTFStrSave (name
)) == (char *) NULL
)
1075 RTFPanic (info
,"RTFSetInputName: out of memory");
1079 char *RTFGetInputName(RTF_Info
*info
)
1081 return (info
->inputName
);
1085 void RTFSetOutputName(RTF_Info
*info
, char *name
)
1089 if ((info
->outputName
= RTFStrSave (name
)) == (char *) NULL
)
1090 RTFPanic (info
, "RTFSetOutputName: out of memory");
1094 char *RTFGetOutputName(RTF_Info
*info
)
1096 return (info
->outputName
);
1101 /* ---------------------------------------------------------------------- */
1104 * Callback table manipulation routines
1109 * Install or return a writer callback for a token class
1112 void RTFSetClassCallback(RTF_Info
*info
, int class, RTFFuncPtr callback
)
1114 if (class >= 0 && class < rtfMaxClass
)
1115 info
->ccb
[class] = callback
;
1119 RTFFuncPtr
RTFGetClassCallback(RTF_Info
*info
, int class)
1121 if (class >= 0 && class < rtfMaxClass
)
1122 return (info
->ccb
[class]);
1123 return ((RTFFuncPtr
) NULL
);
1128 * Install or return a writer callback for a destination type
1131 void RTFSetDestinationCallback(RTF_Info
*info
, int dest
, RTFFuncPtr callback
)
1133 if (dest
>= 0 && dest
< rtfMaxDestination
)
1134 info
->dcb
[dest
] = callback
;
1138 RTFFuncPtr
RTFGetDestinationCallback(RTF_Info
*info
, int dest
)
1140 if (dest
>= 0 && dest
< rtfMaxDestination
)
1141 return (info
->dcb
[dest
]);
1142 return ((RTFFuncPtr
) NULL
);
1146 /* ---------------------------------------------------------------------- */
1149 * Token reading routines
1154 * Read the input stream, invoking the writer's callbacks
1155 * where appropriate.
1158 void RTFRead(RTF_Info
*info
)
1160 while (RTFGetToken (info
) != rtfEOF
)
1161 RTFRouteToken (info
);
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.
1171 void RTFRouteToken(RTF_Info
*info
)
1177 if (info
->rtfClass
< 0 || info
->rtfClass
>= rtfMaxClass
) /* watchdog */
1179 RTFPanic (info
,"Unknown class %d: %s (reader malfunction)",
1180 info
->rtfClass
, info
->rtfTextBuf
);
1182 if (RTFCheckCM (info
, rtfControl
, rtfDestination
))
1184 /* invoke destination-specific callback if there is one */
1185 if ((p
= RTFGetDestinationCallback (info
, info
->rtfMinor
))
1186 != (RTFFuncPtr
) NULL
)
1192 /* invoke class callback if there is one */
1193 if ((p
= RTFGetClassCallback (info
, info
->rtfClass
)) != (RTFFuncPtr
) NULL
)
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
1205 void RTFSkipGroup(RTF_Info
*info
)
1211 while (RTFGetToken (info
) != rtfEOF
)
1213 if (info
->rtfClass
== rtfGroup
)
1215 if (info
->rtfMajor
== rtfBeginGroup
)
1217 else if (info
->rtfMajor
== rtfEndGroup
)
1220 break; /* end of initial group */
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.
1233 int RTFGetToken(RTF_Info
*info
)
1241 _RTFGetToken (info
);
1242 if ((p
= RTFGetReadHook (info
)) != (RTFFuncPtr
) NULL
)
1243 (*p
) (info
); /* give read hook a look at token */
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')))
1250 return (info
->rtfClass
);
1255 * Install or return a token reader hook.
1258 void RTFSetReadHook(RTF_Info
*info
, RTFFuncPtr f
)
1264 RTFFuncPtr
RTFGetReadHook(RTF_Info
*info
)
1266 return (info
->readHook
);
1270 void RTFUngetToken(RTF_Info
*info
)
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
);
1286 int RTFPeekToken(RTF_Info
*info
)
1288 _RTFGetToken (info
);
1289 RTFUngetToken (info
);
1290 return (info
->rtfClass
);
1294 static void _RTFGetToken(RTF_Info
*info
)
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
;
1308 info
->rtfClass
= rtfText
;
1312 /* first check for pushed token from RTFUngetToken() */
1314 if (info
->pushedClass
>= 0)
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;
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.
1331 _RTFGetToken2 (info
);
1332 if (info
->rtfClass
== rtfText
) /* map RTF char to standard code */
1333 info
->rtfMinor
= RTFMapChar (info
, info
->rtfMajor
);
1336 * If auto-charset stuff is activated, see if anything needs doing,
1337 * like reading the charset maps or switching between them.
1340 if (info
->autoCharSetFlags
== 0)
1343 if ((info
->autoCharSetFlags
& rtfReadCharSet
)
1344 && RTFCheckCM (info
, rtfControl
, rtfCharSet
))
1346 ReadCharSetMaps (info
);
1348 else if ((info
->autoCharSetFlags
& rtfSwitchCharSet
)
1349 && RTFCheckCMM (info
, rtfControl
, rtfCharAttr
, rtfFontNum
))
1351 if ((fp
= RTFGetFont (info
, info
->rtfParam
)) != (RTFFont
*) NULL
)
1353 if (strncmp (fp
->rtfFName
, "Symbol", 6) == 0)
1354 info
->curCharSet
= rtfCSSymbol
;
1356 info
->curCharSet
= rtfCSGeneral
;
1357 RTFSetCharSet (info
, info
->curCharSet
);
1360 else if ((info
->autoCharSetFlags
& rtfSwitchCharSet
) && info
->rtfClass
== rtfGroup
)
1362 switch (info
->rtfMajor
)
1365 if (info
->csTop
>= maxCSStack
)
1366 RTFPanic (info
, "_RTFGetToken: stack overflow");
1367 info
->csStack
[info
->csTop
++] = info
->curCharSet
;
1371 * If stack top is 1 at this point, we are ending the
1372 * group started by the initial {, which ends the
1375 if (info
->csTop
<= 0)
1376 RTFPanic (info
,"_RTFGetToken: stack underflow");
1377 else if (info
->csTop
== 1)
1378 info
->rtfClass
= rtfEOF
;
1381 info
->curCharSet
= info
->csStack
[--info
->csTop
];
1382 RTFSetCharSet (info
, info
->curCharSet
);
1390 /* this shouldn't be called anywhere but from _RTFGetToken() */
1392 static void _RTFGetToken2(RTF_Info
*info
)
1399 /* initialize token vars */
1401 info
->rtfClass
= rtfUnknown
;
1402 info
->rtfParam
= rtfNoParam
;
1403 info
->rtfTextBuf
[info
->rtfTextLen
= 0] = '\0';
1405 /* get first character, which may be a pushback from previous token */
1407 if (info
->pushedChar
!= EOF
)
1409 c
= info
->pushedChar
;
1410 info
->rtfTextBuf
[info
->rtfTextLen
++] = c
;
1411 info
->rtfTextBuf
[info
->rtfTextLen
] = '\0';
1412 info
->pushedChar
= EOF
;
1414 else if ((c
= GetChar (info
)) == EOF
)
1416 info
->rtfClass
= rtfEOF
;
1422 info
->rtfClass
= rtfGroup
;
1423 info
->rtfMajor
= rtfBeginGroup
;
1428 info
->rtfClass
= rtfGroup
;
1429 info
->rtfMajor
= rtfEndGroup
;
1435 * Two possibilities here:
1436 * 1) ASCII 9, effectively like \tab control symbol
1437 * 2) literal text char
1439 if (c
== '\t') /* ASCII 9 */
1441 info
->rtfClass
= rtfControl
;
1442 info
->rtfMajor
= rtfSpecialChar
;
1443 info
->rtfMinor
= rtfTab
;
1447 info
->rtfClass
= rtfText
;
1452 if ((c
= GetChar (info
)) == EOF
)
1454 /* early eof, whoops (class is rtfUnknown) */
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>
1465 if (c
== '\'') /* hex char */
1469 if ((c
= GetChar (info
)) != EOF
&& (c2
= GetChar (info
)) != EOF
)
1471 /* should do isxdigit check! */
1472 info
->rtfClass
= rtfText
;
1473 info
->rtfMajor
= RTFCharToHex (c
) * 16
1474 + RTFCharToHex (c2
);
1477 /* early eof, whoops (class is rtfUnknown) */
1482 /*if (index (":{}\\", c) != (char *) NULL)*/ /* escaped char */
1483 if (c
== ':' || c
== '{' || c
== '}' || c
== '\\')
1485 info
->rtfClass
= rtfText
;
1490 /* control symbol */
1491 Lookup (info
, info
->rtfTextBuf
); /* sets class, major, minor */
1497 if ((c
= GetChar (info
)) == EOF
)
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
1510 info
->rtfTextBuf
[info
->rtfTextLen
-1] = '\0';
1511 Lookup (info
, info
->rtfTextBuf
); /* sets class, major, minor */
1513 info
->rtfTextBuf
[info
->rtfTextLen
-1] = c
;
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.
1527 if (c
!= EOF
&& isdigit (c
))
1530 while (isdigit (c
)) /* gobble parameter */
1532 info
->rtfParam
= info
->rtfParam
* 10 + c
- '0';
1533 if ((c
= GetChar (info
)) == EOF
)
1536 info
->rtfParam
*= sign
;
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.
1547 info
->pushedChar
= c
;
1548 info
->rtfTextBuf
[--info
->rtfTextLen
] = '\0';
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
1559 * bumpLine indicates whether the line number should be incremented on
1560 * the *next* input character.
1564 static int GetChar(RTF_Info
*info
)
1571 if ((c
= _RTFGetChar(info
)) != EOF
)
1573 info
->rtfTextBuf
[info
->rtfTextLen
++] = c
;
1574 info
->rtfTextBuf
[info
->rtfTextLen
] = '\0';
1576 if (info
->prevChar
== EOF
)
1578 oldBumpLine
= info
->bumpLine
; /* non-zero if prev char was line ending */
1585 if (info
->prevChar
== '\r') /* oops, previous \r wasn't */
1586 oldBumpLine
= 0; /* really a line ending */
1589 if (oldBumpLine
) /* were we supposed to increment the */
1590 { /* line count on this char? */
1592 info
->rtfLinePos
= 1;
1600 * Synthesize a token by setting the global variables to the
1601 * values supplied. Typically this is followed with a call
1602 * to RTFRouteToken().
1604 * If a param value other than rtfNoParam is passed, it becomes
1605 * part of the token text.
1608 void RTFSetToken(RTF_Info
*info
, int class, int major
, int minor
, int param
, const char *text
)
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
);
1619 sprintf (info
->rtfTextBuf
, "%s%d", text
, param
);
1620 info
->rtfTextLen
= strlen (info
->rtfTextBuf
);
1624 /* ---------------------------------------------------------------------- */
1627 * Routines to handle mapping of RTF character sets
1628 * onto standard characters.
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
1636 * See ../h/README for more information about charset names and codes.
1641 * Initialize charset stuff.
1644 static void CharSetInit(RTF_Info
*info
)
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
;
1661 * Specify the name of a file to be read when auto-charset-file reading is
1665 void RTFSetCharSetMap (RTF_Info
*info
, char *name
, int csId
)
1669 if ((name
= RTFStrSave (name
)) == (char *) NULL
) /* make copy */
1670 RTFPanic (info
,"RTFSetCharSetMap: out of memory");
1674 RTFFree (info
->genCharSetFile
); /* free any previous value */
1675 info
->genCharSetFile
= name
;
1678 RTFFree (info
->symCharSetFile
); /* free any previous value */
1679 info
->symCharSetFile
= name
;
1686 * Do auto-charset-file reading.
1687 * will always use the ansi charset no mater what the value
1688 * of the rtfTextBuf is.
1690 * TODO: add support for other charset in the future.
1694 static void ReadCharSetMaps(RTF_Info
*info
)
1696 char buf
[rtfBufSiz
];
1700 if (info
->genCharSetFile
!= (char *) NULL
)
1701 (void) strcpy (buf
, info
->genCharSetFile
);
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
);
1709 sprintf (buf
, "%s-sym", &info
->rtfTextBuf
[1]);
1710 if (RTFReadCharSetMap (info
, rtfCSSymbol
) == 0)
1711 RTFPanic (info
,"ReadCharSetMaps: Cannot read charset map %s", buf
);
1717 * Convert a CharSetMap (character_name, character) into
1718 * this form : array[character_ident] = character;
1721 int RTFReadCharSetMap(RTF_Info
*info
, int csId
)
1731 return (0); /* illegal charset id */
1734 info
->haveGenCharSet
= 1;
1735 stdCodeArray
= info
->genCharCode
;
1736 for (i
= 0; i
< charSetSize
; i
++)
1738 stdCodeArray
[i
] = rtfSC_nothing
;
1741 for ( i
= 0 ; i
< sizeof(ansi_gen
)/(sizeof(int));i
+=2)
1743 stdCodeArray
[ ansi_gen
[i
+1] ] = ansi_gen
[i
];
1749 info
->haveSymCharSet
= 1;
1750 stdCodeArray
= info
->symCharCode
;
1751 for (i
= 0; i
< charSetSize
; i
++)
1753 stdCodeArray
[i
] = rtfSC_nothing
;
1756 for ( i
= 0 ; i
< sizeof(ansi_sym
)/(sizeof(int));i
+=2)
1758 stdCodeArray
[ ansi_sym
[i
+1] ] = ansi_sym
[i
];
1768 * Given a standard character name (a string), find its code (a number).
1769 * Return -1 if name is unknown.
1772 int RTFStdCharCode(RTF_Info
*info
, const char *name
)
1778 for (i
= 0; i
< rtfSC_MaxChar
; i
++)
1780 if (strcmp (name
, stdCharName
[i
]) == 0)
1788 * Given a standard character code (a number), find its name (a string).
1789 * Return NULL if code is unknown.
1792 const char *RTFStdCharName(RTF_Info
*info
, int code
)
1794 if (code
< 0 || code
>= rtfSC_MaxChar
)
1795 return ((char *) NULL
);
1796 return (stdCharName
[code
]);
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.
1809 int RTFMapChar(RTF_Info
*info
, int c
)
1813 switch (info
->curCharSet
)
1816 if (!info
->haveGenCharSet
)
1818 if (RTFReadCharSetMap (info
, rtfCSGeneral
) == 0)
1819 RTFPanic (info
,"RTFMapChar: cannot read ansi-gen");
1823 if (!info
->haveSymCharSet
)
1825 if (RTFReadCharSetMap (info
, rtfCSSymbol
) == 0)
1826 RTFPanic (info
,"RTFMapChar: cannot read ansi-sym");
1830 if (c
< 0 || c
>= charSetSize
)
1831 return (rtfSC_nothing
);
1832 return (info
->curCharCode
[c
]);
1837 * Set the current character set. If csId is illegal, uses general charset.
1840 void RTFSetCharSet(RTF_Info
*info
, int csId
)
1846 default: /* use general if csId unknown */
1848 info
->curCharCode
= info
->genCharCode
;
1849 info
->curCharSet
= csId
;
1852 info
->curCharCode
= info
->symCharCode
;
1853 info
->curCharSet
= csId
;
1859 int RTFGetCharSet(RTF_Info
*info
)
1861 return (info
->curCharSet
);
1865 /* ---------------------------------------------------------------------- */
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.
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
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.
1889 * Read { \fonttbl ... } destination. Old font tables don't have
1890 * braces around each table entry; try to adjust for that.
1893 static void ReadFontTbl(RTF_Info
*info
)
1896 char buf
[rtfBufSiz
], *bp
;
1898 const char *fn
= "ReadFontTbl";
1904 (void) RTFGetToken (info
);
1905 if (RTFCheckCM (info
, rtfGroup
, rtfEndGroup
))
1907 if (old
< 0) /* first entry - determine tbl type */
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
);
1916 if (old
== 0) /* need to find "{" here */
1918 if (!RTFCheckCM (info
, rtfGroup
, rtfBeginGroup
))
1919 RTFPanic (info
, "%s: missing \"{\"", fn
);
1920 (void) RTFGetToken (info
); /* yes, skip to next token */
1922 if ((fp
= New (RTFFont
)) == (RTFFont
*) NULL
)
1923 RTFPanic (info
, "%s: cannot allocate font entry", fn
);
1925 fp
->rtfNextFont
= info
->fontList
;
1926 info
->fontList
= fp
;
1928 fp
->rtfFName
= (char *) NULL
;
1929 fp
->rtfFAltName
= (char *) NULL
;
1932 fp
->rtfFCharSet
= 0;
1935 fp
->rtfFCodePage
= 0;
1937 while (info
->rtfClass
!= rtfEOF
1938 && !RTFCheckCM (info
, rtfText
, ';')
1939 && !RTFCheckCM (info
, rtfGroup
, rtfEndGroup
))
1941 if (info
->rtfClass
== rtfControl
)
1943 switch (info
->rtfMajor
)
1946 /* ignore token but announce it */
1947 RTFMsg (info
,"%s: unknown token \"%s\"\n",
1948 fn
, info
->rtfTextBuf
);
1951 fp
->rtfFFamily
= info
->rtfMinor
;
1954 switch (info
->rtfMinor
)
1957 break; /* ignore unknown? */
1959 fp
->rtfFNum
= info
->rtfParam
;
1964 switch (info
->rtfMinor
)
1967 break; /* ignore unknown? */
1968 case rtfFontCharSet
:
1969 fp
->rtfFCharSet
= info
->rtfParam
;
1972 fp
->rtfFPitch
= info
->rtfParam
;
1974 case rtfFontCodePage
:
1975 fp
->rtfFCodePage
= info
->rtfParam
;
1978 case rtfFTypeTrueType
:
1979 fp
->rtfFType
= info
->rtfParam
;
1985 else if (RTFCheckCM (info
, rtfGroup
, rtfBeginGroup
)) /* dest */
1987 RTFSkipGroup (info
); /* ignore for now */
1989 else if (info
->rtfClass
== rtfText
) /* font name */
1992 while (info
->rtfClass
== rtfText
1993 && !RTFCheckCM (info
, rtfText
, ';'))
1995 *bp
++ = info
->rtfMajor
;
1996 (void) RTFGetToken (info
);
1999 /* FIX: in some cases the <fontinfo> isn't finished with a semi-column */
2000 if(RTFCheckCM (info
, rtfGroup
, rtfEndGroup
))
2002 RTFUngetToken (info
);
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 */
2014 /* ignore token but announce it */
2015 RTFMsg (info
, "%s: unknown token \"%s\"\n",
2016 fn
,info
->rtfTextBuf
);
2018 (void) RTFGetToken (info
);
2020 if (old
== 0) /* need to see "}" here */
2022 (void) RTFGetToken (info
);
2023 if (!RTFCheckCM (info
, rtfGroup
, rtfEndGroup
))
2024 RTFPanic (info
, "%s: missing \"}\"", fn
);
2027 if (fp
->rtfFNum
== -1)
2028 RTFPanic (info
,"%s: missing font number", fn
);
2030 * Could check other pieces of structure here, too, I suppose.
2032 RTFRouteToken (info
); /* feed "}" back to router */
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
2045 static void ReadColorTbl(RTF_Info
*info
)
2049 const char *fn
= "ReadColorTbl";
2055 (void) RTFGetToken (info
);
2056 if (RTFCheckCM (info
, rtfGroup
, rtfEndGroup
))
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
))
2066 switch (info
->rtfMinor
)
2068 case rtfRed
: cp
->rtfCRed
= info
->rtfParam
; break;
2069 case rtfGreen
: cp
->rtfCGreen
= info
->rtfParam
; break;
2070 case rtfBlue
: cp
->rtfCBlue
= info
->rtfParam
; break;
2074 if (!RTFCheckCM (info
, rtfText
, (int) ';'))
2075 RTFPanic (info
,"%s: malformed entry", fn
);
2077 RTFRouteToken (info
); /* feed "}" back to router */
2082 * The "Normal" style definition doesn't contain any style number,
2083 * all others do. Normal style is given style rtfNormalStyleNum.
2086 static void ReadStyleSheet(RTF_Info
*info
)
2089 RTFStyleElt
*sep
, *sepLast
;
2090 char buf
[rtfBufSiz
], *bp
;
2091 const char *fn
= "ReadStyleSheet";
2097 (void) RTFGetToken (info
);
2098 if (RTFCheckCM (info
, rtfGroup
, rtfEndGroup
))
2100 if ((sp
= New (RTFStyle
)) == (RTFStyle
*) NULL
)
2101 RTFPanic (info
,"%s: cannot allocate stylesheet entry", fn
);
2102 sp
->rtfSName
= (char *) NULL
;
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
);
2116 (void) RTFGetToken (info
);
2117 if (info
->rtfClass
== rtfEOF
2118 || RTFCheckCM (info
, rtfText
, ';'))
2120 if (info
->rtfClass
== rtfControl
)
2122 if (RTFCheckMM (info
, rtfSpecialChar
, rtfOptDest
))
2123 continue; /* ignore "\*" */
2124 if (RTFCheckMM (info
, rtfParAttr
, rtfStyleNum
))
2126 sp
->rtfSNum
= info
->rtfParam
;
2127 sp
->rtfSType
= rtfParStyle
;
2130 if (RTFCheckMM (info
, rtfCharAttr
, rtfCharStyleNum
))
2132 sp
->rtfSNum
= info
->rtfParam
;
2133 sp
->rtfSType
= rtfCharStyle
;
2136 if (RTFCheckMM (info
, rtfSectAttr
, rtfSectStyleNum
))
2138 sp
->rtfSNum
= info
->rtfParam
;
2139 sp
->rtfSType
= rtfSectStyle
;
2142 if (RTFCheckMM (info
, rtfStyleAttr
, rtfBasedOn
))
2144 sp
->rtfSBasedOn
= info
->rtfParam
;
2147 if (RTFCheckMM (info
, rtfStyleAttr
, rtfAdditive
))
2149 sp
->rtfSAdditive
= 1;
2152 if (RTFCheckMM (info
, rtfStyleAttr
, rtfNext
))
2154 sp
->rtfSNextPar
= info
->rtfParam
;
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
))
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
;
2173 else if (RTFCheckCM (info
, rtfGroup
, rtfBeginGroup
))
2176 * This passes over "{\*\keycode ... }, among
2177 * other things. A temporary (perhaps) hack.
2179 RTFSkipGroup (info
);
2182 else if (info
->rtfClass
== rtfText
) /* style name */
2185 while (info
->rtfClass
== rtfText
)
2187 if (info
->rtfMajor
== ';')
2189 /* put back for "for" loop */
2190 (void) RTFUngetToken (info
);
2193 *bp
++ = info
->rtfMajor
;
2194 (void) RTFGetToken (info
);
2197 if ((sp
->rtfSName
= RTFStrSave (buf
)) == (char *) NULL
)
2198 RTFPanic (info
, "%s: cannot allocate style name", fn
);
2200 else /* unrecognized */
2202 /* ignore token but announce it */
2203 RTFMsg (info
, "%s: unknown token \"%s\"\n",
2204 fn
, info
->rtfTextBuf
);
2207 (void) RTFGetToken (info
);
2208 if (!RTFCheckCM (info
, rtfGroup
, rtfEndGroup
))
2209 RTFPanic (info
, "%s: missing \"}\"", fn
);
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.
2219 * Some German RTF writers use "Standard" instead of "Normal".
2221 if (sp
->rtfSName
== (char *) NULL
)
2222 RTFPanic (info
,"%s: missing style name", fn
);
2223 if (sp
->rtfSNum
< 0)
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
;
2230 if (sp
->rtfSNextPar
== -1) /* if \snext not given, */
2231 sp
->rtfSNextPar
= sp
->rtfSNum
; /* next is itself */
2233 RTFRouteToken (info
); /* feed "}" back to router */
2237 static void ReadInfoGroup(RTF_Info
*info
)
2239 RTFSkipGroup (info
);
2240 RTFRouteToken (info
); /* feed "}" back to router */
2244 static void ReadPictGroup(RTF_Info
*info
)
2246 RTFSkipGroup (info
);
2247 RTFRouteToken (info
); /* feed "}" back to router */
2251 static void ReadObjGroup(RTF_Info
*info
)
2253 RTFSkipGroup (info
);
2254 RTFRouteToken (info
); /* feed "}" back to router */
2258 /* ---------------------------------------------------------------------- */
2261 * Routines to return pieces of stylesheet, or font or color tables.
2262 * References to style 0 are mapped onto the Normal style.
2266 RTFStyle
*RTFGetStyle(RTF_Info
*info
, int num
)
2271 return (info
->styleList
);
2272 for (s
= info
->styleList
; s
!= (RTFStyle
*) NULL
; s
= s
->rtfNextStyle
)
2274 if (s
->rtfSNum
== num
)
2277 return (s
); /* NULL if not found */
2281 RTFFont
*RTFGetFont(RTF_Info
*info
, int num
)
2286 return (info
->fontList
);
2287 for (f
= info
->fontList
; f
!= (RTFFont
*) NULL
; f
= f
->rtfNextFont
)
2289 if (f
->rtfFNum
== num
)
2292 return (f
); /* NULL if not found */
2296 RTFColor
*RTFGetColor(RTF_Info
*info
, int num
)
2301 return (info
->colorList
);
2302 for (c
= info
->colorList
; c
!= (RTFColor
*) NULL
; c
= c
->rtfNextColor
)
2304 if (c
->rtfCNum
== num
)
2307 return (c
); /* NULL if not found */
2311 /* ---------------------------------------------------------------------- */
2315 * Expand style n, if there is such a style.
2318 void RTFExpandStyle(RTF_Info
*info
, int n
)
2325 if (n
== -1 || (s
= RTFGetStyle (info
, n
)) == (RTFStyle
*) NULL
)
2327 if (s
->rtfExpanding
!= 0)
2328 RTFPanic (info
,"Style expansion loop, style %d", n
);
2329 s
->rtfExpanding
= 1; /* set expansion flag for loop detection */
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.
2338 if (n
!= s
->rtfSBasedOn
)
2340 RTFSetToken (info
, rtfControl
, rtfParAttr
, rtfStyleNum
,
2341 s
->rtfSBasedOn
, "\\s");
2342 RTFRouteToken (info
);
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.
2349 for (se
= s
->rtfSSEList
; se
!= (RTFStyleElt
*) NULL
; se
= se
->rtfNextSE
)
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
);
2359 s
->rtfExpanding
= 0; /* done - clear expansion flag */
2363 /* ---------------------------------------------------------------------- */
2366 * Control symbol lookup routines
2370 typedef struct RTFKey RTFKey
;
2374 int rtfKMajor
; /* major number */
2375 int rtfKMinor
; /* minor number */
2376 const char *rtfKStr
; /* symbol name */
2377 int rtfKHash
; /* symbol name hash value */
2381 * A minor number of -1 means the token has no minor number
2382 * (all valid minor numbers are >= 0).
2385 static RTFKey rtfKey
[] =
2388 * Special characters
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 },
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 },
2456 * Character formatting attributes
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 },
2498 * Paragraph formatting attributes
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 },
2524 { rtfParAttr
, rtfSubDocument
, "subdocument", 0 },
2526 { rtfParAttr
, rtfRTLPar
, "rtlpar", 0 },
2527 { rtfParAttr
, rtfLTRPar
, "ltrpar", 0 },
2529 { rtfParAttr
, rtfTabPos
, "tx", 0 },
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.
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 },
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 },
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 },
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 },
2618 * Section formatting attributes
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 },
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 },
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 },
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 },
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 },
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 },
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 },
2681 { rtfSectAttr
, rtfRTLSect
, "rtlsect", 0 },
2682 { rtfSectAttr
, rtfLTRSect
, "ltrsect", 0 },
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,*/
2692 * Document formatting attributes
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 },
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 },
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 },
2754 { rtfDocAttr
, rtfLinkStyles
, "linkstyles", 0 },
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 },
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 },
2775 { rtfDocAttr
, rtfRevProtected
, "revprot", 0 },
2776 { rtfDocAttr
, rtfRevisions
, "revisions", 0 },
2777 { rtfDocAttr
, rtfRevDisplay
, "revprop", 0 },
2778 { rtfDocAttr
, rtfRevBar
, "revbar", 0 },
2780 { rtfDocAttr
, rtfAnnotProtected
, "annotprot", 0 },
2782 { rtfDocAttr
, rtfRTLDoc
, "rtldoc", 0 },
2783 { rtfDocAttr
, rtfLTRDoc
, "ltrdoc", 0 },
2789 { rtfStyleAttr
, rtfAdditive
, "additive", 0 },
2790 { rtfStyleAttr
, rtfBasedOn
, "sbasedon", 0 },
2791 { rtfStyleAttr
, rtfNext
, "snext", 0 },
2794 * Picture attributes
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 },
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 },
2821 { rtfPictAttr
, rtfPicMFHasBitmap
, "picbmp", 0 },
2822 { rtfPictAttr
, rtfPicMFBitsPerPixel
, "picbpp", 0 },
2824 { rtfPictAttr
, rtfPicBinary
, "bin", 0 },
2827 * NeXT graphic attributes
2830 { rtfNeXTGrAttr
, rtfNeXTGWidth
, "width", 0 },
2831 { rtfNeXTGrAttr
, rtfNeXTGHeight
, "height", 0 },
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 },
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 },
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 },
2938 * File table attributes
2941 { rtfFileAttr
, rtfFileNum
, "fid", 0 },
2942 { rtfFileAttr
, rtfFileRelPath
, "frelative", 0 },
2943 { rtfFileAttr
, rtfFileOSNum
, "fosnum", 0 },
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 },
2959 { rtfColorName
, rtfRed
, "red", 0 },
2960 { rtfColorName
, rtfGreen
, "green", 0 },
2961 { rtfColorName
, rtfBlue
, "blue", 0 },
2967 { rtfCharSet
, rtfMacCharSet
, "mac", 0 },
2968 { rtfCharSet
, rtfAnsiCharSet
, "ansi", 0 },
2969 { rtfCharSet
, rtfPcCharSet
, "pc", 0 },
2970 { rtfCharSet
, rtfPcaCharSet
, "pca", 0 },
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 },
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 },
2990 { rtfTblAttr
, rtfRTLRow
, "rtlrow", 0 },
2991 { rtfTblAttr
, rtfLTRRow
, "ltrrow", 0 },
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 },
3000 { rtfTblAttr
, rtfCellBordBottom
, "clbrdrb", 0 },
3001 { rtfTblAttr
, rtfCellBordTop
, "clbrdrt", 0 },
3002 { rtfTblAttr
, rtfCellBordLeft
, "clbrdrl", 0 },
3003 { rtfTblAttr
, rtfCellBordRight
, "clbrdrr", 0 },
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 },
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".
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 },
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 },
3038 * Positioning attributes
3041 { rtfPosAttr
, rtfAbsWid
, "absw", 0 },
3042 { rtfPosAttr
, rtfAbsHt
, "absh", 0 },
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 },
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 },
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 },
3073 { rtfPosAttr
, rtfDropCapLines
, "dropcapli", 0 },
3074 { rtfPosAttr
, rtfDropCapType
, "dropcapt", 0 },
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 },
3087 { rtfObjAttr
, rtfObjLinkSelf
, "linkself", 0 },
3088 { rtfObjAttr
, rtfObjLock
, "objupdate", 0 },
3089 { rtfObjAttr
, rtfObjUpdate
, "objlock", 0 },
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 },
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 },
3109 { rtfObjAttr
, rtfObjBookmarkPubObj
, "bkmkpub", 0 },
3110 { rtfObjAttr
, rtfObjPubAutoUpdate
, "pubauto", 0 },
3113 * Associated character formatting attributes
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 },
3137 * Footnote attributes
3140 { rtfFNoteAttr
, rtfFNAlt
, "ftnalt", 0 },
3143 * Key code attributes
3146 { rtfKeyCodeAttr
, rtfAltKey
, "alt", 0 },
3147 { rtfKeyCodeAttr
, rtfShiftKey
, "shift", 0 },
3148 { rtfKeyCodeAttr
, rtfControlKey
, "ctrl", 0 },
3149 { rtfKeyCodeAttr
, rtfFunctionKey
, "fn", 0 },
3152 * Bookmark attributes
3155 { rtfBookmarkAttr
, rtfBookmarkFirstCol
, "bkmkcolf", 0 },
3156 { rtfBookmarkAttr
, rtfBookmarkLastCol
, "bkmkcoll", 0 },
3159 * Index entry attributes
3162 { rtfIndexAttr
, rtfIndexNumber
, "xef", 0 },
3163 { rtfIndexAttr
, rtfIndexBold
, "bxe", 0 },
3164 { rtfIndexAttr
, rtfIndexItalic
, "ixe", 0 },
3167 * Table of contents attributes
3170 { rtfTOCAttr
, rtfTOCType
, "tcf", 0 },
3171 { rtfTOCAttr
, rtfTOCLevel
, "tcl", 0 },
3174 * Drawing object attributes
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 },
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 },
3198 { rtfDrawAttr
, rtfDrawOffsetX
, "dpx", 0 },
3199 { rtfDrawAttr
, rtfDrawSizeX
, "dpxsize", 0 },
3200 { rtfDrawAttr
, rtfDrawOffsetY
, "dpy", 0 },
3201 { rtfDrawAttr
, rtfDrawSizeY
, "dpysize", 0 },
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 },
3221 { rtfDrawAttr
, rtfDrawTextBoxMargin
, "dptxbxmar", 0 },
3222 { rtfDrawAttr
, rtfDrawTextBoxText
, "dptxbxtext", 0 },
3223 { rtfDrawAttr
, rtfDrawRoundRect
, "dproundr", 0 },
3225 { rtfDrawAttr
, rtfDrawPointX
, "dpptx", 0 },
3226 { rtfDrawAttr
, rtfDrawPointY
, "dppty", 0 },
3227 { rtfDrawAttr
, rtfDrawPolyCount
, "dppolycount", 0 },
3229 { rtfDrawAttr
, rtfDrawArcFlipX
, "dparcflipx", 0 },
3230 { rtfDrawAttr
, rtfDrawArcFlipY
, "dparcflipy", 0 },
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 },
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 },
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 },
3266 { rtfDrawAttr
, rtfDrawShadow
, "dpshadow", 0 },
3267 { rtfDrawAttr
, rtfDrawShadowXOffset
, "dpshadx", 0 },
3268 { rtfDrawAttr
, rtfDrawShadowYOffset
, "dpshady", 0 },
3270 { rtfVersion
, -1, "rtf", 0 },
3271 { rtfDefFont
, -1, "deff", 0 },
3273 { 0, -1, (char *) NULL
, 0 }
3278 * Initialize lookup table hash values. Only need to do this once.
3281 static void LookupInit(void)
3283 static int inited
= 0;
3288 for (rp
= rtfKey
; rp
->rtfKStr
!= (char *) NULL
; rp
++)
3289 rp
->rtfKHash
= Hash ((char*)rp
->rtfKStr
);
3296 * Determine major and minor number of control token. If it's
3297 * not found, the class turns into rtfUnknown.
3300 static void Lookup(RTF_Info
*info
, char *s
)
3306 ++s
; /* skip over the leading \ character */
3308 for (rp
= rtfKey
; rp
->rtfKStr
!= (char *) NULL
; rp
++)
3310 if (hash
== rp
->rtfKHash
&& strcmp (s
, rp
->rtfKStr
) == 0)
3312 info
->rtfClass
= rtfControl
;
3313 info
->rtfMajor
= rp
->rtfKMajor
;
3314 info
->rtfMinor
= rp
->rtfKMinor
;
3318 info
->rtfClass
= rtfUnknown
;
3323 * Compute hash value of symbol
3326 static int Hash(char *s
)
3331 while ((c
= *s
++) != '\0')
3337 /* ---------------------------------------------------------------------- */
3340 * Memory allocation routines
3345 * Return pointer to block of size bytes, or NULL if there's
3346 * not enough memory available.
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.
3353 char *_RTFAlloc(int size
)
3355 return HeapAlloc(me_heap
, 0, size
);
3360 * Saves a string on the heap and returns a pointer to it.
3364 char *RTFStrSave(char *s
)
3368 if ((p
= RTFAlloc ((int) (strlen (s
) + 1))) == (char *) NULL
)
3369 return ((char *) NULL
);
3370 return (strcpy (p
, s
));
3374 void RTFFree(char *p
)
3376 HeapFree(me_heap
, 0, p
);
3380 /* ---------------------------------------------------------------------- */
3384 * Token comparison routines
3387 int RTFCheckCM(RTF_Info
*info
, int class, int major
)
3389 return (info
->rtfClass
== class && info
->rtfMajor
== major
);
3393 int RTFCheckCMM(RTF_Info
*info
, int class, int major
, int minor
)
3395 return (info
->rtfClass
== class && info
->rtfMajor
== major
&& info
->rtfMinor
== minor
);
3399 int RTFCheckMM(RTF_Info
*info
, int major
, int minor
)
3401 return (info
->rtfMajor
== major
&& info
->rtfMinor
== minor
);
3405 /* ---------------------------------------------------------------------- */
3408 int RTFCharToHex(char c
)
3413 return (c
- '0'); /* '0'..'9' */
3414 return (c
- 'a' + 10); /* 'a'..'f' */
3418 int RTFHexToChar(int i
)
3422 return (i
- 10 + 'a');
3426 /* ---------------------------------------------------------------------- */
3429 * RTFReadOutputMap() -- Read output translation map
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.
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:
3440 * char *outMap[rtfSC_MaxChar];
3442 * reinit should be non-zero if outMap should be initialized
3447 int RTFReadOutputMap(RTF_Info
*info
, char *outMap
[], int reinit
)
3454 for (i
= 0; i
< rtfSC_MaxChar
; i
++)
3456 outMap
[i
] = (char *) NULL
;
3460 for (i
=0 ;i
< sizeof(text_map
)/sizeof(char*); i
+=2)
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
;
3471 /* ---------------------------------------------------------------------- */
3474 * Open a library file.
3478 void RTFSetOpenLibFileProc(RTF_Info
*info
, FILE *(*proc
)())
3480 info
->libFileOpen
= proc
;
3484 FILE *RTFOpenLibFile (RTF_Info
*info
, char *file
, char *mode
)
3486 if (info
->libFileOpen
== NULL
)
3487 return ((FILE *) NULL
);
3488 return ((*info
->libFileOpen
) (file
, mode
));
3492 /* ---------------------------------------------------------------------- */
3495 * Print message. Default is to send message to stderr
3496 * but this may be overridden with RTFSetMsgProc().
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.
3505 void RTFMsg (RTF_Info
*info
, const char *fmt
, ...)
3507 char buf
[rtfBufSiz
];
3510 va_start (args
,fmt
);
3511 vsprintf (buf
, fmt
, args
);
3513 MESSAGE( "%s", buf
);
3517 /* ---------------------------------------------------------------------- */
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).
3527 static void DefaultPanicProc(RTF_Info
*info
, char *s
)
3535 void RTFPanic(RTF_Info
*info
, const char *fmt
, ...)
3537 char buf
[rtfBufSiz
];
3540 va_start (args
,fmt
);
3541 vsprintf (buf
, fmt
, args
);
3543 (void) strcat (buf
, "\n");
3544 if (info
->prevChar
!= EOF
&& info
->rtfTextBuf
!= (char *) NULL
)
3546 sprintf (buf
+ strlen (buf
),
3547 "Last token read was \"%s\" near line %ld, position %d.\n",
3548 info
->rtfTextBuf
, info
->rtfLineNum
, info
->rtfLinePos
);
3550 DefaultPanicProc(info
, buf
);
3553 /* ---------------------------------------------------------------------- */
3556 * originally from RTF tools' text-writer.c
3558 * text-writer -- RTF-to-text translation writer code.
3560 * Read RTF input, write text of document (text extraction).
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
);
3572 * Initialize the writer.
3576 WriterInit (RTF_Info
*info
)
3578 RTFReadOutputMap (info
, info
->outMap
,1);
3583 BeginFile (RTF_Info
*info
)
3585 /* install class callbacks */
3587 RTFSetClassCallback (info
, rtfText
, TextClass
);
3588 RTFSetClassCallback (info
, rtfControl
, ControlClass
);
3595 * Write out a character. rtfMajor contains the input character, rtfMinor
3596 * contains the corresponding standard character code.
3598 * If the input character isn't in the charset map, try to print some
3599 * representation of it.
3603 TextClass (RTF_Info
*info
)
3605 char buf
[rtfBufSiz
];
3609 if (info
->rtfFormat
== SF_TEXT
)
3610 PutLitChar (info
, info
->rtfMajor
);
3611 else if (info
->rtfMinor
!= rtfSC_nothing
)
3612 PutStdChar (info
, info
->rtfMinor
);
3615 if (info
->rtfMajor
< 128) /* in ASCII range */
3616 sprintf (buf
, "[[%c]]", info
->rtfMajor
);
3618 sprintf (buf
, "[[\\'%02x]]", info
->rtfMajor
);
3619 PutLitStr (info
, buf
);
3625 ControlClass (RTF_Info
*info
)
3629 switch (info
->rtfMajor
)
3631 case rtfDestination
:
3634 case rtfSpecialChar
:
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.
3648 Destination (RTF_Info
*info
)
3652 switch (info
->rtfMinor
)
3656 case rtfFNContNotice
:
3667 RTFSkipGroup (info
);
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.
3679 void SpecialChar (RTF_Info
*info
)
3684 switch (info
->rtfMinor
)
3691 PutLitChar (info
, '\n');
3694 PutStdChar (info
, rtfSC_space
); /* make sure cells are separated */
3697 PutStdChar (info
, rtfSC_nobrkspace
);
3700 PutLitChar (info
, '\t');
3702 case rtfNoBrkHyphen
:
3703 PutStdChar (info
, rtfSC_nobrkhyphen
);
3706 PutStdChar (info
, rtfSC_bullet
);
3709 PutStdChar (info
, rtfSC_emdash
);
3712 PutStdChar (info
, rtfSC_endash
);
3715 PutStdChar (info
, rtfSC_quoteleft
);
3718 PutStdChar (info
, rtfSC_quoteright
);
3721 PutStdChar (info
, rtfSC_quotedblleft
);
3724 PutStdChar (info
, rtfSC_quotedblright
);
3731 * Eventually this should keep track of the destination of the
3732 * current state and only write text when in the initial state.
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. :-)
3739 void PutStdChar (RTF_Info
*info
, int stdCode
)
3742 char *oStr
= (char *) NULL
;
3743 char buf
[rtfBufSiz
];
3745 /* if (stdCode == rtfSC_nothing)
3746 RTFPanic ("Unknown character code, logic error\n");
3750 oStr
= info
->outMap
[stdCode
];
3751 if (oStr
== (char *) NULL
) /* no output sequence in map */
3753 sprintf (buf
, "[[%s]]", RTFStdCharName (info
, stdCode
));
3756 PutLitStr (info
, oStr
);
3759 void PutLitChar (RTF_Info
*info
, int c
)
3761 if( info
->dwOutputCount
>= ( sizeof info
->OutputBuffer
- 1 ) )
3762 RTFFlushOutputBuffer( info
);
3763 info
->OutputBuffer
[info
->dwOutputCount
++] = c
;
3766 void RTFFlushOutputBuffer( RTF_Info
*info
)
3768 info
->OutputBuffer
[info
->dwOutputCount
] = 0;
3769 SendMessageA( info
->hwndEdit
, EM_REPLACESEL
, FALSE
, (LPARAM
) info
->OutputBuffer
);
3770 info
->dwOutputCount
= 0;
3773 static void PutLitStr (RTF_Info
*info
, char *str
)
3775 int len
= strlen( str
);
3777 if( ( len
+ info
->dwOutputCount
+ 1 ) > sizeof info
->OutputBuffer
)
3778 RTFFlushOutputBuffer( info
);
3779 if( ( len
+ 1 ) >= sizeof info
->OutputBuffer
)
3781 SendMessageA( info
->hwndEdit
, EM_REPLACESEL
, FALSE
, (LPARAM
) str
);
3784 strcpy( &info
->OutputBuffer
[info
->dwOutputCount
], str
);
3785 info
->dwOutputCount
+= len
;