Browse Source

+ Added RTFparser object and Demo

michael 26 years ago
parent
commit
124fe6744b
4 changed files with 1946 additions and 0 deletions
  1. 768 0
      fcl/inc/rtfdata.inc
  2. 1072 0
      fcl/inc/rtfpars.pp
  3. BIN
      fcl/tests/overview.rtf
  4. 106 0
      fcl/tests/testrtf.pp

+ 768 - 0
fcl/inc/rtfdata.inc

@@ -0,0 +1,768 @@
+{
+    $Id$
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 1998 by Michael Van Canneyt, member of the
+    Free Pascal development team
+
+    All major and minor RTF class definitions.
+    
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+{ ---------------------------------------------------------------------
+  Twentieths of a point (twips) per inch (Many RTF measurements
+  are in twips per inch (tpi) units).  Assumes 72 points/inch. 
+  ---------------------------------------------------------------------}
+
+Const
+ rtfTpi		= 1440;
+ rtfBufSiz	= 255; { buffer size}
+
+{ ---------------------------------------------------------------------
+	Tokens are associated with up to three classification numbers:
+
+	Class number: Broadest (least detailed) breakdown.  For programs
+		that only care about gross token distinctions.
+	Major/minor numbers: Within their class, tokens have a major
+		number, and may also have a minor number to further
+		distinquish tokens with the same major number.
+
+	*** Class, major and minor token numbers are all >= 0 ***
+
+	Tokens that can't be classified are put in the "unknown" class.
+	For such, the major and minor numbers are meaningless, although
+	rtfTextBuf may be of interest then.
+
+	Text tokens are a single character, and the major number indicates
+	the character value (note: can be non-ascii, i.e., greater than 127).
+	There is no minor number.
+
+	Control symbols may have a parameter value, which will be found in
+	rtfParam.  If no parameter was given, rtfParam = rtfNoParam.
+
+	RTFGetToken() return value is the class number, but it sets all the
+	global token vars.
+
+	rtfEOF is a fake token used by the reader; the writer never sees
+	it (except in the token reader hook, if it installs one).
+
+	Information pertaining to last token read by RTFToken.  The
+	text is exactly as it occurs in the input file, e.g., 
+	will be found in rtfTextBuf as, even though it means .
+	
+	These variables are also set when styles are reprocessed.
+ ----------------------------------------------------------------------}
+	rtfNoParam = (-1000000);
+	
+{	Token classes (zero-based and sequential) }
+	rtfUnknown	= 0;
+	rtfGroup	= 1;
+	rtfText		= 2;
+	rtfControl	= 3;
+	rtfEOF		= 4;
+	rtfMaxClass	= 5	{ highest class + 1 };
+
+{	Group class major numbers }
+	rtfBeginGroup	= 0;
+	rtfEndGroup	= 1;
+{	Control class major and minor numbers.}
+	rtfVersion	= 0;
+
+	rtfDefFont	= 1;
+
+	rtfCharSet	= 2;
+		rtfAnsiCharSet		= 0;
+		rtfMacCharSet		= 1;
+		rtfPcCharSet		= 2;
+		rtfPcaCharSet		= 3;
+{	destination minor numbers should be zero-based, sequential }
+	rtfDestination	= 3;
+		rtfPict			= 0;
+		rtfNeXTGraphic		= 1;
+		rtfFootnote		= 2;
+		rtfHeader		= 3;
+		rtfHeaderLeft		= 4;
+		rtfHeaderRight		= 5;
+		rtfHeaderFirst		= 6;
+		rtfFooter		= 7;
+		rtfFooterLeft		= 8;
+		rtfFooterRight		= 9;
+		rtfFooterFirst		= 10;
+		rtfFNSep		= 11;
+		rtfFNContSep		= 12;
+		rtfFNContNotice		= 13;
+		rtfInfo			= 14;
+		rtfStyleSheet		= 15;
+		rtfFontTbl		= 16;
+		rtfColorTbl		= 17;
+		rtfField		= 18;
+		rtfFieldInst		= 19;
+		rtfFieldResult		= 20;
+		rtfIndex		= 21;
+		rtfIndexBold		= 22;
+		rtfIndexItalic		= 23;
+		rtfIndexText		= 24;
+		rtfIndexRange		= 25;
+		rtfTOC			= 26;
+		rtfBookmarkStart	= 27;
+		rtfBookmarkEnd		= 28;
+		rtfITitle		= 29;
+		rtfISubject		= 30;
+		rtfIAuthor		= 31;
+		rtfIOperator		= 32;
+		rtfIKeywords		= 33;
+		rtfIComment		= 34;
+		rtfIVersion		= 35;
+		rtfIDoccomm		= 36;
+		rtfMaxDestination	= 37	{ highest dest + 1 };
+
+	rtfFontFamily	= 4;
+		rtfFFNil		= 0;
+		rtfFFRoman		= 1;
+		rtfFFSwiss		= 2;
+		rtfFFModern		= 3;
+		rtfFFScript		= 4;
+		rtfFFDecor		= 5;
+		rtfFFTech		= 6;
+
+	rtfColorName	= 5;
+		rtfRed			= 0;
+		rtfGreen		= 1;
+		rtfBlue			= 2;
+
+        rtfSpecialChar = 6;
+		rtfCurHeadPage		= 0;
+		rtfCurFNote		= 1;
+		rtfCurHeadPict		= 2	{ valid? };
+		rtfCurHeadDate		= 3;
+		rtfCurHeadTime		= 4;
+		rtfFormula		= 5;
+		rtfNoBrkSpace		= 6;
+		rtfNoReqHyphen		= 7;
+		rtfNoBrkHyphen		= 8;
+		rtfPage			= 9;
+		rtfLine			= 10;
+		rtfPar			= 11;
+		rtfSect			= 12;
+		rtfTab			= 13;
+		rtfCell			= 14;
+		rtfRow			= 15;
+		rtfCurAnnot		= 16;
+		rtfAnnotation		= 17;
+		rtfAnnotID		= 18;
+		rtfCurAnnotRef		= 19;
+		rtfFNoteSep		= 20;
+		rtfFNoteCont		= 21;
+		rtfColumn		= 22;
+		rtfOptDest		= 23;
+		rtfIIntVersion		= 24;
+		rtfICreateTime		= 25;
+		rtfIRevisionTime	= 26;
+		rtfIPrintTime		= 27;
+		rtfIBackupTime		= 28;
+		rtfIEditTime		= 29;
+		rtfIYear		= 30;
+		rtfIMonth		= 31;
+		rtfIDay			= 32;
+		rtfIHour		= 33;
+		rtfIMinute		= 34;
+		rtfINPages		= 35;
+		rtfINWords		= 36;
+		rtfINChars		= 37;
+		rtfIIntID		= 38;
+
+	rtfStyleAttr	= 7;
+		rtfBasedOn		= 0;
+		rtfNext			= 1;
+
+	rtfDocAttr	= 8;
+		rtfPaperWidth		= 0;
+		rtfPaperHeight		= 1;
+		rtfLeftMargin		= 2;
+		rtfRightMargin		= 3;
+		rtfTopMargin		= 4;
+		rtfBottomMargin		= 5;
+		rtfFacingPage		= 6;
+		rtfGutterWid		= 7;
+		rtfDefTab		= 8;
+		rtfWidowCtrl		= 9;
+		rtfHyphHotZone		= 10;
+		rtfFNoteEndSect		= 11;
+		rtfFNoteEndDoc		= 12;
+		rtfFNoteText		= 13;
+		rtfFNoteBottom		= 14;
+		rtfFNoteStart		= 15;
+		rtfFNoteRestart		= 16;
+		rtfPageStart		= 17;
+		rtfLineStart		= 18;
+		rtfLandscape		= 19;
+		rtfFracWidth		= 20;
+		rtfNextFile		= 21;
+		rtfTemplate		= 22;
+		rtfMakeBackup		= 23;
+		rtfRTFDefault		= 24;
+		rtfRevisions		= 25;
+		rtfMirrorMargin		= 26;
+		rtfRevDisplay		= 27;
+		rtfRevBar		= 28;
+
+	rtfSectAttr	= 9;
+		rtfSectDef		= 0;
+		rtfNoBreak		= 1;
+		rtfColBreak		= 2;
+		rtfPageBreak		= 3;
+		rtfEvenBreak		= 4;
+		rtfOddBreak		= 5;
+		rtfPageStarts		= 6;
+		rtfPageCont		= 7;
+		rtfPageRestart		= 8;
+		rtfPageDecimal		= 9;
+		rtfPageURoman		= 10;
+		rtfPageLRoman		= 11;
+		rtfPageULetter		= 12;
+		rtfPageLLetter		= 13;
+		rtfPageNumLeft		= 14;
+		rtfPageNumTop		= 15;
+		rtfHeaderY		= 16;
+		rtfFooterY		= 17;
+		rtfLineModulus		= 18;
+		rtfLineDist		= 19;
+		rtfLineStarts		= 20;
+		rtfLineRestart		= 21;
+		rtfLineRestartPg	= 22;
+		rtfLineCont		= 23;
+		rtfTopVAlign		= 24;
+		rtfBottomVAlign		= 25;
+		rtfCenterVAlign		= 26;
+		rtfJustVAlign		= 27;
+		rtfColumns		= 28;
+		rtfColumnSpace		= 29;
+		rtfColumnLine		= 30;
+		rtfENoteHere		= 31;
+		rtfTitleSpecial		= 32;
+
+	rtfTblAttr	= 10;
+		rtfCellBordBottom	= 0;
+		rtfCellBordTop		= 1;
+		rtfCellBordLeft		= 2;
+		rtfCellBordRight	= 3;
+		rtfRowDef		= 4;
+		rtfRowLeft		= 5;
+		rtfRowRight		= 6;
+		rtfRowCenter		= 7;
+		rtfRowGapH		= 8;
+		rtfRowHt		= 9;
+		rtfRowLeftEdge		= 10;
+		rtfCellPos		= 11;
+		rtfMergeRngFirst	= 12;
+		rtfMergePrevious	= 13;
+
+	rtfParAttr	= 11;
+		rtfParDef		= 0;
+		rtfStyleNum		= 1;
+		rtfQuadLeft		= 2;
+		rtfQuadRight		= 3;
+		rtfQuadJust		= 4;
+		rtfQuadCenter		= 5;
+		rtfFirstIndent		= 6;
+		rtfLeftIndent		= 7;
+		rtfRightIndent		= 8;
+		rtfSpaceBefore		= 9;
+		rtfSpaceAfter		= 10;
+		rtfSpaceBetween		= 11;
+		rtfInTable		= 12;
+		rtfKeep			= 13;
+		rtfKeepNext		= 14;
+		rtfSideBySide		= 15;
+		rtfPBBefore		= 16;
+		rtfNoLineNum		= 17;
+		rtfTabPos		= 18;
+		rtfTabRight		= 19;
+		rtfTabCenter		= 20;
+		rtfTabDecimal		= 21;
+		rtfTabBar		= 22;
+		rtfBorderTop		= 23;
+		rtfBorderBottom		= 24;
+		rtfBorderLeft		= 25;
+		rtfBorderRight		= 26;
+		rtfBorderBox		= 27;
+		rtfBorderBar		= 28;
+		rtfBorderBetween	= 29;
+		rtfBorderSingle		= 30;
+		rtfBorderThick		= 31;
+		rtfBorderShadow		= 32;
+		rtfBorderDouble		= 33;
+		rtfBorderDot		= 34;
+		rtfBorderHair		= 35;
+		rtfBorderSpace		= 36;
+		rtfLeaderDot		= 37;
+		rtfLeaderHyphen		= 38;
+		rtfLeaderUnder		= 39;
+		rtfLeaderThick		= 40;
+
+	rtfCharAttr	= 12;
+		rtfPlain		= 0;
+		rtfBold			= 1;
+		rtfItalic		= 2;
+		rtfStrikeThru		= 3;
+		rtfOutline		= 4;
+		rtfShadow		= 5;
+		rtfSmallCaps		= 6;
+		rtfAllCaps		= 7;
+		rtfInvisible		= 8;
+		rtfFontNum		= 9;
+		rtfFontSize		= 10;
+		rtfExpand		= 11;
+		rtfUnderline		= 12;
+		rtfWUnderline		= 13;
+		rtfDUnderline		= 14;
+		rtfDbUnderline		= 15;
+		rtfNoUnderline		= 16;
+		rtfSuperScript		= 17;
+		rtfSubScript		= 18;
+		rtfRevised		= 19;
+		rtfForeColor		= 20;
+		rtfBackColor		= 21;
+		rtfGray			= 22;
+
+	rtfPictAttr	= 13;
+		rtfMacQD		= 0;
+		rtfWinMetafile		= 1;
+		rtfWinBitmap		= 2;
+		rtfPicWid		= 3;
+		rtfPicHt		= 4;
+		rtfPicGoalWid		= 5;
+		rtfPicGoalHt		= 6;
+		rtfPicScaleX		= 7;
+		rtfPicScaleY		= 8;
+		rtfPicScaled		= 9;
+		rtfPicCropTop		= 10;
+		rtfPicCropBottom	= 11;
+		rtfPicCropLeft		= 12;
+		rtfPicCropRight		= 13;
+		rtfPixelBits		= 14;
+		rtfBitmapPlanes		= 15;
+		rtfBitmapWid		= 16;
+		rtfPicBinary		= 17;
+
+	rtfNeXTGrAttr	= 14;
+		rtfNeXTGWidth		= 0;
+		rtfNeXTGHeight		= 1;
+
+	rtfFieldAttr	= 15;
+		rtfFieldDirty		= 0;
+		rtfFieldEdited		= 1;
+		rtfFieldLocked		= 2;
+		rtfFieldPrivate		= 3;
+
+		rtfTOCAttr	= 16;
+		rtfTOCType		= 0;
+		rtfTOCLevel		= 1;
+
+	rtfPosAttr	= 17;
+		rtfPosX			= 0;
+		rtfPosXCenter		= 1;
+		rtfPosXInside		= 2;
+		rtfPosXLeft		= 3;
+		rtfPosXOutSide		= 4;
+		rtfPosXRight		= 5;
+		rtfPosY			= 6;
+		rtfPosYInline		= 7;
+		rtfPosYTop		= 8;
+		rtfPosYCenter		= 9;
+		rtfPosYBottom		= 10;
+		rtfAbsWid		= 11;
+		rtfTextDist		= 12;
+		rtfRPosMargV		= 13;
+		rtfRPosPageV		= 14;
+		rtfRPosMargH		= 15;
+		rtfRPosPageH		= 16;
+		rtfRPosColH		= 17;
+
+	rtfBasedOnNone	= 222;	{ "no based-on style" }
+
+
+Type
+
+{ ---------------------------------------------------------------------
+     Callback Types 
+  ---------------------------------------------------------------------}
+  
+TRTFFunc = Procedure of object;
+TRTFFuncPtr = procedure of object;
+
+{ ---------------------------------------------------------------------
+    RTF font, color and style structures.  Used for font table,
+    color table, and stylesheet processing. 
+  ---------------------------------------------------------------------}
+  
+PRTFFONT = ^TRTFFONT;
+TRTFFont = Record
+	rtfFName    : string;		{ font name }
+	rtfFNum     : integer;		{ font number }
+	rtfFFamily  : integer;		{ font family }
+	rtfNextFont : PRTFFONT;		{ next font in list }
+end;
+
+
+{ ----------------------------------------------------------------------
+	Color values are -1 if the default color for the the color
+	number should be used.  The default color is writer-dependent.
+  ----------------------------------------------------------------------}
+ 
+PRTFColor = ^TRTFColor;
+TRTFColor = Record
+	rtfCNum : integer;	{ color number }
+	rtfCRed : INteger;	{ red value }
+	rtfCGreen : INteger;	{ green value }
+	rtfCBlue : integer;	{ blue value }
+	rtfNextColor : PRTFColor;	{ next color in list }
+end;
+
+PRTFStyleElt = ^TRTFStyleElt;
+TRTFStyleElt = record
+	rtfSEClass,			{ token class }
+	rtfSEMajor,			{ token major number }
+	rtfSEMinor,			{ token minor number }
+	rtfSEParam : Integer;		{ control symbol parameter }
+	rtfSEText : String;		{ text of symbol }
+	rtfNextSE : PRTFStyleElt;	{ next element in style }
+end;
+
+PRTFSTyle = ^TRTFStyle;
+TRTFStyle = record
+	rtfSName : string;		{ style name }
+	rtfSNum,			{ style number }
+	rtfSBasedOn,			{ style this one's based on }
+	rtfSNextPar : integer;		{ style next paragraph style }
+	rtfSSEList : PRTFStyleElt;	{ list of style words }
+	rtfExpanding : Integer;		{ non-zero = being expanded }
+	rtfNextStyle : PRTFStyle;	{ next style in style list }
+end;
+
+{ ---------------------------------------------------------------------
+       Control symbol lookup routines
+  ---------------------------------------------------------------------}
+
+
+Type
+  TRTFKey = record
+    rtfKMajor : Integer;	{ major number }
+    rtfKMinor : Integer;	{ minor number }
+    rtfKStr   : string[20];	{ symbol name }
+    rtfKHash  : Integer;	{ symbol name hash value }
+    End;
+
+{ ---------------------------------------------------------------------
+    A minor number of -1 means the token has no minor number
+   (all valid minor numbers are >= 0).
+  ---------------------------------------------------------------------}
+
+Const rtfKey : Array [0..281] of TRTFKey =
+(
+( rtfKMajor: RTFSPECIALCHAR; rtfKMinor : rtfCURHEADPICT; rtfKStr  : 'chpict'; rtfKhash :	0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfCurHeadDate; rtfKstr : 'chdate'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfCurHeadTime; rtfKstr : 'chtime'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfCurHeadPage; rtfKstr : 'chpgn'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfCurFNote; rtfKstr : 'chftn'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfCurAnnotRef; rtfKstr : 'chatn'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfFNoteSep; rtfKstr : 'chftnsep'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfFNoteCont; rtfKstr : 'chftnsepc'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfFormula; rtfKstr : '|'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfNoBrkSpace; rtfKstr : '~'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfNoReqHyphen; rtfKstr : '-'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfNoBrkHyphen; rtfKstr : '_'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfCell; rtfKstr : 'cell'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfRow; rtfKstr : 'row'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfPar; rtfKstr : 'par'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfPar; rtfKstr : #10; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfPar; rtfKstr : #13; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfSect; rtfKstr : 'sect'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfPage; rtfKstr : 'page'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfColumn; rtfKstr : 'column'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfLine; rtfKstr : 'line'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfTab; rtfKstr : 'tab'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfOptDest; rtfKstr : '*'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIIntVersion; rtfKstr : 'vern'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfICreateTime; rtfKstr : 'creatim'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIRevisionTime; rtfKstr : 'revtim'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIPrintTime; rtfKstr : 'printim'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIBackupTime; rtfKstr : 'buptim'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIEditTime; rtfKstr : 'edmins'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIYear; rtfKstr : 'yr'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIMonth; rtfKstr : 'mo'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIDay; rtfKstr : 'dy'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIHour; rtfKstr : 'hr'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIMinute; rtfKstr : 'min'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfINPages; rtfKstr : 'nofpages'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfINWords; rtfKstr : 'nofwords'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfINChars; rtfKstr : 'nofchars'; rtfkHash : 0),
+( rtfKMajor: rtfSpecialChar; rtfKMinor: 	rtfIIntID; rtfKstr : 'id'; rtfkHash : 0),
+
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfPlain; rtfKstr : 'plain'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfBold; rtfKstr : 'b'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfItalic; rtfKstr : 'i'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfStrikeThru; rtfKstr : 'strike'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfOutline; rtfKstr : 'outl'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfShadow; rtfKstr : 'shad'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfSmallCaps; rtfKstr : 'scaps'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfAllCaps; rtfKstr : 'caps'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfInvisible; rtfKstr : 'v'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfFontNum; rtfKstr : 'f'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfFontSize; rtfKstr : 'fs'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfExpand; rtfKstr : 'expnd'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfUnderline; rtfKstr : 'ul'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfWUnderline; rtfKstr : 'ulw'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfDUnderline; rtfKstr : 'uld'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfDbUnderline; rtfKstr : 'uldb'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfNoUnderline; rtfKstr : 'ulnone'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfSuperScript; rtfKstr : 'up'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfSubScript; rtfKstr : 'dn'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfRevised; rtfKstr : 'revised'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfForeColor; rtfKstr : 'cf'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfBackColor; rtfKstr : 'cb'; rtfkHash : 0),
+( rtfKMajor: rtfCharAttr; rtfKMinor: 	rtfGray; rtfKstr : 'gray'; rtfkHash : 0),
+
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfParDef; rtfKstr : 'pard'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfStyleNum; rtfKstr : 's'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfQuadLeft; rtfKstr : 'ql'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfQuadRight; rtfKstr : 'qr'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfQuadJust; rtfKstr : 'qj'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfQuadCenter; rtfKstr : 'qc'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfFirstIndent; rtfKstr : 'fi'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfLeftIndent; rtfKstr : 'li'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfRightIndent; rtfKstr : 'ri'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfSpaceBefore; rtfKstr : 'sb'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfSpaceAfter; rtfKstr : 'sa'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfSpaceBetween; rtfKstr : 'sl'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfInTable; rtfKstr : 'intbl'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfKeep; rtfKstr : 'keep'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfKeepNext; rtfKstr : 'keepn'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfSideBySide; rtfKstr : 'sbys'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfPBBefore; rtfKstr : 'pagebb'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfNoLineNum; rtfKstr : 'noline'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfTabPos; rtfKstr : 'tx'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfTabRight; rtfKstr : 'tqr'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfTabCenter; rtfKstr : 'tqc'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfTabDecimal; rtfKstr : 'tqdec'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfTabBar; rtfKstr : 'tb'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderTop; rtfKstr : 'brdrt'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderBottom; rtfKstr : 'brdrb'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderLeft; rtfKstr : 'brdrl'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderRight; rtfKstr : 'brdrr'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderBar; rtfKstr : 'bar'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderBox; rtfKstr : 'box'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderBetween; rtfKstr : 'brdrbtw'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderSingle; rtfKstr : 'brdrs'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderThick; rtfKstr : 'brdrth'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderShadow; rtfKstr : 'brdrsh'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderDouble; rtfKstr : 'brdrdb'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderDot; rtfKstr : 'brdrdot'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderHair; rtfKstr : 'brdrhair'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfLeaderDot; rtfKstr : 'tldot'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfLeaderHyphen; rtfKstr : 'tlhyph'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfLeaderUnder; rtfKstr : 'tlul'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfLeaderThick; rtfKstr : 'tlth'; rtfkHash : 0),
+( rtfKMajor: rtfParAttr; rtfKMinor: 	rtfBorderSpace; rtfKstr : 'brsp'; rtfkHash : 0),
+
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfSectDef; rtfKstr : 'sectd'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfNoBreak; rtfKstr : 'sbknone'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfColBreak; rtfKstr : 'sbkcol'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageBreak; rtfKstr : 'sbkpage'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfEvenBreak; rtfKstr : 'sbkeven'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfOddBreak; rtfKstr : 'sbkodd'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageCont; rtfKstr : 'pgncont'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageStarts; rtfKstr : 'pgnstarts'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageRestart; rtfKstr : 'pgnrestart'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageDecimal; rtfKstr : 'pgndec'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageURoman; rtfKstr : 'pgnucrm'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageLRoman; rtfKstr : 'pgnlcrm'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageULetter; rtfKstr : 'pgnucltr'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageLLetter; rtfKstr : 'pgnlcltr'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageNumLeft; rtfKstr : 'pgnx'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfPageNumTop; rtfKstr : 'pgny'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfHeaderY; rtfKstr : 'headery'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfFooterY; rtfKstr : 'footery'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfLineModulus; rtfKstr : 'linemod'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfLineDist; rtfKstr : 'linex'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfLineStarts; rtfKstr : 'linestarts'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfLineRestart; rtfKstr : 'linerestart'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfLineRestartPg; rtfKstr : 'lineppage'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfLineCont; rtfKstr : 'linecont'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfTopVAlign; rtfKstr : 'vertalt'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfBottomVAlign; rtfKstr : 'vertal'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfCenterVAlign; rtfKstr : 'vertalc'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfJustVAlign; rtfKstr : 'vertalj'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfColumns; rtfKstr : 'cols'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfColumnSpace; rtfKstr : 'colsx'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfColumnLine; rtfKstr : 'linebetcol'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfENoteHere; rtfKstr : 'endnhere'; rtfkHash : 0),
+( rtfKMajor: rtfSectAttr; rtfKMinor: 	rtfTitleSpecial; rtfKstr : 'titlepg'; rtfkHash : 0),
+
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfPaperWidth; rtfKstr : 'paperw'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfPaperHeight; rtfKstr : 'paperh'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfLeftMargin; rtfKstr : 'margl'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfRightMargin; rtfKstr : 'margr'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfTopMargin; rtfKstr : 'margt'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfBottomMargin; rtfKstr : 'margb'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfFacingPage; rtfKstr : 'facingp'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfGutterWid; rtfKstr : 'gutter'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfDefTab; rtfKstr : 'deftab'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfWidowCtrl; rtfKstr : 'widowctrl'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfHyphHotZone; rtfKstr : 'hyphhotz'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfFNoteEndSect; rtfKstr : 'endnotes'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfFNoteEndDoc; rtfKstr : 'enddoc'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfFNoteBottom; rtfKstr : 'ftnbj'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfFNoteText; rtfKstr : 'ftntj'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfFNoteStart; rtfKstr : 'ftnstart'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfFNoteRestart; rtfKstr : 'ftnrestart'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfPageStart; rtfKstr : 'pgnstart'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfLineStart; rtfKstr : 'linestart'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfLandscape; rtfKstr : 'landscape'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfFracWidth; rtfKstr : 'fracwidth'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfNextFile; rtfKstr : 'nextfile'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfTemplate; rtfKstr : 'template'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfMakeBackup; rtfKstr : 'makeback'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfRTFDefault; rtfKstr : 'defformat'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfRevisions; rtfKstr : 'revisions'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfMirrorMargin; rtfKstr : 'margmirror'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfRevDisplay; rtfKstr : 'revprop'; rtfkHash : 0),
+( rtfKMajor: rtfDocAttr; rtfKMinor: 	rtfRevBar; rtfKstr : 'revbar'; rtfkHash : 0),
+
+( rtfKMajor: rtfStyleAttr; rtfKMinor: 	rtfBasedOn; rtfKstr : 'sbasedon'; rtfkHash : 0),
+( rtfKMajor: rtfStyleAttr; rtfKMinor: 	rtfNext; rtfKstr : 'snext'; rtfkHash : 0),
+
+( rtfKMajor: rtfPictAttr; rtfKstr : 'macpict'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfWinMetafile; rtfKstr : 'wmetafile'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfWinBitmap; rtfKstr : 'wbitmap'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicWid; rtfKstr : 'picw'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicHt; rtfKstr : 'pich'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicGoalWid; rtfKstr : 'picwgoal'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicGoalWid; rtfKstr : 'picwGoal'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicGoalHt; rtfKstr : 'pichgoal'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicGoalHt; rtfKstr : 'pichGoal'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicScaleX; rtfKstr : 'picscalex'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicScaleY; rtfKstr : 'picscaley'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicScaled; rtfKstr : 'picscaled'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicCropTop; rtfKstr : 'piccropt'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicCropBottom; rtfKstr : 'piccropb'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicCropLeft; rtfKstr : 'piccropl'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPicCropRight; rtfKstr : 'piccropr'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfPixelBits; rtfKstr : 'wbmbitspixel'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfBitmapPlanes; rtfKstr : 'wbmplanes'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor: 	rtfBitmapWid; rtfKstr : 'wbmwidthbytes'; rtfkHash : 0),
+( rtfKMajor: rtfPictAttr; rtfKMinor:	rtfPicBinary; rtfKstr : 'bin'; rtfkHash : 0),
+
+( rtfKMajor: rtfNeXTGrAttr; rtfKMinor:	rtfNeXTGWidth; rtfKstr : 'width'; rtfkHash : 0),
+( rtfKMajor: rtfNeXTGrAttr; rtfKMinor:	rtfNeXTGHeight; rtfKstr : 'height'; rtfkHash : 0),
+
+( rtfKMajor: rtfDestination; rtfKMinor:         rtfPict; rtfKstr : 'pict'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor:         rtfNeXTGraphic; rtfKstr : 'NeXTGraphic'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFootnote; rtfKstr : 'footnote'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfHeader; rtfKstr : 'header'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfHeaderLeft; rtfKstr : 'headerl'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfHeaderRight; rtfKstr : 'headerr'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfHeaderFirst; rtfKstr : 'headerf'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFooter; rtfKstr : 'footer'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFooterLeft; rtfKstr : 'footerl'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFooterRight; rtfKstr : 'footerr'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFooterFirst; rtfKstr : 'footerf'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFNSep; rtfKstr : 'ftnsep'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFNContSep; rtfKstr : 'ftnsepc'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFNContNotice; rtfKstr : 'ftncn'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfInfo; rtfKstr : 'info'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfStyleSheet; rtfKstr : 'stylesheet'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFontTbl; rtfKstr : 'fonttbl'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfColorTbl; rtfKstr : 'colortbl'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfAnnotation; rtfKstr : 'annotation'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfAnnotID; rtfKstr : 'atnid'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfField; rtfKstr : 'field'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFieldInst; rtfKstr : 'fldinst'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfFieldResult; rtfKstr : 'fldrslt'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIndex; rtfKstr : 'xe'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIndexBold; rtfKstr : 'bxe'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIndexItalic; rtfKstr : 'ixe'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIndexText; rtfKstr : 'txe'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIndexRange; rtfKstr : 'rxe'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfTOC; rtfKstr : 'tc'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfBookmarkStart; rtfKstr : 'bkmkstart'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfBookmarkEnd; rtfKstr : 'bkmkend'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfITitle; rtfKstr : 'title'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfISubject; rtfKstr : 'subject'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIAuthor; rtfKstr : 'author'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIOperator; rtfKstr : 'operator'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIKeywords; rtfKstr : 'keywords'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIComment; rtfKstr : 'comment'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIVersion; rtfKstr : 'version'; rtfkHash : 0),
+( rtfKMajor: rtfDestination; rtfKMinor: 	rtfIDoccomm; rtfKstr : 'doccomm'; rtfkHash : 0),
+
+( rtfKMajor: rtfTOCAttr; rtfKMinor: 	rtfTOCType; rtfKstr : 'tcf'; rtfkHash : 0),
+( rtfKMajor: rtfTOCAttr; rtfKMinor: 	rtfTOCLevel; rtfKstr : 'tcl'; rtfkHash : 0),
+
+( rtfKMajor: rtfFontFamily; rtfKMinor: 	rtfFFNil; rtfKstr : 'fnil'; rtfkHash : 0),
+( rtfKMajor: rtfFontFamily; rtfKMinor: 	rtfFFRoman; rtfKstr : 'froman'; rtfkHash : 0),
+( rtfKMajor: rtfFontFamily; rtfKMinor: 	rtfFFSwiss; rtfKstr : 'fswiss'; rtfkHash : 0),
+( rtfKMajor: rtfFontFamily; rtfKMinor: 	rtfFFModern; rtfKstr : 'fmodern'; rtfkHash : 0),
+( rtfKMajor: rtfFontFamily; rtfKMinor: 	rtfFFScript; rtfKstr : 'fscript'; rtfkHash : 0),
+( rtfKMajor: rtfFontFamily; rtfKMinor: 	rtfFFDecor; rtfKstr : 'fdecor'; rtfkHash : 0),
+( rtfKMajor: rtfFontFamily; rtfKMinor: 	rtfFFTech; rtfKstr : 'ftech'; rtfkHash : 0),
+
+( rtfKMajor: rtfColorName; rtfKMinor: 	rtfRed; rtfKstr : 'red'; rtfkHash : 0),
+( rtfKMajor: rtfColorName; rtfKMinor: 	rtfGreen; rtfKstr : 'green'; rtfkHash : 0),
+( rtfKMajor: rtfColorName; rtfKMinor: 	rtfBlue; rtfKstr : 'blue'; rtfkHash : 0),
+
+( rtfKMajor: rtfCharSet; rtfKMinor: 	rtfMacCharSet; rtfKstr : 'mac'; rtfkHash : 0),
+( rtfKMajor: rtfCharSet; rtfKMinor: 	rtfAnsiCharSet; rtfKstr : 'ansi'; rtfkHash : 0),
+( rtfKMajor: rtfCharSet; rtfKMinor: 	rtfPcCharSet; rtfKstr : 'pc'; rtfkHash : 0),
+( rtfKMajor: rtfCharSet; rtfKMinor: 	rtfPcaCharSet; rtfKstr : 'pca'; rtfkHash : 0),
+
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfCellBordBottom; rtfKstr : 'clbrdrb'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfCellBordTop; rtfKstr : 'clbrdrt'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfCellBordLeft; rtfKstr : 'clbrdrl'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfCellBordRight; rtfKstr : 'clbrdrr'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfRowDef; rtfKstr : 'trowd'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfRowLeft; rtfKstr : 'trql'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfRowRight; rtfKstr : 'trqr'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfRowCenter; rtfKstr : 'trqc'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfRowGapH; rtfKstr : 'trgaph'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfRowHt; rtfKstr : 'trrh'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfRowLeftEdge; rtfKstr : 'trleft'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfCellPos; rtfKstr : 'cellx'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfMergeRngFirst; rtfKstr : 'clmgf'; rtfkHash : 0),
+( rtfKMajor: rtfTblAttr; rtfKMinor: 	rtfMergePrevious; rtfKstr : 'clmrg'; rtfkHash : 0),
+
+( rtfKMajor: rtfFieldAttr; rtfKMinor: 	rtfFieldDirty; rtfKstr : 'flddirty'; rtfkHash : 0),
+( rtfKMajor: rtfFieldAttr; rtfKMinor: 	rtfFieldEdited; rtfKstr : 'fldedit'; rtfkHash : 0),
+( rtfKMajor: rtfFieldAttr; rtfKMinor: 	rtfFieldLocked; rtfKstr : 'fldlock'; rtfkHash : 0),
+( rtfKMajor: rtfFieldAttr; rtfKMinor: 	rtfFieldPrivate; rtfKstr : 'fldpriv'; rtfkHash : 0),
+
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosX; rtfKstr : 'posx'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosXCenter; rtfKstr : 'posxc'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosXInside; rtfKstr : 'posxi'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosXLeft; rtfKstr : 'posxl'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosXOutSide; rtfKstr : 'posxo'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosXRight; rtfKstr : 'posxr'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosY; rtfKstr : 'posy'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosYInline; rtfKstr : 'posyil'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosYTop; rtfKstr : 'posyt'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosYCenter; rtfKstr : 'posyc'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfPosYBottom; rtfKstr : 'posyb'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfAbsWid; rtfKstr : 'absw'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfTextDist; rtfKstr : 'dxfrtext'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfRPosMargV; rtfKstr : 'pvmrg'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfRPosPageV; rtfKstr : 'pvpg'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfRPosMargH; rtfKstr : 'phmrg'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfRPosPageH; rtfKstr : 'phpg'; rtfkHash : 0),
+( rtfKMajor: rtfPosAttr; rtfKMinor: 	rtfRPosColH; rtfKstr : 'phcol'; rtfkHash : 0),
+
+( rtfKMajor: rtfVersion; rtfKMinor: 	-1; rtfKstr : 'rtf'; rtfkHash : 0),
+( rtfKMajor: rtfDefFont; rtfKMinor: 	-1; rtfKstr : 'deff'; rtfkHash : 0),
+
+( rtfKMajor: 0; rtfKMinor: 		-1; rtfKstr : ''; rtfkHash : 0)
+);

