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.
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
53 extern HANDLE me_heap;
55 static int _RTFGetChar(RTF_Info *);
56 static void _RTFGetToken (RTF_Info *);
57 static void _RTFGetToken2 (RTF_Info *);
58 static int GetChar (RTF_Info *);
59 static void ReadFontTbl (RTF_Info *);
60 static void ReadColorTbl (RTF_Info *);
61 static void ReadStyleSheet (RTF_Info *);
62 static void ReadInfoGroup (RTF_Info *);
63 static void ReadPictGroup (RTF_Info *);
64 static void ReadObjGroup (RTF_Info *);
65 static void LookupInit (void);
66 static void Lookup (RTF_Info *, char *);
67 static int Hash (char*);
69 static void CharSetInit (RTF_Info *);
70 static void ReadCharSetMaps (RTF_Info *);
74 RTF ANSI character set (\ansi) general map
75 These are taken from the ISO-Latin-1 (ISO-8859-1) encodings, with
78 Field 1 is the standard character name which the character value in
79 field 2 maps onto. (It doesn't mean "to produce the character in field 1,
80 use the value in field 2.)
82 The character value may be given either as a single character (which will be
83 converted to the ASCII value of the character), or in numeric format, either
84 in decimal or 0xyy as hex yy. Single or double quotes may be used to quote
90 rtfSC_nobrkhyphen ,0x1e,
91 rtfSC_opthyphen ,0x1f,
95 rtfSC_numbersign ,'#',
99 rtfSC_quoteright ,'\'',
100 rtfSC_parenleft ,'(',
101 rtfSC_parenright ,')',
119 rtfSC_semicolon ,';',
151 rtfSC_bracketleft ,'[',
152 rtfSC_backslash ,'\\',
153 rtfSC_bracketright ,']',
154 rtfSC_asciicircum ,'^',
155 rtfSC_underscore ,'_',
156 rtfSC_quoteleft ,'`',
183 rtfSC_braceleft ,'{',
185 rtfSC_braceright ,'}',
186 rtfSC_asciitilde ,'~',
187 rtfSC_nobrkspace ,0xa0,
188 rtfSC_exclamdown ,0xa1,
190 rtfSC_sterling ,0xa3,
191 rtfSC_currency ,0xa4,
193 rtfSC_brokenbar ,0xa6,
195 rtfSC_dieresis ,0xa8,
196 rtfSC_copyright ,0xa9,
197 rtfSC_ordfeminine ,0xaa,
198 rtfSC_guillemotleft ,0xab,
199 rtfSC_logicalnot ,0xac,
200 rtfSC_opthyphen ,0xad,
201 rtfSC_registered ,0xae,
204 rtfSC_plusminus ,0xb1,
205 rtfSC_twosuperior ,0xb2,
206 rtfSC_threesuperior ,0xb3,
209 rtfSC_paragraph ,0xb6,
210 rtfSC_periodcentered ,0xb7,
212 rtfSC_onesuperior ,0xb9,
213 rtfSC_ordmasculine ,0xba,
214 rtfSC_guillemotright ,0xbb,
215 rtfSC_onequarter ,0xbc,
217 rtfSC_threequarters ,0xbe,
218 rtfSC_questiondown ,0xbf,
221 rtfSC_Acircumflex ,0xc2,
223 rtfSC_Adieresis ,0xc4,
226 rtfSC_Ccedilla ,0xc7,
229 rtfSC_Ecircumflex ,0xca,
230 rtfSC_Edieresis ,0xcb,
233 rtfSC_Icircumflex ,0xce,
234 rtfSC_Idieresis ,0xcf,
239 rtfSC_Ocircumflex ,0xd4,
241 rtfSC_Odieresis ,0xd6,
242 rtfSC_multiply ,0xd7,
246 rtfSC_Ucircumflex ,0xdb,
247 rtfSC_Udieresis ,0xdc,
250 rtfSC_germandbls ,0xdf,
253 rtfSC_acircumflex ,0xe2,
255 rtfSC_adieresis ,0xe4,
258 rtfSC_ccedilla ,0xe7,
261 rtfSC_ecircumflex ,0xea,
262 rtfSC_edieresis ,0xeb,
265 rtfSC_icircumflex ,0xee,
266 rtfSC_idieresis ,0xef,
271 rtfSC_ocircumflex ,0xf4,
273 rtfSC_odieresis ,0xf6,
278 rtfSC_ucircumflex ,0xfb,
279 rtfSC_udieresis ,0xfc,
282 rtfSC_ydieresis ,0xff
286 * RTF ANSI character set (\ansi) Symbol font map
288 * Field 1 is the standard character name which the character value in
289 * field 2 maps onto. (It doesn't mean "to produce the character in field 1,
290 * use the value in field 2.)
292 * The character value may be given either as a single character (which will be
293 * converted to the ASCII value of the character), or in numeric format, either
294 * in decimal or 0xyy as hex yy. Single or double quotes may be used to quote
302 rtfSC_nobrkhyphen ,0x1e,
303 rtfSC_opthyphen ,0x1f,
306 rtfSC_universal ,'"',
307 rtfSC_mathnumbersign ,'#',
308 rtfSC_existential ,'$',
310 rtfSC_ampersand ,'&',
311 rtfSC_suchthat ,'\\',
312 rtfSC_parenleft ,'(',
313 rtfSC_parenright ,')',
314 rtfSC_mathasterisk ,'*',
317 rtfSC_mathminus ,'-',
331 rtfSC_semicolon ,';',
333 rtfSC_mathequal ,'=',
336 rtfSC_congruent ,'@',
362 rtfSC_bracketleft ,'[',
363 rtfSC_backslash ,'\\',
364 rtfSC_bracketright ,']',
365 rtfSC_asciicircum ,'^',
366 rtfSC_underscore ,'_',
367 rtfSC_quoteleft ,'`',
392 rtfSC_braceleft ,'{',
394 rtfSC_braceright ,'}',
399 * Output sequence map for rtf2text
401 * Field 1 is the standard character name. Field 2 is the output sequence
402 * to produce for that character.
404 * The output sequence is simply a string of characters. If it contains
405 * whitespace, it may be quoted. If it contains quotes, it may be quoted
406 * with a different quote character.
408 * characters in ASCII range (32-127
411 const char *text_map[] = {
514 "arrowdblboth" ,"<=>",
515 "arrowdblleft" ,"<=",
516 "arrowdblright" ,"=>",
523 "copyrightsans" ,"(c)",
535 "greaterequal" ,">=",
536 "guillemotleft" ,"<<",
537 "guillemotright" ,">>",
538 "guilsinglleft" ,"<",
539 "guilsinglright" ,">",
545 "mathnumbersign" ,"#",
557 "periodcentered" ,".",
559 "quotedblbase" ,",,",
560 "quotedblleft" ,"\"",
561 "quotedblright" ,"\"",
562 "quotesinglbase" ,",",
563 "registered" ,"reg.",
564 "registersans" ,"reg.",
565 "threequarters" ,"3/4",
568 "trademarksans" ,"(TM)"
572 * This array is used to map standard character names onto their numeric codes.
573 * The position of the name within the array is the code.
574 * stdcharnames.h is generated in the ../h directory.
577 const char *stdCharName[] =
934 int _RTFGetChar(RTF_Info *info)
940 /* if the last buffer wasn't full, it's EOF */
941 if (info->dwInputSize > 0 &&
942 info->dwInputSize == info->dwInputUsed && info->dwInputSize < sizeof(info->InputBuffer))
944 if (info->dwInputSize <= info->dwInputUsed)
947 info->editstream.dwError = info->editstream.pfnCallback(info->editstream.dwCookie,
948 info->InputBuffer, sizeof(info->InputBuffer), &count);
949 /* if error, it's EOF */
950 if (info->editstream.dwError)
952 /* if no bytes read, it's EOF */
955 info->dwInputSize = count;
956 info->dwInputUsed = 0;
958 ch = info->InputBuffer[info->dwInputUsed++];
964 void RTFSetEditStream(RTF_Info *info, EDITSTREAM *es)
968 info->editstream.dwCookie = es->dwCookie;
969 info->editstream.dwError = es->dwError;
970 info->editstream.pfnCallback = es->pfnCallback;
974 * Initialize the reader. This may be called multiple times,
975 * to read multiple files. The only thing not reset is the input
976 * stream; that must be done with RTFSetStream().
979 void RTFInit(RTF_Info *info)
985 RTFStyleElt *eltList, *ep;
989 if (info->rtfTextBuf == (char *) NULL) /* initialize the text buffers */
991 info->rtfTextBuf = RTFAlloc (rtfBufSiz);
992 info->pushedTextBuf = RTFAlloc (rtfBufSiz);
993 if (info->rtfTextBuf == (char *) NULL
994 || info->pushedTextBuf == (char *) NULL)
995 RTFPanic (info,"Cannot allocate text buffers.");
996 info->rtfTextBuf[0] = info->pushedTextBuf[0] = '\0';
999 RTFFree (info->inputName);
1000 RTFFree (info->outputName);
1001 info->inputName = info->outputName = (char *) NULL;
1003 /* initialize lookup table */
1006 for (i = 0; i < rtfMaxClass; i++)
1007 RTFSetClassCallback (info, i, (RTFFuncPtr) NULL);
1008 for (i = 0; i < rtfMaxDestination; i++)
1009 RTFSetDestinationCallback (info, i, (RTFFuncPtr) NULL);
1011 /* install built-in destination readers */
1012 RTFSetDestinationCallback (info, rtfFontTbl, ReadFontTbl);
1013 RTFSetDestinationCallback (info, rtfColorTbl, ReadColorTbl);
1014 RTFSetDestinationCallback (info, rtfStyleSheet, ReadStyleSheet);
1015 RTFSetDestinationCallback (info, rtfInfo, ReadInfoGroup);
1016 RTFSetDestinationCallback (info, rtfPict, ReadPictGroup);
1017 RTFSetDestinationCallback (info, rtfObject, ReadObjGroup);
1020 RTFSetReadHook (info, (RTFFuncPtr) NULL);
1022 /* dump old lists if necessary */
1024 while (info->fontList != (RTFFont *) NULL)
1026 fp = info->fontList->rtfNextFont;
1027 RTFFree (info->fontList->rtfFName);
1028 RTFFree ((char *) info->fontList);
1029 info->fontList = fp;
1031 while (info->colorList != (RTFColor *) NULL)
1033 cp = info->colorList->rtfNextColor;
1034 RTFFree ((char *) info->colorList);
1035 info->colorList = cp;
1037 while (info->styleList != (RTFStyle *) NULL)
1039 sp = info->styleList->rtfNextStyle;
1040 eltList = info->styleList->rtfSSEList;
1041 while (eltList != (RTFStyleElt *) NULL)
1043 ep = eltList->rtfNextSE;
1044 RTFFree (eltList->rtfSEText);
1045 RTFFree ((char *) eltList);
1048 RTFFree (info->styleList->rtfSName);
1049 RTFFree ((char *) info->styleList);
1050 info->styleList = sp;
1053 info->rtfClass = -1;
1054 info->pushedClass = -1;
1055 info->pushedChar = EOF;
1057 info->rtfLineNum = 0;
1058 info->rtfLinePos = 0;
1059 info->prevChar = EOF;
1067 * Set or get the input or output file name. These are never guaranteed
1068 * to be accurate, only insofar as the calling program makes them so.
1071 void RTFSetInputName(RTF_Info *info, char *name)
1075 if ((info->inputName = RTFStrSave (name)) == (char *) NULL)
1076 RTFPanic (info,"RTFSetInputName: out of memory");
1080 char *RTFGetInputName(RTF_Info *info)
1082 return (info->inputName);
1086 void RTFSetOutputName(RTF_Info *info, char *name)
1090 if ((info->outputName = RTFStrSave (name)) == (char *) NULL)
1091 RTFPanic (info, "RTFSetOutputName: out of memory");
1095 char *RTFGetOutputName(RTF_Info *info)
1097 return (info->outputName);
1102 /* ---------------------------------------------------------------------- */
1105 * Callback table manipulation routines
1110 * Install or return a writer callback for a token class
1113 void RTFSetClassCallback(RTF_Info *info, int class, RTFFuncPtr callback)
1115 if (class >= 0 && class < rtfMaxClass)
1116 info->ccb[class] = callback;
1120 RTFFuncPtr RTFGetClassCallback(RTF_Info *info, int class)
1122 if (class >= 0 && class < rtfMaxClass)
1123 return (info->ccb[class]);
1124 return ((RTFFuncPtr) NULL);
1129 * Install or return a writer callback for a destination type
1132 void RTFSetDestinationCallback(RTF_Info *info, int dest, RTFFuncPtr callback)
1134 if (dest >= 0 && dest < rtfMaxDestination)
1135 info->dcb[dest] = callback;
1139 RTFFuncPtr RTFGetDestinationCallback(RTF_Info *info, int dest)
1141 if (dest >= 0 && dest < rtfMaxDestination)
1142 return (info->dcb[dest]);
1143 return ((RTFFuncPtr) NULL);
1147 /* ---------------------------------------------------------------------- */
1150 * Token reading routines
1155 * Read the input stream, invoking the writer's callbacks
1156 * where appropriate.
1159 void RTFRead(RTF_Info *info)
1161 while (RTFGetToken (info) != rtfEOF)
1162 RTFRouteToken (info);
1167 * Route a token. If it's a destination for which a reader is
1168 * installed, process the destination internally, otherwise
1169 * pass the token to the writer's class callback.
1172 void RTFRouteToken(RTF_Info *info)
1178 if (info->rtfClass < 0 || info->rtfClass >= rtfMaxClass) /* watchdog */
1180 RTFPanic (info,"Unknown class %d: %s (reader malfunction)",
1181 info->rtfClass, info->rtfTextBuf);
1183 if (RTFCheckCM (info, rtfControl, rtfDestination))
1185 /* invoke destination-specific callback if there is one */
1186 if ((p = RTFGetDestinationCallback (info, info->rtfMinor))
1187 != (RTFFuncPtr) NULL)
1193 /* invoke class callback if there is one */
1194 if ((p = RTFGetClassCallback (info, info->rtfClass)) != (RTFFuncPtr) NULL)
1200 * Skip to the end of the current group. When this returns,
1201 * writers that maintain a state stack may want to call their
1202 * state unstacker; global vars will still be set to the group's
1206 void RTFSkipGroup(RTF_Info *info)
1212 while (RTFGetToken (info) != rtfEOF)
1214 if (info->rtfClass == rtfGroup)
1216 if (info->rtfMajor == rtfBeginGroup)
1218 else if (info->rtfMajor == rtfEndGroup)
1221 break; /* end of initial group */
1229 * Read one token. Call the read hook if there is one. The
1230 * token class is the return value. Returns rtfEOF when there
1231 * are no more tokens.
1234 int RTFGetToken(RTF_Info *info)
1242 _RTFGetToken (info);
1243 if ((p = RTFGetReadHook (info)) != (RTFFuncPtr) NULL)
1244 (*p) (info); /* give read hook a look at token */
1246 /* Silently discard newlines, carriage returns, nulls. */
1247 if (!(info->rtfClass == rtfText && info->rtfFormat != SF_TEXT
1248 && (info->rtfMajor == '\r' || info->rtfMajor == '\n' || info->rtfMajor == '\0')))
1251 return (info->rtfClass);
1256 * Install or return a token reader hook.
1259 void RTFSetReadHook(RTF_Info *info, RTFFuncPtr f)
1265 RTFFuncPtr RTFGetReadHook(RTF_Info *info)
1267 return (info->readHook);
1271 void RTFUngetToken(RTF_Info *info)
1275 if (info->pushedClass >= 0) /* there's already an ungotten token */
1276 RTFPanic (info,"cannot unget two tokens");
1277 if (info->rtfClass < 0)
1278 RTFPanic (info,"no token to unget");
1279 info->pushedClass = info->rtfClass;
1280 info->pushedMajor = info->rtfMajor;
1281 info->pushedMinor = info->rtfMinor;
1282 info->pushedParam = info->rtfParam;
1283 (void) strcpy (info->pushedTextBuf, info->rtfTextBuf);
1287 int RTFPeekToken(RTF_Info *info)
1289 _RTFGetToken (info);
1290 RTFUngetToken (info);
1291 return (info->rtfClass);
1295 static void _RTFGetToken(RTF_Info *info)
1301 if (info->rtfFormat == SF_TEXT) {
1302 info->rtfMajor = GetChar (info);
1303 info->rtfMinor = rtfSC_nothing;
1304 info->rtfParam = rtfNoParam;
1305 info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
1306 if (info->rtfMajor == EOF)
1307 info->rtfClass = rtfEOF;
1309 info->rtfClass = rtfText;
1313 /* first check for pushed token from RTFUngetToken() */
1315 if (info->pushedClass >= 0)
1317 info->rtfClass = info->pushedClass;
1318 info->rtfMajor = info->pushedMajor;
1319 info->rtfMinor = info->pushedMinor;
1320 info->rtfParam = info->pushedParam;
1321 (void) strcpy (info->rtfTextBuf, info->pushedTextBuf);
1322 info->rtfTextLen = strlen (info->rtfTextBuf);
1323 info->pushedClass = -1;
1328 * Beyond this point, no token is ever seen twice, which is
1329 * important, e.g., for making sure no "}" pops the font stack twice.
1332 _RTFGetToken2 (info);
1333 if (info->rtfClass == rtfText) /* map RTF char to standard code */
1334 info->rtfMinor = RTFMapChar (info, info->rtfMajor);
1337 * If auto-charset stuff is activated, see if anything needs doing,
1338 * like reading the charset maps or switching between them.
1341 if (info->autoCharSetFlags == 0)
1344 if ((info->autoCharSetFlags & rtfReadCharSet)
1345 && RTFCheckCM (info, rtfControl, rtfCharSet))
1347 ReadCharSetMaps (info);
1349 else if ((info->autoCharSetFlags & rtfSwitchCharSet)
1350 && RTFCheckCMM (info, rtfControl, rtfCharAttr, rtfFontNum))
1352 if ((fp = RTFGetFont (info, info->rtfParam)) != (RTFFont *) NULL)
1354 if (strncmp (fp->rtfFName, "Symbol", 6) == 0)
1355 info->curCharSet = rtfCSSymbol;
1357 info->curCharSet = rtfCSGeneral;
1358 RTFSetCharSet (info, info->curCharSet);
1361 else if ((info->autoCharSetFlags & rtfSwitchCharSet) && info->rtfClass == rtfGroup)
1363 switch (info->rtfMajor)
1366 if (info->csTop >= maxCSStack)
1367 RTFPanic (info, "_RTFGetToken: stack overflow");
1368 info->csStack[info->csTop++] = info->curCharSet;
1372 * If stack top is 1 at this point, we are ending the
1373 * group started by the initial {, which ends the
1376 if (info->csTop <= 0)
1377 RTFPanic (info,"_RTFGetToken: stack underflow");
1378 else if (info->csTop == 1)
1379 info->rtfClass = rtfEOF;
1382 info->curCharSet = info->csStack[--info->csTop];
1383 RTFSetCharSet (info, info->curCharSet);
1391 /* this shouldn't be called anywhere but from _RTFGetToken() */
1393 static void _RTFGetToken2(RTF_Info *info)
1400 /* initialize token vars */
1402 info->rtfClass = rtfUnknown;
1403 info->rtfParam = rtfNoParam;
1404 info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
1406 /* get first character, which may be a pushback from previous token */
1408 if (info->pushedChar != EOF)
1410 c = info->pushedChar;
1411 info->rtfTextBuf[info->rtfTextLen++] = c;
1412 info->rtfTextBuf[info->rtfTextLen] = '\0';
1413 info->pushedChar = EOF;
1415 else if ((c = GetChar (info)) == EOF)
1417 info->rtfClass = rtfEOF;
1423 info->rtfClass = rtfGroup;
1424 info->rtfMajor = rtfBeginGroup;
1429 info->rtfClass = rtfGroup;
1430 info->rtfMajor = rtfEndGroup;
1436 * Two possibilities here:
1437 * 1) ASCII 9, effectively like \tab control symbol
1438 * 2) literal text char
1440 if (c == '\t') /* ASCII 9 */
1442 info->rtfClass = rtfControl;
1443 info->rtfMajor = rtfSpecialChar;
1444 info->rtfMinor = rtfTab;
1448 info->rtfClass = rtfText;
1453 if ((c = GetChar (info)) == EOF)
1455 /* early eof, whoops (class is rtfUnknown) */
1461 * Three possibilities here:
1462 * 1) hex encoded text char, e.g., \'d5, \'d3
1463 * 2) special escaped text char, e.g., \{, \}
1464 * 3) control symbol, e.g., \_, \-, \|, \<10>
1466 if (c == '\'') /* hex char */
1470 if ((c = GetChar (info)) != EOF && (c2 = GetChar (info)) != EOF)
1472 /* should do isxdigit check! */
1473 info->rtfClass = rtfText;
1474 info->rtfMajor = RTFCharToHex (c) * 16
1475 + RTFCharToHex (c2);
1478 /* early eof, whoops (class is rtfUnknown) */
1483 /*if (index (":{}\\", c) != (char *) NULL)*/ /* escaped char */
1484 if (c == ':' || c == '{' || c == '}' || c == '\\')
1486 info->rtfClass = rtfText;
1491 /* control symbol */
1492 Lookup (info, info->rtfTextBuf); /* sets class, major, minor */
1498 if ((c = GetChar (info)) == EOF)
1503 * At this point, the control word is all collected, so the
1504 * major/minor numbers are determined before the parameter
1505 * (if any) is scanned. There will be one too many characters
1506 * in the buffer, though, so fix up before and restore after
1511 info->rtfTextBuf[info->rtfTextLen-1] = '\0';
1512 Lookup (info, info->rtfTextBuf); /* sets class, major, minor */
1514 info->rtfTextBuf[info->rtfTextLen-1] = c;
1517 * Should be looking at first digit of parameter if there
1518 * is one, unless it's negative. In that case, next char
1519 * is '-', so need to gobble next char, and remember sign.
1528 if (c != EOF && isdigit (c))
1531 while (isdigit (c)) /* gobble parameter */
1533 info->rtfParam = info->rtfParam * 10 + c - '0';
1534 if ((c = GetChar (info)) == EOF)
1537 info->rtfParam *= sign;
1540 * If control symbol delimiter was a blank, gobble it.
1541 * Otherwise the character is first char of next token, so
1542 * push it back for next call. In either case, delete the
1543 * delimiter from the token buffer.
1548 info->pushedChar = c;
1549 info->rtfTextBuf[--info->rtfTextLen] = '\0';
1555 * Read the next character from the input. This handles setting the
1556 * current line and position-within-line variables. Those variable are
1557 * set correctly whether lines end with CR, LF, or CRLF (the last being
1560 * bumpLine indicates whether the line number should be incremented on
1561 * the *next* input character.
1565 static int GetChar(RTF_Info *info)
1572 if ((c = _RTFGetChar(info)) != EOF)
1574 info->rtfTextBuf[info->rtfTextLen++] = c;
1575 info->rtfTextBuf[info->rtfTextLen] = '\0';
1577 if (info->prevChar == EOF)
1579 oldBumpLine = info->bumpLine; /* non-zero if prev char was line ending */
1586 if (info->prevChar == '\r') /* oops, previous \r wasn't */
1587 oldBumpLine = 0; /* really a line ending */
1590 if (oldBumpLine) /* were we supposed to increment the */
1591 { /* line count on this char? */
1593 info->rtfLinePos = 1;
1601 * Synthesize a token by setting the global variables to the
1602 * values supplied. Typically this is followed with a call
1603 * to RTFRouteToken().
1605 * If a param value other than rtfNoParam is passed, it becomes
1606 * part of the token text.
1609 void RTFSetToken(RTF_Info *info, int class, int major, int minor, int param, const char *text)
1613 info->rtfClass = class;
1614 info->rtfMajor = major;
1615 info->rtfMinor = minor;
1616 info->rtfParam = param;
1617 if (param == rtfNoParam)
1618 (void) strcpy (info->rtfTextBuf, text);
1620 sprintf (info->rtfTextBuf, "%s%d", text, param);
1621 info->rtfTextLen = strlen (info->rtfTextBuf);
1625 /* ---------------------------------------------------------------------- */
1628 * Routines to handle mapping of RTF character sets
1629 * onto standard characters.
1631 * RTFStdCharCode(name) given char name, produce numeric code
1632 * RTFStdCharName(code) given char code, return name
1633 * RTFMapChar(c) map input (RTF) char code to std code
1634 * RTFSetCharSet(id) select given charset map
1635 * RTFGetCharSet() get current charset map
1637 * See ../h/README for more information about charset names and codes.
1642 * Initialize charset stuff.
1645 static void CharSetInit(RTF_Info *info)
1649 info->autoCharSetFlags = (rtfReadCharSet | rtfSwitchCharSet);
1650 RTFFree (info->genCharSetFile);
1651 info->genCharSetFile = (char *) NULL;
1652 info->haveGenCharSet = 0;
1653 RTFFree (info->symCharSetFile);
1654 info->symCharSetFile = (char *) NULL;
1655 info->haveSymCharSet = 0;
1656 info->curCharSet = rtfCSGeneral;
1657 info->curCharCode = info->genCharCode;
1662 * Specify the name of a file to be read when auto-charset-file reading is
1666 void RTFSetCharSetMap (RTF_Info *info, char *name, int csId)
1670 if ((name = RTFStrSave (name)) == (char *) NULL) /* make copy */
1671 RTFPanic (info,"RTFSetCharSetMap: out of memory");
1675 RTFFree (info->genCharSetFile); /* free any previous value */
1676 info->genCharSetFile = name;
1679 RTFFree (info->symCharSetFile); /* free any previous value */
1680 info->symCharSetFile = name;
1687 * Do auto-charset-file reading.
1688 * will always use the ansi charset no mater what the value
1689 * of the rtfTextBuf is.
1691 * TODO: add support for other charset in the future.
1695 static void ReadCharSetMaps(RTF_Info *info)
1697 char buf[rtfBufSiz];
1701 if (info->genCharSetFile != (char *) NULL)
1702 (void) strcpy (buf, info->genCharSetFile);
1704 sprintf (buf, "%s-gen", &info->rtfTextBuf[1]);
1705 if (RTFReadCharSetMap (info, rtfCSGeneral) == 0)
1706 RTFPanic (info,"ReadCharSetMaps: Cannot read charset map %s", buf);
1707 if (info->symCharSetFile != (char *) NULL)
1708 (void) strcpy (buf, info->symCharSetFile);
1710 sprintf (buf, "%s-sym", &info->rtfTextBuf[1]);
1711 if (RTFReadCharSetMap (info, rtfCSSymbol) == 0)
1712 RTFPanic (info,"ReadCharSetMaps: Cannot read charset map %s", buf);
1718 * Convert a CharSetMap (character_name, character) into
1719 * this form : array[character_ident] = character;
1722 int RTFReadCharSetMap(RTF_Info *info, int csId)
1732 return (0); /* illegal charset id */
1735 info->haveGenCharSet = 1;
1736 stdCodeArray = info->genCharCode;
1737 for (i = 0; i < charSetSize; i++)
1739 stdCodeArray[i] = rtfSC_nothing;
1742 for ( i = 0 ; i< sizeof(ansi_gen)/(sizeof(int));i+=2)
1744 stdCodeArray[ ansi_gen[i+1] ] = ansi_gen[i];
1750 info->haveSymCharSet = 1;
1751 stdCodeArray = info->symCharCode;
1752 for (i = 0; i < charSetSize; i++)
1754 stdCodeArray[i] = rtfSC_nothing;
1757 for ( i = 0 ; i< sizeof(ansi_sym)/(sizeof(int));i+=2)
1759 stdCodeArray[ ansi_sym[i+1] ] = ansi_sym[i];
1769 * Given a standard character name (a string), find its code (a number).
1770 * Return -1 if name is unknown.
1773 int RTFStdCharCode(RTF_Info *info, const char *name)
1779 for (i = 0; i < rtfSC_MaxChar; i++)
1781 if (strcmp (name, stdCharName[i]) == 0)
1789 * Given a standard character code (a number), find its name (a string).
1790 * Return NULL if code is unknown.
1793 const char *RTFStdCharName(RTF_Info *info, int code)
1795 if (code < 0 || code >= rtfSC_MaxChar)
1796 return ((char *) NULL);
1797 return (stdCharName[code]);
1802 * Given an RTF input character code, find standard character code.
1803 * The translator should read the appropriate charset maps when it finds a
1804 * charset control. However, the file might not contain one. In this
1805 * case, no map will be available. When the first attempt is made to
1806 * map a character under these circumstances, RTFMapChar() assumes ANSI
1807 * and reads the map as necessary.
1810 int RTFMapChar(RTF_Info *info, int c)
1814 switch (info->curCharSet)
1817 if (!info->haveGenCharSet)
1819 if (RTFReadCharSetMap (info, rtfCSGeneral) == 0)
1820 RTFPanic (info,"RTFMapChar: cannot read ansi-gen");
1824 if (!info->haveSymCharSet)
1826 if (RTFReadCharSetMap (info, rtfCSSymbol) == 0)
1827 RTFPanic (info,"RTFMapChar: cannot read ansi-sym");
1831 if (c < 0 || c >= charSetSize)
1832 return (rtfSC_nothing);
1833 return (info->curCharCode[c]);
1838 * Set the current character set. If csId is illegal, uses general charset.
1841 void RTFSetCharSet(RTF_Info *info, int csId)
1847 default: /* use general if csId unknown */
1849 info->curCharCode = info->genCharCode;
1850 info->curCharSet = csId;
1853 info->curCharCode = info->symCharCode;
1854 info->curCharSet = csId;
1860 int RTFGetCharSet(RTF_Info *info)
1862 return (info->curCharSet);
1866 /* ---------------------------------------------------------------------- */
1869 * Special destination readers. They gobble the destination so the
1870 * writer doesn't have to deal with them. That's wrong for any
1871 * translator that wants to process any of these itself. In that
1872 * case, these readers should be overridden by installing a different
1873 * destination callback.
1875 * NOTE: The last token read by each of these reader will be the
1876 * destination's terminating '}', which will then be the current token.
1877 * That '}' token is passed to RTFRouteToken() - the writer has already
1878 * seen the '{' that began the destination group, and may have pushed a
1879 * state; it also needs to know at the end of the group that a state
1882 * It's important that rtf.h and the control token lookup table list
1883 * as many symbols as possible, because these destination readers
1884 * unfortunately make strict assumptions about the input they expect,
1885 * and a token of class rtfUnknown will throw them off easily.
1890 * Read { \fonttbl ... } destination. Old font tables don't have
1891 * braces around each table entry; try to adjust for that.
1894 static void ReadFontTbl(RTF_Info *info)
1897 char buf[rtfBufSiz], *bp;
1899 const char *fn = "ReadFontTbl";
1905 (void) RTFGetToken (info);
1906 if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
1908 if (old < 0) /* first entry - determine tbl type */
1910 if (RTFCheckCMM (info, rtfControl, rtfCharAttr, rtfFontNum))
1911 old = 1; /* no brace */
1912 else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))
1913 old = 0; /* brace */
1914 else /* can't tell! */
1915 RTFPanic (info, "%s: Cannot determine format", fn);
1917 if (old == 0) /* need to find "{" here */
1919 if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
1920 RTFPanic (info, "%s: missing \"{\"", fn);
1921 (void) RTFGetToken (info); /* yes, skip to next token */
1923 if ((fp = New (RTFFont)) == (RTFFont *) NULL)
1924 RTFPanic (info, "%s: cannot allocate font entry", fn);
1926 fp->rtfNextFont = info->fontList;
1927 info->fontList = fp;
1929 fp->rtfFName = (char *) NULL;
1930 fp->rtfFAltName = (char *) NULL;
1933 fp->rtfFCharSet = 0;
1936 fp->rtfFCodePage = 0;
1938 while (info->rtfClass != rtfEOF
1939 && !RTFCheckCM (info, rtfText, ';')
1940 && !RTFCheckCM (info, rtfGroup, rtfEndGroup))
1942 if (info->rtfClass == rtfControl)
1944 switch (info->rtfMajor)
1947 /* ignore token but announce it */
1948 RTFMsg (info,"%s: unknown token \"%s\"\n",
1949 fn, info->rtfTextBuf);
1952 fp->rtfFFamily = info->rtfMinor;
1955 switch (info->rtfMinor)
1958 break; /* ignore unknown? */
1960 fp->rtfFNum = info->rtfParam;
1965 switch (info->rtfMinor)
1968 break; /* ignore unknown? */
1969 case rtfFontCharSet:
1970 fp->rtfFCharSet = info->rtfParam;
1973 fp->rtfFPitch = info->rtfParam;
1975 case rtfFontCodePage:
1976 fp->rtfFCodePage = info->rtfParam;
1979 case rtfFTypeTrueType:
1980 fp->rtfFType = info->rtfParam;
1986 else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup)) /* dest */
1988 RTFSkipGroup (info); /* ignore for now */
1990 else if (info->rtfClass == rtfText) /* font name */
1993 while (info->rtfClass == rtfText
1994 && !RTFCheckCM (info, rtfText, ';'))
1996 *bp++ = info->rtfMajor;
1997 (void) RTFGetToken (info);
2000 /* FIX: in some cases the <fontinfo> isn't finished with a semi-column */
2001 if(RTFCheckCM (info, rtfGroup, rtfEndGroup))
2003 RTFUngetToken (info);
2006 fp->rtfFName = RTFStrSave (buf);
2007 if (fp->rtfFName == (char *) NULL)
2008 RTFPanic (info, "%s: cannot allocate font name", fn);
2009 /* already have next token; don't read one */
2010 /* at bottom of loop */
2015 /* ignore token but announce it */
2016 RTFMsg (info, "%s: unknown token \"%s\"\n",
2017 fn,info->rtfTextBuf);
2019 (void) RTFGetToken (info);
2021 if (old == 0) /* need to see "}" here */
2023 (void) RTFGetToken (info);
2024 if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
2025 RTFPanic (info, "%s: missing \"}\"", fn);
2028 if (fp->rtfFNum == -1)
2029 RTFPanic (info,"%s: missing font number", fn);
2031 * Could check other pieces of structure here, too, I suppose.
2033 RTFRouteToken (info); /* feed "}" back to router */
2038 * The color table entries have color values of -1 if
2039 * the default color should be used for the entry (only
2040 * a semi-colon is given in the definition, no color values).
2041 * There will be a problem if a partial entry (1 or 2 but
2042 * not 3 color values) is given. The possibility is ignored
2046 static void ReadColorTbl(RTF_Info *info)
2050 const char *fn = "ReadColorTbl";
2056 (void) RTFGetToken (info);
2057 if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
2059 if ((cp = New (RTFColor)) == (RTFColor *) NULL)
2060 RTFPanic (info,"%s: cannot allocate color entry", fn);
2061 cp->rtfCNum = cnum++;
2062 cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
2063 cp->rtfNextColor = info->colorList;
2064 info->colorList = cp;
2065 while (RTFCheckCM (info, rtfControl, rtfColorName))
2067 switch (info->rtfMinor)
2069 case rtfRed: cp->rtfCRed = info->rtfParam; break;
2070 case rtfGreen: cp->rtfCGreen = info->rtfParam; break;
2071 case rtfBlue: cp->rtfCBlue = info->rtfParam; break;
2075 if (!RTFCheckCM (info, rtfText, (int) ';'))
2076 RTFPanic (info,"%s: malformed entry", fn);
2078 RTFRouteToken (info); /* feed "}" back to router */
2083 * The "Normal" style definition doesn't contain any style number,
2084 * all others do. Normal style is given style rtfNormalStyleNum.
2087 static void ReadStyleSheet(RTF_Info *info)
2090 RTFStyleElt *sep, *sepLast;
2091 char buf[rtfBufSiz], *bp;
2092 const char *fn = "ReadStyleSheet";
2098 (void) RTFGetToken (info);
2099 if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
2101 if ((sp = New (RTFStyle)) == (RTFStyle *) NULL)
2102 RTFPanic (info,"%s: cannot allocate stylesheet entry", fn);
2103 sp->rtfSName = (char *) NULL;
2105 sp->rtfSType = rtfParStyle;
2106 sp->rtfSAdditive = 0;
2107 sp->rtfSBasedOn = rtfNoStyleNum;
2108 sp->rtfSNextPar = -1;
2109 sp->rtfSSEList = sepLast = (RTFStyleElt *) NULL;
2110 sp->rtfNextStyle = info->styleList;
2111 sp->rtfExpanding = 0;
2112 info->styleList = sp;
2113 if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
2114 RTFPanic (info,"%s: missing \"{\"", fn);
2117 (void) RTFGetToken (info);
2118 if (info->rtfClass == rtfEOF
2119 || RTFCheckCM (info, rtfText, ';'))
2121 if (info->rtfClass == rtfControl)
2123 if (RTFCheckMM (info, rtfSpecialChar, rtfOptDest))
2124 continue; /* ignore "\*" */
2125 if (RTFCheckMM (info, rtfParAttr, rtfStyleNum))
2127 sp->rtfSNum = info->rtfParam;
2128 sp->rtfSType = rtfParStyle;
2131 if (RTFCheckMM (info, rtfCharAttr, rtfCharStyleNum))
2133 sp->rtfSNum = info->rtfParam;
2134 sp->rtfSType = rtfCharStyle;
2137 if (RTFCheckMM (info, rtfSectAttr, rtfSectStyleNum))
2139 sp->rtfSNum = info->rtfParam;
2140 sp->rtfSType = rtfSectStyle;
2143 if (RTFCheckMM (info, rtfStyleAttr, rtfBasedOn))
2145 sp->rtfSBasedOn = info->rtfParam;
2148 if (RTFCheckMM (info, rtfStyleAttr, rtfAdditive))
2150 sp->rtfSAdditive = 1;
2153 if (RTFCheckMM (info, rtfStyleAttr, rtfNext))
2155 sp->rtfSNextPar = info->rtfParam;
2158 if ((sep = New (RTFStyleElt)) == (RTFStyleElt *) NULL)
2159 RTFPanic (info,"%s: cannot allocate style element", fn);
2160 sep->rtfSEClass = info->rtfClass;
2161 sep->rtfSEMajor = info->rtfMajor;
2162 sep->rtfSEMinor = info->rtfMinor;
2163 sep->rtfSEParam = info->rtfParam;
2164 if ((sep->rtfSEText = RTFStrSave (info->rtfTextBuf))
2166 RTFPanic (info,"%s: cannot allocate style element text", fn);
2167 if (sepLast == (RTFStyleElt *) NULL)
2168 sp->rtfSSEList = sep; /* first element */
2169 else /* add to end */
2170 sepLast->rtfNextSE = sep;
2171 sep->rtfNextSE = (RTFStyleElt *) NULL;
2174 else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))
2177 * This passes over "{\*\keycode ... }, among
2178 * other things. A temporary (perhaps) hack.
2180 RTFSkipGroup (info);
2183 else if (info->rtfClass == rtfText) /* style name */
2186 while (info->rtfClass == rtfText)
2188 if (info->rtfMajor == ';')
2190 /* put back for "for" loop */
2191 (void) RTFUngetToken (info);
2194 *bp++ = info->rtfMajor;
2195 (void) RTFGetToken (info);
2198 if ((sp->rtfSName = RTFStrSave (buf)) == (char *) NULL)
2199 RTFPanic (info, "%s: cannot allocate style name", fn);
2201 else /* unrecognized */
2203 /* ignore token but announce it */
2204 RTFMsg (info, "%s: unknown token \"%s\"\n",
2205 fn, info->rtfTextBuf);
2208 (void) RTFGetToken (info);
2209 if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
2210 RTFPanic (info, "%s: missing \"}\"", fn);
2213 * Check over the style structure. A name is a must.
2214 * If no style number was specified, check whether it's the
2215 * Normal style (in which case it's given style number
2216 * rtfNormalStyleNum). Note that some "normal" style names
2217 * just begin with "Normal" and can have other stuff following,
2218 * e.g., "Normal,Times 10 point". Ugh.
2220 * Some German RTF writers use "Standard" instead of "Normal".
2222 if (sp->rtfSName == (char *) NULL)
2223 RTFPanic (info,"%s: missing style name", fn);
2224 if (sp->rtfSNum < 0)
2226 if (strncmp (buf, "Normal", 6) != 0
2227 && strncmp (buf, "Standard", 8) != 0)
2228 RTFPanic (info,"%s: missing style number", fn);
2229 sp->rtfSNum = rtfNormalStyleNum;
2231 if (sp->rtfSNextPar == -1) /* if \snext not given, */
2232 sp->rtfSNextPar = sp->rtfSNum; /* next is itself */
2234 RTFRouteToken (info); /* feed "}" back to router */
2238 static void ReadInfoGroup(RTF_Info *info)
2240 RTFSkipGroup (info);
2241 RTFRouteToken (info); /* feed "}" back to router */
2245 static void ReadPictGroup(RTF_Info *info)
2247 RTFSkipGroup (info);
2248 RTFRouteToken (info); /* feed "}" back to router */
2252 static void ReadObjGroup(RTF_Info *info)
2254 RTFSkipGroup (info);
2255 RTFRouteToken (info); /* feed "}" back to router */
2259 /* ---------------------------------------------------------------------- */
2262 * Routines to return pieces of stylesheet, or font or color tables.
2263 * References to style 0 are mapped onto the Normal style.
2267 RTFStyle *RTFGetStyle(RTF_Info *info, int num)
2272 return (info->styleList);
2273 for (s = info->styleList; s != (RTFStyle *) NULL; s = s->rtfNextStyle)
2275 if (s->rtfSNum == num)
2278 return (s); /* NULL if not found */
2282 RTFFont *RTFGetFont(RTF_Info *info, int num)
2287 return (info->fontList);
2288 for (f = info->fontList; f != (RTFFont *) NULL; f = f->rtfNextFont)
2290 if (f->rtfFNum == num)
2293 return (f); /* NULL if not found */
2297 RTFColor *RTFGetColor(RTF_Info *info, int num)
2302 return (info->colorList);
2303 for (c = info->colorList; c != (RTFColor *) NULL; c = c->rtfNextColor)
2305 if (c->rtfCNum == num)
2308 return (c); /* NULL if not found */
2312 /* ---------------------------------------------------------------------- */
2316 * Expand style n, if there is such a style.
2319 void RTFExpandStyle(RTF_Info *info, int n)
2326 if (n == -1 || (s = RTFGetStyle (info, n)) == (RTFStyle *) NULL)
2328 if (s->rtfExpanding != 0)
2329 RTFPanic (info,"Style expansion loop, style %d", n);
2330 s->rtfExpanding = 1; /* set expansion flag for loop detection */
2332 * Expand "based-on" style (unless it's the same as the current
2333 * style -- Normal style usually gives itself as its own based-on
2334 * style). Based-on style expansion is done by synthesizing
2335 * the token that the writer needs to see in order to trigger
2336 * another style expansion, and feeding to token back through
2337 * the router so the writer sees it.
2339 if (n != s->rtfSBasedOn)
2341 RTFSetToken (info, rtfControl, rtfParAttr, rtfStyleNum,
2342 s->rtfSBasedOn, "\\s");
2343 RTFRouteToken (info);
2346 * Now route the tokens unique to this style. RTFSetToken()
2347 * isn't used because it would add the param value to the end
2348 * of the token text, which already has it in.
2350 for (se = s->rtfSSEList; se != (RTFStyleElt *) NULL; se = se->rtfNextSE)
2352 info->rtfClass = se->rtfSEClass;
2353 info->rtfMajor = se->rtfSEMajor;
2354 info->rtfMinor = se->rtfSEMinor;
2355 info->rtfParam = se->rtfSEParam;
2356 (void) strcpy (info->rtfTextBuf, se->rtfSEText);
2357 info->rtfTextLen = strlen (info->rtfTextBuf);
2358 RTFRouteToken (info);
2360 s->rtfExpanding = 0; /* done - clear expansion flag */
2364 /* ---------------------------------------------------------------------- */
2367 * Control symbol lookup routines
2371 typedef struct RTFKey RTFKey;
2375 int rtfKMajor; /* major number */
2376 int rtfKMinor; /* minor number */
2377 const char *rtfKStr; /* symbol name */
2378 int rtfKHash; /* symbol name hash value */
2382 * A minor number of -1 means the token has no minor number
2383 * (all valid minor numbers are >= 0).
2386 static RTFKey rtfKey[] =
2389 * Special characters
2392 { rtfSpecialChar, rtfIIntVersion, "vern", 0 },
2393 { rtfSpecialChar, rtfICreateTime, "creatim", 0 },
2394 { rtfSpecialChar, rtfIRevisionTime, "revtim", 0 },
2395 { rtfSpecialChar, rtfIPrintTime, "printim", 0 },
2396 { rtfSpecialChar, rtfIBackupTime, "buptim", 0 },
2397 { rtfSpecialChar, rtfIEditTime, "edmins", 0 },
2398 { rtfSpecialChar, rtfIYear, "yr", 0 },
2399 { rtfSpecialChar, rtfIMonth, "mo", 0 },
2400 { rtfSpecialChar, rtfIDay, "dy", 0 },
2401 { rtfSpecialChar, rtfIHour, "hr", 0 },
2402 { rtfSpecialChar, rtfIMinute, "min", 0 },
2403 { rtfSpecialChar, rtfISecond, "sec", 0 },
2404 { rtfSpecialChar, rtfINPages, "nofpages", 0 },
2405 { rtfSpecialChar, rtfINWords, "nofwords", 0 },
2406 { rtfSpecialChar, rtfINChars, "nofchars", 0 },
2407 { rtfSpecialChar, rtfIIntID, "id", 0 },
2409 { rtfSpecialChar, rtfCurHeadDate, "chdate", 0 },
2410 { rtfSpecialChar, rtfCurHeadDateLong, "chdpl", 0 },
2411 { rtfSpecialChar, rtfCurHeadDateAbbrev, "chdpa", 0 },
2412 { rtfSpecialChar, rtfCurHeadTime, "chtime", 0 },
2413 { rtfSpecialChar, rtfCurHeadPage, "chpgn", 0 },
2414 { rtfSpecialChar, rtfSectNum, "sectnum", 0 },
2415 { rtfSpecialChar, rtfCurFNote, "chftn", 0 },
2416 { rtfSpecialChar, rtfCurAnnotRef, "chatn", 0 },
2417 { rtfSpecialChar, rtfFNoteSep, "chftnsep", 0 },
2418 { rtfSpecialChar, rtfFNoteCont, "chftnsepc", 0 },
2419 { rtfSpecialChar, rtfCell, "cell", 0 },
2420 { rtfSpecialChar, rtfRow, "row", 0 },
2421 { rtfSpecialChar, rtfPar, "par", 0 },
2422 /* newline and carriage return are synonyms for */
2423 /* \par when they are preceded by a \ character */
2424 { rtfSpecialChar, rtfPar, "\n", 0 },
2425 { rtfSpecialChar, rtfPar, "\r", 0 },
2426 { rtfSpecialChar, rtfSect, "sect", 0 },
2427 { rtfSpecialChar, rtfPage, "page", 0 },
2428 { rtfSpecialChar, rtfColumn, "column", 0 },
2429 { rtfSpecialChar, rtfLine, "line", 0 },
2430 { rtfSpecialChar, rtfSoftPage, "softpage", 0 },
2431 { rtfSpecialChar, rtfSoftColumn, "softcol", 0 },
2432 { rtfSpecialChar, rtfSoftLine, "softline", 0 },
2433 { rtfSpecialChar, rtfSoftLineHt, "softlheight", 0 },
2434 { rtfSpecialChar, rtfTab, "tab", 0 },
2435 { rtfSpecialChar, rtfEmDash, "emdash", 0 },
2436 { rtfSpecialChar, rtfEnDash, "endash", 0 },
2437 { rtfSpecialChar, rtfEmSpace, "emspace", 0 },
2438 { rtfSpecialChar, rtfEnSpace, "enspace", 0 },
2439 { rtfSpecialChar, rtfBullet, "bullet", 0 },
2440 { rtfSpecialChar, rtfLQuote, "lquote", 0 },
2441 { rtfSpecialChar, rtfRQuote, "rquote", 0 },
2442 { rtfSpecialChar, rtfLDblQuote, "ldblquote", 0 },
2443 { rtfSpecialChar, rtfRDblQuote, "rdblquote", 0 },
2444 { rtfSpecialChar, rtfFormula, "|", 0 },
2445 { rtfSpecialChar, rtfNoBrkSpace, "~", 0 },
2446 { rtfSpecialChar, rtfNoReqHyphen, "-", 0 },
2447 { rtfSpecialChar, rtfNoBrkHyphen, "_", 0 },
2448 { rtfSpecialChar, rtfOptDest, "*", 0 },
2449 { rtfSpecialChar, rtfLTRMark, "ltrmark", 0 },
2450 { rtfSpecialChar, rtfRTLMark, "rtlmark", 0 },
2451 { rtfSpecialChar, rtfNoWidthJoiner, "zwj", 0 },
2452 { rtfSpecialChar, rtfNoWidthNonJoiner, "zwnj", 0 },
2453 /* is this valid? */
2454 { rtfSpecialChar, rtfCurHeadPict, "chpict", 0 },
2457 * Character formatting attributes
2460 { rtfCharAttr, rtfPlain, "plain", 0 },
2461 { rtfCharAttr, rtfBold, "b", 0 },
2462 { rtfCharAttr, rtfAllCaps, "caps", 0 },
2463 { rtfCharAttr, rtfDeleted, "deleted", 0 },
2464 { rtfCharAttr, rtfSubScript, "dn", 0 },
2465 { rtfCharAttr, rtfSubScrShrink, "sub", 0 },
2466 { rtfCharAttr, rtfNoSuperSub, "nosupersub", 0 },
2467 { rtfCharAttr, rtfExpand, "expnd", 0 },
2468 { rtfCharAttr, rtfExpandTwips, "expndtw", 0 },
2469 { rtfCharAttr, rtfKerning, "kerning", 0 },
2470 { rtfCharAttr, rtfFontNum, "f", 0 },
2471 { rtfCharAttr, rtfFontSize, "fs", 0 },
2472 { rtfCharAttr, rtfItalic, "i", 0 },
2473 { rtfCharAttr, rtfOutline, "outl", 0 },
2474 { rtfCharAttr, rtfRevised, "revised", 0 },
2475 { rtfCharAttr, rtfRevAuthor, "revauth", 0 },
2476 { rtfCharAttr, rtfRevDTTM, "revdttm", 0 },
2477 { rtfCharAttr, rtfSmallCaps, "scaps", 0 },
2478 { rtfCharAttr, rtfShadow, "shad", 0 },
2479 { rtfCharAttr, rtfStrikeThru, "strike", 0 },
2480 { rtfCharAttr, rtfUnderline, "ul", 0 },
2481 { rtfCharAttr, rtfDotUnderline, "uld", 0 },
2482 { rtfCharAttr, rtfDbUnderline, "uldb", 0 },
2483 { rtfCharAttr, rtfNoUnderline, "ulnone", 0 },
2484 { rtfCharAttr, rtfWordUnderline, "ulw", 0 },
2485 { rtfCharAttr, rtfSuperScript, "up", 0 },
2486 { rtfCharAttr, rtfSuperScrShrink, "super", 0 },
2487 { rtfCharAttr, rtfInvisible, "v", 0 },
2488 { rtfCharAttr, rtfForeColor, "cf", 0 },
2489 { rtfCharAttr, rtfBackColor, "cb", 0 },
2490 { rtfCharAttr, rtfRTLChar, "rtlch", 0 },
2491 { rtfCharAttr, rtfLTRChar, "ltrch", 0 },
2492 { rtfCharAttr, rtfCharStyleNum, "cs", 0 },
2493 { rtfCharAttr, rtfCharCharSet, "cchs", 0 },
2494 { rtfCharAttr, rtfLanguage, "lang", 0 },
2495 /* this has disappeared from spec 1.2 */
2496 { rtfCharAttr, rtfGray, "gray", 0 },
2499 * Paragraph formatting attributes
2502 { rtfParAttr, rtfParDef, "pard", 0 },
2503 { rtfParAttr, rtfStyleNum, "s", 0 },
2504 { rtfParAttr, rtfHyphenate, "hyphpar", 0 },
2505 { rtfParAttr, rtfInTable, "intbl", 0 },
2506 { rtfParAttr, rtfKeep, "keep", 0 },
2507 { rtfParAttr, rtfNoWidowControl, "nowidctlpar", 0 },
2508 { rtfParAttr, rtfKeepNext, "keepn", 0 },
2509 { rtfParAttr, rtfOutlineLevel, "level", 0 },
2510 { rtfParAttr, rtfNoLineNum, "noline", 0 },
2511 { rtfParAttr, rtfPBBefore, "pagebb", 0 },
2512 { rtfParAttr, rtfSideBySide, "sbys", 0 },
2513 { rtfParAttr, rtfQuadLeft, "ql", 0 },
2514 { rtfParAttr, rtfQuadRight, "qr", 0 },
2515 { rtfParAttr, rtfQuadJust, "qj", 0 },
2516 { rtfParAttr, rtfQuadCenter, "qc", 0 },
2517 { rtfParAttr, rtfFirstIndent, "fi", 0 },
2518 { rtfParAttr, rtfLeftIndent, "li", 0 },
2519 { rtfParAttr, rtfRightIndent, "ri", 0 },
2520 { rtfParAttr, rtfSpaceBefore, "sb", 0 },
2521 { rtfParAttr, rtfSpaceAfter, "sa", 0 },
2522 { rtfParAttr, rtfSpaceBetween, "sl", 0 },
2523 { rtfParAttr, rtfSpaceMultiply, "slmult", 0 },
2525 { rtfParAttr, rtfSubDocument, "subdocument", 0 },
2527 { rtfParAttr, rtfRTLPar, "rtlpar", 0 },
2528 { rtfParAttr, rtfLTRPar, "ltrpar", 0 },
2530 { rtfParAttr, rtfTabPos, "tx", 0 },
2532 * FrameMaker writes \tql (to mean left-justified tab, apparently)
2533 * although it's not in the spec. It's also redundant, since lj
2534 * tabs are the default.
2536 { rtfParAttr, rtfTabLeft, "tql", 0 },
2537 { rtfParAttr, rtfTabRight, "tqr", 0 },
2538 { rtfParAttr, rtfTabCenter, "tqc", 0 },
2539 { rtfParAttr, rtfTabDecimal, "tqdec", 0 },
2540 { rtfParAttr, rtfTabBar, "tb", 0 },
2541 { rtfParAttr, rtfLeaderDot, "tldot", 0 },
2542 { rtfParAttr, rtfLeaderHyphen, "tlhyph", 0 },
2543 { rtfParAttr, rtfLeaderUnder, "tlul", 0 },
2544 { rtfParAttr, rtfLeaderThick, "tlth", 0 },
2545 { rtfParAttr, rtfLeaderEqual, "tleq", 0 },
2547 { rtfParAttr, rtfParLevel, "pnlvl", 0 },
2548 { rtfParAttr, rtfParBullet, "pnlvlblt", 0 },
2549 { rtfParAttr, rtfParSimple, "pnlvlbody", 0 },
2550 { rtfParAttr, rtfParNumCont, "pnlvlcont", 0 },
2551 { rtfParAttr, rtfParNumOnce, "pnnumonce", 0 },
2552 { rtfParAttr, rtfParNumAcross, "pnacross", 0 },
2553 { rtfParAttr, rtfParHangIndent, "pnhang", 0 },
2554 { rtfParAttr, rtfParNumRestart, "pnrestart", 0 },
2555 { rtfParAttr, rtfParNumCardinal, "pncard", 0 },
2556 { rtfParAttr, rtfParNumDecimal, "pndec", 0 },
2557 { rtfParAttr, rtfParNumULetter, "pnucltr", 0 },
2558 { rtfParAttr, rtfParNumURoman, "pnucrm", 0 },
2559 { rtfParAttr, rtfParNumLLetter, "pnlcltr", 0 },
2560 { rtfParAttr, rtfParNumLRoman, "pnlcrm", 0 },
2561 { rtfParAttr, rtfParNumOrdinal, "pnord", 0 },
2562 { rtfParAttr, rtfParNumOrdinalText, "pnordt", 0 },
2563 { rtfParAttr, rtfParNumBold, "pnb", 0 },
2564 { rtfParAttr, rtfParNumItalic, "pni", 0 },
2565 { rtfParAttr, rtfParNumAllCaps, "pncaps", 0 },
2566 { rtfParAttr, rtfParNumSmallCaps, "pnscaps", 0 },
2567 { rtfParAttr, rtfParNumUnder, "pnul", 0 },
2568 { rtfParAttr, rtfParNumDotUnder, "pnuld", 0 },
2569 { rtfParAttr, rtfParNumDbUnder, "pnuldb", 0 },
2570 { rtfParAttr, rtfParNumNoUnder, "pnulnone", 0 },
2571 { rtfParAttr, rtfParNumWordUnder, "pnulw", 0 },
2572 { rtfParAttr, rtfParNumStrikethru, "pnstrike", 0 },
2573 { rtfParAttr, rtfParNumForeColor, "pncf", 0 },
2574 { rtfParAttr, rtfParNumFont, "pnf", 0 },
2575 { rtfParAttr, rtfParNumFontSize, "pnfs", 0 },
2576 { rtfParAttr, rtfParNumIndent, "pnindent", 0 },
2577 { rtfParAttr, rtfParNumSpacing, "pnsp", 0 },
2578 { rtfParAttr, rtfParNumInclPrev, "pnprev", 0 },
2579 { rtfParAttr, rtfParNumCenter, "pnqc", 0 },
2580 { rtfParAttr, rtfParNumLeft, "pnql", 0 },
2581 { rtfParAttr, rtfParNumRight, "pnqr", 0 },
2582 { rtfParAttr, rtfParNumStartAt, "pnstart", 0 },
2584 { rtfParAttr, rtfBorderTop, "brdrt", 0 },
2585 { rtfParAttr, rtfBorderBottom, "brdrb", 0 },
2586 { rtfParAttr, rtfBorderLeft, "brdrl", 0 },
2587 { rtfParAttr, rtfBorderRight, "brdrr", 0 },
2588 { rtfParAttr, rtfBorderBetween, "brdrbtw", 0 },
2589 { rtfParAttr, rtfBorderBar, "brdrbar", 0 },
2590 { rtfParAttr, rtfBorderBox, "box", 0 },
2591 { rtfParAttr, rtfBorderSingle, "brdrs", 0 },
2592 { rtfParAttr, rtfBorderThick, "brdrth", 0 },
2593 { rtfParAttr, rtfBorderShadow, "brdrsh", 0 },
2594 { rtfParAttr, rtfBorderDouble, "brdrdb", 0 },
2595 { rtfParAttr, rtfBorderDot, "brdrdot", 0 },
2596 { rtfParAttr, rtfBorderDot, "brdrdash", 0 },
2597 { rtfParAttr, rtfBorderHair, "brdrhair", 0 },
2598 { rtfParAttr, rtfBorderWidth, "brdrw", 0 },
2599 { rtfParAttr, rtfBorderColor, "brdrcf", 0 },
2600 { rtfParAttr, rtfBorderSpace, "brsp", 0 },
2602 { rtfParAttr, rtfShading, "shading", 0 },
2603 { rtfParAttr, rtfBgPatH, "bghoriz", 0 },
2604 { rtfParAttr, rtfBgPatV, "bgvert", 0 },
2605 { rtfParAttr, rtfFwdDiagBgPat, "bgfdiag", 0 },
2606 { rtfParAttr, rtfBwdDiagBgPat, "bgbdiag", 0 },
2607 { rtfParAttr, rtfHatchBgPat, "bgcross", 0 },
2608 { rtfParAttr, rtfDiagHatchBgPat, "bgdcross", 0 },
2609 { rtfParAttr, rtfDarkBgPatH, "bgdkhoriz", 0 },
2610 { rtfParAttr, rtfDarkBgPatV, "bgdkvert", 0 },
2611 { rtfParAttr, rtfFwdDarkBgPat, "bgdkfdiag", 0 },
2612 { rtfParAttr, rtfBwdDarkBgPat, "bgdkbdiag", 0 },
2613 { rtfParAttr, rtfDarkHatchBgPat, "bgdkcross", 0 },
2614 { rtfParAttr, rtfDarkDiagHatchBgPat, "bgdkdcross", 0 },
2615 { rtfParAttr, rtfBgPatLineColor, "cfpat", 0 },
2616 { rtfParAttr, rtfBgPatColor, "cbpat", 0 },
2619 * Section formatting attributes
2622 { rtfSectAttr, rtfSectDef, "sectd", 0 },
2623 { rtfSectAttr, rtfENoteHere, "endnhere", 0 },
2624 { rtfSectAttr, rtfPrtBinFirst, "binfsxn", 0 },
2625 { rtfSectAttr, rtfPrtBin, "binsxn", 0 },
2626 { rtfSectAttr, rtfSectStyleNum, "ds", 0 },
2628 { rtfSectAttr, rtfNoBreak, "sbknone", 0 },
2629 { rtfSectAttr, rtfColBreak, "sbkcol", 0 },
2630 { rtfSectAttr, rtfPageBreak, "sbkpage", 0 },
2631 { rtfSectAttr, rtfEvenBreak, "sbkeven", 0 },
2632 { rtfSectAttr, rtfOddBreak, "sbkodd", 0 },
2634 { rtfSectAttr, rtfColumns, "cols", 0 },
2635 { rtfSectAttr, rtfColumnSpace, "colsx", 0 },
2636 { rtfSectAttr, rtfColumnNumber, "colno", 0 },
2637 { rtfSectAttr, rtfColumnSpRight, "colsr", 0 },
2638 { rtfSectAttr, rtfColumnWidth, "colw", 0 },
2639 { rtfSectAttr, rtfColumnLine, "linebetcol", 0 },
2641 { rtfSectAttr, rtfLineModulus, "linemod", 0 },
2642 { rtfSectAttr, rtfLineDist, "linex", 0 },
2643 { rtfSectAttr, rtfLineStarts, "linestarts", 0 },
2644 { rtfSectAttr, rtfLineRestart, "linerestart", 0 },
2645 { rtfSectAttr, rtfLineRestartPg, "lineppage", 0 },
2646 { rtfSectAttr, rtfLineCont, "linecont", 0 },
2648 { rtfSectAttr, rtfSectPageWid, "pgwsxn", 0 },
2649 { rtfSectAttr, rtfSectPageHt, "pghsxn", 0 },
2650 { rtfSectAttr, rtfSectMarginLeft, "marglsxn", 0 },
2651 { rtfSectAttr, rtfSectMarginRight, "margrsxn", 0 },
2652 { rtfSectAttr, rtfSectMarginTop, "margtsxn", 0 },
2653 { rtfSectAttr, rtfSectMarginBottom, "margbsxn", 0 },
2654 { rtfSectAttr, rtfSectMarginGutter, "guttersxn", 0 },
2655 { rtfSectAttr, rtfSectLandscape, "lndscpsxn", 0 },
2656 { rtfSectAttr, rtfTitleSpecial, "titlepg", 0 },
2657 { rtfSectAttr, rtfHeaderY, "headery", 0 },
2658 { rtfSectAttr, rtfFooterY, "footery", 0 },
2660 { rtfSectAttr, rtfPageStarts, "pgnstarts", 0 },
2661 { rtfSectAttr, rtfPageCont, "pgncont", 0 },
2662 { rtfSectAttr, rtfPageRestart, "pgnrestart", 0 },
2663 { rtfSectAttr, rtfPageNumRight, "pgnx", 0 },
2664 { rtfSectAttr, rtfPageNumTop, "pgny", 0 },
2665 { rtfSectAttr, rtfPageDecimal, "pgndec", 0 },
2666 { rtfSectAttr, rtfPageURoman, "pgnucrm", 0 },
2667 { rtfSectAttr, rtfPageLRoman, "pgnlcrm", 0 },
2668 { rtfSectAttr, rtfPageULetter, "pgnucltr", 0 },
2669 { rtfSectAttr, rtfPageLLetter, "pgnlcltr", 0 },
2670 { rtfSectAttr, rtfPageNumHyphSep, "pgnhnsh", 0 },
2671 { rtfSectAttr, rtfPageNumSpaceSep, "pgnhnsp", 0 },
2672 { rtfSectAttr, rtfPageNumColonSep, "pgnhnsc", 0 },
2673 { rtfSectAttr, rtfPageNumEmdashSep, "pgnhnsm", 0 },
2674 { rtfSectAttr, rtfPageNumEndashSep, "pgnhnsn", 0 },
2676 { rtfSectAttr, rtfTopVAlign, "vertalt", 0 },
2677 /* misspelled as "vertal" in specification 1.0 */
2678 { rtfSectAttr, rtfBottomVAlign, "vertalb", 0 },
2679 { rtfSectAttr, rtfCenterVAlign, "vertalc", 0 },
2680 { rtfSectAttr, rtfJustVAlign, "vertalj", 0 },
2682 { rtfSectAttr, rtfRTLSect, "rtlsect", 0 },
2683 { rtfSectAttr, rtfLTRSect, "ltrsect", 0 },
2685 /* I've seen these in an old spec, but not in real files... */
2686 /*rtfSectAttr, rtfNoBreak, "nobreak", 0,*/
2687 /*rtfSectAttr, rtfColBreak, "colbreak", 0,*/
2688 /*rtfSectAttr, rtfPageBreak, "pagebreak", 0,*/
2689 /*rtfSectAttr, rtfEvenBreak, "evenbreak", 0,*/
2690 /*rtfSectAttr, rtfOddBreak, "oddbreak", 0,*/
2693 * Document formatting attributes
2696 { rtfDocAttr, rtfDefTab, "deftab", 0 },
2697 { rtfDocAttr, rtfHyphHotZone, "hyphhotz", 0 },
2698 { rtfDocAttr, rtfHyphConsecLines, "hyphconsec", 0 },
2699 { rtfDocAttr, rtfHyphCaps, "hyphcaps", 0 },
2700 { rtfDocAttr, rtfHyphAuto, "hyphauto", 0 },
2701 { rtfDocAttr, rtfLineStart, "linestart", 0 },
2702 { rtfDocAttr, rtfFracWidth, "fracwidth", 0 },
2703 /* \makeback was given in old version of spec, it's now */
2704 /* listed as \makebackup */
2705 { rtfDocAttr, rtfMakeBackup, "makeback", 0 },
2706 { rtfDocAttr, rtfMakeBackup, "makebackup", 0 },
2707 { rtfDocAttr, rtfRTFDefault, "defformat", 0 },
2708 { rtfDocAttr, rtfPSOverlay, "psover", 0 },
2709 { rtfDocAttr, rtfDocTemplate, "doctemp", 0 },
2710 { rtfDocAttr, rtfDefLanguage, "deflang", 0 },
2712 { rtfDocAttr, rtfFENoteType, "fet", 0 },
2713 { rtfDocAttr, rtfFNoteEndSect, "endnotes", 0 },
2714 { rtfDocAttr, rtfFNoteEndDoc, "enddoc", 0 },
2715 { rtfDocAttr, rtfFNoteText, "ftntj", 0 },
2716 { rtfDocAttr, rtfFNoteBottom, "ftnbj", 0 },
2717 { rtfDocAttr, rtfENoteEndSect, "aendnotes", 0 },
2718 { rtfDocAttr, rtfENoteEndDoc, "aenddoc", 0 },
2719 { rtfDocAttr, rtfENoteText, "aftntj", 0 },
2720 { rtfDocAttr, rtfENoteBottom, "aftnbj", 0 },
2721 { rtfDocAttr, rtfFNoteStart, "ftnstart", 0 },
2722 { rtfDocAttr, rtfENoteStart, "aftnstart", 0 },
2723 { rtfDocAttr, rtfFNoteRestartPage, "ftnrstpg", 0 },
2724 { rtfDocAttr, rtfFNoteRestart, "ftnrestart", 0 },
2725 { rtfDocAttr, rtfFNoteRestartCont, "ftnrstcont", 0 },
2726 { rtfDocAttr, rtfENoteRestart, "aftnrestart", 0 },
2727 { rtfDocAttr, rtfENoteRestartCont, "aftnrstcont", 0 },
2728 { rtfDocAttr, rtfFNoteNumArabic, "ftnnar", 0 },
2729 { rtfDocAttr, rtfFNoteNumLLetter, "ftnnalc", 0 },
2730 { rtfDocAttr, rtfFNoteNumULetter, "ftnnauc", 0 },
2731 { rtfDocAttr, rtfFNoteNumLRoman, "ftnnrlc", 0 },
2732 { rtfDocAttr, rtfFNoteNumURoman, "ftnnruc", 0 },
2733 { rtfDocAttr, rtfFNoteNumChicago, "ftnnchi", 0 },
2734 { rtfDocAttr, rtfENoteNumArabic, "aftnnar", 0 },
2735 { rtfDocAttr, rtfENoteNumLLetter, "aftnnalc", 0 },
2736 { rtfDocAttr, rtfENoteNumULetter, "aftnnauc", 0 },
2737 { rtfDocAttr, rtfENoteNumLRoman, "aftnnrlc", 0 },
2738 { rtfDocAttr, rtfENoteNumURoman, "aftnnruc", 0 },
2739 { rtfDocAttr, rtfENoteNumChicago, "aftnnchi", 0 },
2741 { rtfDocAttr, rtfPaperWidth, "paperw", 0 },
2742 { rtfDocAttr, rtfPaperHeight, "paperh", 0 },
2743 { rtfDocAttr, rtfPaperSize, "psz", 0 },
2744 { rtfDocAttr, rtfLeftMargin, "margl", 0 },
2745 { rtfDocAttr, rtfRightMargin, "margr", 0 },
2746 { rtfDocAttr, rtfTopMargin, "margt", 0 },
2747 { rtfDocAttr, rtfBottomMargin, "margb", 0 },
2748 { rtfDocAttr, rtfFacingPage, "facingp", 0 },
2749 { rtfDocAttr, rtfGutterWid, "gutter", 0 },
2750 { rtfDocAttr, rtfMirrorMargin, "margmirror", 0 },
2751 { rtfDocAttr, rtfLandscape, "landscape", 0 },
2752 { rtfDocAttr, rtfPageStart, "pgnstart", 0 },
2753 { rtfDocAttr, rtfWidowCtrl, "widowctrl", 0 },
2755 { rtfDocAttr, rtfLinkStyles, "linkstyles", 0 },
2757 { rtfDocAttr, rtfNoAutoTabIndent, "notabind", 0 },
2758 { rtfDocAttr, rtfWrapSpaces, "wraptrsp", 0 },
2759 { rtfDocAttr, rtfPrintColorsBlack, "prcolbl", 0 },
2760 { rtfDocAttr, rtfNoExtraSpaceRL, "noextrasprl", 0 },
2761 { rtfDocAttr, rtfNoColumnBalance, "nocolbal", 0 },
2762 { rtfDocAttr, rtfCvtMailMergeQuote, "cvmme", 0 },
2763 { rtfDocAttr, rtfSuppressTopSpace, "sprstsp", 0 },
2764 { rtfDocAttr, rtfSuppressPreParSpace, "sprsspbf", 0 },
2765 { rtfDocAttr, rtfCombineTblBorders, "otblrul", 0 },
2766 { rtfDocAttr, rtfTranspMetafiles, "transmf", 0 },
2767 { rtfDocAttr, rtfSwapBorders, "swpbdr", 0 },
2768 { rtfDocAttr, rtfShowHardBreaks, "brkfrm", 0 },
2770 { rtfDocAttr, rtfFormProtected, "formprot", 0 },
2771 { rtfDocAttr, rtfAllProtected, "allprot", 0 },
2772 { rtfDocAttr, rtfFormShading, "formshade", 0 },
2773 { rtfDocAttr, rtfFormDisplay, "formdisp", 0 },
2774 { rtfDocAttr, rtfPrintData, "printdata", 0 },
2776 { rtfDocAttr, rtfRevProtected, "revprot", 0 },
2777 { rtfDocAttr, rtfRevisions, "revisions", 0 },
2778 { rtfDocAttr, rtfRevDisplay, "revprop", 0 },
2779 { rtfDocAttr, rtfRevBar, "revbar", 0 },
2781 { rtfDocAttr, rtfAnnotProtected, "annotprot", 0 },
2783 { rtfDocAttr, rtfRTLDoc, "rtldoc", 0 },
2784 { rtfDocAttr, rtfLTRDoc, "ltrdoc", 0 },
2790 { rtfStyleAttr, rtfAdditive, "additive", 0 },
2791 { rtfStyleAttr, rtfBasedOn, "sbasedon", 0 },
2792 { rtfStyleAttr, rtfNext, "snext", 0 },
2795 * Picture attributes
2798 { rtfPictAttr, rtfMacQD, "macpict", 0 },
2799 { rtfPictAttr, rtfPMMetafile, "pmmetafile", 0 },
2800 { rtfPictAttr, rtfWinMetafile, "wmetafile", 0 },
2801 { rtfPictAttr, rtfDevIndBitmap, "dibitmap", 0 },
2802 { rtfPictAttr, rtfWinBitmap, "wbitmap", 0 },
2803 { rtfPictAttr, rtfPixelBits, "wbmbitspixel", 0 },
2804 { rtfPictAttr, rtfBitmapPlanes, "wbmplanes", 0 },
2805 { rtfPictAttr, rtfBitmapWid, "wbmwidthbytes", 0 },
2807 { rtfPictAttr, rtfPicWid, "picw", 0 },
2808 { rtfPictAttr, rtfPicHt, "pich", 0 },
2809 { rtfPictAttr, rtfPicGoalWid, "picwgoal", 0 },
2810 { rtfPictAttr, rtfPicGoalHt, "pichgoal", 0 },
2811 /* these two aren't in the spec, but some writers emit them */
2812 { rtfPictAttr, rtfPicGoalWid, "picwGoal", 0 },
2813 { rtfPictAttr, rtfPicGoalHt, "pichGoal", 0 },
2814 { rtfPictAttr, rtfPicScaleX, "picscalex", 0 },
2815 { rtfPictAttr, rtfPicScaleY, "picscaley", 0 },
2816 { rtfPictAttr, rtfPicScaled, "picscaled", 0 },
2817 { rtfPictAttr, rtfPicCropTop, "piccropt", 0 },
2818 { rtfPictAttr, rtfPicCropBottom, "piccropb", 0 },
2819 { rtfPictAttr, rtfPicCropLeft, "piccropl", 0 },
2820 { rtfPictAttr, rtfPicCropRight, "piccropr", 0 },
2822 { rtfPictAttr, rtfPicMFHasBitmap, "picbmp", 0 },
2823 { rtfPictAttr, rtfPicMFBitsPerPixel, "picbpp", 0 },
2825 { rtfPictAttr, rtfPicBinary, "bin", 0 },
2828 * NeXT graphic attributes
2831 { rtfNeXTGrAttr, rtfNeXTGWidth, "width", 0 },
2832 { rtfNeXTGrAttr, rtfNeXTGHeight, "height", 0 },
2838 { rtfDestination, rtfFontTbl, "fonttbl", 0 },
2839 { rtfDestination, rtfFontAltName, "falt", 0 },
2840 { rtfDestination, rtfEmbeddedFont, "fonteb", 0 },
2841 { rtfDestination, rtfFontFile, "fontfile", 0 },
2842 { rtfDestination, rtfFileTbl, "filetbl", 0 },
2843 { rtfDestination, rtfFileInfo, "file", 0 },
2844 { rtfDestination, rtfColorTbl, "colortbl", 0 },
2845 { rtfDestination, rtfStyleSheet, "stylesheet", 0 },
2846 { rtfDestination, rtfKeyCode, "keycode", 0 },
2847 { rtfDestination, rtfRevisionTbl, "revtbl", 0 },
2848 { rtfDestination, rtfGenerator, "generator", 0 },
2849 { rtfDestination, rtfInfo, "info", 0 },
2850 { rtfDestination, rtfITitle, "title", 0 },
2851 { rtfDestination, rtfISubject, "subject", 0 },
2852 { rtfDestination, rtfIAuthor, "author", 0 },
2853 { rtfDestination, rtfIOperator, "operator", 0 },
2854 { rtfDestination, rtfIKeywords, "keywords", 0 },
2855 { rtfDestination, rtfIComment, "comment", 0 },
2856 { rtfDestination, rtfIVersion, "version", 0 },
2857 { rtfDestination, rtfIDoccomm, "doccomm", 0 },
2858 /* \verscomm may not exist -- was seen in earlier spec version */
2859 { rtfDestination, rtfIVerscomm, "verscomm", 0 },
2860 { rtfDestination, rtfNextFile, "nextfile", 0 },
2861 { rtfDestination, rtfTemplate, "template", 0 },
2862 { rtfDestination, rtfFNSep, "ftnsep", 0 },
2863 { rtfDestination, rtfFNContSep, "ftnsepc", 0 },
2864 { rtfDestination, rtfFNContNotice, "ftncn", 0 },
2865 { rtfDestination, rtfENSep, "aftnsep", 0 },
2866 { rtfDestination, rtfENContSep, "aftnsepc", 0 },
2867 { rtfDestination, rtfENContNotice, "aftncn", 0 },
2868 { rtfDestination, rtfPageNumLevel, "pgnhn", 0 },
2869 { rtfDestination, rtfParNumLevelStyle, "pnseclvl", 0 },
2870 { rtfDestination, rtfHeader, "header", 0 },
2871 { rtfDestination, rtfFooter, "footer", 0 },
2872 { rtfDestination, rtfHeaderLeft, "headerl", 0 },
2873 { rtfDestination, rtfHeaderRight, "headerr", 0 },
2874 { rtfDestination, rtfHeaderFirst, "headerf", 0 },
2875 { rtfDestination, rtfFooterLeft, "footerl", 0 },
2876 { rtfDestination, rtfFooterRight, "footerr", 0 },
2877 { rtfDestination, rtfFooterFirst, "footerf", 0 },
2878 { rtfDestination, rtfParNumText, "pntext", 0 },
2879 { rtfDestination, rtfParNumbering, "pn", 0 },
2880 { rtfDestination, rtfParNumTextAfter, "pntexta", 0 },
2881 { rtfDestination, rtfParNumTextBefore, "pntextb", 0 },
2882 { rtfDestination, rtfBookmarkStart, "bkmkstart", 0 },
2883 { rtfDestination, rtfBookmarkEnd, "bkmkend", 0 },
2884 { rtfDestination, rtfPict, "pict", 0 },
2885 { rtfDestination, rtfObject, "object", 0 },
2886 { rtfDestination, rtfObjClass, "objclass", 0 },
2887 { rtfDestination, rtfObjName, "objname", 0 },
2888 { rtfObjAttr, rtfObjTime, "objtime", 0 },
2889 { rtfDestination, rtfObjData, "objdata", 0 },
2890 { rtfDestination, rtfObjAlias, "objalias", 0 },
2891 { rtfDestination, rtfObjSection, "objsect", 0 },
2892 /* objitem and objtopic aren't documented in the spec! */
2893 { rtfDestination, rtfObjItem, "objitem", 0 },
2894 { rtfDestination, rtfObjTopic, "objtopic", 0 },
2895 { rtfDestination, rtfObjResult, "result", 0 },
2896 { rtfDestination, rtfDrawObject, "do", 0 },
2897 { rtfDestination, rtfFootnote, "footnote", 0 },
2898 { rtfDestination, rtfAnnotRefStart, "atrfstart", 0 },
2899 { rtfDestination, rtfAnnotRefEnd, "atrfend", 0 },
2900 { rtfDestination, rtfAnnotID, "atnid", 0 },
2901 { rtfDestination, rtfAnnotAuthor, "atnauthor", 0 },
2902 { rtfDestination, rtfAnnotation, "annotation", 0 },
2903 { rtfDestination, rtfAnnotRef, "atnref", 0 },
2904 { rtfDestination, rtfAnnotTime, "atntime", 0 },
2905 { rtfDestination, rtfAnnotIcon, "atnicn", 0 },
2906 { rtfDestination, rtfField, "field", 0 },
2907 { rtfDestination, rtfFieldInst, "fldinst", 0 },
2908 { rtfDestination, rtfFieldResult, "fldrslt", 0 },
2909 { rtfDestination, rtfDataField, "datafield", 0 },
2910 { rtfDestination, rtfIndex, "xe", 0 },
2911 { rtfDestination, rtfIndexText, "txe", 0 },
2912 { rtfDestination, rtfIndexRange, "rxe", 0 },
2913 { rtfDestination, rtfTOC, "tc", 0 },
2914 { rtfDestination, rtfNeXTGraphic, "NeXTGraphic", 0 },
2920 { rtfFontFamily, rtfFFNil, "fnil", 0 },
2921 { rtfFontFamily, rtfFFRoman, "froman", 0 },
2922 { rtfFontFamily, rtfFFSwiss, "fswiss", 0 },
2923 { rtfFontFamily, rtfFFModern, "fmodern", 0 },
2924 { rtfFontFamily, rtfFFScript, "fscript", 0 },
2925 { rtfFontFamily, rtfFFDecor, "fdecor", 0 },
2926 { rtfFontFamily, rtfFFTech, "ftech", 0 },
2927 { rtfFontFamily, rtfFFBidirectional, "fbidi", 0 },
2933 { rtfFontAttr, rtfFontCharSet, "fcharset", 0 },
2934 { rtfFontAttr, rtfFontPitch, "fprq", 0 },
2935 { rtfFontAttr, rtfFontCodePage, "cpg", 0 },
2936 { rtfFontAttr, rtfFTypeNil, "ftnil", 0 },
2937 { rtfFontAttr, rtfFTypeTrueType, "fttruetype", 0 },
2940 * File table attributes
2943 { rtfFileAttr, rtfFileNum, "fid", 0 },
2944 { rtfFileAttr, rtfFileRelPath, "frelative", 0 },
2945 { rtfFileAttr, rtfFileOSNum, "fosnum", 0 },
2951 { rtfFileSource, rtfSrcMacintosh, "fvalidmac", 0 },
2952 { rtfFileSource, rtfSrcDOS, "fvaliddos", 0 },
2953 { rtfFileSource, rtfSrcNTFS, "fvalidntfs", 0 },
2954 { rtfFileSource, rtfSrcHPFS, "fvalidhpfs", 0 },
2955 { rtfFileSource, rtfSrcNetwork, "fnetwork", 0 },
2961 { rtfColorName, rtfRed, "red", 0 },
2962 { rtfColorName, rtfGreen, "green", 0 },
2963 { rtfColorName, rtfBlue, "blue", 0 },
2969 { rtfCharSet, rtfMacCharSet, "mac", 0 },
2970 { rtfCharSet, rtfAnsiCharSet, "ansi", 0 },
2971 { rtfCharSet, rtfPcCharSet, "pc", 0 },
2972 { rtfCharSet, rtfPcaCharSet, "pca", 0 },
2978 { rtfTblAttr, rtfRowDef, "trowd", 0 },
2979 { rtfTblAttr, rtfRowGapH, "trgaph", 0 },
2980 { rtfTblAttr, rtfCellPos, "cellx", 0 },
2981 { rtfTblAttr, rtfMergeRngFirst, "clmgf", 0 },
2982 { rtfTblAttr, rtfMergePrevious, "clmrg", 0 },
2984 { rtfTblAttr, rtfRowLeft, "trql", 0 },
2985 { rtfTblAttr, rtfRowRight, "trqr", 0 },
2986 { rtfTblAttr, rtfRowCenter, "trqc", 0 },
2987 { rtfTblAttr, rtfRowLeftEdge, "trleft", 0 },
2988 { rtfTblAttr, rtfRowHt, "trrh", 0 },
2989 { rtfTblAttr, rtfRowHeader, "trhdr", 0 },
2990 { rtfTblAttr, rtfRowKeep, "trkeep", 0 },
2992 { rtfTblAttr, rtfRTLRow, "rtlrow", 0 },
2993 { rtfTblAttr, rtfLTRRow, "ltrrow", 0 },
2995 { rtfTblAttr, rtfRowBordTop, "trbrdrt", 0 },
2996 { rtfTblAttr, rtfRowBordLeft, "trbrdrl", 0 },
2997 { rtfTblAttr, rtfRowBordBottom, "trbrdrb", 0 },
2998 { rtfTblAttr, rtfRowBordRight, "trbrdrr", 0 },
2999 { rtfTblAttr, rtfRowBordHoriz, "trbrdrh", 0 },
3000 { rtfTblAttr, rtfRowBordVert, "trbrdrv", 0 },
3002 { rtfTblAttr, rtfCellBordBottom, "clbrdrb", 0 },
3003 { rtfTblAttr, rtfCellBordTop, "clbrdrt", 0 },
3004 { rtfTblAttr, rtfCellBordLeft, "clbrdrl", 0 },
3005 { rtfTblAttr, rtfCellBordRight, "clbrdrr", 0 },
3007 { rtfTblAttr, rtfCellShading, "clshdng", 0 },
3008 { rtfTblAttr, rtfCellBgPatH, "clbghoriz", 0 },
3009 { rtfTblAttr, rtfCellBgPatV, "clbgvert", 0 },
3010 { rtfTblAttr, rtfCellFwdDiagBgPat, "clbgfdiag", 0 },
3011 { rtfTblAttr, rtfCellBwdDiagBgPat, "clbgbdiag", 0 },
3012 { rtfTblAttr, rtfCellHatchBgPat, "clbgcross", 0 },
3013 { rtfTblAttr, rtfCellDiagHatchBgPat, "clbgdcross", 0 },
3015 * The spec lists "clbgdkhor", but the corresponding non-cell
3016 * control is "bgdkhoriz". At any rate Macintosh Word seems
3017 * to accept both "clbgdkhor" and "clbgdkhoriz".
3019 { rtfTblAttr, rtfCellDarkBgPatH, "clbgdkhoriz", 0 },
3020 { rtfTblAttr, rtfCellDarkBgPatH, "clbgdkhor", 0 },
3021 { rtfTblAttr, rtfCellDarkBgPatV, "clbgdkvert", 0 },
3022 { rtfTblAttr, rtfCellFwdDarkBgPat, "clbgdkfdiag", 0 },
3023 { rtfTblAttr, rtfCellBwdDarkBgPat, "clbgdkbdiag", 0 },
3024 { rtfTblAttr, rtfCellDarkHatchBgPat, "clbgdkcross", 0 },
3025 { rtfTblAttr, rtfCellDarkDiagHatchBgPat, "clbgdkdcross", 0 },
3026 { rtfTblAttr, rtfCellBgPatLineColor, "clcfpat", 0 },
3027 { rtfTblAttr, rtfCellBgPatColor, "clcbpat", 0 },
3033 { rtfFieldAttr, rtfFieldDirty, "flddirty", 0 },
3034 { rtfFieldAttr, rtfFieldEdited, "fldedit", 0 },
3035 { rtfFieldAttr, rtfFieldLocked, "fldlock", 0 },
3036 { rtfFieldAttr, rtfFieldPrivate, "fldpriv", 0 },
3037 { rtfFieldAttr, rtfFieldAlt, "fldalt", 0 },
3040 * Positioning attributes
3043 { rtfPosAttr, rtfAbsWid, "absw", 0 },
3044 { rtfPosAttr, rtfAbsHt, "absh", 0 },
3046 { rtfPosAttr, rtfRPosMargH, "phmrg", 0 },
3047 { rtfPosAttr, rtfRPosPageH, "phpg", 0 },
3048 { rtfPosAttr, rtfRPosColH, "phcol", 0 },
3049 { rtfPosAttr, rtfPosX, "posx", 0 },
3050 { rtfPosAttr, rtfPosNegX, "posnegx", 0 },
3051 { rtfPosAttr, rtfPosXCenter, "posxc", 0 },
3052 { rtfPosAttr, rtfPosXInside, "posxi", 0 },
3053 { rtfPosAttr, rtfPosXOutSide, "posxo", 0 },
3054 { rtfPosAttr, rtfPosXRight, "posxr", 0 },
3055 { rtfPosAttr, rtfPosXLeft, "posxl", 0 },
3057 { rtfPosAttr, rtfRPosMargV, "pvmrg", 0 },
3058 { rtfPosAttr, rtfRPosPageV, "pvpg", 0 },
3059 { rtfPosAttr, rtfRPosParaV, "pvpara", 0 },
3060 { rtfPosAttr, rtfPosY, "posy", 0 },
3061 { rtfPosAttr, rtfPosNegY, "posnegy", 0 },
3062 { rtfPosAttr, rtfPosYInline, "posyil", 0 },
3063 { rtfPosAttr, rtfPosYTop, "posyt", 0 },
3064 { rtfPosAttr, rtfPosYCenter, "posyc", 0 },
3065 { rtfPosAttr, rtfPosYBottom, "posyb", 0 },
3067 { rtfPosAttr, rtfNoWrap, "nowrap", 0 },
3068 { rtfPosAttr, rtfDistFromTextAll, "dxfrtext", 0 },
3069 { rtfPosAttr, rtfDistFromTextX, "dfrmtxtx", 0 },
3070 { rtfPosAttr, rtfDistFromTextY, "dfrmtxty", 0 },
3071 /* \dyfrtext no longer exists in spec 1.2, apparently */
3072 /* replaced by \dfrmtextx and \dfrmtexty. */
3073 { rtfPosAttr, rtfTextDistY, "dyfrtext", 0 },
3075 { rtfPosAttr, rtfDropCapLines, "dropcapli", 0 },
3076 { rtfPosAttr, rtfDropCapType, "dropcapt", 0 },
3082 { rtfObjAttr, rtfObjEmb, "objemb", 0 },
3083 { rtfObjAttr, rtfObjLink, "objlink", 0 },
3084 { rtfObjAttr, rtfObjAutoLink, "objautlink", 0 },
3085 { rtfObjAttr, rtfObjSubscriber, "objsub", 0 },
3086 { rtfObjAttr, rtfObjPublisher, "objpub", 0 },
3087 { rtfObjAttr, rtfObjICEmb, "objicemb", 0 },
3089 { rtfObjAttr, rtfObjLinkSelf, "linkself", 0 },
3090 { rtfObjAttr, rtfObjLock, "objupdate", 0 },
3091 { rtfObjAttr, rtfObjUpdate, "objlock", 0 },
3093 { rtfObjAttr, rtfObjHt, "objh", 0 },
3094 { rtfObjAttr, rtfObjWid, "objw", 0 },
3095 { rtfObjAttr, rtfObjSetSize, "objsetsize", 0 },
3096 { rtfObjAttr, rtfObjAlign, "objalign", 0 },
3097 { rtfObjAttr, rtfObjTransposeY, "objtransy", 0 },
3098 { rtfObjAttr, rtfObjCropTop, "objcropt", 0 },
3099 { rtfObjAttr, rtfObjCropBottom, "objcropb", 0 },
3100 { rtfObjAttr, rtfObjCropLeft, "objcropl", 0 },
3101 { rtfObjAttr, rtfObjCropRight, "objcropr", 0 },
3102 { rtfObjAttr, rtfObjScaleX, "objscalex", 0 },
3103 { rtfObjAttr, rtfObjScaleY, "objscaley", 0 },
3105 { rtfObjAttr, rtfObjResRTF, "rsltrtf", 0 },
3106 { rtfObjAttr, rtfObjResPict, "rsltpict", 0 },
3107 { rtfObjAttr, rtfObjResBitmap, "rsltbmp", 0 },
3108 { rtfObjAttr, rtfObjResText, "rslttxt", 0 },
3109 { rtfObjAttr, rtfObjResMerge, "rsltmerge", 0 },
3111 { rtfObjAttr, rtfObjBookmarkPubObj, "bkmkpub", 0 },
3112 { rtfObjAttr, rtfObjPubAutoUpdate, "pubauto", 0 },
3115 * Associated character formatting attributes
3118 { rtfACharAttr, rtfACBold, "ab", 0 },
3119 { rtfACharAttr, rtfACAllCaps, "caps", 0 },
3120 { rtfACharAttr, rtfACForeColor, "acf", 0 },
3121 { rtfACharAttr, rtfACSubScript, "adn", 0 },
3122 { rtfACharAttr, rtfACExpand, "aexpnd", 0 },
3123 { rtfACharAttr, rtfACFontNum, "af", 0 },
3124 { rtfACharAttr, rtfACFontSize, "afs", 0 },
3125 { rtfACharAttr, rtfACItalic, "ai", 0 },
3126 { rtfACharAttr, rtfACLanguage, "alang", 0 },
3127 { rtfACharAttr, rtfACOutline, "aoutl", 0 },
3128 { rtfACharAttr, rtfACSmallCaps, "ascaps", 0 },
3129 { rtfACharAttr, rtfACShadow, "ashad", 0 },
3130 { rtfACharAttr, rtfACStrikeThru, "astrike", 0 },
3131 { rtfACharAttr, rtfACUnderline, "aul", 0 },
3132 { rtfACharAttr, rtfACDotUnderline, "auld", 0 },
3133 { rtfACharAttr, rtfACDbUnderline, "auldb", 0 },
3134 { rtfACharAttr, rtfACNoUnderline, "aulnone", 0 },
3135 { rtfACharAttr, rtfACWordUnderline, "aulw", 0 },
3136 { rtfACharAttr, rtfACSuperScript, "aup", 0 },
3139 * Footnote attributes
3142 { rtfFNoteAttr, rtfFNAlt, "ftnalt", 0 },
3145 * Key code attributes
3148 { rtfKeyCodeAttr, rtfAltKey, "alt", 0 },
3149 { rtfKeyCodeAttr, rtfShiftKey, "shift", 0 },
3150 { rtfKeyCodeAttr, rtfControlKey, "ctrl", 0 },
3151 { rtfKeyCodeAttr, rtfFunctionKey, "fn", 0 },
3154 * Bookmark attributes
3157 { rtfBookmarkAttr, rtfBookmarkFirstCol, "bkmkcolf", 0 },
3158 { rtfBookmarkAttr, rtfBookmarkLastCol, "bkmkcoll", 0 },
3161 * Index entry attributes
3164 { rtfIndexAttr, rtfIndexNumber, "xef", 0 },
3165 { rtfIndexAttr, rtfIndexBold, "bxe", 0 },
3166 { rtfIndexAttr, rtfIndexItalic, "ixe", 0 },
3169 * Table of contents attributes
3172 { rtfTOCAttr, rtfTOCType, "tcf", 0 },
3173 { rtfTOCAttr, rtfTOCLevel, "tcl", 0 },
3176 * Drawing object attributes
3179 { rtfDrawAttr, rtfDrawLock, "dolock", 0 },
3180 { rtfDrawAttr, rtfDrawPageRelX, "doxpage", 0 },
3181 { rtfDrawAttr, rtfDrawColumnRelX, "dobxcolumn", 0 },
3182 { rtfDrawAttr, rtfDrawMarginRelX, "dobxmargin", 0 },
3183 { rtfDrawAttr, rtfDrawPageRelY, "dobypage", 0 },
3184 { rtfDrawAttr, rtfDrawColumnRelY, "dobycolumn", 0 },
3185 { rtfDrawAttr, rtfDrawMarginRelY, "dobymargin", 0 },
3186 { rtfDrawAttr, rtfDrawHeight, "dobhgt", 0 },
3188 { rtfDrawAttr, rtfDrawBeginGroup, "dpgroup", 0 },
3189 { rtfDrawAttr, rtfDrawGroupCount, "dpcount", 0 },
3190 { rtfDrawAttr, rtfDrawEndGroup, "dpendgroup", 0 },
3191 { rtfDrawAttr, rtfDrawArc, "dparc", 0 },
3192 { rtfDrawAttr, rtfDrawCallout, "dpcallout", 0 },
3193 { rtfDrawAttr, rtfDrawEllipse, "dpellipse", 0 },
3194 { rtfDrawAttr, rtfDrawLine, "dpline", 0 },
3195 { rtfDrawAttr, rtfDrawPolygon, "dppolygon", 0 },
3196 { rtfDrawAttr, rtfDrawPolyLine, "dppolyline", 0 },
3197 { rtfDrawAttr, rtfDrawRect, "dprect", 0 },
3198 { rtfDrawAttr, rtfDrawTextBox, "dptxbx", 0 },
3200 { rtfDrawAttr, rtfDrawOffsetX, "dpx", 0 },
3201 { rtfDrawAttr, rtfDrawSizeX, "dpxsize", 0 },
3202 { rtfDrawAttr, rtfDrawOffsetY, "dpy", 0 },
3203 { rtfDrawAttr, rtfDrawSizeY, "dpysize", 0 },
3205 { rtfDrawAttr, rtfCOAngle, "dpcoa", 0 },
3206 { rtfDrawAttr, rtfCOAccentBar, "dpcoaccent", 0 },
3207 { rtfDrawAttr, rtfCOBestFit, "dpcobestfit", 0 },
3208 { rtfDrawAttr, rtfCOBorder, "dpcoborder", 0 },
3209 { rtfDrawAttr, rtfCOAttachAbsDist, "dpcodabs", 0 },
3210 { rtfDrawAttr, rtfCOAttachBottom, "dpcodbottom", 0 },
3211 { rtfDrawAttr, rtfCOAttachCenter, "dpcodcenter", 0 },
3212 { rtfDrawAttr, rtfCOAttachTop, "dpcodtop", 0 },
3213 { rtfDrawAttr, rtfCOLength, "dpcolength", 0 },
3214 { rtfDrawAttr, rtfCONegXQuadrant, "dpcominusx", 0 },
3215 { rtfDrawAttr, rtfCONegYQuadrant, "dpcominusy", 0 },
3216 { rtfDrawAttr, rtfCOOffset, "dpcooffset", 0 },
3217 { rtfDrawAttr, rtfCOAttachSmart, "dpcosmarta", 0 },
3218 { rtfDrawAttr, rtfCODoubleLine, "dpcotdouble", 0 },
3219 { rtfDrawAttr, rtfCORightAngle, "dpcotright", 0 },
3220 { rtfDrawAttr, rtfCOSingleLine, "dpcotsingle", 0 },
3221 { rtfDrawAttr, rtfCOTripleLine, "dpcottriple", 0 },
3223 { rtfDrawAttr, rtfDrawTextBoxMargin, "dptxbxmar", 0 },
3224 { rtfDrawAttr, rtfDrawTextBoxText, "dptxbxtext", 0 },
3225 { rtfDrawAttr, rtfDrawRoundRect, "dproundr", 0 },
3227 { rtfDrawAttr, rtfDrawPointX, "dpptx", 0 },
3228 { rtfDrawAttr, rtfDrawPointY, "dppty", 0 },
3229 { rtfDrawAttr, rtfDrawPolyCount, "dppolycount", 0 },
3231 { rtfDrawAttr, rtfDrawArcFlipX, "dparcflipx", 0 },
3232 { rtfDrawAttr, rtfDrawArcFlipY, "dparcflipy", 0 },
3234 { rtfDrawAttr, rtfDrawLineBlue, "dplinecob", 0 },
3235 { rtfDrawAttr, rtfDrawLineGreen, "dplinecog", 0 },
3236 { rtfDrawAttr, rtfDrawLineRed, "dplinecor", 0 },
3237 { rtfDrawAttr, rtfDrawLinePalette, "dplinepal", 0 },
3238 { rtfDrawAttr, rtfDrawLineDashDot, "dplinedado", 0 },
3239 { rtfDrawAttr, rtfDrawLineDashDotDot, "dplinedadodo", 0 },
3240 { rtfDrawAttr, rtfDrawLineDash, "dplinedash", 0 },
3241 { rtfDrawAttr, rtfDrawLineDot, "dplinedot", 0 },
3242 { rtfDrawAttr, rtfDrawLineGray, "dplinegray", 0 },
3243 { rtfDrawAttr, rtfDrawLineHollow, "dplinehollow", 0 },
3244 { rtfDrawAttr, rtfDrawLineSolid, "dplinesolid", 0 },
3245 { rtfDrawAttr, rtfDrawLineWidth, "dplinew", 0 },
3247 { rtfDrawAttr, rtfDrawHollowEndArrow, "dpaendhol", 0 },
3248 { rtfDrawAttr, rtfDrawEndArrowLength, "dpaendl", 0 },
3249 { rtfDrawAttr, rtfDrawSolidEndArrow, "dpaendsol", 0 },
3250 { rtfDrawAttr, rtfDrawEndArrowWidth, "dpaendw", 0 },
3251 { rtfDrawAttr, rtfDrawHollowStartArrow,"dpastarthol", 0 },
3252 { rtfDrawAttr, rtfDrawStartArrowLength,"dpastartl", 0 },
3253 { rtfDrawAttr, rtfDrawSolidStartArrow, "dpastartsol", 0 },
3254 { rtfDrawAttr, rtfDrawStartArrowWidth, "dpastartw", 0 },
3256 { rtfDrawAttr, rtfDrawBgFillBlue, "dpfillbgcb", 0 },
3257 { rtfDrawAttr, rtfDrawBgFillGreen, "dpfillbgcg", 0 },
3258 { rtfDrawAttr, rtfDrawBgFillRed, "dpfillbgcr", 0 },
3259 { rtfDrawAttr, rtfDrawBgFillPalette, "dpfillbgpal", 0 },
3260 { rtfDrawAttr, rtfDrawBgFillGray, "dpfillbggray", 0 },
3261 { rtfDrawAttr, rtfDrawFgFillBlue, "dpfillfgcb", 0 },
3262 { rtfDrawAttr, rtfDrawFgFillGreen, "dpfillfgcg", 0 },
3263 { rtfDrawAttr, rtfDrawFgFillRed, "dpfillfgcr", 0 },
3264 { rtfDrawAttr, rtfDrawFgFillPalette, "dpfillfgpal", 0 },
3265 { rtfDrawAttr, rtfDrawFgFillGray, "dpfillfggray", 0 },
3266 { rtfDrawAttr, rtfDrawFillPatIndex, "dpfillpat", 0 },
3268 { rtfDrawAttr, rtfDrawShadow, "dpshadow", 0 },
3269 { rtfDrawAttr, rtfDrawShadowXOffset, "dpshadx", 0 },
3270 { rtfDrawAttr, rtfDrawShadowYOffset, "dpshady", 0 },
3272 { rtfVersion, -1, "rtf", 0 },
3273 { rtfDefFont, -1, "deff", 0 },
3275 { 0, -1, (char *) NULL, 0 }
3277 #define RTF_KEY_COUNT (sizeof(rtfKey) / sizeof(RTFKey))
3279 typedef struct tagRTFHashTableEntry {
3282 } RTFHashTableEntry;
3284 static RTFHashTableEntry rtfHashTable[RTF_KEY_COUNT];
3288 * Initialize lookup table hash values. Only need to do this once.
3291 static void LookupInit(void)
3293 static int inited = 0;
3298 memset(rtfHashTable, 0, RTF_KEY_COUNT * sizeof(*rtfHashTable));
3299 for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++) {
3302 rp->rtfKHash = Hash ((char*)rp->rtfKStr);
3303 index = rp->rtfKHash % RTF_KEY_COUNT;
3304 if (!rtfHashTable[index].count)
3305 rtfHashTable[index].value = (void *)RTFAlloc(sizeof(RTFKey *));
3307 rtfHashTable[index].value = (void *)RTFReAlloc((void *)rtfHashTable[index].value, sizeof(RTFKey *) * (rtfHashTable[index].count + 1));
3308 rtfHashTable[index].value[rtfHashTable[index].count++] = rp;
3316 * Determine major and minor number of control token. If it's
3317 * not found, the class turns into rtfUnknown.
3320 static void Lookup(RTF_Info *info, char *s)
3324 RTFHashTableEntry *entry;
3328 ++s; /* skip over the leading \ character */
3330 entry = &rtfHashTable[hash % RTF_KEY_COUNT];
3331 for (i = 0; i < entry->count; i++)
3333 rp = entry->value[i];
3334 if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0)
3336 info->rtfClass = rtfControl;
3337 info->rtfMajor = rp->rtfKMajor;
3338 info->rtfMinor = rp->rtfKMinor;
3342 info->rtfClass = rtfUnknown;
3347 * Compute hash value of symbol
3350 static int Hash(char *s)
3355 while ((c = *s++) != '\0')
3361 /* ---------------------------------------------------------------------- */
3364 * Memory allocation routines
3369 * Return pointer to block of size bytes, or NULL if there's
3370 * not enough memory available.
3372 * This is called through RTFAlloc(), a define which coerces the
3373 * argument to int. This avoids the persistent problem of allocation
3374 * failing under THINK C when a long is passed.
3377 char *_RTFAlloc(int size)
3379 return HeapAlloc(me_heap, 0, size);
3384 RTFReAlloc(char *ptr, int size)
3386 return HeapReAlloc(me_heap, 0, ptr, size);
3391 * Saves a string on the heap and returns a pointer to it.
3395 char *RTFStrSave(char *s)
3399 if ((p = RTFAlloc ((int) (strlen (s) + 1))) == (char *) NULL)
3400 return ((char *) NULL);
3401 return (strcpy (p, s));
3405 void RTFFree(char *p)
3407 HeapFree(me_heap, 0, p);
3411 /* ---------------------------------------------------------------------- */
3415 * Token comparison routines
3418 int RTFCheckCM(RTF_Info *info, int class, int major)
3420 return (info->rtfClass == class && info->rtfMajor == major);
3424 int RTFCheckCMM(RTF_Info *info, int class, int major, int minor)
3426 return (info->rtfClass == class && info->rtfMajor == major && info->rtfMinor == minor);
3430 int RTFCheckMM(RTF_Info *info, int major, int minor)
3432 return (info->rtfMajor == major && info->rtfMinor == minor);
3436 /* ---------------------------------------------------------------------- */
3439 int RTFCharToHex(char c)
3444 return (c - '0'); /* '0'..'9' */
3445 return (c - 'a' + 10); /* 'a'..'f' */
3449 int RTFHexToChar(int i)
3453 return (i - 10 + 'a');
3457 /* ---------------------------------------------------------------------- */
3460 * RTFReadOutputMap() -- Read output translation map
3464 * Read in an array describing the relation between the standard character set
3465 * and an RTF translator's corresponding output sequences. Each line consists
3466 * of a standard character name and the output sequence for that character.
3468 * outMap is an array of strings into which the sequences should be placed.
3469 * It should be declared like this in the calling program:
3471 * char *outMap[rtfSC_MaxChar];
3473 * reinit should be non-zero if outMap should be initialized
3478 int RTFReadOutputMap(RTF_Info *info, char *outMap[], int reinit)
3485 for (i = 0; i < rtfSC_MaxChar; i++)
3487 outMap[i] = (char *) NULL;
3491 for (i=0 ;i< sizeof(text_map)/sizeof(char*); i+=2)
3493 const char *name = text_map[i];
3494 const char *seq = text_map[i+1];
3495 stdCode = RTFStdCharCode( info, name );
3496 outMap[stdCode] = (char*)seq;
3502 /* ---------------------------------------------------------------------- */
3505 * Open a library file.
3509 void RTFSetOpenLibFileProc(RTF_Info *info, FILE *(*proc)())
3511 info->libFileOpen = proc;
3515 FILE *RTFOpenLibFile (RTF_Info *info, char *file, char *mode)
3517 if (info->libFileOpen == NULL)
3518 return ((FILE *) NULL);
3519 return ((*info->libFileOpen) (file, mode));
3523 /* ---------------------------------------------------------------------- */
3526 * Print message. Default is to send message to stderr
3527 * but this may be overridden with RTFSetMsgProc().
3529 * Message should include linefeeds as necessary. If the default
3530 * function is overridden, the overriding function may want to
3531 * map linefeeds to another line ending character or sequence if
3532 * the host system doesn't use linefeeds.
3536 void RTFMsg (RTF_Info *info, const char *fmt, ...)
3538 char buf[rtfBufSiz];
3541 va_start (args,fmt);
3542 vsprintf (buf, fmt, args);
3544 MESSAGE( "%s", buf);
3548 /* ---------------------------------------------------------------------- */
3552 * Process termination. Print error message and exit. Also prints
3553 * current token, and current input line number and position within
3554 * line if any input has been read from the current file. (No input
3555 * has been read if prevChar is EOF).
3558 static void DefaultPanicProc(RTF_Info *info, char *s)
3566 void RTFPanic(RTF_Info *info, const char *fmt, ...)
3568 char buf[rtfBufSiz];
3571 va_start (args,fmt);
3572 vsprintf (buf, fmt, args);
3574 (void) strcat (buf, "\n");
3575 if (info->prevChar != EOF && info->rtfTextBuf != (char *) NULL)
3577 sprintf (buf + strlen (buf),
3578 "Last token read was \"%s\" near line %ld, position %d.\n",
3579 info->rtfTextBuf, info->rtfLineNum, info->rtfLinePos);
3581 DefaultPanicProc(info, buf);
3584 /* ---------------------------------------------------------------------- */
3587 * originally from RTF tools' text-writer.c
3589 * text-writer -- RTF-to-text translation writer code.
3591 * Read RTF input, write text of document (text extraction).
3594 static void TextClass (RTF_Info *info);
3595 static void ControlClass (RTF_Info *info);
3596 static void Destination (RTF_Info *info);
3597 static void SpecialChar (RTF_Info *info);
3598 static void PutStdChar (RTF_Info *info, int stdCode);
3599 static void PutLitChar (RTF_Info *info, int c);
3600 static void PutLitStr (RTF_Info *info, char *s);
3603 * Initialize the writer.
3607 WriterInit (RTF_Info *info )
3609 RTFReadOutputMap (info, info->outMap,1);
3614 BeginFile (RTF_Info *info )
3616 /* install class callbacks */
3618 RTFSetClassCallback (info, rtfText, TextClass);
3619 RTFSetClassCallback (info, rtfControl, ControlClass);
3625 * Write out a character. Seems to work for the default ANSI codepage,
3626 * contrary to TextClass_orig.
3630 TextClass (RTF_Info *info)
3632 PutLitChar (info, info->rtfMajor);
3636 * Write out a character. rtfMajor contains the input character, rtfMinor
3637 * contains the corresponding standard character code.
3639 * If the input character isn't in the charset map, try to print some
3640 * representation of it.
3642 * I'm not removing it, because it may be helpful if someone else decides
3643 * to rewrite the character handler in a i18n-friendly way
3647 TextClass_orig (RTF_Info *info)
3649 char buf[rtfBufSiz];
3653 if (info->rtfFormat == SF_TEXT)
3654 PutLitChar (info, info->rtfMajor);
3655 else if (info->rtfMinor != rtfSC_nothing)
3656 PutStdChar (info, info->rtfMinor);
3659 if (info->rtfMajor < 256) /* in ASCII range */
3660 PutLitChar(info, info->rtfMajor);
3662 sprintf (buf, "[[\\'%02x]]", info->rtfMajor);
3663 PutLitStr (info, buf);
3671 ControlClass (RTF_Info *info)
3675 switch (info->rtfMajor)
3677 case rtfDestination:
3680 case rtfSpecialChar:
3688 * This function notices destinations that aren't explicitly handled
3689 * and skips to their ends. This keeps, for instance, picture
3690 * data from being considered as plain text.
3694 Destination (RTF_Info *info)
3697 if (!RTFGetDestinationCallback(info, info->rtfMinor))
3698 RTFSkipGroup (info);
3703 * The reason these use the rtfSC_xxx thingies instead of just writing
3704 * out ' ', '-', '"', etc., is so that the mapping for these characters
3705 * can be controlled by the text-map file.
3708 void SpecialChar (RTF_Info *info)
3713 switch (info->rtfMinor)
3716 /* the next token determines destination, if it's unknown, skip the group */
3717 /* this way we filter out the garbage coming from unknown destinations */
3719 if (info->rtfClass != rtfDestination)
3722 RTFRouteToken(info); /* "\*" is ignored with known destinations */
3729 PutLitChar (info, '\n');
3732 PutStdChar (info, rtfSC_space); /* make sure cells are separated */
3735 PutStdChar (info, rtfSC_nobrkspace);
3738 PutLitChar (info, '\t');
3740 case rtfNoBrkHyphen:
3741 PutStdChar (info, rtfSC_nobrkhyphen);
3744 PutStdChar (info, rtfSC_bullet);
3747 PutStdChar (info, rtfSC_emdash);
3750 PutStdChar (info, rtfSC_endash);
3753 PutStdChar (info, rtfSC_quoteleft);
3756 PutStdChar (info, rtfSC_quoteright);
3759 PutStdChar (info, rtfSC_quotedblleft);
3762 PutStdChar (info, rtfSC_quotedblright);
3769 * Eventually this should keep track of the destination of the
3770 * current state and only write text when in the initial state.
3772 * If the output sequence is unspecified in the output map, write
3773 * the character's standard name instead. This makes map deficiencies
3774 * obvious and provides incentive to fix it. :-)
3777 void PutStdChar (RTF_Info *info, int stdCode)
3780 char *oStr = (char *) NULL;
3781 char buf[rtfBufSiz];
3783 /* if (stdCode == rtfSC_nothing)
3784 RTFPanic ("Unknown character code, logic error\n");
3788 oStr = info->outMap[stdCode];
3789 if (oStr == (char *) NULL) /* no output sequence in map */
3791 sprintf (buf, "[[%s]]", RTFStdCharName (info, stdCode));
3794 PutLitStr (info, oStr);
3797 void PutLitChar (RTF_Info *info, int c)
3799 if( info->dwOutputCount >= ( sizeof info->OutputBuffer - 1 ) )
3800 RTFFlushOutputBuffer( info );
3801 info->OutputBuffer[info->dwOutputCount++] = c;
3804 void RTFOutputANSIString( RTF_Info *info, char *str, int len )
3806 assert(str[len] == '\0');
3807 if (len) SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str);
3810 void RTFFlushOutputBuffer( RTF_Info *info )
3812 info->OutputBuffer[info->dwOutputCount] = 0;
3813 RTFOutputANSIString(info, info->OutputBuffer, info->dwOutputCount);
3814 info->dwOutputCount = 0;
3817 static void PutLitStr (RTF_Info *info, char *str )
3819 int len = strlen( str );
3821 if( ( len + info->dwOutputCount + 1 ) > sizeof info->OutputBuffer )
3822 RTFFlushOutputBuffer( info );
3823 if( ( len + 1 ) >= sizeof info->OutputBuffer )
3825 RTFOutputANSIString(info, str, len);
3828 strcpy( &info->OutputBuffer[info->dwOutputCount], str );
3829 info->dwOutputCount += len;