ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

reader.c
Go to the documentation of this file.
00001 /*
00002  * WINE RTF file reader
00003  *
00004  * Portions Copyright 2004 Mike McCormack for CodeWeavers
00005  * Portions Copyright 2006 by Phil Krylov
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 /*
00023  * Derived from RTF Tools by Paul DuBois (dubois@primate.wisc.edu)
00024  * Homepage: http://www.snake.net/software/RTF/
00025  * Original license follows:
00026  */
00027 
00028 /*
00029  * reader.c - RTF file reader.  Release 1.10.
00030  *
00031  * ....
00032  *
00033  * Author: Paul DuBois  dubois@primate.wisc.edu
00034  *
00035  * This software may be redistributed without restriction and used for
00036  * any purpose whatsoever.
00037  */
00038 
00039 #include <stdio.h>
00040 #include <ctype.h>
00041 #include <string.h>
00042 #include <stdarg.h>
00043 #include <stdlib.h>
00044 #include <assert.h>
00045 
00046 #include "windef.h"
00047 #include "winbase.h"
00048 #include "wine/debug.h"
00049 
00050 #include "editor.h"
00051 #include "rtf.h"
00052 
00053 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
00054 
00055 extern HANDLE me_heap;
00056 
00057 static int  _RTFGetChar(RTF_Info *);
00058 static void _RTFGetToken (RTF_Info *);
00059 static void _RTFGetToken2 (RTF_Info *);
00060 static int  GetChar (RTF_Info *);
00061 static void ReadFontTbl (RTF_Info *);
00062 static void ReadColorTbl (RTF_Info *);
00063 static void ReadStyleSheet (RTF_Info *);
00064 static void ReadInfoGroup (RTF_Info *);
00065 static void ReadPictGroup (RTF_Info *);
00066 static void ReadObjGroup (RTF_Info *);
00067 static void Lookup (RTF_Info *, char *);
00068 static int  Hash (const char *);
00069 
00070 static void CharAttr(RTF_Info *info);
00071 static void CharSet(RTF_Info *info);
00072 static void DocAttr(RTF_Info *info);
00073 
00074 static void RTFFlushCPOutputBuffer(RTF_Info *info);
00075 static void RTFPutCodePageChar(RTF_Info *info, int c);
00076 
00077 /* ---------------------------------------------------------------------- */
00078 
00079 
00080 /*
00081  * Saves a string on the heap and returns a pointer to it.
00082  */
00083 static inline char *RTFStrSave(const char *s)
00084 {
00085     char    *p;
00086 
00087     p = heap_alloc (lstrlenA(s) + 1);
00088     if (p == NULL)
00089         return NULL;
00090     return lstrcpyA (p, s);
00091 }
00092 
00093 
00094 /* ---------------------------------------------------------------------- */
00095 
00096 
00097 int _RTFGetChar(RTF_Info *info)
00098 {
00099     int ch;
00100         ME_InStream *stream = info->stream;
00101 
00102     if (stream->dwSize <= stream->dwUsed)
00103     {
00104                 ME_StreamInFill(stream);
00105         /* if error, it's EOF */
00106         if (stream->editstream->dwError)
00107             return EOF;
00108         /* if no bytes read, it's EOF */
00109         if (stream->dwSize == 0)
00110             return EOF;
00111     }
00112     ch = (unsigned char)stream->buffer[stream->dwUsed++];
00113     if (!ch)
00114          return EOF;
00115     return ch;
00116 }
00117 
00118 void RTFSetEditStream(RTF_Info *info, ME_InStream *stream)
00119 {
00120         info->stream = stream;
00121 }
00122 
00123 static void
00124 RTFDestroyAttrs(RTF_Info *info)
00125 {
00126     RTFColor    *cp;
00127     RTFFont     *fp;
00128     RTFStyle    *sp;
00129     RTFStyleElt *eltList, *ep;
00130 
00131     while (info->fontList)
00132     {
00133         fp = info->fontList->rtfNextFont;
00134         heap_free (info->fontList->rtfFName);
00135         heap_free (info->fontList);
00136         info->fontList = fp;
00137     }
00138     while (info->colorList)
00139     {
00140         cp = info->colorList->rtfNextColor;
00141         heap_free (info->colorList);
00142         info->colorList = cp;
00143     }
00144     while (info->styleList)
00145     {
00146         sp = info->styleList->rtfNextStyle;
00147         eltList = info->styleList->rtfSSEList;
00148         while (eltList)
00149         {
00150             ep = eltList->rtfNextSE;
00151             heap_free (eltList->rtfSEText);
00152             heap_free (eltList);
00153             eltList = ep;
00154         }
00155         heap_free (info->styleList->rtfSName);
00156         heap_free (info->styleList);
00157         info->styleList = sp;
00158     }
00159 }
00160 
00161 
00162 void
00163 RTFDestroy(RTF_Info *info)
00164 {
00165     if (info->rtfTextBuf)
00166     {
00167         heap_free(info->rtfTextBuf);
00168         heap_free(info->pushedTextBuf);
00169     }
00170     RTFDestroyAttrs(info);
00171     heap_free(info->cpOutputBuffer);
00172         while (info->tableDef)
00173         {
00174                 RTFTable *tableDef = info->tableDef;
00175                 info->tableDef = tableDef->parent;
00176                 heap_free(tableDef);
00177         }
00178 }
00179 
00180 
00181 
00182 /* ---------------------------------------------------------------------- */
00183 
00184 /*
00185  * Callback table manipulation routines
00186  */
00187 
00188 
00189 /*
00190  * Install or return a writer callback for a token class
00191  */
00192 
00193 static void RTFSetClassCallback(RTF_Info *info, int class, RTFFuncPtr callback)
00194 {
00195     if (class >= 0 && class < rtfMaxClass)
00196         info->ccb[class] = callback;
00197 }
00198 
00199 
00200 static RTFFuncPtr RTFGetClassCallback(const RTF_Info *info, int class)
00201 {
00202     if (class >= 0 && class < rtfMaxClass)
00203         return info->ccb[class];
00204     return NULL;
00205 }
00206 
00207 
00208 /*
00209  * Initialize the reader.  This may be called multiple times,
00210  * to read multiple files.  The only thing not reset is the input
00211  * stream; that must be done with RTFSetStream().
00212  */
00213 
00214 void RTFInit(RTF_Info *info)
00215 {
00216     int i;
00217 
00218     if (info->rtfTextBuf == NULL)   /* initialize the text buffers */
00219     {
00220         info->rtfTextBuf = heap_alloc (rtfBufSiz);
00221         info->pushedTextBuf = heap_alloc (rtfBufSiz);
00222         if (info->rtfTextBuf == NULL || info->pushedTextBuf == NULL) {
00223             ERR ("Cannot allocate text buffers.\n");
00224             return;
00225         }
00226         info->rtfTextBuf[0] = info->pushedTextBuf[0] = '\0';
00227     }
00228 
00229     for (i = 0; i < rtfMaxClass; i++)
00230         RTFSetClassCallback (info, i, NULL);
00231     for (i = 0; i < rtfMaxDestination; i++)
00232         RTFSetDestinationCallback (info, i, NULL);
00233 
00234     /* install built-in destination readers */
00235     RTFSetDestinationCallback (info, rtfFontTbl, ReadFontTbl);
00236     RTFSetDestinationCallback (info, rtfColorTbl, ReadColorTbl);
00237     RTFSetDestinationCallback (info, rtfStyleSheet, ReadStyleSheet);
00238     RTFSetDestinationCallback (info, rtfInfo, ReadInfoGroup);
00239     RTFSetDestinationCallback (info, rtfPict, ReadPictGroup);
00240     RTFSetDestinationCallback (info, rtfObject, ReadObjGroup);
00241 
00242 
00243     RTFSetReadHook (info, NULL);
00244 
00245     /* dump old lists if necessary */
00246 
00247     RTFDestroyAttrs(info);
00248 
00249         info->ansiCodePage = 1252; /* Latin-1; actually unused */
00250     info->unicodeLength = 1; /* \uc1 is the default */
00251     info->codePage = info->ansiCodePage;
00252         info->defFont = 0;
00253 
00254     info->rtfClass = -1;
00255     info->pushedClass = -1;
00256     info->pushedChar = EOF;
00257 
00258     info->rtfLineNum = 0;
00259     info->rtfLinePos = 0;
00260     info->prevChar = EOF;
00261     info->bumpLine = 0;
00262 
00263     info->dwCPOutputCount = 0;
00264         if (!info->cpOutputBuffer)
00265     {
00266         info->dwMaxCPOutputCount = 0x1000;
00267         info->cpOutputBuffer = heap_alloc(info->dwMaxCPOutputCount);
00268     }
00269 
00270         info->tableDef = NULL;
00271         info->nestingLevel = 0;
00272         info->canInheritInTbl = FALSE;
00273         info->borderType = 0;
00274 }
00275 
00276 /*
00277  * Install or return a writer callback for a destination type
00278  */
00279 
00280 void RTFSetDestinationCallback(RTF_Info *info, int dest, RTFFuncPtr callback)
00281 {
00282     if (dest >= 0 && dest < rtfMaxDestination)
00283         info->dcb[dest] = callback;
00284 }
00285 
00286 
00287 static RTFFuncPtr RTFGetDestinationCallback(const RTF_Info *info, int dest)
00288 {
00289     if (dest >= 0 && dest < rtfMaxDestination)
00290         return info->dcb[dest];
00291     return NULL;
00292 }
00293 
00294 
00295 /* ---------------------------------------------------------------------- */
00296 
00297 /*
00298  * Token reading routines
00299  */
00300 
00301 
00302 /*
00303  * Read the input stream, invoking the writer's callbacks
00304  * where appropriate.
00305  */
00306 
00307 void RTFRead(RTF_Info *info)
00308 {
00309     while (RTFGetToken (info) != rtfEOF)
00310         RTFRouteToken (info);
00311 }
00312 
00313 
00314 /*
00315  * Route a token.  If it's a destination for which a reader is
00316  * installed, process the destination internally, otherwise
00317  * pass the token to the writer's class callback.
00318  */
00319 
00320 void RTFRouteToken(RTF_Info *info)
00321 {
00322     RTFFuncPtr  p;
00323 
00324     if (info->rtfClass < 0 || info->rtfClass >= rtfMaxClass)    /* watchdog */
00325     {
00326         ERR( "Unknown class %d: %s (reader malfunction)\n",
00327                             info->rtfClass, info->rtfTextBuf);
00328     }
00329     if (RTFCheckCM (info, rtfControl, rtfDestination))
00330     {
00331         /* invoke destination-specific callback if there is one */
00332         p = RTFGetDestinationCallback (info, info->rtfMinor);
00333         if (p != NULL)
00334         {
00335             (*p) (info);
00336             return;
00337         }
00338     }
00339     /* invoke class callback if there is one */
00340     p = RTFGetClassCallback (info, info->rtfClass);
00341     if (p != NULL)
00342         (*p) (info);
00343 }
00344 
00345 
00346 /*
00347  * Skip to the end of the current group.  When this returns,
00348  * writers that maintain a state stack may want to call their
00349  * state unstacker; global vars will still be set to the group's
00350  * closing brace.
00351  */
00352 
00353 void RTFSkipGroup(RTF_Info *info)
00354 {
00355     int level = 1;
00356 
00357     while (RTFGetToken (info) != rtfEOF)
00358     {
00359         if (info->rtfClass == rtfGroup)
00360         {
00361             if (info->rtfMajor == rtfBeginGroup)
00362                 ++level;
00363             else if (info->rtfMajor == rtfEndGroup)
00364             {
00365                 if (--level < 1)
00366                     break;  /* end of initial group */
00367             }
00368         }
00369     }
00370 }
00371 
00372 /*
00373  * Do no special processing on the group.
00374  *
00375  * This acts as a placeholder for a callback in order to indicate that it
00376  * shouldn't be ignored.  Instead it will fallback on the loop in RTFRead.
00377  */
00378 void RTFReadGroup (RTF_Info *info)
00379 {
00380 }
00381 
00382 
00383 /*
00384  * Install or return a token reader hook.
00385  */
00386 
00387 void RTFSetReadHook(RTF_Info *info, RTFFuncPtr f)
00388 {
00389     info->readHook = f;
00390 }
00391 
00392 
00393 static RTFFuncPtr RTFGetReadHook(const RTF_Info *info)
00394 {
00395     return (info->readHook);
00396 }
00397 
00398 
00399 /*
00400  * Read one token.  Call the read hook if there is one.  The
00401  * token class is the return value.  Returns rtfEOF when there
00402  * are no more tokens.
00403  */
00404 
00405 int RTFGetToken(RTF_Info *info)
00406 {
00407     RTFFuncPtr  p;
00408 
00409     /* don't try to return anything once EOF is reached */
00410     if (info->rtfClass == rtfEOF) {
00411         return rtfEOF;
00412     }
00413 
00414     for (;;)
00415     {
00416         _RTFGetToken (info);
00417         p = RTFGetReadHook (info);
00418         if (p != NULL)
00419             (*p) (info);    /* give read hook a look at token */
00420 
00421         /* Silently discard newlines, carriage returns, nulls.  */
00422         if (!(info->rtfClass == rtfText && info->rtfFormat != SF_TEXT
00423             && (info->rtfMajor == '\r' || info->rtfMajor == '\n' || info->rtfMajor == '\0')))
00424             break;
00425     }
00426     return (info->rtfClass);
00427 }
00428 
00429 
00430 static void RTFUngetToken(RTF_Info *info)
00431 {
00432     if (info->pushedClass >= 0) /* there's already an ungotten token */
00433         ERR ("cannot unget two tokens\n");
00434     if (info->rtfClass < 0)
00435         ERR ("no token to unget\n");
00436     info->pushedClass = info->rtfClass;
00437     info->pushedMajor = info->rtfMajor;
00438     info->pushedMinor = info->rtfMinor;
00439     info->pushedParam = info->rtfParam;
00440     lstrcpyA (info->pushedTextBuf, info->rtfTextBuf);
00441     /* The read hook decrements stackTop on rtfEndGroup, so
00442      * increment the value to compensate for it being decremented
00443      * twice due to the RTFUngetToken. */
00444     if(RTFCheckCM (info, rtfGroup, rtfEndGroup))
00445     {
00446         info->stack[info->stackTop].style = info->style;
00447         ME_AddRefStyle(info->style);
00448         info->stackTop++;
00449     }
00450 }
00451 
00452 
00453 static void _RTFGetToken(RTF_Info *info)
00454 {
00455     if (info->rtfFormat == SF_TEXT)
00456     {
00457         info->rtfMajor = GetChar (info);
00458         info->rtfMinor = 0;
00459         info->rtfParam = rtfNoParam;
00460         info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
00461         if (info->rtfMajor == EOF)
00462             info->rtfClass = rtfEOF;
00463         else
00464             info->rtfClass = rtfText;
00465         return;
00466     }
00467 
00468     /* first check for pushed token from RTFUngetToken() */
00469 
00470     if (info->pushedClass >= 0)
00471     {
00472         info->rtfClass = info->pushedClass;
00473         info->rtfMajor = info->pushedMajor;
00474         info->rtfMinor = info->pushedMinor;
00475         info->rtfParam = info->pushedParam;
00476         lstrcpyA (info->rtfTextBuf, info->pushedTextBuf);
00477         info->rtfTextLen = lstrlenA(info->rtfTextBuf);
00478         info->pushedClass = -1;
00479         return;
00480     }
00481 
00482     /*
00483      * Beyond this point, no token is ever seen twice, which is
00484      * important, e.g., for making sure no "}" pops the font stack twice.
00485      */
00486 
00487     _RTFGetToken2 (info);
00488 }
00489 
00490 
00491 int
00492 RTFCharSetToCodePage(RTF_Info *info, int charset)
00493 {
00494     switch (charset)
00495         {
00496                 case ANSI_CHARSET:
00497                         return 1252;
00498                 case DEFAULT_CHARSET:
00499                         return CP_ACP;
00500                 case SYMBOL_CHARSET:
00501                         return CP_SYMBOL;
00502                 case MAC_CHARSET:
00503                         return CP_MACCP;
00504                 case SHIFTJIS_CHARSET:
00505                         return 932;
00506                 case HANGEUL_CHARSET:
00507                         return 949;
00508                 case JOHAB_CHARSET:
00509                         return 1361;
00510                 case GB2312_CHARSET:
00511                         return 936;
00512                 case CHINESEBIG5_CHARSET:
00513                         return 950;
00514                 case GREEK_CHARSET:
00515                         return 1253;
00516                 case TURKISH_CHARSET:
00517                         return 1254;
00518                 case VIETNAMESE_CHARSET:
00519                         return 1258;
00520                 case HEBREW_CHARSET:
00521                         return 1255;
00522                 case ARABIC_CHARSET:
00523                         return 1256;
00524                 case BALTIC_CHARSET:
00525                         return 1257;
00526                 case RUSSIAN_CHARSET:
00527                         return 1251;
00528                 case THAI_CHARSET:
00529                         return 874;
00530                 case EASTEUROPE_CHARSET:
00531                         return 1250;
00532                 case OEM_CHARSET:
00533                         return CP_OEMCP;
00534                 default:
00535         {
00536                         CHARSETINFO csi;
00537                         DWORD n = charset;
00538 
00539                         /* FIXME: TranslateCharsetInfo does not work as good as it
00540                          * should, so let's use it only when all else fails */
00541                         if (!TranslateCharsetInfo(&n, &csi, TCI_SRCCHARSET))
00542                                 ERR("unknown charset %d\n", charset);
00543             else
00544                                 return csi.ciACP;
00545         }
00546     }
00547         return 0;
00548 }
00549 
00550 
00551 /* this shouldn't be called anywhere but from _RTFGetToken() */
00552 
00553 static void _RTFGetToken2(RTF_Info *info)
00554 {
00555     int sign;
00556     int c;
00557 
00558     /* initialize token vars */
00559 
00560     info->rtfClass = rtfUnknown;
00561     info->rtfParam = rtfNoParam;
00562     info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
00563 
00564     /* get first character, which may be a pushback from previous token */
00565 
00566     if (info->pushedChar != EOF)
00567     {
00568         c = info->pushedChar;
00569         info->rtfTextBuf[info->rtfTextLen++] = c;
00570         info->rtfTextBuf[info->rtfTextLen] = '\0';
00571         info->pushedChar = EOF;
00572     }
00573     else if ((c = GetChar (info)) == EOF)
00574     {
00575         info->rtfClass = rtfEOF;
00576         return;
00577     }
00578 
00579     if (c == '{')
00580     {
00581         info->rtfClass = rtfGroup;
00582         info->rtfMajor = rtfBeginGroup;
00583         return;
00584     }
00585     if (c == '}')
00586     {
00587         info->rtfClass = rtfGroup;
00588         info->rtfMajor = rtfEndGroup;
00589         return;
00590     }
00591     if (c != '\\')
00592     {
00593         /*
00594          * Two possibilities here:
00595          * 1) ASCII 9, effectively like \tab control symbol
00596          * 2) literal text char
00597          */
00598         if (c == '\t')          /* ASCII 9 */
00599         {
00600             info->rtfClass = rtfControl;
00601             info->rtfMajor = rtfSpecialChar;
00602             info->rtfMinor = rtfTab;
00603         }
00604         else
00605         {
00606             info->rtfClass = rtfText;
00607             info->rtfMajor = c;
00608         }
00609         return;
00610     }
00611     if ((c = GetChar (info)) == EOF)
00612     {
00613         /* early eof, whoops (class is rtfUnknown) */
00614         return;
00615     }
00616     if (!isalpha (c))
00617     {
00618         /*
00619          * Three possibilities here:
00620          * 1) hex encoded text char, e.g., \'d5, \'d3
00621          * 2) special escaped text char, e.g., \{, \}
00622          * 3) control symbol, e.g., \_, \-, \|, <10>
00623          */
00624         if (c == '\'')              /* hex char */
00625         {
00626         int c2;
00627 
00628             if ((c = GetChar (info)) != EOF && (c2 = GetChar (info)) != EOF
00629                 && isxdigit(c) && isxdigit(c2))
00630             {
00631                 info->rtfClass = rtfText;
00632                 info->rtfMajor = RTFCharToHex (c) * 16 + RTFCharToHex (c2);
00633                 return;
00634             }
00635             /* early eof, whoops */
00636             info->rtfClass = rtfEOF;
00637             info->stream->editstream->dwError = -14;
00638             return;
00639         }
00640 
00641         /* escaped char */
00642         /*if (index (":{}\\", c) != NULL)*/ /* escaped char */
00643         if (c == ':' || c == '{' || c == '}' || c == '\\')
00644         {
00645             info->rtfClass = rtfText;
00646             info->rtfMajor = c;
00647             return;
00648         }
00649 
00650         /* control symbol */
00651         Lookup (info, info->rtfTextBuf);    /* sets class, major, minor */
00652         return;
00653     }
00654     /* control word */
00655     while (isalpha (c))
00656     {
00657         if ((c = GetChar (info)) == EOF)
00658             break;
00659     }
00660 
00661     /*
00662      * At this point, the control word is all collected, so the
00663      * major/minor numbers are determined before the parameter
00664      * (if any) is scanned.  There will be one too many characters
00665      * in the buffer, though, so fix up before and restore after
00666      * looking up.
00667      */
00668 
00669     if (c != EOF)
00670         info->rtfTextBuf[info->rtfTextLen-1] = '\0';
00671     Lookup (info, info->rtfTextBuf);    /* sets class, major, minor */
00672     if (c != EOF)
00673         info->rtfTextBuf[info->rtfTextLen-1] = c;
00674 
00675     /*
00676      * Should be looking at first digit of parameter if there
00677      * is one, unless it's negative.  In that case, next char
00678      * is '-', so need to gobble next char, and remember sign.
00679      */
00680 
00681     sign = 1;
00682     if (c == '-')
00683     {
00684         sign = -1;
00685         c = GetChar (info);
00686     }
00687     if (c != EOF && isdigit (c))
00688     {
00689         info->rtfParam = 0;
00690         while (isdigit (c)) /* gobble parameter */
00691         {
00692             info->rtfParam = info->rtfParam * 10 + c - '0';
00693             if ((c = GetChar (info)) == EOF)
00694                 break;
00695         }
00696         info->rtfParam *= sign;
00697     }
00698     /*
00699      * If control symbol delimiter was a blank, gobble it.
00700      * Otherwise the character is first char of next token, so
00701      * push it back for next call.  In either case, delete the
00702      * delimiter from the token buffer.
00703      */
00704     if (c != EOF)
00705     {
00706         if (c != ' ')
00707             info->pushedChar = c;
00708         info->rtfTextBuf[--info->rtfTextLen] = '\0';
00709     }
00710 }
00711 
00712 
00713 /*
00714  * Read the next character from the input.  This handles setting the
00715  * current line and position-within-line variables.  Those variable are
00716  * set correctly whether lines end with CR, LF, or CRLF (the last being
00717  * the tricky case).
00718  *
00719  * bumpLine indicates whether the line number should be incremented on
00720  * the *next* input character.
00721  */
00722 
00723 
00724 static int GetChar(RTF_Info *info)
00725 {
00726     int c;
00727     int oldBumpLine;
00728 
00729     if ((c = _RTFGetChar(info)) != EOF)
00730     {
00731         info->rtfTextBuf[info->rtfTextLen++] = c;
00732         info->rtfTextBuf[info->rtfTextLen] = '\0';
00733     }
00734     if (info->prevChar == EOF)
00735         info->bumpLine = 1;
00736     oldBumpLine = info->bumpLine;   /* non-zero if prev char was line ending */
00737     info->bumpLine = 0;
00738     if (c == '\r')
00739         info->bumpLine = 1;
00740     else if (c == '\n')
00741     {
00742         info->bumpLine = 1;
00743         if (info->prevChar == '\r')     /* oops, previous \r wasn't */
00744             oldBumpLine = 0;    /* really a line ending */
00745     }
00746     ++info->rtfLinePos;
00747     if (oldBumpLine)    /* were we supposed to increment the */
00748     {           /* line count on this char? */
00749         ++info->rtfLineNum;
00750         info->rtfLinePos = 1;
00751     }
00752     info->prevChar = c;
00753     return (c);
00754 }
00755 
00756 
00757 /* ---------------------------------------------------------------------- */
00758 
00759 /*
00760  * Special destination readers.  They gobble the destination so the
00761  * writer doesn't have to deal with them.  That's wrong for any
00762  * translator that wants to process any of these itself.  In that
00763  * case, these readers should be overridden by installing a different
00764  * destination callback.
00765  *
00766  * NOTE: The last token read by each of these reader will be the
00767  * destination's terminating '}', which will then be the current token.
00768  * That '}' token is passed to RTFRouteToken() - the writer has already
00769  * seen the '{' that began the destination group, and may have pushed a
00770  * state; it also needs to know at the end of the group that a state
00771  * should be popped.
00772  *
00773  * It's important that rtf.h and the control token lookup table list
00774  * as many symbols as possible, because these destination readers
00775  * unfortunately make strict assumptions about the input they expect,
00776  * and a token of class rtfUnknown will throw them off easily.
00777  */
00778 
00779 
00780 /*
00781  * Read { \fonttbl ... } destination.  Old font tables don't have
00782  * braces around each table entry; try to adjust for that.
00783  */
00784 
00785 static void ReadFontTbl(RTF_Info *info)
00786 {
00787     RTFFont     *fp = NULL;
00788     char        buf[rtfBufSiz], *bp;
00789     int     old = -1;
00790 
00791     for (;;)
00792     {
00793         RTFGetToken (info);
00794         if (info->rtfClass == rtfEOF)
00795             break;
00796         if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
00797             break;
00798         if (old < 0)        /* first entry - determine tbl type */
00799         {
00800             if (RTFCheckCMM (info, rtfControl, rtfCharAttr, rtfFontNum))
00801                 old = 1;    /* no brace */
00802             else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))
00803                 old = 0;    /* brace */
00804             else            /* can't tell! */
00805                 ERR ("cannot determine format\n");
00806         }
00807         if (old == 0)       /* need to find "{" here */
00808         {
00809             if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
00810                 ERR ("missing \"{\"\n");
00811             RTFGetToken (info); /* yes, skip to next token */
00812             if (info->rtfClass == rtfEOF)
00813                 break;
00814         }
00815         fp = New (RTFFont);
00816         if (fp == NULL) {
00817             ERR ("cannot allocate font entry\n");
00818             break;
00819         }
00820 
00821         fp->rtfNextFont = info->fontList;
00822         info->fontList = fp;
00823 
00824         fp->rtfFName = NULL;
00825         fp->rtfFAltName = NULL;
00826         fp->rtfFNum = -1;
00827         fp->rtfFFamily = FF_DONTCARE;
00828         fp->rtfFCharSet = DEFAULT_CHARSET; /* 1 */
00829         fp->rtfFPitch = DEFAULT_PITCH;
00830         fp->rtfFType = 0;
00831         fp->rtfFCodePage = CP_ACP;
00832 
00833         while (info->rtfClass != rtfEOF
00834                && !RTFCheckCM (info, rtfText, ';')
00835                && !RTFCheckCM (info, rtfGroup, rtfEndGroup))
00836         {
00837             if (info->rtfClass == rtfControl)
00838             {
00839                 switch (info->rtfMajor)
00840                 {
00841                 default:
00842                     /* ignore token but announce it */
00843                     WARN ("unknown token \"%s\"\n",
00844                         info->rtfTextBuf);
00845                                         break;
00846                 case rtfFontFamily:
00847                     fp->rtfFFamily = info->rtfMinor;
00848                     break;
00849                 case rtfCharAttr:
00850                     switch (info->rtfMinor)
00851                     {
00852                     default:
00853                         break;  /* ignore unknown? */
00854                     case rtfFontNum:
00855                         fp->rtfFNum = info->rtfParam;
00856                         break;
00857                     }
00858                     break;
00859                 case rtfFontAttr:
00860                     switch (info->rtfMinor)
00861                     {
00862                     default:
00863                         break;  /* ignore unknown? */
00864                     case rtfFontCharSet:
00865                         fp->rtfFCharSet = info->rtfParam;
00866                                                 if (!fp->rtfFCodePage)
00867                                                         fp->rtfFCodePage = RTFCharSetToCodePage(info, info->rtfParam);
00868                         break;
00869                     case rtfFontPitch:
00870                         fp->rtfFPitch = info->rtfParam;
00871                         break;
00872                     case rtfFontCodePage:
00873                         fp->rtfFCodePage = info->rtfParam;
00874                         break;
00875                     case rtfFTypeNil:
00876                     case rtfFTypeTrueType:
00877                         fp->rtfFType = info->rtfParam;
00878                         break;
00879                     }
00880                     break;
00881                 }
00882             }
00883             else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))    /* dest */
00884             {
00885                 RTFSkipGroup (info);    /* ignore for now */
00886             }
00887             else if (info->rtfClass == rtfText) /* font name */
00888             {
00889                 bp = buf;
00890                                 while (info->rtfClass == rtfText
00891                                         && !RTFCheckCM (info, rtfText, ';'))
00892                 {
00893                     *bp++ = info->rtfMajor;
00894                     RTFGetToken (info);
00895                 }
00896 
00897                 /* FIX: in some cases the <fontinfo> isn't finished with a semi-column */
00898                 if(RTFCheckCM (info, rtfGroup, rtfEndGroup))
00899                 {
00900                     RTFUngetToken (info);
00901                 }
00902                 *bp = '\0';
00903                 fp->rtfFName = RTFStrSave (buf);
00904                 if (fp->rtfFName == NULL)
00905                     ERR ("cannot allocate font name\n");
00906                 /* already have next token; don't read one */
00907                 /* at bottom of loop */
00908                 continue;
00909             }
00910             else
00911             {
00912                 /* ignore token but announce it */
00913                 WARN ("unknown token \"%s\"\n", info->rtfTextBuf);
00914             }
00915             RTFGetToken (info);
00916             if (info->rtfClass == rtfEOF)
00917                 break;
00918         }
00919         if (info->rtfClass == rtfEOF)
00920             break;
00921         if (old == 0)   /* need to see "}" here */
00922         {
00923             RTFGetToken (info);
00924             if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
00925                 ERR ("missing \"}\"\n");
00926             if (info->rtfClass == rtfEOF)
00927                 break;
00928         }
00929 
00930                 /* Apply the real properties of the default font */
00931                 if (fp->rtfFNum == info->defFont)
00932                 {
00933                         if (info->ansiCodePage != CP_UTF8)
00934                                 info->codePage = fp->rtfFCodePage;
00935                         TRACE("default font codepage %d\n", info->codePage);
00936                 }
00937     }
00938     if (!fp || (fp->rtfFNum == -1))
00939         ERR("missing font number\n");
00940 /*
00941  * Could check other pieces of structure here, too, I suppose.
00942  */
00943     RTFRouteToken (info);   /* feed "}" back to router */
00944 
00945         /* Set default font */
00946     info->rtfClass = rtfControl;
00947     info->rtfMajor = rtfCharAttr;
00948     info->rtfMinor = rtfFontNum;
00949     info->rtfParam = info->defFont;
00950     lstrcpyA(info->rtfTextBuf, "f");
00951         RTFUngetToken(info);
00952 }
00953 
00954 
00955 /*
00956  * The color table entries have color values of -1 if
00957  * the default color should be used for the entry (only
00958  * a semi-colon is given in the definition, no color values).
00959  * There will be a problem if a partial entry (1 or 2 but
00960  * not 3 color values) is given.  The possibility is ignored
00961  * here.
00962  */
00963 
00964 static void ReadColorTbl(RTF_Info *info)
00965 {
00966     RTFColor    *cp;
00967     int     cnum = 0;
00968         int group_level = 1;
00969 
00970     for (;;)
00971     {
00972         RTFGetToken (info);
00973         if (info->rtfClass == rtfEOF)
00974             break;
00975         if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
00976                 {
00977                         group_level--;
00978                         if (!group_level)
00979                                 break;
00980                         continue;
00981                 }
00982                 else if (RTFCheckCM(info, rtfGroup, rtfBeginGroup))
00983                 {
00984                         group_level++;
00985                         continue;
00986                 }
00987 
00988         cp = New (RTFColor);
00989         if (cp == NULL) {
00990             ERR ("cannot allocate color entry\n");
00991             break;
00992         }
00993         cp->rtfCNum = cnum++;
00994         cp->rtfNextColor = info->colorList;
00995         info->colorList = cp;
00996         if (!RTFCheckCM (info, rtfControl, rtfColorName))
00997             cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
00998         else {
00999             cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = 0;
01000             do {
01001                 switch (info->rtfMinor)
01002                 {
01003                 case rtfRed:    cp->rtfCRed = info->rtfParam & 0xFF; break;
01004                 case rtfGreen:  cp->rtfCGreen = info->rtfParam & 0xFF; break;
01005                 case rtfBlue:   cp->rtfCBlue = info->rtfParam & 0xFF; break;
01006                 }
01007                 RTFGetToken (info);
01008             } while (RTFCheckCM (info, rtfControl, rtfColorName));
01009         }
01010         if (info->rtfClass == rtfEOF)
01011             break;
01012         if (!RTFCheckCM (info, rtfText, ';'))
01013             ERR ("malformed entry\n");
01014     }
01015     RTFRouteToken (info);   /* feed "}" back to router */
01016 }
01017 
01018 
01019 /*
01020  * The "Normal" style definition doesn't contain any style number,
01021  * all others do.  Normal style is given style rtfNormalStyleNum.
01022  */
01023 
01024 static void ReadStyleSheet(RTF_Info *info)
01025 {
01026     RTFStyle    *sp;
01027     RTFStyleElt *sep, *sepLast;
01028     char        buf[rtfBufSiz], *bp;
01029     int             real_style;
01030 
01031     for (;;)
01032     {
01033         RTFGetToken (info);
01034         if (info->rtfClass == rtfEOF)
01035             break;
01036         if (RTFCheckCM (info, rtfGroup, rtfEndGroup))
01037             break;
01038         sp = New (RTFStyle);
01039         if (sp == NULL) {
01040             ERR ("cannot allocate stylesheet entry\n");
01041             break;
01042         }
01043         sp->rtfSName = NULL;
01044         sp->rtfSNum = -1;
01045         sp->rtfSType = rtfParStyle;
01046         sp->rtfSAdditive = 0;
01047         sp->rtfSBasedOn = rtfNoStyleNum;
01048         sp->rtfSNextPar = -1;
01049         sp->rtfSSEList = sepLast = NULL;
01050         sp->rtfNextStyle = info->styleList;
01051         sp->rtfExpanding = 0;
01052         info->styleList = sp;
01053         if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup))
01054             ERR ("missing \"{\"\n");
01055         real_style = TRUE;
01056         for (;;)
01057         {
01058             RTFGetToken (info);
01059             if (info->rtfClass == rtfEOF
01060                 || RTFCheckCM (info, rtfText, ';'))
01061                 break;
01062             if (info->rtfClass == rtfControl)
01063             {
01064                 if (RTFCheckMM (info, rtfSpecialChar, rtfOptDest)) {
01065                     RTFGetToken(info);
01066                     ERR("skipping optional destination\n");
01067                     RTFSkipGroup(info);
01068                     info->rtfClass = rtfGroup;
01069                     info->rtfMajor = rtfEndGroup;
01070                     real_style = FALSE;
01071                     break; /* ignore "\*" */
01072                 }
01073                 if (RTFCheckMM (info, rtfParAttr, rtfStyleNum))
01074                 {
01075                     sp->rtfSNum = info->rtfParam;
01076                     sp->rtfSType = rtfParStyle;
01077                     continue;
01078                 }
01079                 if (RTFCheckMM (info, rtfCharAttr, rtfCharStyleNum))
01080                 {
01081                     sp->rtfSNum = info->rtfParam;
01082                     sp->rtfSType = rtfCharStyle;
01083                     continue;
01084                 }
01085                 if (RTFCheckMM (info, rtfSectAttr, rtfSectStyleNum))
01086                 {
01087                     sp->rtfSNum = info->rtfParam;
01088                     sp->rtfSType = rtfSectStyle;
01089                     continue;
01090                 }
01091                 if (RTFCheckMM (info, rtfStyleAttr, rtfBasedOn))
01092                 {
01093                     sp->rtfSBasedOn = info->rtfParam;
01094                     continue;
01095                 }
01096                 if (RTFCheckMM (info, rtfStyleAttr, rtfAdditive))
01097                 {
01098                     sp->rtfSAdditive = 1;
01099                     continue;
01100                 }
01101                 if (RTFCheckMM (info, rtfStyleAttr, rtfNext))
01102                 {
01103                     sp->rtfSNextPar = info->rtfParam;
01104                     continue;
01105                 }
01106                 sep = New (RTFStyleElt);
01107                 if (sep == NULL)
01108                                 {
01109                     ERR ("cannot allocate style element\n");
01110                     break;
01111                 }
01112                 sep->rtfSEClass = info->rtfClass;
01113                 sep->rtfSEMajor = info->rtfMajor;
01114                 sep->rtfSEMinor = info->rtfMinor;
01115                 sep->rtfSEParam = info->rtfParam;
01116                 sep->rtfSEText = RTFStrSave (info->rtfTextBuf);
01117                 if (sep->rtfSEText == NULL)
01118                     ERR ("cannot allocate style element text\n");
01119                 if (sepLast == NULL)
01120                     sp->rtfSSEList = sep;   /* first element */
01121                 else                /* add to end */
01122                     sepLast->rtfNextSE = sep;
01123                 sep->rtfNextSE = NULL;
01124                 sepLast = sep;
01125             }
01126             else if (RTFCheckCM (info, rtfGroup, rtfBeginGroup))
01127             {
01128                 /*
01129                  * This passes over "{\*\keycode ... }, among
01130                  * other things. A temporary (perhaps) hack.
01131                  */
01132                 ERR("skipping begin\n");
01133                 RTFSkipGroup (info);
01134                 continue;
01135             }
01136             else if (info->rtfClass == rtfText) /* style name */
01137             {
01138                 bp = buf;
01139                 while (info->rtfClass == rtfText)
01140                 {
01141                     if (info->rtfMajor == ';')
01142                     {
01143                         /* put back for "for" loop */
01144                         RTFUngetToken (info);
01145                         break;
01146                     }
01147                     *bp++ = info->rtfMajor;
01148                     RTFGetToken (info);
01149                 }
01150                 *bp = '\0';
01151                 sp->rtfSName = RTFStrSave (buf);
01152                 if (sp->rtfSName == NULL)
01153                     ERR ("cannot allocate style name\n");
01154             }
01155             else        /* unrecognized */
01156             {
01157                 /* ignore token but announce it */
01158                 WARN ("unknown token \"%s\"\n", info->rtfTextBuf);
01159             }
01160         }
01161         if (real_style) {
01162             RTFGetToken (info);
01163             if (!RTFCheckCM (info, rtfGroup, rtfEndGroup))
01164                 ERR ("missing \"}\"\n");
01165             /*
01166              * Check over the style structure.  A name is a must.
01167              * If no style number was specified, check whether it's the
01168              * Normal style (in which case it's given style number
01169              * rtfNormalStyleNum).  Note that some "normal" style names
01170              * just begin with "Normal" and can have other stuff following,
01171              * e.g., "Normal,Times 10 point".  Ugh.
01172              *
01173              * Some German RTF writers use "Standard" instead of "Normal".
01174              */
01175             if (sp->rtfSName == NULL)
01176                 ERR ("missing style name\n");
01177             if (sp->rtfSNum < 0)
01178             {
01179                 if (strncmp (buf, "Normal", 6) != 0
01180                     && strncmp (buf, "Standard", 8) != 0)
01181                     ERR ("missing style number\n");
01182                 sp->rtfSNum = rtfNormalStyleNum;
01183             }
01184             if (sp->rtfSNextPar == -1)  /* if \snext not given, */
01185                 sp->rtfSNextPar = sp->rtfSNum;  /* next is itself */
01186         }
01187         /* otherwise we're just dealing with fake end group from skipped group */
01188     }
01189     RTFRouteToken (info);   /* feed "}" back to router */
01190 }
01191 
01192 
01193 static void ReadInfoGroup(RTF_Info *info)
01194 {
01195     RTFSkipGroup (info);
01196     RTFRouteToken (info);   /* feed "}" back to router */
01197 }
01198 
01199 
01200 static void ReadPictGroup(RTF_Info *info)
01201 {
01202     RTFSkipGroup (info);
01203     RTFRouteToken (info);   /* feed "}" back to router */
01204 }
01205 
01206 
01207 static void ReadObjGroup(RTF_Info *info)
01208 {
01209     RTFSkipGroup (info);
01210     RTFRouteToken (info);   /* feed "}" back to router */
01211 }
01212 
01213 
01214 /* ---------------------------------------------------------------------- */
01215 
01216 /*
01217  * Routines to return pieces of stylesheet, or font or color tables.
01218  * References to style 0 are mapped onto the Normal style.
01219  */
01220 
01221 RTFFont *RTFGetFont(const RTF_Info *info, int num)
01222 {
01223     RTFFont *f;
01224 
01225     if (num == -1)
01226         return (info->fontList);
01227     for (f = info->fontList; f != NULL; f = f->rtfNextFont)
01228     {
01229         if (f->rtfFNum == num)
01230             break;
01231     }
01232     return (f);     /* NULL if not found */
01233 }
01234 
01235 
01236 RTFColor *RTFGetColor(const RTF_Info *info, int num)
01237 {
01238     RTFColor    *c;
01239 
01240     if (num == -1)
01241         return (info->colorList);
01242     for (c = info->colorList; c != NULL; c = c->rtfNextColor)
01243     {
01244         if (c->rtfCNum == num)
01245             break;
01246     }
01247     return (c);     /* NULL if not found */
01248 }
01249 
01250 
01251 /* ---------------------------------------------------------------------- */
01252 
01253 /*
01254  * Control symbol lookup routines
01255  */
01256 
01257 
01258 typedef struct RTFKey   RTFKey;
01259 
01260 struct RTFKey
01261 {
01262     int        rtfKMajor;   /* major number */
01263     int        rtfKMinor;   /* minor number */
01264     const char *rtfKStr;    /* symbol name */
01265     int        rtfKHash;    /* symbol name hash value */
01266 };
01267 
01268 /*
01269  * A minor number of -1 means the token has no minor number
01270  * (all valid minor numbers are >= 0).
01271  */
01272 
01273 static RTFKey   rtfKey[] =
01274 {
01275     /*
01276      * Special characters
01277      */
01278 
01279     { rtfSpecialChar,   rtfIIntVersion,     "vern",     0 },
01280     { rtfSpecialChar,   rtfICreateTime,     "creatim",  0 },
01281     { rtfSpecialChar,   rtfIRevisionTime,   "revtim",   0 },
01282     { rtfSpecialChar,   rtfIPrintTime,      "printim",  0 },
01283     { rtfSpecialChar,   rtfIBackupTime,     "buptim",   0 },
01284     { rtfSpecialChar,   rtfIEditTime,       "edmins",   0 },
01285     { rtfSpecialChar,   rtfIYear,       "yr",       0 },
01286     { rtfSpecialChar,   rtfIMonth,      "mo",       0 },
01287     { rtfSpecialChar,   rtfIDay,        "dy",       0 },
01288     { rtfSpecialChar,   rtfIHour,       "hr",       0 },
01289     { rtfSpecialChar,   rtfIMinute,     "min",      0 },
01290     { rtfSpecialChar,   rtfISecond,     "sec",      0 },
01291     { rtfSpecialChar,   rtfINPages,     "nofpages", 0 },
01292     { rtfSpecialChar,   rtfINWords,     "nofwords", 0 },
01293     { rtfSpecialChar,   rtfINChars,     "nofchars", 0 },
01294     { rtfSpecialChar,   rtfIIntID,      "id",       0 },
01295 
01296     { rtfSpecialChar,   rtfCurHeadDate,     "chdate",   0 },
01297     { rtfSpecialChar,   rtfCurHeadDateLong, "chdpl",    0 },
01298     { rtfSpecialChar,   rtfCurHeadDateAbbrev,   "chdpa",    0 },
01299     { rtfSpecialChar,   rtfCurHeadTime,     "chtime",   0 },
01300     { rtfSpecialChar,   rtfCurHeadPage,     "chpgn",    0 },
01301     { rtfSpecialChar,   rtfSectNum,     "sectnum",  0 },
01302     { rtfSpecialChar,   rtfCurFNote,        "chftn",    0 },
01303     { rtfSpecialChar,   rtfCurAnnotRef,     "chatn",    0 },
01304     { rtfSpecialChar,   rtfFNoteSep,        "chftnsep", 0 },
01305     { rtfSpecialChar,   rtfFNoteCont,       "chftnsepc",    0 },
01306     { rtfSpecialChar,   rtfCell,        "cell",     0 },
01307     { rtfSpecialChar,   rtfRow,         "row",      0 },
01308     { rtfSpecialChar,   rtfPar,         "par",      0 },
01309     /* newline and carriage return are synonyms for */
01310     /* \par when they are preceded by a \ character */
01311     { rtfSpecialChar,   rtfPar,         "\n",       0 },
01312     { rtfSpecialChar,   rtfPar,         "\r",       0 },
01313     { rtfSpecialChar,   rtfSect,        "sect",     0 },
01314     { rtfSpecialChar,   rtfPage,        "page",     0 },
01315     { rtfSpecialChar,   rtfColumn,      "column",   0 },
01316     { rtfSpecialChar,   rtfLine,        "line",     0 },
01317     { rtfSpecialChar,   rtfSoftPage,        "softpage", 0 },
01318     { rtfSpecialChar,   rtfSoftColumn,      "softcol",  0 },
01319     { rtfSpecialChar,   rtfSoftLine,        "softline", 0 },
01320     { rtfSpecialChar,   rtfSoftLineHt,      "softlheight",  0 },
01321     { rtfSpecialChar,   rtfTab,         "tab",      0 },
01322     { rtfSpecialChar,   rtfEmDash,      "emdash",   0 },
01323     { rtfSpecialChar,   rtfEnDash,      "endash",   0 },
01324     { rtfSpecialChar,   rtfEmSpace,     "emspace",  0 },
01325     { rtfSpecialChar,   rtfEnSpace,     "enspace",  0 },
01326     { rtfSpecialChar,   rtfBullet,      "bullet",   0 },
01327     { rtfSpecialChar,   rtfLQuote,      "lquote",   0 },
01328     { rtfSpecialChar,   rtfRQuote,      "rquote",   0 },
01329     { rtfSpecialChar,   rtfLDblQuote,       "ldblquote",    0 },
01330     { rtfSpecialChar,   rtfRDblQuote,       "rdblquote",    0 },
01331     { rtfSpecialChar,   rtfFormula,     "|",        0 },
01332     { rtfSpecialChar,   rtfNoBrkSpace,      "~",        0 },
01333     { rtfSpecialChar,   rtfNoReqHyphen,     "-",        0 },
01334     { rtfSpecialChar,   rtfNoBrkHyphen,     "_",        0 },
01335     { rtfSpecialChar,   rtfOptDest,     "*",        0 },
01336     { rtfSpecialChar,   rtfLTRMark,     "ltrmark",  0 },
01337     { rtfSpecialChar,   rtfRTLMark,     "rtlmark",  0 },
01338     { rtfSpecialChar,   rtfNoWidthJoiner,   "zwj",      0 },
01339     { rtfSpecialChar,   rtfNoWidthNonJoiner,    "zwnj",     0 },
01340     /* is this valid? */
01341     { rtfSpecialChar,   rtfCurHeadPict,     "chpict",   0 },
01342     { rtfSpecialChar,   rtfUnicode,     "u",        0 },
01343     { rtfSpecialChar,   rtfNestCell,        "nestcell", 0 },
01344     { rtfSpecialChar,   rtfNestRow,     "nestrow",  0 },
01345 
01346     /*
01347      * Character formatting attributes
01348      */
01349 
01350     { rtfCharAttr,  rtfPlain,       "plain",    0 },
01351     { rtfCharAttr,  rtfBold,        "b",        0 },
01352     { rtfCharAttr,  rtfAllCaps,     "caps",     0 },
01353     { rtfCharAttr,  rtfDeleted,     "deleted",  0 },
01354     { rtfCharAttr,  rtfSubScript,       "dn",       0 },
01355     { rtfCharAttr,  rtfSubScrShrink,    "sub",      0 },
01356     { rtfCharAttr,  rtfNoSuperSub,      "nosupersub",   0 },
01357     { rtfCharAttr,  rtfExpand,      "expnd",    0 },
01358     { rtfCharAttr,  rtfExpandTwips,     "expndtw",  0 },
01359     { rtfCharAttr,  rtfKerning,     "kerning",  0 },
01360     { rtfCharAttr,  rtfFontNum,     "f",        0 },
01361     { rtfCharAttr,  rtfFontSize,        "fs",       0 },
01362     { rtfCharAttr,  rtfItalic,      "i",        0 },
01363     { rtfCharAttr,  rtfOutline,     "outl",     0 },
01364     { rtfCharAttr,  rtfRevised,     "revised",  0 },
01365     { rtfCharAttr,  rtfRevAuthor,       "revauth",  0 },
01366     { rtfCharAttr,  rtfRevDTTM,     "revdttm",  0 },
01367     { rtfCharAttr,  rtfSmallCaps,       "scaps",    0 },
01368     { rtfCharAttr,  rtfShadow,      "shad",     0 },
01369     { rtfCharAttr,  rtfStrikeThru,      "strike",   0 },
01370     { rtfCharAttr,  rtfUnderline,       "ul",       0 },
01371     { rtfCharAttr,  rtfDotUnderline,    "uld",      0 },
01372     { rtfCharAttr,  rtfDbUnderline,     "uldb",     0 },
01373     { rtfCharAttr,  rtfNoUnderline,     "ulnone",   0 },
01374     { rtfCharAttr,  rtfWordUnderline,   "ulw",      0 },
01375     { rtfCharAttr,  rtfSuperScript,     "up",       0 },
01376     { rtfCharAttr,  rtfSuperScrShrink,  "super",    0 },
01377     { rtfCharAttr,  rtfInvisible,       "v",        0 },
01378     { rtfCharAttr,  rtfForeColor,       "cf",       0 },
01379     { rtfCharAttr,  rtfBackColor,       "cb",       0 },
01380     { rtfCharAttr,  rtfRTLChar,     "rtlch",    0 },
01381     { rtfCharAttr,  rtfLTRChar,     "ltrch",    0 },
01382     { rtfCharAttr,  rtfCharStyleNum,    "cs",       0 },
01383     { rtfCharAttr,  rtfCharCharSet,     "cchs",     0 },
01384     { rtfCharAttr,  rtfLanguage,        "lang",     0 },
01385     /* this has disappeared from spec 1.2 */
01386     { rtfCharAttr,  rtfGray,        "gray",     0 },
01387         { rtfCharAttr,  rtfUnicodeLength,   "uc",       0 },
01388 
01389     /*
01390      * Paragraph formatting attributes
01391      */
01392 
01393     { rtfParAttr,   rtfParDef,      "pard",     0 },
01394     { rtfParAttr,   rtfStyleNum,        "s",        0 },
01395     { rtfParAttr,   rtfHyphenate,       "hyphpar",  0 },
01396     { rtfParAttr,   rtfInTable,     "intbl",    0 },
01397     { rtfParAttr,   rtfKeep,        "keep",     0 },
01398     { rtfParAttr,   rtfNoWidowControl,  "nowidctlpar",  0 },
01399     { rtfParAttr,   rtfKeepNext,        "keepn",    0 },
01400     { rtfParAttr,   rtfOutlineLevel,    "level",    0 },
01401     { rtfParAttr,   rtfNoLineNum,       "noline",   0 },
01402     { rtfParAttr,   rtfPBBefore,        "pagebb",   0 },
01403     { rtfParAttr,   rtfSideBySide,      "sbys",     0 },
01404     { rtfParAttr,   rtfQuadLeft,        "ql",       0 },
01405     { rtfParAttr,   rtfQuadRight,       "qr",       0 },
01406     { rtfParAttr,   rtfQuadJust,        "qj",       0 },
01407     { rtfParAttr,   rtfQuadCenter,      "qc",       0 },
01408     { rtfParAttr,   rtfFirstIndent,     "fi",       0 },
01409     { rtfParAttr,   rtfLeftIndent,      "li",       0 },
01410     { rtfParAttr,   rtfRightIndent,     "ri",       0 },
01411     { rtfParAttr,   rtfSpaceBefore,     "sb",       0 },
01412     { rtfParAttr,   rtfSpaceAfter,      "sa",       0 },
01413     { rtfParAttr,   rtfSpaceBetween,    "sl",       0 },
01414     { rtfParAttr,   rtfSpaceMultiply,   "slmult",   0 },
01415 
01416     { rtfParAttr,   rtfSubDocument,     "subdocument",  0 },
01417 
01418     { rtfParAttr,   rtfRTLPar,      "rtlpar",   0 },
01419     { rtfParAttr,   rtfLTRPar,      "ltrpar",   0 },
01420 
01421     { rtfParAttr,   rtfTabPos,      "tx",       0 },
01422     /*
01423      * FrameMaker writes \tql (to mean left-justified tab, apparently)
01424      * although it's not in the spec.  It's also redundant, since lj
01425      * tabs are the default.
01426      */
01427     { rtfParAttr,   rtfTabLeft,     "tql",      0 },
01428     { rtfParAttr,   rtfTabRight,        "tqr",      0 },
01429     { rtfParAttr,   rtfTabCenter,       "tqc",      0 },
01430     { rtfParAttr,   rtfTabDecimal,      "tqdec",    0 },
01431     { rtfParAttr,   rtfTabBar,      "tb",       0 },
01432     { rtfParAttr,   rtfLeaderDot,       "tldot",    0 },
01433     { rtfParAttr,   rtfLeaderHyphen,    "tlhyph",   0 },
01434     { rtfParAttr,   rtfLeaderUnder,     "tlul",     0 },
01435     { rtfParAttr,   rtfLeaderThick,     "tlth",     0 },
01436     { rtfParAttr,   rtfLeaderEqual,     "tleq",     0 },
01437 
01438     { rtfParAttr,   rtfParLevel,        "pnlvl",    0 },
01439     { rtfParAttr,   rtfParBullet,       "pnlvlblt", 0 },
01440     { rtfParAttr,   rtfParSimple,       "pnlvlbody",    0 },
01441     { rtfParAttr,   rtfParNumCont,      "pnlvlcont",    0 },
01442     { rtfParAttr,   rtfParNumOnce,      "pnnumonce",    0 },
01443     { rtfParAttr,   rtfParNumAcross,    "pnacross", 0 },
01444     { rtfParAttr,   rtfParHangIndent,   "pnhang",   0 },
01445     { rtfParAttr,   rtfParNumRestart,   "pnrestart",    0 },
01446     { rtfParAttr,   rtfParNumCardinal,  "pncard",   0 },
01447     { rtfParAttr,   rtfParNumDecimal,   "pndec",    0 },
01448     { rtfParAttr,   rtfParNumULetter,   "pnucltr",  0 },
01449     { rtfParAttr,   rtfParNumURoman,    "pnucrm",   0 },
01450     { rtfParAttr,   rtfParNumLLetter,   "pnlcltr",  0 },
01451     { rtfParAttr,   rtfParNumLRoman,    "pnlcrm",   0 },
01452     { rtfParAttr,   rtfParNumOrdinal,   "pnord",    0 },
01453     { rtfParAttr,   rtfParNumOrdinalText,   "pnordt",   0 },
01454     { rtfParAttr,   rtfParNumBold,      "pnb",      0 },
01455     { rtfParAttr,   rtfParNumItalic,    "pni",      0 },
01456     { rtfParAttr,   rtfParNumAllCaps,   "pncaps",   0 },
01457     { rtfParAttr,   rtfParNumSmallCaps, "pnscaps",  0 },
01458     { rtfParAttr,   rtfParNumUnder,     "pnul",     0 },
01459     { rtfParAttr,   rtfParNumDotUnder,  "pnuld",    0 },
01460     { rtfParAttr,   rtfParNumDbUnder,   "pnuldb",   0 },
01461     { rtfParAttr,   rtfParNumNoUnder,   "pnulnone", 0 },
01462     { rtfParAttr,   rtfParNumWordUnder, "pnulw",    0 },
01463     { rtfParAttr,   rtfParNumStrikethru,    "pnstrike", 0 },
01464     { rtfParAttr,   rtfParNumForeColor, "pncf",     0 },
01465     { rtfParAttr,   rtfParNumFont,      "pnf",      0 },
01466     { rtfParAttr,   rtfParNumFontSize,  "pnfs",     0 },
01467     { rtfParAttr,   rtfParNumIndent,    "pnindent", 0 },
01468     { rtfParAttr,   rtfParNumSpacing,   "pnsp",     0 },
01469     { rtfParAttr,   rtfParNumInclPrev,  "pnprev",   0 },
01470     { rtfParAttr,   rtfParNumCenter,    "pnqc",     0 },
01471     { rtfParAttr,   rtfParNumLeft,      "pnql",     0 },
01472     { rtfParAttr,   rtfParNumRight,     "pnqr",     0 },
01473     { rtfParAttr,   rtfParNumStartAt,   "pnstart",  0 },
01474 
01475     { rtfParAttr,   rtfBorderTop,       "brdrt",    0 },
01476     { rtfParAttr,   rtfBorderBottom,    "brdrb",    0 },
01477     { rtfParAttr,   rtfBorderLeft,      "brdrl",    0 },
01478     { rtfParAttr,   rtfBorderRight,     "brdrr",    0 },
01479     { rtfParAttr,   rtfBorderBetween,   "brdrbtw",  0 },
01480     { rtfParAttr,   rtfBorderBar,       "brdrbar",  0 },
01481     { rtfParAttr,   rtfBorderBox,       "box",      0 },
01482     { rtfParAttr,   rtfBorderSingle,    "brdrs",    0 },
01483     { rtfParAttr,   rtfBorderThick,     "brdrth",   0 },
01484     { rtfParAttr,   rtfBorderShadow,    "brdrsh",   0 },
01485     { rtfParAttr,   rtfBorderDouble,    "brdrdb",   0 },
01486     { rtfParAttr,   rtfBorderDot,       "brdrdot",  0 },
01487     { rtfParAttr,   rtfBorderDot,       "brdrdash", 0 },
01488     { rtfParAttr,   rtfBorderHair,      "brdrhair", 0 },
01489     { rtfParAttr,   rtfBorderWidth,     "brdrw",    0 },
01490     { rtfParAttr,   rtfBorderColor,     "brdrcf",   0 },
01491     { rtfParAttr,   rtfBorderSpace,     "brsp",     0 },
01492 
01493     { rtfParAttr,   rtfShading,     "shading",  0 },
01494     { rtfParAttr,   rtfBgPatH,      "bghoriz",  0 },
01495     { rtfParAttr,   rtfBgPatV,      "bgvert",   0 },
01496     { rtfParAttr,   rtfFwdDiagBgPat,    "bgfdiag",  0 },
01497     { rtfParAttr,   rtfBwdDiagBgPat,    "bgbdiag",  0 },
01498     { rtfParAttr,   rtfHatchBgPat,      "bgcross",  0 },
01499     { rtfParAttr,   rtfDiagHatchBgPat,  "bgdcross", 0 },
01500     { rtfParAttr,   rtfDarkBgPatH,      "bgdkhoriz",    0 },
01501     { rtfParAttr,   rtfDarkBgPatV,      "bgdkvert", 0 },
01502     { rtfParAttr,   rtfFwdDarkBgPat,    "bgdkfdiag",    0 },
01503     { rtfParAttr,   rtfBwdDarkBgPat,    "bgdkbdiag",    0 },
01504     { rtfParAttr,   rtfDarkHatchBgPat,  "bgdkcross",    0 },
01505     { rtfParAttr,   rtfDarkDiagHatchBgPat,  "bgdkdcross",   0 },
01506     { rtfParAttr,   rtfBgPatLineColor,  "cfpat",    0 },
01507     { rtfParAttr,   rtfBgPatColor,      "cbpat",    0 },
01508     { rtfParAttr,   rtfNestLevel,       "itap",     0 },
01509 
01510     /*
01511      * Section formatting attributes
01512      */
01513 
01514     { rtfSectAttr,  rtfSectDef,     "sectd",    0 },
01515     { rtfSectAttr,  rtfENoteHere,       "endnhere", 0 },
01516     { rtfSectAttr,  rtfPrtBinFirst,     "binfsxn",  0 },
01517     { rtfSectAttr,  rtfPrtBin,      "binsxn",   0 },
01518     { rtfSectAttr,  rtfSectStyleNum,    "ds",       0 },
01519 
01520     { rtfSectAttr,  rtfNoBreak,     "sbknone",  0 },
01521     { rtfSectAttr,  rtfColBreak,        "sbkcol",   0 },
01522     { rtfSectAttr,  rtfPageBreak,       "sbkpage",  0 },
01523     { rtfSectAttr,  rtfEvenBreak,       "sbkeven",  0 },
01524     { rtfSectAttr,  rtfOddBreak,        "sbkodd",   0 },
01525 
01526     { rtfSectAttr,  rtfColumns,     "cols",     0 },
01527     { rtfSectAttr,  rtfColumnSpace,     "colsx",    0 },
01528     { rtfSectAttr,  rtfColumnNumber,    "colno",    0 },
01529     { rtfSectAttr,  rtfColumnSpRight,   "colsr",    0 },
01530     { rtfSectAttr,  rtfColumnWidth,     "colw",     0 },
01531     { rtfSectAttr,  rtfColumnLine,      "linebetcol",   0 },
01532 
01533     { rtfSectAttr,  rtfLineModulus,     "linemod",  0 },
01534     { rtfSectAttr,  rtfLineDist,        "linex",    0 },
01535     { rtfSectAttr,  rtfLineStarts,      "linestarts",   0 },
01536     { rtfSectAttr,  rtfLineRestart,     "linerestart",  0 },
01537     { rtfSectAttr,  rtfLineRestartPg,   "lineppage",    0 },
01538     { rtfSectAttr,  rtfLineCont,        "linecont", 0 },
01539 
01540     { rtfSectAttr,  rtfSectPageWid,     "pgwsxn",   0 },
01541     { rtfSectAttr,  rtfSectPageHt,      "pghsxn",   0 },
01542     { rtfSectAttr,  rtfSectMarginLeft,  "marglsxn", 0 },
01543     { rtfSectAttr,  rtfSectMarginRight, "margrsxn", 0 },
01544     { rtfSectAttr,  rtfSectMarginTop,   "margtsxn", 0 },
01545     { rtfSectAttr,  rtfSectMarginBottom,    "margbsxn", 0 },
01546     { rtfSectAttr,  rtfSectMarginGutter,    "guttersxn",    0 },
01547     { rtfSectAttr,  rtfSectLandscape,   "lndscpsxn",    0 },
01548     { rtfSectAttr,  rtfTitleSpecial,    "titlepg",  0 },
01549     { rtfSectAttr,  rtfHeaderY,     "headery",  0 },
01550     { rtfSectAttr,  rtfFooterY,     "footery",  0 },
01551 
01552     { rtfSectAttr,  rtfPageStarts,      "pgnstarts",    0 },
01553     { rtfSectAttr,  rtfPageCont,        "pgncont",  0 },
01554     { rtfSectAttr,  rtfPageRestart,     "pgnrestart",   0 },
01555     { rtfSectAttr,  rtfPageNumRight,    "pgnx",     0 },
01556     { rtfSectAttr,  rtfPageNumTop,      "pgny",     0 },
01557     { rtfSectAttr,  rtfPageDecimal,     "pgndec",   0 },
01558     { rtfSectAttr,  rtfPageURoman,      "pgnucrm",  0 },
01559     { rtfSectAttr,  rtfPageLRoman,      "pgnlcrm",  0 },
01560     { rtfSectAttr,  rtfPageULetter,     "pgnucltr", 0 },
01561     { rtfSectAttr,  rtfPageLLetter,     "pgnlcltr", 0 },
01562     { rtfSectAttr,  rtfPageNumHyphSep,  "pgnhnsh",  0 },
01563     { rtfSectAttr,  rtfPageNumSpaceSep, "pgnhnsp",  0 },
01564     { rtfSectAttr,  rtfPageNumColonSep, "pgnhnsc",  0 },
01565     { rtfSectAttr,  rtfPageNumEmdashSep,    "pgnhnsm",  0 },
01566     { rtfSectAttr,  rtfPageNumEndashSep,    "pgnhnsn",  0 },
01567 
01568     { rtfSectAttr,  rtfTopVAlign,       "vertalt",  0 },
01569     /* misspelled as "vertal" in specification 1.0 */
01570     { rtfSectAttr,  rtfBottomVAlign,    "vertalb",  0 },
01571     { rtfSectAttr,  rtfCenterVAlign,    "vertalc",  0 },
01572     { rtfSectAttr,  rtfJustVAlign,      "vertalj",  0 },
01573 
01574     { rtfSectAttr,  rtfRTLSect,     "rtlsect",  0 },
01575     { rtfSectAttr,  rtfLTRSect,     "ltrsect",  0 },
01576 
01577     /* I've seen these in an old spec, but not in real files... */
01578     /*rtfSectAttr,  rtfNoBreak,     "nobreak",  0,*/
01579     /*rtfSectAttr,  rtfColBreak,        "colbreak", 0,*/
01580     /*rtfSectAttr,  rtfPageBreak,       "pagebreak",    0,*/
01581     /*rtfSectAttr,  rtfEvenBreak,       "evenbreak",    0,*/
01582     /*rtfSectAttr,  rtfOddBreak,        "oddbreak", 0,*/
01583 
01584     /*
01585      * Document formatting attributes
01586      */
01587 
01588     { rtfDocAttr,   rtfDefTab,      "deftab",   0 },
01589     { rtfDocAttr,   rtfHyphHotZone,     "hyphhotz", 0 },
01590     { rtfDocAttr,   rtfHyphConsecLines, "hyphconsec",   0 },
01591     { rtfDocAttr,   rtfHyphCaps,        "hyphcaps", 0 },
01592     { rtfDocAttr,   rtfHyphAuto,        "hyphauto", 0 },
01593     { rtfDocAttr,   rtfLineStart,       "linestart",    0 },
01594     { rtfDocAttr,   rtfFracWidth,       "fracwidth",    0 },
01595     /* \makeback was given in old version of spec, it's now */
01596     /* listed as \makebackup */
01597     { rtfDocAttr,   rtfMakeBackup,      "makeback", 0 },
01598     { rtfDocAttr,   rtfMakeBackup,      "makebackup",   0 },
01599     { rtfDocAttr,   rtfRTFDefault,      "defformat",    0 },
01600     { rtfDocAttr,   rtfPSOverlay,       "psover",   0 },
01601     { rtfDocAttr,   rtfDocTemplate,     "doctemp",  0 },
01602     { rtfDocAttr,   rtfDefLanguage,     "deflang",  0 },
01603 
01604     { rtfDocAttr,   rtfFENoteType,      "fet",      0 },
01605     { rtfDocAttr,   rtfFNoteEndSect,    "endnotes", 0 },
01606     { rtfDocAttr,   rtfFNoteEndDoc,     "enddoc",   0 },
01607     { rtfDocAttr,   rtfFNoteText,       "ftntj",    0 },
01608     { rtfDocAttr,   rtfFNoteBottom,     "ftnbj",    0 },
01609     { rtfDocAttr,   rtfENoteEndSect,    "aendnotes",    0 },
01610     { rtfDocAttr,   rtfENoteEndDoc,     "aenddoc",  0 },
01611     { rtfDocAttr,   rtfENoteText,       "aftntj",   0 },
01612     { rtfDocAttr,   rtfENoteBottom,     "aftnbj",   0 },
01613     { rtfDocAttr,   rtfFNoteStart,      "ftnstart", 0 },
01614     { rtfDocAttr,   rtfENoteStart,      "aftnstart",    0 },
01615     { rtfDocAttr,   rtfFNoteRestartPage,    "ftnrstpg", 0 },
01616     { rtfDocAttr,   rtfFNoteRestart,    "ftnrestart",   0 },
01617     { rtfDocAttr,   rtfFNoteRestartCont,    "ftnrstcont",   0 },
01618     { rtfDocAttr,   rtfENoteRestart,    "aftnrestart",  0 },
01619     { rtfDocAttr,   rtfENoteRestartCont,    "aftnrstcont",  0 },
01620     { rtfDocAttr,   rtfFNoteNumArabic,  "ftnnar",   0 },
01621     { rtfDocAttr,   rtfFNoteNumLLetter, "ftnnalc",  0 },
01622     { rtfDocAttr,   rtfFNoteNumULetter, "ftnnauc",  0 },
01623     { rtfDocAttr,   rtfFNoteNumLRoman,  "ftnnrlc",  0 },
01624     { rtfDocAttr,   rtfFNoteNumURoman,  "ftnnruc",  0 },
01625     { rtfDocAttr,   rtfFNoteNumChicago, "ftnnchi",  0 },
01626     { rtfDocAttr,   rtfENoteNumArabic,  "aftnnar",  0 },
01627     { rtfDocAttr,   rtfENoteNumLLetter, "aftnnalc", 0 },
01628     { rtfDocAttr,   rtfENoteNumULetter, "aftnnauc", 0 },
01629     { rtfDocAttr,   rtfENoteNumLRoman,  "aftnnrlc", 0 },
01630     { rtfDocAttr,   rtfENoteNumURoman,  "aftnnruc", 0 },
01631     { rtfDocAttr,   rtfENoteNumChicago, "aftnnchi", 0 },
01632 
01633     { rtfDocAttr,   rtfPaperWidth,      "paperw",   0 },
01634     { rtfDocAttr,   rtfPaperHeight,     "paperh",   0 },
01635     { rtfDocAttr,   rtfPaperSize,       "psz",      0 },
01636     { rtfDocAttr,   rtfLeftMargin,      "margl",    0 },
01637     { rtfDocAttr,   rtfRightMargin,     "margr",    0 },
01638     { rtfDocAttr,   rtfTopMargin,       "margt",    0 },
01639     { rtfDocAttr,   rtfBottomMargin,    "margb",    0 },
01640     { rtfDocAttr,   rtfFacingPage,      "facingp",  0 },
01641     { rtfDocAttr,   rtfGutterWid,       "gutter",   0 },
01642     { rtfDocAttr,   rtfMirrorMargin,    "margmirror",   0 },
01643     { rtfDocAttr,   rtfLandscape,       "landscape",    0 },
01644     { rtfDocAttr,   rtfPageStart,       "pgnstart", 0 },
01645     { rtfDocAttr,   rtfWidowCtrl,       "widowctrl",    0 },
01646 
01647     { rtfDocAttr,   rtfLinkStyles,      "linkstyles",   0 },
01648 
01649     { rtfDocAttr,   rtfNoAutoTabIndent, "notabind", 0 },
01650     { rtfDocAttr,   rtfWrapSpaces,      "wraptrsp", 0 },
01651     { rtfDocAttr,   rtfPrintColorsBlack,    "prcolbl",  0 },
01652     { rtfDocAttr,   rtfNoExtraSpaceRL,  "noextrasprl",  0 },
01653     { rtfDocAttr,   rtfNoColumnBalance, "nocolbal", 0 },
01654     { rtfDocAttr,   rtfCvtMailMergeQuote,   "cvmme",    0 },
01655     { rtfDocAttr,   rtfSuppressTopSpace,    "sprstsp",  0 },
01656     { rtfDocAttr,   rtfSuppressPreParSpace, "sprsspbf", 0 },
01657     { rtfDocAttr,   rtfCombineTblBorders,   "otblrul",  0 },
01658     { rtfDocAttr,   rtfTranspMetafiles, "transmf",  0 },
01659     { rtfDocAttr,   rtfSwapBorders,     "swpbdr",   0 },
01660     { rtfDocAttr,   rtfShowHardBreaks,  "brkfrm",   0 },
01661 
01662     { rtfDocAttr,   rtfFormProtected,   "formprot", 0 },
01663     { rtfDocAttr,   rtfAllProtected,    "allprot",  0 },
01664     { rtfDocAttr,   rtfFormShading,     "formshade",    0 },
01665     { rtfDocAttr,   rtfFormDisplay,     "formdisp", 0 },
01666     { rtfDocAttr,   rtfPrintData,       "printdata",    0 },
01667 
01668     { rtfDocAttr,   rtfRevProtected,    "revprot",  0 },
01669     { rtfDocAttr,   rtfRevisions,       "revisions",    0 },
01670     { rtfDocAttr,   rtfRevDisplay,      "revprop",  0 },
01671     { rtfDocAttr,   rtfRevBar,      "revbar",   0 },
01672 
01673     { rtfDocAttr,   rtfAnnotProtected,  "annotprot",    0 },
01674 
01675     { rtfDocAttr,   rtfRTLDoc,      "rtldoc",   0 },
01676     { rtfDocAttr,   rtfLTRDoc,      "ltrdoc",   0 },
01677 
01678         { rtfDocAttr,   rtfAnsiCodePage,    "ansicpg",  0 },
01679         { rtfDocAttr,   rtfUTF8RTF,     "urtf",     0 },
01680 
01681     /*
01682      * Style attributes
01683      */
01684 
01685     { rtfStyleAttr, rtfAdditive,        "additive", 0 },
01686     { rtfStyleAttr, rtfBasedOn,     "sbasedon", 0 },
01687     { rtfStyleAttr, rtfNext,        "snext",    0 },
01688 
01689     /*
01690      * Picture attributes
01691      */
01692 
01693     { rtfPictAttr,  rtfMacQD,       "macpict",  0 },
01694     { rtfPictAttr,  rtfPMMetafile,      "pmmetafile",   0 },
01695     { rtfPictAttr,  rtfWinMetafile,     "wmetafile",    0 },
01696     { rtfPictAttr,  rtfDevIndBitmap,    "dibitmap", 0 },
01697     { rtfPictAttr,  rtfWinBitmap,       "wbitmap",  0 },
01698     { rtfPictAttr,  rtfEmfBlip,     "emfblip",  0 },
01699     { rtfPictAttr,  rtfPixelBits,       "wbmbitspixel", 0 },
01700     { rtfPictAttr,  rtfBitmapPlanes,    "wbmplanes",    0 },
01701     { rtfPictAttr,  rtfBitmapWid,       "wbmwidthbytes", 0 },
01702 
01703     { rtfPictAttr,  rtfPicWid,      "picw",     0 },
01704     { rtfPictAttr,  rtfPicHt,       "pich",     0 },
01705     { rtfPictAttr,  rtfPicGoalWid,      "picwgoal", 0 },
01706     { rtfPictAttr,  rtfPicGoalHt,       "pichgoal", 0 },
01707     /* these two aren't in the spec, but some writers emit them */
01708     { rtfPictAttr,  rtfPicGoalWid,      "picwGoal", 0 },
01709     { rtfPictAttr,  rtfPicGoalHt,       "pichGoal", 0 },
01710     { rtfPictAttr,  rtfPicScaleX,       "picscalex",    0 },
01711     { rtfPictAttr,  rtfPicScaleY,       "picscaley",    0 },
01712     { rtfPictAttr,  rtfPicScaled,       "picscaled",    0 },
01713     { rtfPictAttr,  rtfPicCropTop,      "piccropt", 0 },
01714     { rtfPictAttr,  rtfPicCropBottom,   "piccropb", 0 },
01715     { rtfPictAttr,  rtfPicCropLeft,     "piccropl", 0 },
01716     { rtfPictAttr,  rtfPicCropRight,    "piccropr", 0 },
01717 
01718     { rtfPictAttr,  rtfPicMFHasBitmap,  "picbmp",   0 },
01719     { rtfPictAttr,  rtfPicMFBitsPerPixel,   "picbpp",   0 },
01720 
01721     { rtfPictAttr,  rtfPicBinary,       "bin",      0 },
01722 
01723     /*
01724      * NeXT graphic attributes
01725      */
01726 
01727     { rtfNeXTGrAttr,    rtfNeXTGWidth,      "width",    0 },
01728     { rtfNeXTGrAttr,    rtfNeXTGHeight,     "height",   0 },
01729 
01730     /*
01731      * Destinations
01732      */
01733 
01734     { rtfDestination,   rtfFontTbl,     "fonttbl",  0 },
01735     { rtfDestination,   rtfFontAltName,     "falt",     0 },
01736     { rtfDestination,   rtfEmbeddedFont,    "fonteb",   0 },
01737     { rtfDestination,   rtfFontFile,        "fontfile", 0 },
01738     { rtfDestination,   rtfFileTbl,     "filetbl",  0 },
01739     { rtfDestination,   rtfFileInfo,        "file",     0 },
01740     { rtfDestination,   rtfColorTbl,        "colortbl", 0 },
01741     { rtfDestination,   rtfStyleSheet,      "stylesheet",   0 },
01742     { rtfDestination,   rtfKeyCode,     "keycode",  0 },
01743     { rtfDestination,   rtfRevisionTbl,     "revtbl",   0 },
01744     { rtfDestination,   rtfGenerator,       "generator",    0 },
01745     { rtfDestination,   rtfInfo,        "info",     0 },
01746     { rtfDestination,   rtfITitle,      "title",    0 },
01747     { rtfDestination,   rtfISubject,        "subject",  0 },
01748     { rtfDestination,   rtfIAuthor,     "author",   0 },
01749     { rtfDestination,   rtfIOperator,       "operator", 0 },
01750     { rtfDestination,   rtfIKeywords,       "keywords", 0 },
01751     { rtfDestination,   rtfIComment,        "comment",  0 },
01752     { rtfDestination,   rtfIVersion,        "version",  0 },
01753     { rtfDestination,   rtfIDoccomm,        "doccomm",  0 },
01754     /* \verscomm may not exist -- was seen in earlier spec version */
01755     { rtfDestination,   rtfIVerscomm,       "verscomm", 0 },
01756     { rtfDestination,   rtfNextFile,        "nextfile", 0 },
01757     { rtfDestination,   rtfTemplate,        "template", 0 },
01758     { rtfDestination,   rtfFNSep,       "ftnsep",   0 },
01759     { rtfDestination,   rtfFNContSep,       "ftnsepc",  0 },
01760     { rtfDestination,   rtfFNContNotice,    "ftncn",    0 },
01761     { rtfDestination,   rtfENSep,       "aftnsep",  0 },
01762     { rtfDestination,   rtfENContSep,       "aftnsepc", 0 },
01763     { rtfDestination,   rtfENContNotice,    "aftncn",   0 },
01764     { rtfDestination,   rtfPageNumLevel,    "pgnhn",    0 },
01765     { rtfDestination,   rtfParNumLevelStyle,    "pnseclvl", 0 },
01766     { rtfDestination,   rtfHeader,      "header",   0 },
01767     { rtfDestination,   rtfFooter,      "footer",   0 },
01768     { rtfDestination,   rtfHeaderLeft,      "headerl",  0 },
01769     { rtfDestination,   rtfHeaderRight,     "headerr",  0 },
01770     { rtfDestination,   rtfHeaderFirst,     "headerf",  0 },
01771     { rtfDestination,   rtfFooterLeft,      "footerl",  0 },
01772     { rtfDestination,   rtfFooterRight,     "footerr",  0 },
01773     { rtfDestination,   rtfFooterFirst,     "footerf",  0 },
01774     { rtfDestination,   rtfParNumText,      "pntext",   0 },
01775     { rtfDestination,   rtfParNumbering,    "pn",       0 },
01776     { rtfDestination,   rtfParNumTextAfter, "pntexta",  0 },
01777     { rtfDestination,   rtfParNumTextBefore,    "pntextb",  0 },
01778     { rtfDestination,   rtfBookmarkStart,   "bkmkstart",    0 },
01779     { rtfDestination,   rtfBookmarkEnd,     "bkmkend",  0 },
01780     { rtfDestination,   rtfPict,        "pict",     0 },
01781     { rtfDestination,   rtfObject,      "object",   0 },
01782     { rtfDestination,   rtfObjClass,        "objclass", 0 },
01783     { rtfDestination,   rtfObjName,     "objname",  0 },
01784     { rtfObjAttr,   rtfObjTime,     "objtime",  0 },
01785     { rtfDestination,   rtfObjData,     "objdata",  0 },
01786     { rtfDestination,   rtfObjAlias,        "objalias", 0 },
01787     { rtfDestination,   rtfObjSection,      "objsect",  0 },
01788     /* objitem and objtopic aren't documented in the spec! */
01789     { rtfDestination,   rtfObjItem,     "objitem",  0 },
01790     { rtfDestination,   rtfObjTopic,        "objtopic", 0 },
01791     { rtfDestination,   rtfObjResult,       "result",   0 },
01792     { rtfDestination,   rtfDrawObject,      "do",       0 },
01793     { rtfDestination,   rtfFootnote,        "footnote", 0 },
01794     { rtfDestination,   rtfAnnotRefStart,   "atrfstart",    0 },
01795     { rtfDestination,   rtfAnnotRefEnd,     "atrfend",  0 },
01796     { rtfDestination,   rtfAnnotID,     "atnid",    0 },
01797     { rtfDestination,   rtfAnnotAuthor,     "atnauthor",    0 },
01798     { rtfDestination,   rtfAnnotation,      "annotation",   0 },
01799     { rtfDestination,   rtfAnnotRef,        "atnref",   0 },
01800     { rtfDestination,   rtfAnnotTime,       "atntime",  0 },
01801     { rtfDestination,   rtfAnnotIcon,       "atnicn",   0 },
01802     { rtfDestination,   rtfField,       "field",    0 },
01803     { rtfDestination,   rtfFieldInst,       "fldinst",  0 },
01804     { rtfDestination,   rtfFieldResult,     "fldrslt",  0 },
01805     { rtfDestination,   rtfDataField,       "datafield",    0 },
01806     { rtfDestination,   rtfIndex,       "xe",       0 },
01807     { rtfDestination,   rtfIndexText,       "txe",      0 },
01808     { rtfDestination,   rtfIndexRange,      "rxe",      0 },
01809     { rtfDestination,   rtfTOC,         "tc",       0 },
01810     { rtfDestination,   rtfNeXTGraphic,     "NeXTGraphic",  0 },
01811     { rtfDestination,   rtfNestTableProps,  "nesttableprops", 0 },
01812     { rtfDestination,   rtfNoNestTables,    "nonesttables", 0 },
01813 
01814     /*
01815      * Font families
01816      */
01817 
01818     { rtfFontFamily,    rtfFFNil,       "fnil",     0 },
01819     { rtfFontFamily,    rtfFFRoman,     "froman",   0 },
01820     { rtfFontFamily,    rtfFFSwiss,     "fswiss",   0 },
01821     { rtfFontFamily,    rtfFFModern,        "fmodern",  0 },
01822     { rtfFontFamily,    rtfFFScript,        "fscript",  0 },
01823     { rtfFontFamily,    rtfFFDecor,     "fdecor",   0 },
01824     { rtfFontFamily,    rtfFFTech,      "ftech",    0 },
01825     { rtfFontFamily,    rtfFFBidirectional, "fbidi",    0 },
01826 
01827     /*
01828      * Font attributes
01829      */
01830 
01831     { rtfFontAttr,  rtfFontCharSet,     "fcharset", 0 },
01832     { rtfFontAttr,  rtfFontPitch,       "fprq",     0 },
01833     { rtfFontAttr,  rtfFontCodePage,    "cpg",      0 },
01834     { rtfFontAttr,  rtfFTypeNil,        "ftnil",    0 },
01835     { rtfFontAttr,  rtfFTypeTrueType,   "fttruetype",   0 },
01836 
01837     /*
01838      * File table attributes
01839      */
01840 
01841     { rtfFileAttr,  rtfFileNum,     "fid",      0 },
01842     { rtfFileAttr,  rtfFileRelPath,     "frelative",    0 },
01843     { rtfFileAttr,  rtfFileOSNum,       "fosnum",   0 },
01844 
01845     /*
01846      * File sources
01847      */
01848 
01849     { rtfFileSource,    rtfSrcMacintosh,    "fvalidmac",    0 },
01850     { rtfFileSource,    rtfSrcDOS,      "fvaliddos",    0 },
01851     { rtfFileSource,    rtfSrcNTFS,     "fvalidntfs",   0 },
01852     { rtfFileSource,    rtfSrcHPFS,     "fvalidhpfs",   0 },
01853     { rtfFileSource,    rtfSrcNetwork,      "fnetwork", 0 },
01854 
01855     /*
01856      * Color names
01857      */
01858 
01859     { rtfColorName, rtfRed,         "red",      0 },
01860     { rtfColorName, rtfGreen,       "green",    0 },
01861     { rtfColorName, rtfBlue,        "blue",     0 },
01862 
01863     /*
01864      * Charset names
01865      */
01866 
01867     { rtfCharSet,   rtfMacCharSet,      "mac",      0 },
01868     { rtfCharSet,   rtfAnsiCharSet,     "ansi",     0 },
01869     { rtfCharSet,   rtfPcCharSet,       "pc",       0 },
01870     { rtfCharSet,   rtfPcaCharSet,      "pca",      0 },
01871 
01872     /*
01873      * Table attributes
01874      */
01875 
01876     { rtfTblAttr,   rtfRowDef,      "trowd",    0 },
01877     { rtfTblAttr,   rtfRowGapH,     "trgaph",   0 },
01878     { rtfTblAttr,   rtfCellPos,     "cellx",    0 },
01879     { rtfTblAttr,   rtfMergeRngFirst,   "clmgf",    0 },
01880     { rtfTblAttr,   rtfMergePrevious,   "clmrg",    0 },
01881 
01882     { rtfTblAttr,   rtfRowLeft,     "trql",     0 },
01883     { rtfTblAttr,   rtfRowRight,        "trqr",     0 },
01884     { rtfTblAttr,   rtfRowCenter,       "trqc",     0 },
01885     { rtfTblAttr,   rtfRowLeftEdge,     "trleft",   0 },
01886     { rtfTblAttr,   rtfRowHt,       "trrh",     0 },
01887     { rtfTblAttr,   rtfRowHeader,       "trhdr",    0 },
01888     { rtfTblAttr,   rtfRowKeep,     "trkeep",   0 },
01889 
01890     { rtfTblAttr,   rtfRTLRow,      "rtlrow",   0 },
01891     { rtfTblAttr,   rtfLTRRow,      "ltrrow",   0 },
01892 
01893     { rtfTblAttr,   rtfRowBordTop,      "trbrdrt",  0 },
01894     { rtfTblAttr,   rtfRowBordLeft,     "trbrdrl",  0 },
01895     { rtfTblAttr,   rtfRowBordBottom,   "trbrdrb",  0 },
01896     { rtfTblAttr,   rtfRowBordRight,    "trbrdrr",  0 },
01897     { rtfTblAttr,   rtfRowBordHoriz,    "trbrdrh",  0 },
01898     { rtfTblAttr,   rtfRowBordVert,     "trbrdrv",  0 },
01899 
01900     { rtfTblAttr,   rtfCellBordBottom,  "clbrdrb",  0 },
01901     { rtfTblAttr,   rtfCellBordTop,     "clbrdrt",  0 },
01902     { rtfTblAttr,   rtfCellBordLeft,    "clbrdrl",  0 },
01903     { rtfTblAttr,   rtfCellBordRight,   "clbrdrr",  0 },
01904 
01905     { rtfTblAttr,   rtfCellShading,     "clshdng",  0 },
01906     { rtfTblAttr,   rtfCellBgPatH,      "clbghoriz",    0 },
01907     { rtfTblAttr,   rtfCellBgPatV,      "clbgvert", 0 },
01908     { rtfTblAttr,   rtfCellFwdDiagBgPat,    "clbgfdiag",    0 },
01909     { rtfTblAttr,   rtfCellBwdDiagBgPat,    "clbgbdiag",    0 },
01910     { rtfTblAttr,   rtfCellHatchBgPat,  "clbgcross",    0 },
01911     { rtfTblAttr,   rtfCellDiagHatchBgPat,  "clbgdcross",   0 },
01912     /*
01913      * The spec lists "clbgdkhor", but the corresponding non-cell
01914      * control is "bgdkhoriz".  At any rate Macintosh Word seems
01915      * to accept both "clbgdkhor" and "clbgdkhoriz".
01916      */
01917     { rtfTblAttr,   rtfCellDarkBgPatH,  "clbgdkhoriz",  0 },
01918     { rtfTblAttr,   rtfCellDarkBgPatH,  "clbgdkhor",    0 },
01919     { rtfTblAttr,   rtfCellDarkBgPatV,  "clbgdkvert",   0 },
01920     { rtfTblAttr,   rtfCellFwdDarkBgPat,    "clbgdkfdiag",  0 },
01921     { rtfTblAttr,   rtfCellBwdDarkBgPat,    "clbgdkbdiag",  0 },
01922     { rtfTblAttr,   rtfCellDarkHatchBgPat,  "clbgdkcross",  0 },
01923     { rtfTblAttr,   rtfCellDarkDiagHatchBgPat, "clbgdkdcross",  0 },
01924     { rtfTblAttr,   rtfCellBgPatLineColor, "clcfpat",   0 },
01925     { rtfTblAttr,   rtfCellBgPatColor,  "clcbpat",  0 },
01926 
01927     /*
01928      * Field attributes
01929      */
01930 
01931     { rtfFieldAttr, rtfFieldDirty,      "flddirty", 0 },
01932     { rtfFieldAttr, rtfFieldEdited,     "fldedit",  0 },
01933     { rtfFieldAttr, rtfFieldLocked,     "fldlock",  0 },
01934     { rtfFieldAttr, rtfFieldPrivate,    "fldpriv",  0 },
01935     { rtfFieldAttr, rtfFieldAlt,        "fldalt",   0 },
01936 
01937     /*
01938      * Positioning attributes
01939      */
01940 
01941     { rtfPosAttr,   rtfAbsWid,      "absw",     0 },
01942     { rtfPosAttr,   rtfAbsHt,       "absh",     0 },
01943 
01944     { rtfPosAttr,   rtfRPosMargH,       "phmrg",    0 },
01945     { rtfPosAttr,   rtfRPosPageH,       "phpg",     0 },
01946     { rtfPosAttr,   rtfRPosColH,        "phcol",    0 },
01947     { rtfPosAttr,   rtfPosX,        "posx",     0 },
01948     { rtfPosAttr,   rtfPosNegX,     "posnegx",  0 },
01949     { rtfPosAttr,   rtfPosXCenter,      "posxc",    0 },
01950     { rtfPosAttr,   rtfPosXInside,      "posxi",    0 },
01951     { rtfPosAttr,   rtfPosXOutSide,     "posxo",    0 },
01952     { rtfPosAttr,   rtfPosXRight,       "posxr",    0 },
01953     { rtfPosAttr,   rtfPosXLeft,        "posxl",    0 },
01954 
01955     { rtfPosAttr,   rtfRPosMargV,       "pvmrg",    0 },
01956     { rtfPosAttr,   rtfRPosPageV,       "pvpg",     0 },
01957     { rtfPosAttr,   rtfRPosParaV,       "pvpara",   0 },
01958     { rtfPosAttr,   rtfPosY,        "posy",     0 },
01959     { rtfPosAttr,   rtfPosNegY,     "posnegy",  0 },
01960     { rtfPosAttr,   rtfPosYInline,      "posyil",   0 },
01961     { rtfPosAttr,   rtfPosYTop,     "posyt",    0 },
01962     { rtfPosAttr,   rtfPosYCenter,      "posyc",    0 },
01963     { rtfPosAttr,   rtfPosYBottom,      "posyb",    0 },
01964 
01965     { rtfPosAttr,   rtfNoWrap,      "nowrap",   0 },
01966     { rtfPosAttr,   rtfDistFromTextAll, "dxfrtext", 0 },
01967     { rtfPosAttr,   rtfDistFromTextX,   "dfrmtxtx", 0 },
01968     { rtfPosAttr,   rtfDistFromTextY,   "dfrmtxty", 0 },
01969     /* \dyfrtext no longer exists in spec 1.2, apparently */
01970     /* replaced by \dfrmtextx and \dfrmtexty. */
01971     { rtfPosAttr,   rtfTextDistY,       "dyfrtext", 0 },
01972 
01973     { rtfPosAttr,   rtfDropCapLines,    "dropcapli",    0 },
01974     { rtfPosAttr,   rtfDropCapType,     "dropcapt", 0 },
01975 
01976     /*
01977      * Object controls
01978      */
01979 
01980     { rtfObjAttr,   rtfObjEmb,      "objemb",   0 },
01981     { rtfObjAttr,   rtfObjLink,     "objlink",  0 },
01982     { rtfObjAttr,   rtfObjAutoLink,     "objautlink",   0 },
01983     { rtfObjAttr,   rtfObjSubscriber,   "objsub",   0 },
01984     { rtfObjAttr,   rtfObjPublisher,    "objpub",   0 },
01985     { rtfObjAttr,   rtfObjICEmb,        "objicemb", 0 },
01986 
01987     { rtfObjAttr,   rtfObjLinkSelf,     "linkself", 0 },
01988     { rtfObjAttr,   rtfObjLock,     "objupdate",    0 },
01989     { rtfObjAttr,   rtfObjUpdate,       "objlock",  0 },
01990 
01991     { rtfObjAttr,   rtfObjHt,       "objh",     0 },
01992     { rtfObjAttr,   rtfObjWid,      "objw",     0 },
01993     { rtfObjAttr,   rtfObjSetSize,      "objsetsize",   0 },
01994     { rtfObjAttr,   rtfObjAlign,        "objalign", 0 },
01995     { rtfObjAttr,   rtfObjTransposeY,   "objtransy",    0 },
01996     { rtfObjAttr,   rtfObjCropTop,      "objcropt", 0 },
01997     { rtfObjAttr,   rtfObjCropBottom,   "objcropb", 0 },
01998     { rtfObjAttr,   rtfObjCropLeft,     "objcropl", 0 },
01999     { rtfObjAttr,   rtfObjCropRight,    "objcropr", 0 },
02000     { rtfObjAttr,   rtfObjScaleX,       "objscalex",    0 },
02001     { rtfObjAttr,   rtfObjScaleY,       "objscaley",    0 },
02002 
02003     { rtfObjAttr,   rtfObjResRTF,       "rsltrtf",  0 },
02004     { rtfObjAttr,   rtfObjResPict,      "rsltpict", 0 },
02005     { rtfObjAttr,   rtfObjResBitmap,    "rsltbmp",  0 },
02006     { rtfObjAttr,   rtfObjResText,      "rslttxt",  0 },
02007     { rtfObjAttr,   rtfObjResMerge,     "rsltmerge",    0 },
02008 
02009     { rtfObjAttr,   rtfObjBookmarkPubObj,   "bkmkpub",  0 },
02010     { rtfObjAttr,   rtfObjPubAutoUpdate,    "pubauto",  0 },
02011 
02012     /*
02013      * Associated character formatting attributes
02014      */
02015 
02016     { rtfACharAttr, rtfACBold,      "ab",       0 },
02017     { rtfACharAttr, rtfACAllCaps,       "caps",     0 },
02018     { rtfACharAttr, rtfACForeColor,     "acf",      0 },
02019     { rtfACharAttr, rtfACSubScript,     "adn",      0 },
02020     { rtfACharAttr, rtfACExpand,        "aexpnd",   0 },
02021     { rtfACharAttr, rtfACFontNum,       "af",       0 },
02022     { rtfACharAttr, rtfACFontSize,      "afs",      0 },
02023     { rtfACharAttr, rtfACItalic,        "ai",       0 },
02024     { rtfACharAttr, rtfACLanguage,      "alang",    0 },
02025     { rtfACharAttr, rtfACOutline,       "aoutl",    0 },
02026     { rtfACharAttr, rtfACSmallCaps,     "ascaps",   0 },
02027     { rtfACharAttr, rtfACShadow,        "ashad",    0 },
02028     { rtfACharAttr, rtfACStrikeThru,    "astrike",  0 },
02029     { rtfACharAttr, rtfACUnderline,     "aul",      0 },
02030     { rtfACharAttr, rtfACDotUnderline,  "auld",     0 },
02031     { rtfACharAttr, rtfACDbUnderline,   "auldb",    0 },
02032     { rtfACharAttr, rtfACNoUnderline,   "aulnone",  0 },
02033     { rtfACharAttr, rtfACWordUnderline, "aulw",     0 },
02034     { rtfACharAttr, rtfACSuperScript,   "aup",      0 },
02035 
02036     /*
02037      * Footnote attributes
02038      */
02039 
02040     { rtfFNoteAttr, rtfFNAlt,       "ftnalt",   0 },
02041 
02042     /*
02043      * Key code attributes
02044      */
02045 
02046     { rtfKeyCodeAttr,   rtfAltKey,      "alt",      0 },
02047     { rtfKeyCodeAttr,   rtfShiftKey,        "shift",    0 },
02048     { rtfKeyCodeAttr,   rtfControlKey,      "ctrl",     0 },
02049     { rtfKeyCodeAttr,   rtfFunctionKey,     "fn",       0 },
02050 
02051     /*
02052      * Bookmark attributes
02053      */
02054 
02055     { rtfBookmarkAttr, rtfBookmarkFirstCol, "bkmkcolf", 0 },
02056     { rtfBookmarkAttr, rtfBookmarkLastCol,  "bkmkcoll", 0 },
02057 
02058     /*
02059      * Index entry attributes
02060      */
02061 
02062     { rtfIndexAttr, rtfIndexNumber,     "xef",      0 },
02063     { rtfIndexAttr, rtfIndexBold,       "bxe",      0 },
02064     { rtfIndexAttr, rtfIndexItalic,     "ixe",      0 },
02065 
02066     /*
02067      * Table of contents attributes
02068      */
02069 
02070     { rtfTOCAttr,   rtfTOCType,     "tcf",      0 },
02071     { rtfTOCAttr,   rtfTOCLevel,        "tcl",      0 },
02072 
02073     /*
02074      * Drawing object attributes
02075      */
02076 
02077     { rtfDrawAttr,  rtfDrawLock,        "dolock",   0 },
02078     { rtfDrawAttr,  rtfDrawPageRelX,    "doxpage",  0 },
02079     { rtfDrawAttr,  rtfDrawColumnRelX,  "dobxcolumn",   0 },
02080     { rtfDrawAttr,  rtfDrawMarginRelX,  "dobxmargin",   0 },
02081     { rtfDrawAttr,  rtfDrawPageRelY,    "dobypage", 0 },
02082     { rtfDrawAttr,  rtfDrawColumnRelY,  "dobycolumn",   0 },
02083     { rtfDrawAttr,  rtfDrawMarginRelY,  "dobymargin",   0 },
02084     { rtfDrawAttr,  rtfDrawHeight,      "dobhgt",   0 },
02085 
02086     { rtfDrawAttr,  rtfDrawBeginGroup,  "dpgroup",  0 },
02087     { rtfDrawAttr,  rtfDrawGroupCount,  "dpcount",  0 },
02088     { rtfDrawAttr,  rtfDrawEndGroup,    "dpendgroup",   0 },
02089     { rtfDrawAttr,  rtfDrawArc,     "dparc",    0 },
02090     { rtfDrawAttr,  rtfDrawCallout,     "dpcallout",    0 },
02091     { rtfDrawAttr,  rtfDrawEllipse,     "dpellipse",    0 },
02092     { rtfDrawAttr,  rtfDrawLine,        "dpline",   0 },
02093     { rtfDrawAttr,  rtfDrawPolygon,     "dppolygon",    0 },
02094     { rtfDrawAttr,  rtfDrawPolyLine,    "dppolyline",   0 },
02095     { rtfDrawAttr,  rtfDrawRect,        "dprect",   0 },
02096     { rtfDrawAttr,  rtfDrawTextBox,     "dptxbx",   0 },
02097 
02098     { rtfDrawAttr,  rtfDrawOffsetX,     "dpx",      0 },
02099     { rtfDrawAttr,  rtfDrawSizeX,       "dpxsize",  0 },
02100     { rtfDrawAttr,  rtfDrawOffsetY,     "dpy",      0 },
02101     { rtfDrawAttr,  rtfDrawSizeY,       "dpysize",  0 },
02102 
02103     { rtfDrawAttr,  rtfCOAngle,     "dpcoa",    0 },
02104     { rtfDrawAttr,  rtfCOAccentBar,     "dpcoaccent",   0 },
02105     { rtfDrawAttr,  rtfCOBestFit,       "dpcobestfit",  0 },
02106     { rtfDrawAttr,  rtfCOBorder,        "dpcoborder",   0 },
02107     { rtfDrawAttr,  rtfCOAttachAbsDist, "dpcodabs", 0 },
02108     { rtfDrawAttr,  rtfCOAttachBottom,  "dpcodbottom",  0 },
02109     { rtfDrawAttr,  rtfCOAttachCenter,  "dpcodcenter",  0 },
02110     { rtfDrawAttr,  rtfCOAttachTop,     "dpcodtop", 0 },
02111     { rtfDrawAttr,  rtfCOLength,        "dpcolength",   0 },
02112     { rtfDrawAttr,  rtfCONegXQuadrant,  "dpcominusx",   0 },
02113     { rtfDrawAttr,  rtfCONegYQuadrant,  "dpcominusy",   0 },
02114     { rtfDrawAttr,  rtfCOOffset,        "dpcooffset",   0 },
02115     { rtfDrawAttr,  rtfCOAttachSmart,   "dpcosmarta",   0 },
02116     { rtfDrawAttr,  rtfCODoubleLine,    "dpcotdouble",  0 },
02117     { rtfDrawAttr,  rtfCORightAngle,    "dpcotright",   0 },
02118     { rtfDrawAttr,  rtfCOSingleLine,    "dpcotsingle",  0 },
02119     { rtfDrawAttr,  rtfCOTripleLine,    "dpcottriple",  0 },
02120 
02121     { rtfDrawAttr,  rtfDrawTextBoxMargin,   "dptxbxmar",    0 },
02122     { rtfDrawAttr,  rtfDrawTextBoxText, "dptxbxtext",   0 },
02123     { rtfDrawAttr,  rtfDrawRoundRect,   "dproundr", 0 },
02124 
02125     { rtfDrawAttr,  rtfDrawPointX,      "dpptx",    0 },
02126     { rtfDrawAttr,  rtfDrawPointY,      "dppty",    0 },
02127     { rtfDrawAttr,  rtfDrawPolyCount,   "dppolycount",  0 },
02128 
02129     { rtfDrawAttr,  rtfDrawArcFlipX,    "dparcflipx",   0 },
02130     { rtfDrawAttr,  rtfDrawArcFlipY,    "dparcflipy",   0 },
02131 
02132     { rtfDrawAttr,  rtfDrawLineBlue,    "dplinecob",    0 },
02133     { rtfDrawAttr,  rtfDrawLineGreen,   "dplinecog",    0 },
02134     { rtfDrawAttr,  rtfDrawLineRed,     "dplinecor",    0 },
02135     { rtfDrawAttr,  rtfDrawLinePalette, "dplinepal",    0 },
02136     { rtfDrawAttr,  rtfDrawLineDashDot, "dplinedado",   0 },
02137     { rtfDrawAttr,  rtfDrawLineDashDotDot,  "dplinedadodo", 0 },
02138     { rtfDrawAttr,  rtfDrawLineDash,    "dplinedash",   0 },
02139     { rtfDrawAttr,  rtfDrawLineDot,     "dplinedot",    0 },
02140     { rtfDrawAttr,  rtfDrawLineGray,    "dplinegray",   0 },
02141     { rtfDrawAttr,  rtfDrawLineHollow,  "dplinehollow", 0 },
02142     { rtfDrawAttr,  rtfDrawLineSolid,   "dplinesolid",  0 },
02143     { rtfDrawAttr,  rtfDrawLineWidth,   "dplinew",  0 },
02144 
02145     { rtfDrawAttr,  rtfDrawHollowEndArrow,  "dpaendhol",    0 },
02146     { rtfDrawAttr,  rtfDrawEndArrowLength,  "dpaendl",  0 },
02147     { rtfDrawAttr,  rtfDrawSolidEndArrow,   "dpaendsol",    0 },
02148     { rtfDrawAttr,  rtfDrawEndArrowWidth,   "dpaendw",  0 },
02149     { rtfDrawAttr,  rtfDrawHollowStartArrow,"dpastarthol",  0 },
02150     { rtfDrawAttr,  rtfDrawStartArrowLength,"dpastartl",    0 },
02151     { rtfDrawAttr,  rtfDrawSolidStartArrow, "dpastartsol",  0 },
02152     { rtfDrawAttr,  rtfDrawStartArrowWidth, "dpastartw",    0 },
02153 
02154     { rtfDrawAttr,  rtfDrawBgFillBlue,  "dpfillbgcb",   0 },
02155     { rtfDrawAttr,  rtfDrawBgFillGreen, "dpfillbgcg",   0 },
02156     { rtfDrawAttr,  rtfDrawBgFillRed,   "dpfillbgcr",   0 },
02157     { rtfDrawAttr,  rtfDrawBgFillPalette,   "dpfillbgpal",  0 },
02158     { rtfDrawAttr,  rtfDrawBgFillGray,  "dpfillbggray", 0 },
02159     { rtfDrawAttr,  rtfDrawFgFillBlue,  "dpfillfgcb",   0 },
02160     { rtfDrawAttr,  rtfDrawFgFillGreen, "dpfillfgcg",   0 },
02161     { rtfDrawAttr,  rtfDrawFgFillRed,   "dpfillfgcr",   0 },
02162     { rtfDrawAttr,  rtfDrawFgFillPalette,   "dpfillfgpal",  0 },
02163     { rtfDrawAttr,  rtfDrawFgFillGray,  "dpfillfggray", 0 },
02164     { rtfDrawAttr,  rtfDrawFillPatIndex,    "dpfillpat",    0 },
02165 
02166     { rtfDrawAttr,  rtfDrawShadow,      "dpshadow", 0 },
02167     { rtfDrawAttr,  rtfDrawShadowXOffset,   "dpshadx",  0 },
02168     { rtfDrawAttr,  rtfDrawShadowYOffset,   "dpshady",  0 },
02169 
02170     { rtfVersion,   -1,         "rtf",      0 },
02171     { rtfDefFont,   -1,         "deff",     0 },
02172 
02173     { 0,        -1,         NULL,       0 }
02174 };
02175 #define RTF_KEY_COUNT (sizeof(rtfKey) / sizeof(RTFKey))
02176 
02177 typedef struct tagRTFHashTableEntry {
02178     int count;
02179     RTFKey **value;
02180 } RTFHashTableEntry;
02181 
02182 static RTFHashTableEntry rtfHashTable[RTF_KEY_COUNT * 2];
02183 
02184 
02185 /*
02186  * Initialize lookup table hash values.  Only need to do this once.
02187  */
02188 
02189 void LookupInit(void)
02190 {
02191     RTFKey  *rp;
02192 
02193     memset(rtfHashTable, 0, sizeof rtfHashTable);
02194     for (rp = rtfKey; rp->rtfKStr != NULL; rp++)
02195     {
02196         int index;
02197 
02198         rp->rtfKHash = Hash (rp->rtfKStr);
02199         index = rp->rtfKHash % (RTF_KEY_COUNT * 2);
02200         if (!rtfHashTable[index].count)
02201             rtfHashTable[index].value = heap_alloc(sizeof(RTFKey *));
02202         else
02203             rtfHashTable[index].value = heap_realloc(rtfHashTable[index].value, sizeof(RTFKey *) * (rtfHashTable[index].count + 1));
02204         rtfHashTable[index].value[rtfHashTable[index].count++] = rp;
02205     }
02206 }
02207 
02208 void LookupCleanup(void)
02209 {
02210     unsigned int i;
02211 
02212     for (i=0; i<RTF_KEY_COUNT*2; i++)
02213     {
02214         heap_free( rtfHashTable[i].value );
02215         rtfHashTable[i].value = NULL;
02216         rtfHashTable[i].count = 0;
02217     }
02218 }
02219 
02220 
02221 /*
02222  * Determine major and minor number of control token.  If it's
02223  * not found, the class turns into rtfUnknown.
02224  */
02225 
02226 static void Lookup(RTF_Info *info, char *s)
02227 {
02228     RTFKey  *rp;
02229     int hash;
02230         RTFHashTableEntry *entry;
02231         int i;
02232 
02233     ++s;            /* skip over the leading \ character */
02234     hash = Hash (s);
02235         entry = &rtfHashTable[hash % (RTF_KEY_COUNT * 2)];
02236     for (i = 0; i < entry->count; i++)
02237     {
02238                 rp = entry->value[i];
02239         if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0)
02240         {
02241             info->rtfClass = rtfControl;
02242             info->rtfMajor = rp->rtfKMajor;
02243             info->rtfMinor = rp->rtfKMinor;
02244             return;
02245         }
02246     }
02247     info->rtfClass = rtfUnknown;
02248 }
02249 
02250 
02251 /*
02252  * Compute hash value of symbol
02253  */
02254 
02255 static int Hash(const char *s)
02256 {
02257     char    c;
02258     int val = 0;
02259 
02260     while ((c = *s++) != '\0')
02261         val += c;
02262     return (val);
02263 }
02264 
02265 
02266 
02267 /* ---------------------------------------------------------------------- */
02268 
02269 
02270 /*
02271  * Token comparison routines
02272  */
02273 
02274 int RTFCheckCM(const RTF_Info *info, int class, int major)
02275 {
02276     return (info->rtfClass == class && info->rtfMajor == major);
02277 }
02278 
02279 
02280 int RTFCheckCMM(const RTF_Info *info, int class, int major, int minor)
02281 {
02282     return (info->rtfClass == class && info->rtfMajor == major && info->rtfMinor == minor);
02283 }
02284 
02285 
02286 int RTFCheckMM(const RTF_Info *info, int major, int minor)
02287 {
02288     return (info->rtfMajor == major && info->rtfMinor == minor);
02289 }
02290 
02291 
02292 /* ---------------------------------------------------------------------- */
02293 
02294 
02295 int RTFCharToHex(char c)
02296 {
02297     if (isupper (c))
02298         c = tolower (c);
02299     if (isdigit (c))
02300         return (c - '0');   /* '0'..'9' */
02301     return (c - 'a' + 10);      /* 'a'..'f' */
02302 }
02303 
02304 
02305 /* ---------------------------------------------------------------------- */
02306 
02307 /*
02308  * originally from RTF tools' text-writer.c
02309  *
02310  * text-writer -- RTF-to-text translation writer code.
02311  *
02312  * Read RTF input, write text of document (text extraction).
02313  */
02314 
02315 static void TextClass (RTF_Info *info);
02316 static void ControlClass (RTF_Info *info);
02317 static void     DefFont(RTF_Info *info);
02318 static void Destination (RTF_Info *info);
02319 static void SpecialChar (RTF_Info *info);
02320 static void RTFPutUnicodeChar (RTF_Info *info, int c);
02321 
02322 /*
02323  * Initialize the writer.
02324  */
02325 
02326 void
02327 WriterInit (RTF_Info *info )
02328 {
02329 }
02330 
02331 
02332 int
02333 BeginFile (RTF_Info *info )
02334 {
02335     /* install class callbacks */
02336 
02337     RTFSetClassCallback (info, rtfText, TextClass);
02338     RTFSetClassCallback (info, rtfControl, ControlClass);
02339 
02340     return (1);
02341 }
02342 
02343 /*
02344  * Write out a character.
02345  */
02346 
02347 static void
02348 TextClass (RTF_Info *info)
02349 {
02350     RTFPutCodePageChar(info, info->rtfMajor);
02351 }
02352 
02353 
02354 static void
02355 ControlClass (RTF_Info *info)
02356 {
02357     switch (info->rtfMajor)
02358     {
02359         case rtfCharAttr:
02360                 CharAttr(info);
02361                 ME_RTFCharAttrHook(info);
02362                 break;
02363         case rtfParAttr:
02364                 ME_RTFParAttrHook(info);
02365                 break;
02366         case rtfTblAttr:
02367                 ME_RTFTblAttrHook(info);
02368                 break;
02369         case rtfCharSet:
02370                 CharSet(info);
02371                 break;
02372         case rtfDefFont:
02373                 DefFont(info);
02374                 break;
02375     case rtfDestination:
02376         Destination (info);
02377         break;
02378         case rtfDocAttr:
02379                 DocAttr(info);
02380                 break;
02381     case rtfSpecialChar:
02382                 SpecialChar (info);
02383                 ME_RTFSpecialCharHook(info);
02384         break;
02385     }
02386 }
02387 
02388 
02389 static void
02390 CharAttr(RTF_Info *info)
02391 {
02392         RTFFont *font;
02393 
02394         switch (info->rtfMinor)
02395         {
02396         case rtfFontNum:
02397                 font = RTFGetFont(info, info->rtfParam);
02398                 if (font)
02399                 {
02400                         if (info->ansiCodePage != CP_UTF8)
02401                                 info->codePage = font->rtfFCodePage;
02402                         TRACE("font %d codepage %d\n", info->rtfParam, info->codePage);
02403                 }
02404                 else
02405                         ERR( "unknown font %d\n", info->rtfParam);
02406                 break;
02407         case rtfUnicodeLength:
02408                 info->unicodeLength = info->rtfParam;
02409                 break;
02410         }
02411 }
02412 
02413 
02414 static void
02415 CharSet(RTF_Info *info)
02416 {
02417     if (info->ansiCodePage == CP_UTF8)
02418         return;
02419  
02420         switch (info->rtfMinor)
02421         {
02422         case rtfAnsiCharSet:
02423                 info->ansiCodePage = 1252; /* Latin-1 */
02424                 break;
02425         case rtfMacCharSet:
02426                 info->ansiCodePage = 10000; /* MacRoman */
02427                 break;
02428         case rtfPcCharSet:
02429                 info->ansiCodePage = 437;
02430                 break;
02431         case rtfPcaCharSet:
02432                 info->ansiCodePage = 850;
02433                 break;
02434         }
02435 }
02436 
02437 /*
02438  * This function notices destinations that aren't explicitly handled
02439  * and skips to their ends.  This keeps, for instance, picture
02440  * data from being considered as plain text.
02441  */
02442 
02443 static void
02444 Destination (RTF_Info *info)
02445 {
02446     if (!RTFGetDestinationCallback(info, info->rtfMinor))
02447         RTFSkipGroup (info);    
02448 }
02449 
02450 
02451 static void
02452 DefFont(RTF_Info *info)
02453 {
02454         TRACE("%d\n", info->rtfParam);
02455         info->defFont = info->rtfParam;
02456 }
02457 
02458 
02459 static void
02460 DocAttr(RTF_Info *info)
02461 {
02462         TRACE("minor %d, param %d\n", info->rtfMinor, info->rtfParam);
02463 
02464         switch (info->rtfMinor)
02465         {
02466         case rtfAnsiCodePage:
02467                 info->codePage = info->ansiCodePage = info->rtfParam;
02468                 break;
02469         case rtfUTF8RTF:
02470                 info->codePage = info->ansiCodePage = CP_UTF8;
02471                 break;
02472         }
02473 }
02474 
02475 
02476 static void SpecialChar (RTF_Info *info)
02477 {
02478     switch (info->rtfMinor)
02479     {
02480     case rtfOptDest:
02481         /* the next token determines destination, if it's unknown, skip the group */
02482         /* this way we filter out the garbage coming from unknown destinations */ 
02483         RTFGetToken(info); 
02484         if (info->rtfClass != rtfDestination)
02485             RTFSkipGroup(info);
02486         else
02487             RTFRouteToken(info); /* "\*" is ignored with known destinations */
02488         break;
02489     case rtfUnicode:
02490     {
02491                 int i;
02492 
02493                 RTFPutUnicodeChar(info, info->rtfParam);
02494 
02495                 /* After \u we must skip number of character tokens set by \ucN */
02496                 for (i = 0; i < info->unicodeLength; i++)
02497                 {
02498             RTFGetToken(info);
02499                         if (info->rtfClass != rtfText)
02500                 {
02501                                 ERR("The token behind \\u is not text, but (%d,%d,%d)\n",
02502                 info->rtfClass, info->rtfMajor, info->rtfMinor);
02503                                 RTFUngetToken(info);
02504                                 break;
02505                         }
02506         }
02507         break;
02508     }
02509     case rtfLine:
02510             RTFFlushOutputBuffer(info);
02511             ME_InsertEndRowFromCursor(info->editor, 0);
02512             break;
02513     case rtfPage:
02514     case rtfSect:
02515     case rtfPar:
02516         RTFPutUnicodeChar (info, '\r');
02517         if (info->editor->bEmulateVersion10) RTFPutUnicodeChar (info, '\n');
02518         break;
02519     case rtfNoBrkSpace:
02520         RTFPutUnicodeChar (info, 0x00A0);
02521         break;
02522     case rtfTab:
02523         RTFPutUnicodeChar (info, '\t');
02524         break;
02525     case rtfNoBrkHyphen:
02526         RTFPutUnicodeChar (info, 0x2011);
02527         break;
02528     case rtfBullet:
02529         RTFPutUnicodeChar (info, 0x2022);
02530         break;
02531     case rtfEmDash:
02532         RTFPutUnicodeChar (info, 0x2014);
02533         break;
02534     case rtfEnDash:
02535         RTFPutUnicodeChar (info, 0x2013);
02536         break;
02537     case rtfLQuote:
02538         RTFPutUnicodeChar (info, 0x2018);
02539         break;
02540     case rtfRQuote:
02541         RTFPutUnicodeChar (info, 0x2019);
02542         break;
02543     case rtfLDblQuote:
02544         RTFPutUnicodeChar (info, 0x201C);
02545         break;
02546     case rtfRDblQuote:
02547         RTFPutUnicodeChar (info, 0x201D);
02548         break;
02549     }
02550 }
02551 
02552 
02553 static void
02554 RTFFlushUnicodeOutputBuffer(RTF_Info *info)
02555 {
02556         if (info->dwOutputCount)
02557         {
02558                 ME_InsertTextFromCursor(info->editor, 0, info->OutputBuffer,
02559                                         info->dwOutputCount, info->style);
02560                 info->dwOutputCount = 0;
02561         }
02562 }
02563 
02564 
02565 static void
02566 RTFPutUnicodeString(RTF_Info *info, const WCHAR *string, int length)
02567 {
02568         if (info->dwCPOutputCount)
02569                 RTFFlushCPOutputBuffer(info);
02570         while (length)
02571         {
02572                 int fit = min(length, sizeof(info->OutputBuffer) / sizeof(WCHAR) - info->dwOutputCount);
02573 
02574                 memmove(info->OutputBuffer + info->dwOutputCount, string, fit * sizeof(WCHAR));
02575                 info->dwOutputCount += fit;
02576                 length -= fit;
02577                 string += fit;
02578                 if (sizeof(info->OutputBuffer) / sizeof(WCHAR) == info->dwOutputCount)
02579                         RTFFlushUnicodeOutputBuffer(info);
02580         }
02581 }
02582 
02583 static void
02584 RTFFlushCPOutputBuffer(RTF_Info *info)
02585 {
02586         int bufferMax = info->dwCPOutputCount * 2 * sizeof(WCHAR);
02587         WCHAR *buffer = heap_alloc(bufferMax);
02588         int length;
02589 
02590         length = MultiByteToWideChar(info->codePage, 0, info->cpOutputBuffer,
02591                                      info->dwCPOutputCount, buffer, bufferMax/sizeof(WCHAR));
02592         info->dwCPOutputCount = 0;
02593 
02594         RTFPutUnicodeString(info, buffer, length);
02595         heap_free(buffer);
02596 }
02597 
02598 void
02599 RTFFlushOutputBuffer(RTF_Info *info)
02600 {
02601         if (info->dwCPOutputCount)
02602                 RTFFlushCPOutputBuffer(info);
02603         RTFFlushUnicodeOutputBuffer(info);
02604 }
02605 
02606 static void
02607 RTFPutUnicodeChar(RTF_Info *info, int c)
02608 {
02609     if (info->dwCPOutputCount)
02610                 RTFFlushCPOutputBuffer(info);
02611         if (info->dwOutputCount * sizeof(WCHAR) >= ( sizeof info->OutputBuffer - 1 ) )
02612         RTFFlushUnicodeOutputBuffer( info );
02613     info->OutputBuffer[info->dwOutputCount++] = c;
02614 }
02615 
02616 static void
02617 RTFPutCodePageChar(RTF_Info *info, int c)
02618 {
02619         /* Use dynamic buffer here because it's the best way to handle
02620          * MBCS codepages without having to worry about partial chars */
02621         if (info->dwCPOutputCount >= info->dwMaxCPOutputCount)
02622         {
02623                 info->dwMaxCPOutputCount *= 2;
02624                 info->cpOutputBuffer = heap_realloc(info->cpOutputBuffer, info->dwMaxCPOutputCount);
02625         }
02626         info->cpOutputBuffer[info->dwCPOutputCount++] = c;
02627 }

Generated on Fri May 25 2012 04:24:02 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.