+ 1072 - 0
fcl/inc/rtfpars.pp

@@ -0,0 +1,1072 @@
+Unit RTFPars;
+{
+    $Id$
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 1998 by Michael Van Canneyt, Member of the 
+    Free Pascal development team
+
+    This unit implements a RTF Parser.
+    
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+interface
+
+Uses classes,sysutils;
+
+{$i rtfdata.inc}
+
+type Trtferrorhandler = Procedure (s : string) of object;
+
+TRTFParser = class(TObject)
+  private
+    FOnRTFError : TRTFerrorHandler;
+    FfontList : PRTFFont;
+    FcolorList : PRTFColor;
+    FstyleList : PRTFStyle;
+    FrtfClass,
+    FrtfMajor,
+    FrtfMinor,
+    FrtfParam : Integer;
+    rtfTextBuf : string [rtfBufSiz];
+    rtfTextLen : Integer;
+    pushedChar : Integer;	        { pushback char if read too far }
+    pushedClass : Integer;	{ pushed token info for RTFUngetToken() }
+    pushedMajor,
+    pushedMinor,
+    pushedParam : Integer;
+    pushedTextBuf : String[rtfBufSiz];
+    FStream : TStream;
+    ccb : array [0..rtfMaxClass] of TRTFFuncPtr;		{ class callbacks }
+    dcb : array [0..rtfMaxDestination] of TRTFFuncPtr;	{ destination callbacks }
+    readHook : TRTFFUNCPTR;
+    Procedure Error (msg : String);
+    Procedure LookupInit ;
+    Procedure ReadFontTbl ;
+    Procedure ReadColorTbl;
+    Procedure ReadStyleSheet ;
+    Procedure ReadInfoGroup ;
+    Procedure ReadPictGroup ;
+    Function  CheckCM (Aclass, major: Integer) : Boolean;
+    Function  CheckCMM (Aclass, major, minor : Integer) : Boolean;
+    Function  CheckMM (major, minor : Integer) : Boolean;
+    Procedure Real_RTFGetToken;
+    Function  GetChar : Integer;
+    Procedure Lookup (S : String);
+    Function  GetFont (num : Integer) : PRTFFont;
+    Function  GetColor (num : Integer) : PRTFColor;
+    Function  GetStyle (num : Integer) : PRTFStyle;
+    Procedure setClassCallback (Aclass : Integer; Acallback : TRTFFuncPtr);
+    Function  GetClassCallback (Aclass : Integer) : TRTFFuncPtr;
+    Procedure SetDestinationCallback (ADestination : Integer; Acallback : TRTFFuncPtr);
+    Function  GetDestinationCallback (Adestination : Integer) : TRTFFuncPtr ;
+    Procedure SetStream (Astream : TStream);
+  public
+    Constructor Create (AStream : TStream);
+    Destructor  Destroy; override;
+    Procedure GetReadHook (Var q : TRTFFuncPtr);
+    Function  GetToken : Integer;
+    Function  PeekToken : Integer;
+    Procedure ResetParser;
+    Procedure RouteToken;
+    Procedure SkipGroup;
+    Procedure StartReading;
+    Procedure SetReadHook (Hook : TRTFFuncPtr);
+    Procedure UngetToken;
+    Procedure SetToken (Aclass, major, minor, param : Integer; text : string);
+    Procedure ExpandStyle (n : Integer);
+    { Properties }
+    Property Colors [Index : Integer]: PRTFColor Read GetColor;
+    Property ClassCallBacks [AClass : Integer]: TRTFFuncptr
+       Read GetClassCallBack
+       Write SetClassCallback;
+    Property DestinationCallBacks [Adestination : Integer]: TRTFFuncptr
+       Read GetdestinationCallBack
+       Write SetdestinationCallback;
+    Property Fonts [Index : Integer]: PRTFFont Read GetFont;
+    Property OnRTFError : TRTFerrorHandler Read FOnRTFError Write FOnRTFError;
+    Property rtfClass : Integer Read FrtfClass;
+    Property rtfMajor : Integer Read FrtfMajor;
+    Property rtfMinor : Integer Read FrtfMinor;
+    Property rtfParam : Integer Read FrtfParam;
+    Property Stream : TStream Read FStream Write SetStream;
+    Property Styles [index : Integer] : PRTFStyle Read GetStyle;
+  end;
+
+Implementation
+
+Const EOF = -255;
+
+{ ---------------------------------------------------------------------
+         Utility functions
+  ---------------------------------------------------------------------}
+
+Function Hash (s : String) : Integer;
+
+var
+  val,i : integer;
+
+Begin
+val:=0;
+for i:=1 to length(s) do
+  val:=val+ord(s[i]);
+Hash:=val;
+End;
+
+Function isalpha (s : integer) : Boolean;
+
+begin
+  result:= ( (s>=ord('A')) and (s<=ord('Z')))
+             or (((s>=ord('a')) and ((s<=ord('z')) ))
+            );
+end;
+
+Function isdigit (s : integer) : Boolean;
+
+begin
+  result:= ( (s>=ord('0')) and (s<=ord('9')) )
+end;
+
+Function HexVal (c : Integer) : Integer;
+
+Begin
+  if (c>=ord('A')) and (C<=ord('Z')) then inc (c,32);
+  if c<ord ('A') then
+    result:=(c - ord('0'))	{ '0'..'9' }
+  else
+    result:= (c - ord('a') + 10);		{ 'a'..'f' }
+End;
+
+{ ---------------------------------------------------------------------
+       Initialize the reader.  This may be called multiple times,
+       to read multiple files.  The only thing not reset is the input
+       stream; that must be done with RTFSetStream().
+  ---------------------------------------------------------------------}
+  
+Constructor TRTFParser.Create (Astream : TStream);
+
+Begin
+inherited create;
+{ initialize lookup table }
+LookupInit ;
+Fstream := Astream;
+FfontList  :=nil;
+FcolorList :=nil;
+FstyleList :=nil;
+onrtferror:=nil;
+ResetParser;
+end;
+
+Procedure TRTFParser.ResetParser;
+
+var
+  cp : PRTFColor;
+  fp : PRTFFont;
+  sp : PRTFStyle;
+  ep,eltlist : PRTFStyleElt;
+  i : integer;
+
+begin
+
+for i:=0 to rtfMaxClass-1 do
+  setClassCallback (i, Nil);
+for i:=0 to rtfMaxDestination-1 do
+  SetDestinationCallback (i,nil);
+
+{ install built-in destination readers }
+SetDestinationCallback (rtfFontTbl, @ReadFontTbl);
+SetDestinationCallback (rtfColorTbl, @ReadColorTbl);
+SetDestinationCallback (rtfStyleSheet, @ReadStyleSheet);
+SetDestinationCallback (rtfInfo, @ReadInfoGroup);
+SetDestinationCallback (rtfPict, @ReadPictGroup);
+
+SetReadHook (Nil);
+
+{ dump old lists if necessary }
+
+while FfontList<>nil do
+  Begin
+  fp := FfontList^.rtfNextFont;
+  dispose (FfontList);
+  FfontList := fp;
+  End;
+while FcolorList<>nil do
+  Begin
+  cp := FcolorList^.rtfNextColor;
+  dispose (FcolorList);
+  FcolorList := cp;
+  End;
+while FstyleList<>nil do
+  Begin
+  sp := FstyleList^.rtfNextStyle;
+  eltList := FstyleList^.rtfSSEList;
+  while eltList<>nil do
+    Begin
+    ep:=eltList^.rtfNextSE;
+    dispose(eltList);
+    eltList:= ep;
+    End;
+  Dispose (FstyleList);
+  FstyleList := sp;
+  End;
+FrtfClass := -1;
+pushedClass := -1;
+pushedChar := EOF;
+{ Reset the stream if it is assigned }
+if assigned (FStream) then
+  FStream.seek(0,soFromBeginning);
+End;
+
+
+Destructor TRTFParser.Destroy;
+
+var
+  cp : PRTFColor;
+  fp : PRTFFont;
+  sp : PRTFStyle;
+  ep,eltlist : PRTFStyleElt;
+
+begin
+  { Dump the lists. }
+  while FfontList<>nil do
+    Begin
+    fp := FfontList^.rtfNextFont;
+    dispose (FfontList);
+    FfontList := fp;
+    End;
+  while FcolorList<>nil do
+    Begin
+  cp := FcolorList^.rtfNextColor;
+  dispose (FcolorList);
+    FcolorList := cp;
+    End;
+  while FstyleList<>nil do
+    Begin
+    sp := FstyleList^.rtfNextStyle;
+    eltList := FstyleList^.rtfSSEList;
+    while eltList<>nil do
+      Begin
+      ep:=eltList^.rtfNextSE;
+      dispose(eltList);
+      eltList:= ep;
+      End;
+    Dispose (FstyleList);
+    FstyleList := sp;
+    End;
+  { Dump rest }
+  inherited destroy;
+end;
+
+
+{ ---------------------------------------------------------------------
+       Callback table manipulation routines
+  ---------------------------------------------------------------------}
+
+Procedure TRTFParser.SetClassCallback (Aclass : Integer; Acallback : TRTFFuncPtr);
+
+Begin
+  if (aclass>=0) and (Aclass<rtfMaxClass) then
+    ccb[Aclass]:= Acallback;
+End;
+
+
+Function TRTFParser.GetClassCallback (Aclass : Integer) : TRTFFuncPtr;
+
+Begin
+  if (Aclass>=0) and (Aclass<rtfMaxClass) then
+    GetClassCallback :=ccb[Aclass]
+  else
+    GetClassCallback:=nil;
+End;
+
+{ ---------------------------------------------------------------------
+   Install or return a writer callback for a destination type
+  ---------------------------------------------------------------------}
+  
+Procedure TRTFParser.SetDestinationCallback (ADestination : Integer; Acallback : TRTFFuncPtr);
+
+Begin
+  if (Adestination>=0) and (Adestination<rtfMaxDestination) then
+    dcb[ADestination] := Acallback;
+End;
+
+
+Function TRTFParser.GetDestinationCallback (Adestination : Integer) : TRTFFuncPtr ;
+
+Begin
+  if (Adestination>=0) and (ADestination<rtfMaxDestination) then
+    Result:=dcb[Adestination]
+  Else
+    Result:=nil;
+End;
+
+
+{ ---------------------------------------------------------------------
+       Token reading routines
+  ---------------------------------------------------------------------}
+
+{ Read the input stream, invoking the writer's callbacks where appropriate. }
+Procedure TRTFParser.StartReading;
+
+Begin
+  { Reset stream. }
+  FStream.Seek (0,soFromBeginning);
+  { Start reading. }
+  while (GetToken<>rtfEOF) do
+    RouteToken;
+End;
+
+
+{ Route a token.  If it's a destination for which a reader is
+  installed, process the destination internally, otherwise
+  pass the token to the writer's class callback. }
+Procedure TRTFParser.RouteToken;
+
+Var
+  p : TRTFFuncPtr;
+
+Begin
+  if (rtfClass < 0) or (rtfClass>=rtfMaxClass) then
+    Error ('No such class : '+rtfTextBuf)
+  else
+    begin
+    if (CheckCM (rtfControl, rtfDestination)) then
+      Begin
+      { invoke destination-specific callback if there is one }
+      p:=GetDestinationCallback (rtfMinor);
+      if assigned(p) then
+        Begin
+        p;
+        exit
+        End;
+      End;
+    { invoke class callback if there is one }
+    p:= GetClassCallback (rtfClass);
+    if assigned(p) then
+      p;
+    end;
+End;
+
+
+{ Skip to the end of the current group.  When this returns,
+  writers that maintain a state stack may want to call their
+  state unstacker; global vars will still be set to the group's
+  closing brace. }
+Procedure TRTFParser.SkipGroup;
+
+Var
+  level : Integer;
+Begin
+  level:= 1;
+  while (GetToken<>rtfEOF) do
+    if (rtfClass=rtfGroup) then
+       Begin
+       if (rtfMajor=rtfBeginGroup) then
+         inc(level)
+       else if (rtfMajor=rtfEndGroup) then
+          Begin
+          dec(level);
+          if (level < 1) then
+            exit;	{ end of initial group }
+          End;
+       End;
+End;
+
+{ Read one token.  Call the read hook if there is one.  The
+  token class is the return value.  Returns rtfEOF when there
+  are no more tokens. }
+Function TRTFParser.GetToken : Integer;
+
+var p : TRTFFuncPTR;
+
+Begin
+GetReadHook (p);
+while true do
+  Begin
+  Real_RTFGetToken;
+  if (assigned(p)) then
+    p;	{ give read hook a look at token }
+  { Silently discard newlines and carriage returns.  }
+  if not ((rtfClass=rtfText) and ((rtfMajor=13) or (rtfmajor=10))) then
+    break;
+  End;
+result:=rtfClass;
+End;
+
+
+{ ---------------------------------------------------------------------
+   Install or return a token reader hook.
+  ---------------------------------------------------------------------}
+
+Procedure TRTFParser.SetReadHook (Hook : TRTFFuncPtr);
+
+Begin
+ readHook := Hook;
+End;
+
+Procedure TRTFParser.GetReadHook (Var q : TRTFFuncPtr);
+
+Begin
+  Q:=readHook;
+End;
+
+
+Procedure TRTFParser.UngetToken;
+
+Begin
+if (pushedClass >= 0) then	{ there's already an ungotten token }
+        Error ('cannot unget two tokens');
+if (rtfClass < 0) then
+        Error ('no token to unget');
+pushedClass := rtfClass;
+pushedMajor := rtfMajor;
+pushedMinor := rtfMinor;
+pushedParam := rtfParam;
+rtfTextBuf  := pushedTextBuf;
+End;
+
+
+Function TRTFParser.PeekToken : Integer;
+
+Begin
+  Real_RTFGetToken;
+  UngetToken;
+  Result:=rtfClass;
+End;
+
+
+
+Procedure TRTFParser.Real_RTFGetToken;
+
+var sign,c,c2 : Integer;
+
+Begin
+{ check for pushed token from RTFUngetToken() }
+if (pushedClass >= 0) then
+  Begin
+  FrtfClass    := pushedClass;
+  FrtfMajor    := pushedMajor;
+  FrtfMinor    := pushedMinor;
+  FrtfParam    := pushedParam;
+  rtfTextBuf  := pushedTextBuf;
+  rtfTextLen  := length (rtfTextBuf);
+  pushedClass := -1;
+  exit;
+  End;
+{ initialize token vars }
+FrtfClass   := rtfUnknown;
+FrtfParam   := rtfNoParam;
+rtfTextBuf := '';
+rtfTextLen := 0;
+
+{ get first character, which may be a pushback from previous token }
+
+if (pushedChar <> EOF) then
+  Begin
+  c := pushedChar;
+  rtfTextBuf:=rtfTextBuf+chr(c);
+  inc(rtftextlen);
+  pushedChar := EOF;
+  End
+else
+ begin
+ c:=GetChar;
+ if C=EOF then
+   Begin
+   FrtfClass := rtfEOF;
+   exit;
+   End;
+ end;
+if c=ord('{') then
+  Begin
+  FrtfClass := rtfGroup;
+  FrtfMajor := rtfBeginGroup;
+  exit;
+  End;
+if c=ord('}') then
+  Begin
+  FrtfClass := RTFGROUP;
+  FrtfMajor := rtfEndGroup;
+  exit;
+  End;
+if c<>ord('\') then
+  Begin
+  { Two possibilities here:
+    1) ASCII 9, effectively like \tab control symbol
+    2) literal text char }
+  if c=ord(#8) then			{ ASCII 9 }
+    Begin
+    FrtfClass := rtfControl;
+    FrtfMajor := rtfSpecialChar;
+    FrtfMinor := rtfTab;
+    End
+  else
+    Begin
+    FrtfClass := rtfText;
+    FrtfMajor := c;
+    End;
+  exit;
+End;
+c:=getchar;
+if (c=EOF) then
+  { early eof, whoops (class is rtfUnknown) }
+  exit;
+if ( not isalpha (c)) then
+  Begin
+  { Three possibilities here:
+   1) hex encoded text char, e.g., \'d5, \'d3
+   2) special escaped text char, e.g., \, \;
+   3) control symbol, e.g., \_, \-, \|, \<10> }
+  if c=ord('''') then { hex char }
+     Begin
+     c:=getchar;
+     if (c<>EOF) then
+       begin
+       c2:=getchar;
+       if (c2<>EOF) then
+         Begin
+         { should do isxdigit check! }
+         FrtfClass := rtfText;
+         FrtfMajor := HexVal (c) * 16 + HexVal (c2);
+         exit;
+         End;
+       end;
+       { early eof, whoops (class is rtfUnknown) }
+       exit;
+       End;
+  if pos (chr(c),':{};\')<>0 then { escaped char }
+    Begin
+    FrtfClass := rtfText;
+    FrtfMajor := c;
+    exit;
+    End;
+   { control symbol }
+   Lookup (rtfTextBuf);	{ sets class, major, minor }
+   exit;
+  End;
+{ control word }
+while (isalpha (c)) do
+  Begin
+  c:=GetChar;
+  if (c=EOF) then
+    break;
+  End;
+{ At this point, the control word is all collected, so the
+  major/minor numbers are determined before the parameter
+  (if any) is scanned.  There will be one too many characters
+  in the buffer, though, so fix up before and restore after
+  looking up. }
+if (c<>EOF) then
+  delete(rtfTextBuf,length(rtfTextbuf),1);
+Lookup (rtfTextBuf);	{ sets class, major, minor }
+if (c <>EOF) then
+  rtfTextBuf:=rtfTextBuf+chr(c);
+{ Should be looking at first digit of parameter if there
+  is one, unless it's negative.  In that case, next char
+  is '-', so need to gobble next char, and remember sign. }
+sign := 1;
+if c = ord('-') then
+  Begin
+  sign := -1;
+  c := GetChar;
+  End;
+if (c<>EOF) then
+  if isdigit (c) then
+  Begin
+  FrtfParam := 0;
+  while (isdigit (c)) do	{ gobble parameter }
+    Begin
+    FrtfParam := FrtfParam * 10 + c - ord('0');
+    c:=GetChar;
+    if (c=EOF) then
+      break;
+    End;
+  FrtfParam:= sign*FrtfParam;
+  End;
+{ If control symbol delimiter was a blank, gobble it.
+ Otherwise the character is first char of next token, so
+ push it back for next call.  In either case, delete the
+ delimiter from the token buffer. }
+if (c<>EOF) then
+  Begin
+  if c<>ord (' ') then
+     pushedChar := c;
+  Delete (rtfTextBuf,rtfTextLen,1);
+  Dec (rtfTextLen);
+  End;
+End;
+
+Function TRTFParser.GetChar : Integer;
+
+var c : byte;
+
+Begin
+  if FStream.read(c,1)<>0 then
+    begin
+    if (c and 128)=128 then c:=ord('?');
+    Result:=c;
+    rtfTextBuf:=rtfTextBuf+chr(c);
+    inc(rtfTextLen);
+    end
+  else
+    Result:=EOF;
+End;
+
+{ Synthesize a token by setting the global variables to the
+  values supplied.  Typically this is followed with a call
+  to RTFRouteToken().
+  If param is non-negative, it becomes part of the token text. }
+Procedure TRTFParser.SetToken (Aclass, major, minor, param : Integer; text : string);
+
+Begin
+  FrtfClass := Aclass;
+  FrtfMajor := major;
+  FrtfMinor := minor;
+  FrtfParam := param;
+  if (param=rtfNoParam) then
+     rtfTextBuf:=text
+  else
+     rtfTextBuf:=text+IntTostr(param);
+  rtfTextLen:=length(rtfTextBuf);
+End;
+
+{ ---------------------------------------------------------------------
+       Special destination readers.  They gobble the destination so the
+       writer doesn't have to deal with them.  That's wrong for any
+       translator that wants to process any of these itself.  In that
+       case, these readers should be overridden by installing a different
+       destination callback.
+
+       NOTE: The last token read by each of these reader will be the
+       destination's terminating '', which will then be the current token.
+       That 'End;' token is passed to RTFRouteToken() - the writer has already
+       seen the 'Begin' that began the destination group, and may have pushed a
+       state; it also needs to know at the end of the group that a state
+       should be popped.
+
+       It's important that rtfdata.inc and the control token lookup table list
+       as many symbols as possible, because these readers unfortunately
+       make strict assumptions about the input they expect, and a token
+       of class rtfUnknown will throw them off easily.
+ ----------------------------------------------------------------------}
+
+
+{ Read Begin \fonttbl ... End; destination.  Old font tables don't have
+  braces around each table entry; try to adjust for that.}
+Procedure TRTFParser.ReadFontTbl;
+
+var
+  fp : PRTFFont;
+  bp : string[rtfbufsiz];
+  old : Integer;
+
+Begin
+old := -1;
+While true do
+  Begin
+  GetToken;
+  if CheckCM (rtfGroup, rtfEndGroup) then
+      break;
+  if (old < 0) then		{ first entry - determine tbl type }
+    Begin
+    if CheckCMM (rtfControl, rtfCharAttr, rtfFontNum) then
+      old:=1	{ no brace }
+    else if CheckCM (rtfGroup, rtfBeginGroup) then
+      old:= 0	{ brace }
+    else			{ can't tell! }
+      Error ('FTErr - Cannot determine format')
+    End;
+  if (old=0) then	{ need to find "Begin" here }
+    Begin
+    if not CheckCM (rtfGroup, rtfBeginGroup) then
+      Error ('FTErr - missing {');
+    GetToken;	{ yes, skip to next token }
+    End;
+  new(fp);
+  if (fp=nil) then
+     Error ('FTErr - cannot allocate font entry');
+  fp^.rtfNextFont:= FfontList;
+  FfontList:=fp;
+  if not CheckCMM (rtfControl, rtfCharAttr, rtfFontNum) then
+     Error ('FTErr - missing font number');
+  fp^.rtfFNum := rtfParam;
+  { Read optionalcommands. Recognize only fontfamily}
+  GetToken;
+  if not CheckCM (rtfControl, rtfFontFamily) then
+    error ('FTErr - missing font family ');
+  fp^.rtfFFamily := rtfMinor;
+  { Read optional commands/groups. Recognize none at this point..}
+  GetToken;
+  while (rtfclass=rtfcontrol) or ((rtfclass=rtfgroup) or (rtfclass=rtfunknown)) do
+    begin
+    if rtfclass=rtfgroup then SkipGroup;
+    GetToken
+    end;
+  { Read font name }
+  bp:='';
+  while (rtfclass=rtfText) do
+    Begin
+    if rtfMajor=ord(';') then
+       break;
+    bp:=bp+chr(rtfMajor);
+    GetToken
+    End;
+  if bp='' then
+     Error ('FTErr - missing font name');
+  fp^.rtffname:=bp;
+  { Read alternate font}
+  if (old=0) then	{ need to see "End;" here }
+    Begin
+    GetToken;
+    if not CheckCM (rtfGroup, rtfEndGroup) then
+       Error ('FTErr - missing }');
+    End;
+  End;
+RouteToken;	{ feed "End;" back to router }
+End;
+
+
+{ The color table entries have color values of -1 if
+  the default color should be used for the entry (only
+  a semi-colon is given in the definition, no color values).
+  There will be a problem if a partial entry (1 or 2 but
+  not 3 color values) is given.  The possibility is ignored
+  here. }
+Procedure TRTFParser.ReadColorTbl;
+
+var
+  cp   : PRTFColor;
+  cnum : Integer;
+
+Begin
+cnum:=0;
+While true do
+  Begin
+  GetToken;
+  if CheckCM (rtfGroup, rtfEndGroup) then
+    break;
+  new(cp);
+  if (cp=nil) then
+    Error ('CTErr - cannot allocate color entry');
+  cp^.rtfCNum  :=cnum;
+  cp^.rtfCRed  :=-1;
+  cp^.rtfCGreen:=-1;
+  cp^.rtfCBlue :=-1;
+  cp^.rtfNextColor := FColorList;
+  inc(cnum);
+  FcolorList:=cp;
+  while true do
+    Begin
+    if not CheckCM (rtfControl, rtfColorName) then
+       break;
+    case rtfMinor of
+      rtfRed:	cp^.rtfCRed   :=rtfParam;
+      rtfGreen:	cp^.rtfCGreen :=rtfParam;
+      rtfBlue:	cp^.rtfCBlue  :=rtfParam;
+    End;
+    GetToken;
+    End;
+  if not CheckCM (rtfText, ord(';')) then
+     Error ('CTErr - malformed entry');
+  End;
+RouteToken;	{ feed "End;" back to router }
+End;
+
+
+{ The "Normal" style definition doesn't contain any style number
+ (why?), all others do.  Normal style is given style 0. }
+
+Procedure TRTFParser.ReadStyleSheet;
+
+var
+  sp          : PRTFStyle;
+  sep,sepLast : PRTFStyleElt;
+  bp          : string[rtfBufSiz];
+
+Begin
+While true do
+  Begin
+  GetToken;
+  if CheckCM (rtfGroup, rtfEndGroup) then
+      break;
+  new (sp);
+  if sp=nil then
+     Error ('SSErr - cannot allocate stylesheet entry');
+  sp^.rtfSNum := -1;
+  sp^.rtfSBasedOn := rtfBasedOnNone;
+  sp^.rtfSNextPar := -1;
+  sp^.rtfSSEList := nil;
+  sepLast:=nil;
+  sp^.rtfNextStyle := FstyleList;
+  sp^.rtfExpanding := 0;
+  FstyleList := sp;
+  if not CheckCM (rtfGroup, rtfBeginGroup) then
+     Error ('SSErr - missing {');
+  while GetToken=rtfControl do
+    Begin
+    if (CheckMM (rtfParAttr, rtfStyleNum)) then
+      Begin
+      sp^.rtfSNum:=rtfParam;
+      break;
+      End;
+    if (CheckMM (rtfStyleAttr, rtfBasedOn)) then
+      Begin
+      sp^.rtfSBasedOn:=rtfParam;
+      break;
+      End;
+    if (CheckMM (rtfStyleAttr, rtfNext)) then
+      Begin
+      sp^.rtfSNextPar:=rtfParam;
+      break;
+      End;
+    new(sep);
+    if sep=nil then
+      Error ('SSErr - cannot allocate style element');
+    sep^.rtfSEClass:=rtfClass;
+    sep^.rtfSEMajor:=rtfMajor;
+    sep^.rtfSEMinor:=rtfMinor;
+    sep^.rtfSEParam:=rtfParam;
+    sep^.rtfSEText:=rtfTextBuf;
+    if sepLast=nil then
+       sp^.rtfSSEList:=sep	{ first element }
+    else				{ add to end }
+       sepLast^.rtfNextSE:=sep;
+    sep^.rtfNextSE:=nil;
+    sepLast:=sep;
+    End;
+  if sp^.rtfSNextPar=-1 then		{ \snext not given }
+    sp^.rtfSNextPar:=sp^.rtfSNum;	{ next is itself }
+  if rtfClass<>rtfText then
+     Error ('SSErr - missing style name');
+  while rtfClass=rtfText do
+    Begin
+    if rtfMajor=ord(';') then
+      Begin
+      GetToken;
+      break;
+      End;
+    bp:=bp+chr(rtfMajor);
+    GetToken;
+    End;
+  if (sp^.rtfSNum < 0) then	{ no style number was specified }
+    Begin			{ (only legal for Normal style) }
+    if bp<>'Normal' then
+       Error ('SSErr - missing style number');
+    sp^.rtfSNum:=0;
+    End;
+  sp^.rtfSName:=bp;
+  if not CheckCM (rtfGroup, rtfEndGroup) then
+      Error ('SSErr - missing }');
+  End;
+RouteToken;	{ feed "End;" back to router }
+End;
+
+
+Procedure TRTFParser.ReadInfoGroup;
+
+Begin
+  SkipGroup ;
+  RouteToken ;	{ feed "End;" back to router }
+End;
+
+
+Procedure TRTFParser.ReadPictGroup;
+
+Begin
+  SkipGroup ;
+  RouteToken ;	{ feed "End;" back to router }
+End;
+
+
+{ ----------------------------------------------------------------------
+    Routines to return pieces of stylesheet, or font or color tables
+  ----------------------------------------------------------------------}
+
+
+Function TRTFParser.GetStyle (num : Integer) : PRTFStyle;
+
+var
+  s : PRTFSTyle;
+
+Begin
+s:=Fstylelist;
+if num<>1 then
+  while s<>nil do
+    Begin
+    if (s^.rtfSNum=num) then break;
+    s:=s^.rtfNextStyle;
+    End;
+result:=s;		{ NULL if not found }
+End;
+
+
+Function TRTFParser.GetFont (num : Integer) : PRTFFont;
+
+Var
+  f :PRTFFont;
+
+Begin
+f:=FfontList;
+if num<>-1 then
+  while f<>nil do
+    Begin
+    if f^.rtfFNum=num then break;
+    f:=f^.rtfNextFont;
+    End;
+result:=f;		{ NULL if not found }
+End;
+
+Function TRTFParser.GetColor (num : Integer) : PRTFColor;
+
+var
+  c : PRTFColor;
+
+Begin
+c:=Fcolorlist;
+if (num<>-1) then
+  while c<>nil do
+    Begin
+    if c^.rtfCNum=num then break;
+    c:=c^.rtfNextColor;
+    End;
+Result:=c;		{ NULL if not found }
+End;
+
+{ ---------------------------------------------------------------------
+       Expand style n, if there is such a style.
+  ---------------------------------------------------------------------}
+
+Procedure TRTFParser.ExpandStyle (n : Integer);
+
+var
+  s  : PRTFStyle;
+  se : PRTFStyleElt;
+
+Begin
+if n=-1 then exit;
+s:=GetStyle (n);
+if s=nil then exit;
+
+if (s^.rtfExpanding<>0) then
+  Error ('Style expansion loop, style '+inttostr(n));
+s^.rtfExpanding:=1;	{ set expansion flag for loop detection }
+{
+        Expand "based-on" style.  This is done by synthesizing
+        the token that the writer needs to see in order to trigger
+        another style expansion, and feeding to token back through
+        the router so the writer sees it.
+}
+SetToken (rtfControl, rtfParAttr, rtfStyleNum, s^.rtfSBasedOn, '\s');
+RouteToken;
+{
+        Now route the tokens unique to this style.  RTFSetToken()
+        isn't used because it would add the param value to the end
+        of the token text, which already has it in.
+}
+se:=s^.rtfSSEList;
+while se<>nil do
+  Begin
+  FrtfClass:=se^.rtfSEClass;
+  FrtfMajor:=se^.rtfSEMajor;
+  FrtfMinor:=se^.rtfSEMinor;
+  FrtfParam:=se^.rtfSEParam;
+  rtfTextBuf:=se^.rtfSEText;
+  rtfTextLen:=length (rtfTextBuf);
+  RouteToken;
+  se:=se^.rtfNextSE
+  End;
+s^.rtfExpanding:=0;	{ done - clear expansion flag }
+End;
+
+{ ---------------------------------------------------------------------
+       Initialize lookup table hash values.
+       Only need to do this the first time it's called.
+  ---------------------------------------------------------------------}
+
+Procedure TRTFParser.LookupInit;
+
+var count : Integer;
+
+Begin
+count:=0;
+while rtfkey[count].rtfKStr<>'' do
+  begin
+  rtfkey[count].rtfKHash:=Hash (rtfkey[count].rtfKStr);
+  inc(count)
+  End;
+End;
+
+
+{ ---------------------------------------------------------------------
+       Determine major and minor number of control token.  If it's
+       not found, the class turns into rtfUnknown.
+  ---------------------------------------------------------------------}
+
+Procedure TRTFParser.Lookup (S : String);
+
+var
+ thehash,rp : Integer;
+
+Begin
+delete(s,1,1);			{ skip over the leading \ character }
+thehash:=Hash (s);
+rp:=0;
+while rtfkey[rp].rtfKstr<>'' do
+  Begin
+  if (thehash=rtfkey[rp].rtfKHash) and (s=rtfkey[rp].rtfKStr) then
+     Begin
+     FrtfClass:=rtfControl;
+     FrtfMajor:=rtfkey[rp].rtfKMajor;
+     FrtfMinor:=rtfkey[rp].rtfKMinor;
+     exit;
+     End;
+  inc(rp);
+  End;
+FrtfClass:=rtfUnknown;
+End;
+
+
+Procedure TRTFParser.Error (msg : String);
+
+{ Call errorhandler }
+
+begin
+  if assigned(onrtferror) then onrtferror(msg);
+end;
+
+{ ---------------------------------------------------------------------
+       Token comparison routines
+  ---------------------------------------------------------------------}
+
+Function TRTFParser.CheckCM (Aclass, major: Integer) : Boolean;
+Begin
+  Result:=(rtfClass=Aclass) and (rtfMajor=major);
+End;
+
+
+Function TRTFParser.CheckCMM (Aclass, major, minor : Integer) : Boolean;
+
+Begin
+  Result:=(rtfClass=Aclass) and ((rtfMajor=major) and (rtfMinor=minor));
+End;
+
+
+Function TRTFParser.CheckMM (major, minor : Integer) : Boolean;
+
+Begin
+  Result:=(rtfMajor=major) and (rtfMinor=minor);
+End;
+
+Procedure TRTFParser.SetStream (Astream : TStream);
+
+begin
+  FStream:=Astream;
+end;
+
+end.

BIN
fcl/tests/overview.rtf


+ 106 - 0
fcl/tests/testrtf.pp

@@ -0,0 +1,106 @@
+{
+    $Id$
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 1998 by Michael Van Canneyt, member of the
+    Free Pascal development team
+
+    This program demonstrates the RTF parser object.
+    
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+Program testrtf;
+
+uses rtfpars,classes;
+
+type
+  TRTFDemo = class(TObject)
+    FFileName : string;
+    FParser : TRTFParser;
+    Procedure DoDestination;
+    procedure dospecial;
+    procedure doctrl;
+    Procedure Dowrite;
+    Procedure Start;
+    procedure handleerror ( s : string);
+  end;
+
+Var
+  RTFDemo : TRTFDemo;
+
+procedure TRTFDemo.DoDestination;
+{
+  skip all special destinations.
+}
+begin
+  FParser.skipgroup;
+end;
+
+procedure TRTFDemo.dospecial;
+{
+  Don't do anything special.
+}
+begin
+  if FParser.RTFMinor=rtfpar then
+    Writeln;
+end;
+
+
+procedure TRTFDemo.doctrl;
+
+begin
+  case Fparser.rtfmajor of
+    rtfdestination         : dodestination;
+    rtfspecialchar         : dospecial;
+    end;
+end;
+
+
+Procedure TRTFDemo.Dowrite;
+
+begin
+  { RTFmajor contains the character ASCII Code, we just dump it }
+  Write (chr(FParser.RTFMajor));
+end;
+
+procedure TRTFDemo.Start;
+
+var Thestream : TFilestream;
+
+begin
+  Thestream:=TFileStream.Create(FFileName,fmopenread);
+  FParser:=TRTFParser.Create(TheStream);
+  FParser.classcallbacks[rtfText]:=@dowrite;
+  FParser.classcallbacks[rtfcontrol]:=@doctrl;
+  FParser.onrtferror:=@handleerror;
+  FParser.StartReading;
+  Fparser.Free;
+  Thestream.free;
+end;
+
+procedure TRTFDemo.handleerror ( s : string);
+
+begin
+  Writeln (stderr,s);
+end;
+
+VAr Name : String;
+
+begin
+  RTFDemo:=TRTFDemo.Create;
+  If Paramstr(1)='' then
+    begin
+    Write ('Enter filename to process: ');
+    Readln (name);
+    end
+  else
+    Name:=Paramstr(1);
+  RTFDemo.FFileName:=Name;
+  RTFDemo.Start;
+  RTFDemo.Free;
+end.