diff --git a/components/richmemo/richmemo.pas b/components/richmemo/richmemo.pas index a937621ac..b7e85a39d 100644 --- a/components/richmemo/richmemo.pas +++ b/components/richmemo/richmemo.pas @@ -136,6 +136,10 @@ function GetFontParams(color: TColor; styles: TFontStyles): TFontParams; overloa function GetFontParams(const Name: String; color: TColor; styles: TFontStyles): TFontParams; overload; function GetFontParams(const Name: String; Size: Integer; color: TColor; styles: TFontStyles): TFontParams; overload; +var + RTFLoadStream : function (AMemo: TCustomRichMemo; Source: TStream): Boolean = nil; + RTFSaveStream : function (AMemo: TCustomRichMemo; Dest: TStream): Boolean = nil; + implementation function GetFontParams(styles: TFontStyles): TFontParams; overload; @@ -307,17 +311,25 @@ end; function TCustomRichMemo.LoadRichText(Source: TStream): Boolean; begin - if Assigned(Source) and HandleAllocated then - Result := TWSCustomRichMemoClass(WidgetSetClass).LoadRichText(Self, Source) - else + if Assigned(Source) and HandleAllocated then begin + Result := TWSCustomRichMemoClass(WidgetSetClass).LoadRichText(Self, Source); + if not Result and Assigned(RTFLoadStream) then begin + Self.Lines.BeginUpdate; + Self.Lines.Clear; + Result:=RTFLoadStream(Self, Source); + Self.Lines.EndUpdate; + end; + end else Result := false; end; function TCustomRichMemo.SaveRichText(Dest: TStream): Boolean; begin - if Assigned(Dest) and HandleAllocated then - Result := TWSCustomRichMemoClass(WidgetSetClass).SaveRichText(Self, Dest) - else + if Assigned(Dest) and HandleAllocated then begin + Result := TWSCustomRichMemoClass(WidgetSetClass).SaveRichText(Self, Dest); + if not Result and Assigned(RTFSaveStream) then + Result:=RTFSaveStream(Self, Dest); + end else Result := false; end; diff --git a/components/richmemo/richmemofactory.pas b/components/richmemo/richmemofactory.pas index 7da4e4167..4b965c1a4 100644 --- a/components/richmemo/richmemofactory.pas +++ b/components/richmemo/richmemofactory.pas @@ -18,16 +18,20 @@ function RegisterCustomRichMemo: Boolean; implementation +{$define NoRichMemo} +{$ifdef LCLWin32}{$undef NoRichMemo}{$endif} +{$ifdef LCLCarbon}{$undef NoRichMemo}{$endif} +{$ifdef LCLGtk2}{$undef NoRichMemo}{$endif} + function RegisterCustomRichMemo: Boolean; alias : 'WSRegisterCustomRichMemo'; var cls : TWSLCLComponentClass; begin Result := True; - {$ifdef LCLWin32}RegisterWSComponent(TCustomRichMemo, TWin32WSCustomRichMemo); - {$elif LCLCarbon}RegisterWSComponent(TCustomRichMemo, TCarbonWSCustomRichMemo); - {$elif LCLGtk2}RegisterWSComponent(TCustomRichMemo, TGtk2WSCustomRichMemo); - {$else}RegisterWSComponent(TCustomRichMemo, TWSCustomRichMemo); - {$endif} + {$ifdef LCLWin32}RegisterWSComponent(TCustomRichMemo, TWin32WSCustomRichMemo);{$endif} + {$ifdef LCLCarbon}RegisterWSComponent(TCustomRichMemo, TCarbonWSCustomRichMemo);{$endif} + {$ifdef LCLGtk2}RegisterWSComponent(TCustomRichMemo, TGtk2WSCustomRichMemo);{$endif} + {$ifdef NoRichMemo}RegisterWSComponent(TCustomRichMemo, TWSCustomRichMemo);{$endif} cls:=FindWSComponentClass(TCustomRichMemo); if not Assigned(cls) then RegisterWSComponent(TCustomRichMemo, TWSCustomRichMemo); end; diff --git a/components/richmemo/richmemopackage.lpk b/components/richmemo/richmemopackage.lpk index 26d847079..2f8e61bc3 100644 --- a/components/richmemo/richmemopackage.lpk +++ b/components/richmemo/richmemopackage.lpk @@ -22,7 +22,7 @@ "/> - + @@ -66,6 +66,20 @@ + + + + + + + + + + + + + + diff --git a/components/richmemo/richmemortf.pas b/components/richmemo/richmemortf.pas new file mode 100644 index 000000000..92c18dbb8 --- /dev/null +++ b/components/richmemo/richmemortf.pas @@ -0,0 +1,94 @@ +unit RichMemoRTF; + +interface + +uses + Classes, SysUtils, LCLProc, LCLIntf, + RichMemo, RTFParsPre211; + +//todo: formatting support! + +function MVCParserLoadStream(ARich: TCustomRichMemo; Source: TStream): Boolean; + +implementation + +type + { TRTFMemoParser } + + TRTFMemoParser = class(TRTFParser) + protected + procedure classText; + procedure classControl; + + procedure doSpecialChar; + public + txt : String; + Memo : TCustomRichMemo; + constructor Create(AMemo: TCustomRichMemo; AStream: TStream); + end; + + +{ TRTFMemoParserr } +procedure TRTFMemoParser.classText; +begin + //writeln('txt: ', rtfMajor, ' ',rtfMinor,' ', rtfParam); + case rtfMinor of + rtfOptDest:; + else + txt:=txt+Self.GetRtfText; + end; +end; + +procedure TRTFMemoParser.classControl; +begin + //writeln('ctrl: ', rtfClass,' ', rtfMajor, ' ', Self.GetRtfText, ' ',rtfMinor,' ', rtfParam); + case rtfMajor of + rtfSpecialChar: doSpecialChar; + end; +end; + +procedure TRTFMemoParser.doSpecialChar; +const + CharPara = #10; + CharTab = #9; + CharLine = #13; +begin + case rtfMinor of + rtfLine: txt:=txt+CharLine; + rtfPar: txt:=txt+CharPara; + rtfTab: txt:=txt+CharTab; + end; +end; + +constructor TRTFMemoParser.Create(AMemo:TCustomRichMemo;AStream:TStream); +begin + inherited Create(AStream); + Memo:=AMemo; + ClassCallBacks[rtfText]:=@classText; + ClassCallBacks[rtfControl]:=@classControl; +end; + +function MVCParserLoadStream(ARich: TCustomRichMemo; Source: TStream): Boolean; +var + p : TRTFMemoParser; +begin + Result:=Assigned(ARich) and Assigned(Source); + if not Result then Exit; + + p:=TRTFMemoParser.Create(ARich, Source); + try + p.StartReading; + ARich.SelStart:=0; + ARich.SelLength:=0; + ARich.Text:=p.txt; + finally + p.Free; + end; + Result:=True; +end; + +initialization + RTFLoadStream:=@MVCParserLoadStream; + + +end. diff --git a/components/richmemo/rtfdata.inc b/components/richmemo/rtfdata.inc new file mode 100644 index 000000000..1c58932bb --- /dev/null +++ b/components/richmemo/rtfdata.inc @@ -0,0 +1,768 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 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; rtfKMinor: rtfMacQD; 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) + ); + diff --git a/components/richmemo/rtfparspre211.pp b/components/richmemo/rtfparspre211.pp new file mode 100644 index 000000000..8749c5681 --- /dev/null +++ b/components/richmemo/rtfparspre211.pp @@ -0,0 +1,971 @@ +Unit RTFParsPre211; +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 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. + + **********************************************************************} + +// modified: by Dmitry Boyarintsev 20-may-2010, fixing identation and code-style + +{$mode objfpc} + +interface + +uses + Classes, SysUtils; + +{$i rtfdata.inc} + +type + TRTFErrorHandler = Procedure (s : string) of object; + + { TRTFParser } + + TRTFParser = class(TObject) + private + FOnRTFError : TRTFerrorHandler; + FfontList : PRTFFont; + FcolorList : PRTFColor; + FstyleList : PRTFStyle; + FrtfClass : Integer; + FrtfMajor : Integer; + FrtfMinor : Integer; + FrtfParam : Integer; + rtfTextBuf : string [rtfBufSiz]; + rtfTextLen : Integer; + pushedChar : Integer; { pushback char if read too far } + pushedClass : Integer; { pushed token info for RTFUngetToken() } + pushedMajor : Integer; + pushedMinor : Integer; + 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; + FTokenClass: Integer; + 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); + function GetRtfText: string; + { 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 cnil 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=0) and (Aclass=0) and (Adestination=0) and (ADestinationrtfEOF) 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; + FTokenClass := rtfUnknown; + + { 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 begin { ASCII 9 } + 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 begin{ hex char } + 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 begin{ escaped char } + FrtfClass := rtfText; + FrtfMajor := c; + exit; + end; + + { control symbol } + Lookup (rtfTextBuf); { sets class, major, minor } + FTokenClass:=rtfControl; + 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 } + FTokenClass:=rtfControl; + 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 begin { gobble parameter } + 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 begin { first entry - determine tbl type } + 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 begin { need to find "Begin" here } + 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 begin { need to see "End;" here } + 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) or (FTokenClass=rtfControl) do begin + if rtfClass=rtfUnknown then Continue; + if (CheckMM (rtfParAttr, rtfStyleNum)) then begin + sp^.rtfSNum:=rtfParam; + continue; + end; + if (CheckMM (rtfStyleAttr, rtfBasedOn)) then begin + sp^.rtfSBasedOn:=rtfParam; + continue; + end; + if (CheckMM (rtfStyleAttr, rtfNext)) then begin + sp^.rtfSNextPar:=rtfParam; + Continue; + 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'); + Bp:=''; + while rtfClass=rtfText do begin + if rtfMajor=ord(';') then begin + GetToken; + Break; + end; + bp:=bp+chr(rtfMajor); + GetToken; + end; + if (sp^.rtfSNum < 0) then begin { no style number was specified, (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; + +function TRTFParser.GetRtfText: string; +begin + SetString(Result, @rtfTextBuf[1], rtfTextLen); +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.