mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-27 12:53:50 +02:00
2629 lines
72 KiB
ObjectPascal
2629 lines
72 KiB
ObjectPascal
{Version 7.5}
|
|
{*********************************************************}
|
|
{* LITEPARS.PAS *}
|
|
{* Copyright (c) 1995-2002 by *}
|
|
{* L. David Baldwin *}
|
|
{* All rights reserved. *}
|
|
{*********************************************************}
|
|
|
|
{$i LiteCons.inc}
|
|
|
|
{ The Parser
|
|
This module contains the parser which reads thru the document. It divides it
|
|
into sections storing the pertinent information in Section objects. The
|
|
document itself is then a TList of section objects. See the LiteSubs unit for
|
|
the definition of the section objects.
|
|
|
|
Key Variables:
|
|
|
|
Sy:
|
|
An enumerated type which indicates what the current token is. For
|
|
example, a value of TextSy would indicate a hunk of text, PSy that a <P>
|
|
tag was encountered, etc.
|
|
LCh:
|
|
The next character in the stream to be analyzed. In mixed case.
|
|
Ch:
|
|
The same character in upper case.
|
|
LCToken:
|
|
A string which is associated with the current token. If Sy is TextSy,
|
|
then LCToken contains the text.
|
|
Attributes:
|
|
A list of TAttribute's for tokens such as <img>, <a>, which have
|
|
attributes.
|
|
Section:
|
|
The current section being built.
|
|
SectionList:
|
|
The list of sections which form the document. When in a Table,
|
|
SectionList will contain the list that makes up the current cell.
|
|
|
|
Key Routines:
|
|
|
|
GetCh:
|
|
Gets the next character from the stream. Fills Ch and LCh. Skips
|
|
comments.
|
|
Next:
|
|
Gets the next token. Fills Sy, LCToken, Attributes. Calls GetCh so the
|
|
next character after the present token is available. Each part of the
|
|
parser is responsible for calling Next after it does its thing.
|
|
}
|
|
|
|
unit LitePars;
|
|
|
|
interface
|
|
uses
|
|
{$IFDEF HL_LAZARUS}
|
|
Classes, SysUtils, LCLType, Messages, GraphType, Graphics, Controls,
|
|
Dialogs, StdCtrls, LiteUn2, LiteSubs, LiteSbs1;
|
|
{$ELSE}
|
|
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
|
|
Dialogs, StdCtrls, LiteUn2, LiteSubs, LiteSbs1;
|
|
{$ENDIF}
|
|
|
|
const
|
|
MaxStack = 25;
|
|
FontConv: array[1..7] of integer = (8,10,12,14,18,24,36);
|
|
PreFontConv: array[1..7] of integer = (7,8,10,12,15,20,30);
|
|
|
|
type
|
|
LoadStyleType = (lsPrimary, lsInclude);
|
|
TIncludeType = procedure(Sender: TObject; const Command: string;
|
|
Params: TStrings; var IString: string) of Object;
|
|
TSoundType = procedure(Sender: TObject; const SRC: string; Loop: integer;
|
|
Terminate: boolean) of Object;
|
|
TMetaType = procedure(Sender: TObject; const HttpEq, Name, Content: string) of Object;
|
|
|
|
SymbSet = Set of Symb;
|
|
|
|
TLastChar = (lcOther, lcCR, lcLF);
|
|
|
|
ThlParser = Class
|
|
private
|
|
Sy : Symb;
|
|
PreFormat: boolean; {set when doing preformat <pre> text}
|
|
Justify: JustifyType;
|
|
BaseFontSize: integer;
|
|
InScript: boolean; {when in a <SCRIPT>}
|
|
NoPSpace: boolean; {start a new cell (to avoid paragraph space on <p>}
|
|
TagIndex: integer;
|
|
Section : TSection;
|
|
SectionList: TCell;
|
|
MasterList: TSectionList;
|
|
NameList: TStringList; {a list of the <a Name= > attributes along with the
|
|
section where found}
|
|
FontStack: array[1..MaxStack] of TMyFont; {handy way of keeping track of past
|
|
fonts}
|
|
StackIndex: integer;
|
|
CurrentURLTarget: TURLTarget;
|
|
InHref: boolean;
|
|
Attributes : TAttributeList;
|
|
|
|
LCh, Ch: Char;
|
|
SIndex: integer;
|
|
LastChar: TLastChar;
|
|
Value : integer;
|
|
LCToken : TokenObj;
|
|
LoadStyle: LoadStyleType;
|
|
Buffer, BuffEnd: PChar;
|
|
|
|
IBuff, IBuffEnd: PChar;
|
|
SIBuff: string;
|
|
IncludeEvent: TIncludeType;
|
|
CallingObject: TObject;
|
|
SaveLoadStyle: LoadStyleType;
|
|
SoundEvent: TSoundType;
|
|
MetaEvent: TMetaType;
|
|
NoBreak: boolean; {set when in <NoBr>}
|
|
ALoop: integer;
|
|
ATName: string;
|
|
HttpEq, Content: string;
|
|
InclSL: TStringList;
|
|
InclS: string;
|
|
|
|
procedure SkipWhiteSpace;
|
|
procedure GetCh;
|
|
function GetAttribute(var Sym: Symb;
|
|
var St, S: {$IFDEF HL_LAZARUS}HLString{$ELSE}OpenString{$ENDIF};
|
|
var Val: Integer): boolean;
|
|
function GetID(
|
|
var S: {$IFDEF HL_LAZARUS}HLString{$ELSE}OpenString{$ENDIF}): boolean;
|
|
function GetQuotedStr(
|
|
var S: {$IFDEF HL_LAZARUS}HLString{$ELSE}OpenString{$ENDIF};
|
|
var {$IFDEF HL_LAZARUS}NewValue{$ELSE}Value{$ENDIF}: Integer): boolean;
|
|
procedure GetSomething(
|
|
var S: {$IFDEF HL_LAZARUS}HLString{$ELSE}OpenString{$ENDIF});
|
|
function GetTag: boolean;
|
|
function GetValue(var S: string;
|
|
var {$IFDEF HL_LAZARUS}NewValue{$ELSE}Value{$ENDIF}: Integer): boolean;
|
|
function IsOddChar: boolean;
|
|
function IsText: boolean;
|
|
procedure Next;
|
|
procedure DoAEnd;
|
|
procedure DoBase;
|
|
procedure DoBody(Level: integer; const TermSet: SymbSet);
|
|
procedure DoCommonSy(Lev: integer);
|
|
procedure DoLists(Level: integer; Sym: Symb; const TermSet: SymbSet);
|
|
procedure DoMap;
|
|
procedure DoMeta(Sender: TObject);
|
|
procedure DoScript(Ascript: TScriptEvent);
|
|
procedure DoSound;
|
|
procedure DoTable(ALevel: integer);
|
|
procedure DoText;
|
|
procedure DoTextArea(TxtArea: TTextAreaFormControlObj);
|
|
procedure DoTitle;
|
|
procedure GetOptions(Select: TListBoxFormControlObj);
|
|
procedure ParseInit(ASectionList: TList; ANameList: TStringList;
|
|
AIncludeEvent: TIncludeType);
|
|
procedure PopFont;
|
|
function FindAlignment: JustifyType;
|
|
function PushNewFont: boolean;
|
|
function TranslateCharset(DefCharset: TFontCharset;
|
|
const {$IFDEF HL_LAZARUS}NewContent{$ELSE}Content{$ENDIF}: string): TFontCharset;
|
|
procedure SignalSuspend;
|
|
procedure DoSoundEvent;
|
|
procedure DoMetaEvent;
|
|
procedure DoIncludeEvent;
|
|
public
|
|
Title: string;
|
|
Base: string;
|
|
BaseTarget: string;
|
|
AllowSuspend: boolean;
|
|
ParseThread: {$IFDEF NoThreads}TObject{$ELSE}TThread{$ENDIF};
|
|
CurrentStyle: TFontStyles; {as set by <b>, <i>, etc.}
|
|
CurrentSScript: SubSuperType;
|
|
CurrentForm: ThtmlForm;
|
|
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure HtmlParseTextString(ASectionList: TList;
|
|
ANameList: TStringList);
|
|
procedure HtmlParseString(ASectionList: TList; ANameList: TStringList;
|
|
AIncludeEvent: TIncludeType; ASoundEvent: TSoundType;
|
|
AMetaEvent: TMetaType);
|
|
end;
|
|
|
|
function GetColor(S: String; Var Value: TColor): boolean;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
htmllite, LiteReadThd;
|
|
|
|
Const
|
|
Tab = #9;
|
|
EofChar = ^Z;
|
|
|
|
type
|
|
SymString = string[12];
|
|
|
|
Const
|
|
MaxRes = 66;
|
|
MaxEndRes = 49;
|
|
ResWords : array[1..MaxRes] of SymString =
|
|
('HTML', 'TITLE', 'BODY', 'HEAD', 'B', 'I', 'H', 'EM', 'STRONG',
|
|
'U', 'CITE', 'VAR', 'TT', 'CODE', 'KBD', 'SAMP', 'OL', 'UL', 'DIR',
|
|
'MENU', 'DL',
|
|
'A', 'ADDRESS', 'BLOCKQUOTE', 'PRE', 'CENTER', 'TABLE', 'TD', 'TH',
|
|
'CAPTION', 'FORM', 'TEXTAREA', 'SELECT', 'OPTION', 'FONT', 'SUB', 'SUP',
|
|
'BIG', 'SMALL', 'P', 'MAP', 'FRAMESET', 'NOFRAMES', 'SCRIPT', 'DIV',
|
|
'S', 'STRIKE', 'TR', 'NOBR',
|
|
|
|
'LI', 'BR', 'HR', 'DD', 'DT', 'IMG', 'BASE', 'BUTTON','INPUT',
|
|
'SELECTED', 'BASEFONT', 'AREA', 'FRAME', 'BGSOUND', 'WRAP',
|
|
'META', 'WBR');
|
|
|
|
ResSy : array[1..MaxRes] of Symb =
|
|
(htmlSy, TitleSy, BodySy, HeadSy, BSy, ISy, HeadingSy, EmSy, StrongSy,
|
|
USy, CiteSy, VarSy, TTSy, CodeSy, KbdSy, SampSy, OLSy, ULSy, DirSy,
|
|
MenuSy, DLSy, ASy, AddressSy, BlockQuoteSy, PreSy, CenterSy,TableSy,
|
|
TDsy, THSy, CaptionSy, FormSy, TextAreaSy, SelectSy, OptionSy, FontSy,
|
|
SubSy, SupSy, BigSy, SmallSy, PSy, MapSy, FrameSetSy, NoFramesSy,
|
|
ScriptSy, DivSy, SSy, StrikeSy, TRSy, NoBrSy,
|
|
|
|
LISy, BRSy, HRSy, DDSy, DTSy, ImageSy, BaseSy, ButtonSy,
|
|
InputSy, SelectedSy, BaseFontSy, AreaSy, FrameSy, BgSoundSy,
|
|
WrapSy, MetaSy, WbrSy);
|
|
|
|
{keep these in order with those above}
|
|
EndResSy : array[1..MaxEndRes] of Symb =
|
|
(HtmlEndSy, TitleEndSy, BodyEndSy, HeadEndSy, BEndSy, IEndSy, HeadingEndSy,
|
|
EmEndSy, StrongEndSy, UEndSy, CiteEndSy, VarEndSy, TTEndSy, CodeEndSy,
|
|
KbdEndSy, SampEndSy,
|
|
OLEndSy, ULEndSy, DirEndSy, MenuEndSy, DLEndSy, AEndSy, AddressEndSy,
|
|
BlockQuoteEndSy, PreEndSy, CenterEndSy, TableEndSy, TDEndSy, THEndSy,
|
|
CaptionEndSy, FormEndSy, TextAreaEndSy, SelectEndSy, OptionEndSy, FontEndSy,
|
|
SubEndSy, SupEndSy, BigEndSy, SmallEndSy, PEndSy, MapEndSy, FrameSetEndSy,
|
|
NoFramesEndSy, ScriptEndSy, DivEndSy, SEndSy, StrikeEndSy, TREndSy, NoBrEndSy);
|
|
|
|
TextBuffSize = 2000;
|
|
|
|
Type
|
|
EParseError = class(Exception);
|
|
|
|
procedure ThlParser.SignalSuspend;
|
|
begin
|
|
(CallingObject as ThtmlLite).SignalSuspend;
|
|
end;
|
|
|
|
procedure ThlParser.DoIncludeEvent;
|
|
begin
|
|
IncludeEvent(CallingObject, InclS, InclSL, SIBuff);
|
|
end;
|
|
|
|
{-------------GetCh}
|
|
PROCEDURE ThlParser.GetCh;
|
|
{Return next char in Lch, its uppercase value in Ch. Ignore comments}
|
|
var
|
|
Comment, Done: boolean;
|
|
|
|
function ReadChar: char;
|
|
begin
|
|
case LoadStyle of
|
|
lsPrimary:
|
|
begin
|
|
if Buffer < BuffEnd then
|
|
begin
|
|
Result := Buffer^;
|
|
Inc(Buffer);
|
|
Inc(SIndex);
|
|
end
|
|
else if AllowSuspend then
|
|
begin
|
|
TParseThread(ParseThread).Buffer := Buffer;
|
|
TParseThread(ParseThread).Synchronize(
|
|
{$IFDEF HL_LAZARUS}@{$ENDIF}SignalSuspend);
|
|
TParseThread(ParseThread).Suspend; {wait for more}
|
|
Buffer := TParseThread(ParseThread).Buffer;
|
|
BuffEnd := TParseThread(ParseThread).BuffEnd;
|
|
if Buffer < BuffEnd then
|
|
begin
|
|
Result := Buffer^;
|
|
Inc(Buffer);
|
|
Inc(SIndex);
|
|
end
|
|
else
|
|
Result := EOFChar;
|
|
end
|
|
else
|
|
Result := EOFChar;
|
|
end;
|
|
|
|
lsInclude:
|
|
if IBuff < IBuffEnd then
|
|
begin
|
|
Result := IBuff^;
|
|
Inc(IBuff);
|
|
end
|
|
else
|
|
begin
|
|
LoadStyle := SaveLoadStyle;
|
|
Result := ReadChar;
|
|
end;
|
|
else Result := #0; {to prevent warning msg}
|
|
end;
|
|
end;
|
|
|
|
function Peek: char; {take a look at the next char}
|
|
begin
|
|
case LoadStyle of
|
|
lsPrimary:
|
|
begin
|
|
if Buffer < BuffEnd then
|
|
Result := Buffer^
|
|
else
|
|
Result := EOFChar;
|
|
end;
|
|
|
|
lsInclude:
|
|
if IBuff < IBuffEnd then
|
|
Result := IBuff^
|
|
else
|
|
begin
|
|
LoadStyle := SaveLoadStyle;
|
|
Result := Peek;
|
|
end;
|
|
else Result := #0; {to prevent warning msg}
|
|
end;
|
|
end;
|
|
|
|
procedure GetchBasic; {read a character}
|
|
begin
|
|
LCh := ReadChar;
|
|
case LCh of {skip a ^J after a ^M or a ^M after a ^J}
|
|
^M: if LastChar = lcLF then
|
|
LCh := ReadChar;
|
|
^J: if LastChar = lcCR then
|
|
LCh := ReadChar;
|
|
end;
|
|
case LCh of
|
|
^M: LastChar := lcCR;
|
|
^J: begin
|
|
LastChar := lcLF;
|
|
LCh := ^M;
|
|
end;
|
|
else
|
|
begin
|
|
LastChar := lcOther;
|
|
if LCh = Tab then LCh := ' ';
|
|
end;
|
|
end;
|
|
Ch := UpCase(LCh);
|
|
if (LCh = EofChar) and Comment then
|
|
Raise EParseError.Create('Open Comment at End of HTML File');
|
|
end;
|
|
|
|
procedure DoDashDash; {do the comment after a <!-- }
|
|
begin
|
|
repeat
|
|
while Ch <> '-' do GetChBasic; {get first '-'}
|
|
GetChBasic;
|
|
if Ch = '-' then {second '-'}
|
|
begin
|
|
while Ch = '-' do GetChBasic; {any number of '-'}
|
|
while (Ch = ' ') or (Ch = ^M) do GetChBasic; {eat white space}
|
|
Done := Ch = '>';
|
|
end
|
|
else Done := False;
|
|
until Done;
|
|
end;
|
|
|
|
procedure ReadToGT; {read to the next '>' }
|
|
begin
|
|
while Ch <> '>' do
|
|
GetChBasic;
|
|
end;
|
|
|
|
procedure DoInclude;
|
|
var
|
|
SymStr, AttrStr: String;
|
|
L: integer;
|
|
Sym: Symb;
|
|
begin
|
|
InclS := '';
|
|
GetChBasic;
|
|
while Ch in ['A'..'Z'] do
|
|
begin
|
|
InclS := InclS + LCh;
|
|
GetChBasic;
|
|
end;
|
|
InclSL := TStringList.Create;
|
|
while GetAttribute(Sym, SymStr, AttrStr, L) do
|
|
InclSL.Add(SymStr+'="'+AttrStr+'"');
|
|
DoDashDash;
|
|
SIBuff := '';
|
|
TParseThread(ParseThread).Synchronize(
|
|
{$IFDEF HL_LAZARUS}@{$ENDIF}DoIncludeEvent);
|
|
if Length(SIBuff) > 0 then
|
|
begin
|
|
SaveLoadStyle := LoadStyle;
|
|
LoadStyle := lsInclude;
|
|
IBuff := PAnsiChar(SIBuff);
|
|
IBuffEnd := IBuff+Length(SIBuff);
|
|
end;
|
|
end;
|
|
|
|
begin {Getch}
|
|
repeat {in case a comment immediately follows another comment}
|
|
{comments may be either '<! stuff >' or '<!-- stuff -->' }
|
|
Comment := False;
|
|
GetchBasic;
|
|
if (Ch = '<') and not InScript then
|
|
begin
|
|
if Peek = '!' then
|
|
begin
|
|
GetChBasic;
|
|
Comment:=True;
|
|
GetChBasic;
|
|
if Ch = '-' then
|
|
begin
|
|
GetChBasic;
|
|
if Ch = '-' then
|
|
begin
|
|
GetChBasic;
|
|
if Assigned(IncludeEvent) and (Ch = '#') and (LoadStyle <> lsInclude) then
|
|
DoInclude
|
|
else
|
|
DoDashDash; {a <!-- comment}
|
|
end
|
|
else ReadToGT;
|
|
end
|
|
else ReadToGT;
|
|
end;
|
|
end;
|
|
until not Comment;
|
|
end;
|
|
|
|
{-------------SkipWhiteSpace}
|
|
procedure ThlParser.SkipWhiteSpace;
|
|
begin
|
|
while (LCh in [' ', Tab, ^M]) do
|
|
GetCh;
|
|
end;
|
|
|
|
{----------------GetValue}
|
|
function ThlParser.GetValue(var S: string;
|
|
var {$IFDEF HL_LAZARUS}NewValue{$ELSE}Value{$ENDIF}: integer): boolean;
|
|
{read a numeric}
|
|
var
|
|
Code: integer;
|
|
begin
|
|
Result := Ch in ['-', '+', '0'..'9'];
|
|
if not Result then Exit;
|
|
{$IFDEF HL_LAZARUS}NewValue{$ELSE}Value{$ENDIF} := 0;
|
|
if Ch in ['-', '+'] then
|
|
begin
|
|
S := Ch;
|
|
GetCh;
|
|
end
|
|
else S := '';
|
|
while not (Ch in [' ', Tab, ^M, '>', '%', EofChar]) do
|
|
begin
|
|
S := S + Ch;
|
|
GetCh;
|
|
end;
|
|
SkipWhiteSpace;
|
|
Val(S, {$IFDEF HL_LAZARUS}NewValue{$ELSE}Value{$ENDIF}, Code);
|
|
if Code <> 0 then
|
|
{$IFDEF HL_LAZARUS}NewValue{$ELSE}Value{$ENDIF} := 0;
|
|
if LCh = '%' then
|
|
begin
|
|
S := S + '%';
|
|
GetCh;
|
|
end;
|
|
end;
|
|
|
|
{----------------IsOddChar}
|
|
function ThlParser.IsOddChar : boolean;
|
|
const
|
|
Lim = 8;
|
|
MaxChars = Lim+96;
|
|
OddCharStr : array[1..MaxChars] of string[6] =
|
|
('amp', 'lt', 'gt', 'quot', 'rsquo', 'ndash', 'trade', 'hellip', {Lim special items}
|
|
'nbsp', {no-break space}
|
|
'iexcl', {inverted exclamation mark}
|
|
'cent', {cent sign}
|
|
'pound', {pound sterling sign}
|
|
'curren', {general currency sign}
|
|
'yen', {yen sign}
|
|
'brvbar', {broken (vertical) bar}
|
|
'sect', {section sign}
|
|
'uml', {umlaut (dieresis)}
|
|
'copy', {copyright sign}
|
|
'ordf', {ordinal indicator', feminine}
|
|
'laquo', {angle quotation mark', left}
|
|
'not', {not sign}
|
|
'shy', {soft hyphen}
|
|
'reg', {registered sign}
|
|
'macr', {macron}
|
|
'deg', {degree sign}
|
|
'plusmn', {plus-or-minus sign}
|
|
'sup2', {superscript two}
|
|
'sup3', {superscript three}
|
|
'acute', {acute accent}
|
|
'micro', {micro sign}
|
|
'para', {pilcrow (paragraph sign)}
|
|
'middot', {middle dot}
|
|
'cedil', {cedilla}
|
|
'sup1', {superscript one}
|
|
'ordm', {ordinal indicator', masculine}
|
|
'raquo', {angle quotation mark', right}
|
|
'frac14', {fraction one-quarter}
|
|
'frac12', {fraction one-half}
|
|
'frac34', {fraction three-quarters}
|
|
'iquest', {inverted question mark}
|
|
|
|
'Agrave', {Capital A, grave accent}
|
|
'Aacute', {Capital A, acute accent}
|
|
'Acirc', {Capital A, circumflex accent}
|
|
'Atilde', {Capital A, tilde}
|
|
'Auml', {Capital A, dieresis or umlaut mark}
|
|
'Aring', {Capital A, ring}
|
|
'AElig', {Capital AE dipthong (ligature)}
|
|
'Ccedil', {Capital C, cedilla}
|
|
'Egrave', {Capital E, grave accent}
|
|
'Eacute', {Capital E, acute accent}
|
|
'Ecirc', {Capital E, circumflex accent}
|
|
'Euml', {Capital E, dieresis or umlaut mark}
|
|
'Igrave', {Capital I, grave accent}
|
|
'Iacute', {Capital I, acute accent}
|
|
'Icirc', {Capital I, circumflex accent}
|
|
'Iuml', {Capital I, dieresis or umlaut mark}
|
|
'ETH', {Capital Eth, Icelandic}
|
|
'Ntilde', {Capital N, tilde}
|
|
'Ograve', {Capital O, grave accent}
|
|
'Oacute', {Capital O, acute accent}
|
|
'Ocirc', {Capital O, circumflex accent}
|
|
'Otilde', {Capital O, tilde}
|
|
'Ouml', {Capital O, dieresis or umlaut mark}
|
|
'times', {missing}
|
|
'Oslash', {Capital O, slash}
|
|
'Ugrave', {Capital U, grave accent}
|
|
'Uacute', {Capital U, acute accent}
|
|
'Ucirc', {Capital U, circumflex accent}
|
|
'Uuml', {Capital U, dieresis or umlaut mark}
|
|
'Yacute', {Capital Y, acute accent}
|
|
'THORN', {Capital THORN, Icelandic}
|
|
'szlig', {Small sharp s, German (sz ligature)}
|
|
'agrave', {Small a, grave accent}
|
|
'aacute', {Small a, acute accent}
|
|
'acirc', {Small a, circumflex accent}
|
|
'atilde', {Small a, tilde}
|
|
'auml', {Small a, dieresis or umlaut mark}
|
|
'aring', {Small a, ring}
|
|
'aelig', {Small ae dipthong (ligature)}
|
|
'ccedil', {Small c, cedilla}
|
|
'egrave', {Small e, grave accent}
|
|
'eacute', {Small e, acute accent}
|
|
'ecirc', {Small e, circumflex accent}
|
|
'euml', {Small e, dieresis or umlaut mark}
|
|
'igrave', {Small i, grave accent}
|
|
'iacute', {Small i, acute accent}
|
|
'icirc', {Small i, circumflex accent}
|
|
'iuml', {Small i, dieresis or umlaut mark}
|
|
'eth', {Small eth, Icelandic}
|
|
'ntilde', {Small n, tilde}
|
|
'ograve', {Small o, grave accent}
|
|
'oacute', {Small o, acute accent}
|
|
'ocirc', {Small o, circumflex accent}
|
|
'otilde', {Small o, tilde}
|
|
'ouml', {Small o, dieresis or umlaut mark}
|
|
'divide', {missing}
|
|
'oslash', {Small o, slash}
|
|
'ugrave', {Small u, grave accent}
|
|
'uacute', {Small u, acute accent}
|
|
'ucirc', {Small u, circumflex accent}
|
|
'uuml', {Small u, dieresis or umlaut mark}
|
|
'yacute', {Small y, acute accent}
|
|
'thorn', {Small thorn, Icelandic}
|
|
'yuml'); {Small y, dieresis or umlaut mark}
|
|
|
|
|
|
OddChar : array[1..Lim] of string[3] =
|
|
('&', '<', '>', '"', '''', '-', #153, '...');
|
|
Label 2;
|
|
var
|
|
I, J, N: integer;
|
|
S: string[8];
|
|
Collect: TokenObj;
|
|
SaveIndex: integer;
|
|
W: WideChar;
|
|
|
|
procedure NextCh;
|
|
begin {collect chars and Indices in case of failure}
|
|
Collect.AddChar(LCh, SIndex);
|
|
GetCh;
|
|
end;
|
|
|
|
begin
|
|
if Ch <> '&' then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
Result := True;
|
|
Sy := TextSy;
|
|
I := 0;
|
|
S := '';
|
|
SaveIndex := SIndex;
|
|
Collect := TokenObj.Create;
|
|
try
|
|
NextCh;
|
|
if Ch = '#' then
|
|
begin {look for char #}
|
|
NextCh;
|
|
while I <=5 do
|
|
begin
|
|
if not (Ch in ['0'..'9']) then
|
|
begin
|
|
if Ch = ';' then NextCh;
|
|
if S <> '' then
|
|
begin
|
|
N := StrToInt(S);
|
|
if (N > 255) then
|
|
begin
|
|
//don't know what to do about widechar , comment out for now
|
|
{$IFNDEF HL_LAZARUS}
|
|
W := WideChar(N);
|
|
S := WideCharLenToString(@W, 1);
|
|
LCToken.AddChar(S[1], SaveIndex);
|
|
{$ELSE}
|
|
LCToken.AddChar({S[1]}' ', SaveIndex);
|
|
{$ENDIF}
|
|
GoTo 2;
|
|
end
|
|
else if (byte(N) in [9, 10, 32..255]) then
|
|
begin
|
|
if N = 9 then LCToken.AddChar(' ', SaveIndex)
|
|
else LCToken.AddChar(chr(N), SaveIndex);
|
|
GoTo 2;
|
|
end;
|
|
end;
|
|
LCToken.Concat(Collect);
|
|
GoTo 2;
|
|
end;
|
|
S := S+LCh;
|
|
Inc(I);
|
|
NextCh;
|
|
end;
|
|
LCToken.Concat(Collect);
|
|
GoTo 2;
|
|
end
|
|
else while I <= 6 do
|
|
begin
|
|
if not (Ch in ['A'..'Z', '0'..'9']) then {note: Ch is always upper case}
|
|
begin
|
|
if Ch = ';' then NextCh;
|
|
for J := 1 to MaxChars do
|
|
if S = OddCharStr[J] then
|
|
begin
|
|
if J <= Lim then
|
|
if S = 'hellip' then
|
|
begin
|
|
LCToken.S := '...';
|
|
LCToken.I^[1] := SaveIndex;
|
|
LCToken.I^[2] := SaveIndex+1;
|
|
LCToken.I^[3] := SaveIndex+2;
|
|
end
|
|
else
|
|
LCToken.AddChar(OddChar[J][1], SaveIndex)
|
|
else LCToken.AddChar(chr(J - Lim + 159), SaveIndex);
|
|
GoTo 2;
|
|
end;
|
|
LCToken.Concat(Collect);
|
|
GoTo 2;
|
|
end;
|
|
S := S+LCh;
|
|
Inc(I);
|
|
NextCh;
|
|
end;
|
|
{too many chars, assume it's just text}
|
|
LCToken.Concat(Collect);
|
|
2: ;
|
|
finally
|
|
Collect.Free;
|
|
end;
|
|
end;
|
|
|
|
{----------------GetQuotedStr}
|
|
function ThlParser.GetQuotedStr(
|
|
var S: {$IFDEF HL_LAZARUS}HLString{$ELSE}OpenString{$ENDIF};
|
|
var {$IFDEF HL_LAZARUS}NewValue{$ELSE}Value{$ENDIF}: integer): boolean;
|
|
{get a quoted string but strip the quotes, check to see if it is numerical}
|
|
var
|
|
Term: char;
|
|
S1: string;
|
|
Code: integer;
|
|
SaveSy: Symb;
|
|
begin
|
|
Result := False;
|
|
Term := Ch;
|
|
if (Term <> '"') and (Term <> '''') then Exit;
|
|
Result := True;
|
|
SaveSy := Sy;
|
|
GetCh;
|
|
while not (Ch in [Term, EofChar]) do
|
|
begin
|
|
if LCh <> ^M then
|
|
begin
|
|
if IsOddChar then
|
|
begin
|
|
S := S + LCToken.S;
|
|
LCToken.Clear;
|
|
end
|
|
else
|
|
begin
|
|
S := S + LCh;
|
|
GetCh;
|
|
end;
|
|
end
|
|
else GetCh; {pass ^M by}
|
|
end;
|
|
if Ch = Term then GetCh; {pass termination char}
|
|
S1 := Trim(S);
|
|
if Pos('%', S1) = Length(S1) then SetLength(S1, Length(S1)-1);
|
|
Val(S1, {$IFDEF HL_LAZARUS}NewValue{$ELSE}Value{$ENDIF}, Code);
|
|
if Code <> 0 then
|
|
{$IFDEF HL_LAZARUS}NewValue{$ELSE}Value{$ENDIF} := 0;
|
|
Sy := SaveSy;
|
|
end;
|
|
|
|
{----------------GetSomething}
|
|
procedure ThlParser.GetSomething(
|
|
var S: {$IFDEF HL_LAZARUS}HLString{$ELSE}OpenString{$ENDIF});
|
|
|
|
begin
|
|
while not (Ch in [' ', Tab, ^M, '>', EofChar]) do
|
|
begin
|
|
S := S+LCh;
|
|
GetCh;
|
|
end;
|
|
end;
|
|
|
|
{----------------GetID}
|
|
function ThlParser.GetID(
|
|
var S: {$IFDEF HL_LAZARUS}HLString{$ELSE}OpenString{$ENDIF}): boolean;
|
|
|
|
begin
|
|
Result := False;
|
|
if not (Ch in ['A'..'Z']) then Exit;
|
|
while Ch in ['A'..'Z', '-'] do
|
|
begin
|
|
S := S+Ch;
|
|
GetCh;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
{----------------GetAttribute}
|
|
function ThlParser.GetAttribute(var Sym: Symb;
|
|
var St, S: {$IFDEF HL_LAZARUS}HLString{$ELSE}OpenString{$ENDIF};
|
|
var Val: integer): boolean;
|
|
|
|
const
|
|
MaxAttr = 63;
|
|
Attrib : array[1..MaxAttr] of string[12] =
|
|
('HREF', 'NAME', 'SRC', 'ALT', 'ALIGN', 'TEXT', 'BGCOLOR', 'LINK',
|
|
'BACKGROUND', 'COLSPAN', 'ROWSPAN', 'BORDER', 'CELLPADDING',
|
|
'CELLSPACING', 'VALIGN', 'WIDTH', 'START', 'VALUE', 'TYPE',
|
|
'CHECKBOX', 'RADIO', 'METHOD', 'ACTION', 'CHECKED', 'SIZE',
|
|
'MAXLENGTH', 'COLS', 'ROWS', 'MULTIPLE', 'VALUE', 'SELECTED',
|
|
'FACE', 'COLOR', 'TRANSP', 'CLEAR', 'ISMAP', 'BORDERCOLOR',
|
|
'USEMAP', 'SHAPE', 'COORDS', 'NOHREF', 'HEIGHT', 'PLAIN', 'TARGET',
|
|
'NORESIZE', 'SCROLLING', 'HSPACE', 'LANGUAGE', 'FRAMEBORDER',
|
|
'MARGINWIDTH', 'MARGINHEIGHT', 'LOOP', 'ONCLICK', 'WRAP', 'NOSHADE',
|
|
'HTTP-EQUIV', 'CONTENT', 'ENCTYPE', 'VLINK', 'OLINK', 'ACTIVE',
|
|
'VSPACE', 'NOWRAP');
|
|
AttribSym: array[1..MaxAttr] of Symb =
|
|
(HrefSy, NameSy, SrcSy, AltSy, AlignSy, TextSy, BGColorSy, LinkSy,
|
|
BackgroundSy, ColSpanSy, RowSpanSy, BorderSy, CellPaddingSy,
|
|
CellSpacingSy, VAlignSy, WidthSy, StartSy, ValueSy, TypeSy,
|
|
CheckBoxSy, RadioSy, MethodSy, ActionSy, CheckedSy, SizeSy,
|
|
MaxLengthSy, ColsSy, RowsSy, MultipleSy, ValueSy, SelectedSy,
|
|
FaceSy, ColorSy, TranspSy, ClearSy, IsMapSy, BorderColorSy,
|
|
UseMapSy, ShapeSy, CoordsSy, NoHrefSy, HeightSy, PlainSy, TargetSy,
|
|
NoResizeSy, ScrollingSy, HSpaceSy, LanguageSy, FrameBorderSy,
|
|
MarginWidthSy, MarginHeightSy, LoopSy, OnClickSy, WrapSy, NoShadeSy,
|
|
HttpEqSy, ContentSy, EncTypeSy, VLinkSy, OLinkSy, ActiveSy,
|
|
VSpaceSy, NoWrapSy);
|
|
var
|
|
I: integer;
|
|
begin
|
|
Sym := OtherAttribute;
|
|
Result := False;
|
|
SkipWhiteSpace;
|
|
St := '';
|
|
if GetID(St) then
|
|
begin
|
|
for I := 1 to MaxAttr do
|
|
if St = Attrib[I] then
|
|
begin
|
|
Sym := AttribSym[I];
|
|
Break;
|
|
end;
|
|
end
|
|
else Exit; {no ID}
|
|
SkipWhiteSpace;
|
|
S := '';
|
|
if Sym = BorderSy then Val := 1 else Val := 0;
|
|
Result := True; {at least have an ID}
|
|
if Ch <> '=' then Exit;
|
|
GetCh;
|
|
|
|
SkipWhiteSpace;
|
|
if not GetQuotedStr(S, Val) then {either it's a quoted string or a number}
|
|
if not GetValue(S, Val) then
|
|
GetSomething(S); {in case quotes left off string}
|
|
end;
|
|
|
|
{-------------GetTag}
|
|
function ThlParser.GetTag: boolean; {Pick up a Tag or pass a single '<'}
|
|
Var
|
|
Done, EndTag : Boolean;
|
|
Compare: String[255];
|
|
SymStr, AttrStr: string;
|
|
I: Integer;
|
|
L: integer;
|
|
Save: integer;
|
|
Sym: Symb;
|
|
begin
|
|
if Ch <> '<' then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end
|
|
else Result := True;
|
|
Save := SIndex;
|
|
TagIndex := SIndex;
|
|
Compare := '';
|
|
GetCh;
|
|
if Ch = '/' then
|
|
begin
|
|
EndTag := True;
|
|
GetCh;
|
|
end
|
|
else if not (Ch in ['A'..'Z']) then
|
|
begin {an odd '<'}
|
|
Sy := TextSy;
|
|
LCToken.AddChar('<', Save);
|
|
Exit;
|
|
end
|
|
else
|
|
EndTag := False;
|
|
Sy := CommandSy;
|
|
Done := False;
|
|
while not Done do
|
|
case Ch of
|
|
'A'..'Z' :
|
|
begin
|
|
if Length(Compare) < 255 then
|
|
begin
|
|
Inc(Compare[0]);
|
|
Compare[Length(Compare)] := Ch;
|
|
end;
|
|
GetCh;
|
|
end;
|
|
else Done := True;
|
|
end;
|
|
for I := 1 to MaxRes do
|
|
if Compare = ResWords[I] then
|
|
begin
|
|
if not EndTag then
|
|
Sy := ResSy[I]
|
|
else
|
|
if I <= MaxEndRes then
|
|
Sy := EndResSy[I]; {else Sy := CommandSy}
|
|
Break;
|
|
end;
|
|
SkipWhiteSpace;
|
|
Value := 0;
|
|
if ((Sy = HeadingSy) or (Sy = HeadingEndSy)) and (Ch in ['1'..'6']) then
|
|
begin
|
|
Value := ord(Ch)-ord('0');
|
|
GetCh;
|
|
end;
|
|
|
|
if Sy in [ImageSy, BaseSy, ASy, BodySy, TDSy, THSy, TRSy, TableSy,
|
|
CaptionSy, OLSy, ULSy, InputSy, FormSy, TextAreaSy, SelectSy, OptionSy,
|
|
PSy, FontSy, BaseFontSy, BRSy, HeadingSy, MapSy, AreaSy,
|
|
HRSy, FrameSy, FrameSetSy, NoResizeSy, ScrollingSy, ScriptSy, DivSy,
|
|
BgSoundSy, WrapSy, MetaSy ] then
|
|
Attributes.Clear;
|
|
while GetAttribute(Sym, SymStr, AttrStr, L) do
|
|
if Sy in [ImageSy, BaseSy, ASy, BodySy, TDSy, THSy, TRSy, TableSy,
|
|
CaptionSy, OLSy, ULSy, InputSy, FormSy, TextAreaSy, SelectSy, OptionSy,
|
|
PSy, FontSy, BaseFontSy, BRSy, HeadingSy, MapSy, AreaSy,
|
|
HRSy, FrameSy, FrameSetSy, NoResizeSy, ScrollingSy, ScriptSy, DivSy,
|
|
BgSoundSy, WrapSy, MetaSy] then
|
|
Attributes.Add(TAttribute.Create(Sym, L, AttrStr));
|
|
{else ignore (but pass over) other attributes}
|
|
|
|
while (Ch <> '>') and (Ch <> EofChar) do GetCh;
|
|
GetCh;
|
|
end;
|
|
|
|
{----------------IsText}
|
|
function ThlParser.IsText : boolean;
|
|
begin
|
|
LCToken.Clear;
|
|
while (Length(LCToken.S) < 100) and
|
|
(LCh in [^M, ' '..'%', ''''..';', '=', '?'..#255, '>']) do
|
|
if not PreFormat and ((LCh = ' ') or (LCh = ^M)) then
|
|
begin
|
|
if NoBreak then
|
|
LCToken.AddChar(#5, SIndex) {#5 is NoBreak space representation}
|
|
else
|
|
LCToken.AddChar(' ', SIndex); {^M becomes space}
|
|
SkipWhiteSpace; {eliminate multiple spaces}
|
|
end
|
|
else
|
|
begin
|
|
LCToken.AddChar(LCh, SIndex);
|
|
GetCh;
|
|
end;
|
|
if Length(LCToken.S) > 0 then
|
|
begin
|
|
Sy := TextSy;
|
|
IsText := True;
|
|
end
|
|
else IsText := False;
|
|
end;
|
|
|
|
{-----------Next}
|
|
PROCEDURE ThlParser.Next;
|
|
{Get the next token}
|
|
begin {already have fresh character loaded here}
|
|
LCToken.Clear;
|
|
if LCh = EofChar then Sy := EofSy
|
|
else if GetTag then {handles '<'}
|
|
else if IsOddChar then
|
|
else if IsText then
|
|
else
|
|
begin
|
|
Sy := OtherChar;
|
|
LCToken.AddChar(LCh, SIndex);
|
|
GetCh;
|
|
end;
|
|
if NoPSpace and (Sy in [TextSy, ImageSy, TableSy, InputSy, SelectSy, TextAreaSy,
|
|
BrSy, HeadingSy, HRSy]) then NoPSpace := False;
|
|
end;
|
|
|
|
function ThlParser.PushNewFont: boolean;
|
|
{add a font to the font stack identical to the last one}
|
|
begin
|
|
if StackIndex < MaxStack then
|
|
begin
|
|
Inc(StackIndex);
|
|
FontStack[StackIndex] := TMyFont.Create;
|
|
FontStack[StackIndex].Assign(FontStack[StackIndex-1]);
|
|
Result := True;
|
|
end
|
|
else Result := False;
|
|
end;
|
|
|
|
procedure ThlParser.PopFont;
|
|
{pop and free a font from the font stack}
|
|
begin
|
|
if StackIndex > 1 then
|
|
begin
|
|
FontStack[StackIndex].Free;
|
|
Dec(StackIndex);
|
|
end;
|
|
end;
|
|
|
|
procedure ThlParser.DoTextArea(TxtArea: TTextAreaFormControlObj);
|
|
{read and save the text for a TextArea form control}
|
|
var
|
|
S: string;
|
|
Token: string;
|
|
|
|
procedure Next1;
|
|
{Special Next routine to get the next token}
|
|
procedure GetTag1; {simplified Pick up a Tag routine}
|
|
begin
|
|
Token := '<';
|
|
GetCh;
|
|
Sy := CommandSy;
|
|
while not (LCh in [' ', ^M, Tab, '>']) do
|
|
begin
|
|
Token := Token + LCh;
|
|
GetCh;
|
|
end;
|
|
if CompareText(Token, '</textarea') = 0 then
|
|
Sy := TextAreaEndSy
|
|
else Sy := CommandSy; {anything else}
|
|
end;
|
|
|
|
function IsText1 : boolean;
|
|
begin
|
|
while (Length(Token) < 100) and not (LCh in [^M, '<', '&', EofChar]) do
|
|
begin
|
|
Token := Token+LCh;
|
|
GetCh;
|
|
end;
|
|
if Length(Token) > 0 then
|
|
begin
|
|
Sy := TextSy;
|
|
IsText1 := True;
|
|
end
|
|
else IsText1 := False;
|
|
end;
|
|
|
|
begin {already have fresh character loaded here}
|
|
Token := '';
|
|
LCToken.Clear;
|
|
if LCh = EofChar then Sy := EofSy
|
|
else if LCh = ^M then
|
|
begin
|
|
Sy := EolSy;
|
|
GetCh;
|
|
end
|
|
else if LCh = '<' then
|
|
begin GetTag1; Exit; end
|
|
else if IsOddChar then
|
|
Token := LCToken.S
|
|
else if IsText1 then
|
|
else
|
|
begin
|
|
Sy := OtherChar;
|
|
Token := LCh;
|
|
GetCh;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Next1;
|
|
S := '';
|
|
while (Sy <> TextAreaEndSy) and (Sy <> EofSy) do
|
|
begin
|
|
case Sy of
|
|
TextSy: S := S + Token;
|
|
EolSy:
|
|
begin
|
|
TxtArea.AddStr(S);
|
|
S := '';
|
|
end;
|
|
else
|
|
S := S + Token;
|
|
end;
|
|
Next1;
|
|
end;
|
|
while not (LCh in ['>', EofChar]) do
|
|
GetCh; {remove chars to and past '>'}
|
|
GetCh;
|
|
if S <> '' then TxtArea.AddStr(S);
|
|
end;
|
|
|
|
function ThlParser.FindAlignment: JustifyType; {pick up Align= attribute}
|
|
var
|
|
UpName: string[10];
|
|
T: TAttribute;
|
|
begin
|
|
Result := Justify;
|
|
if Sy = PEndSy then Exit;
|
|
if Attributes.Find(AlignSy, T) then
|
|
begin
|
|
UpName := Lowercase(T.Name);
|
|
if UpName = 'left' then Result := Left
|
|
else if UpName = 'center' then Result := Centered
|
|
else if UpName = 'right' then Result := Right;
|
|
end;
|
|
end;
|
|
|
|
const
|
|
TableTermSet = [TableEndSy, TDSy, TRSy, TREndSy, THSy, THEndSy, TDEndSy,
|
|
CaptionSy, CaptionEndSy];
|
|
|
|
procedure ThlParser.DoAEnd; {do the </a>}
|
|
begin
|
|
if InHref then {see if we're in an href}
|
|
begin
|
|
CurrentUrlTarget.Clear;
|
|
InHref := False;
|
|
PopFont; {the blue stuff}
|
|
end;
|
|
if Assigned(Section) then
|
|
Section.HRef(AEndSy, MasterList, Nil, FontStack[StackIndex]);
|
|
end;
|
|
|
|
{----------------DoTable}
|
|
procedure ThlParser.DoTable(ALevel: integer);
|
|
var
|
|
Table: ThtmlTable;
|
|
SaveSectionList, JunkSaveSectionList: TCell;
|
|
SaveStyle: TFontStyles;
|
|
SaveNoBreak: boolean;
|
|
SaveJustify, RowJustify, TmpJustify: JustifyType;
|
|
RowVAlign, VAlign: AlignmentType;
|
|
Row: TCellList;
|
|
CellObj: TCellObj;
|
|
T: TAttribute;
|
|
SaveIndex: integer;
|
|
|
|
function GetJustify: JustifyType;
|
|
var
|
|
S: string[9];
|
|
T: TAttribute;
|
|
begin
|
|
Result := NoJustify;
|
|
if Attributes.Find(AlignSy, T) then
|
|
begin
|
|
S := LowerCase(T.Name);
|
|
if S = 'left' then Result := Left
|
|
else if S = 'center' then Result := Centered
|
|
else if S = 'right' then Result := Right;
|
|
end;
|
|
end;
|
|
|
|
function GetVAlign(Default: AlignmentType): AlignmentType;
|
|
var
|
|
S: string[9];
|
|
T: TAttribute;
|
|
begin
|
|
Result := Default;
|
|
if Attributes.Find(VAlignSy, T) then
|
|
begin
|
|
S := LowerCase(T.Name);
|
|
if (S = 'top') or (S = 'baseline') then Result := ATop
|
|
else if S = 'middle' then Result := AMiddle
|
|
else if S = 'bottom' then Result := ABottom;
|
|
end;
|
|
end;
|
|
|
|
procedure AddSection;
|
|
begin
|
|
if Assigned(SectionList) then
|
|
begin
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
if CellObj.Cell = SectionList then
|
|
Row.Add(CellObj)
|
|
else SectionList.Free; {won't happen}
|
|
SectionList := Nil;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if InHref then DoAEnd; {terminate <a>}
|
|
SaveIndex := StackIndex;
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
SaveSectionList := SectionList;
|
|
SaveJustify := Justify;
|
|
SaveStyle := CurrentStyle;
|
|
SaveNoBreak := NoBreak;
|
|
SectionList := Nil;
|
|
Table := ThtmlTable.Create(MasterList, Attributes, Justify, SaveSectionList, ALevel);
|
|
Row := Nil;
|
|
RowJustify := NoJustify;
|
|
RowVAlign := AMiddle;
|
|
Next;
|
|
while (Sy <> TableEndSy) and (Sy <> EofSy) do
|
|
case Sy of
|
|
TDSy, THSy:
|
|
Begin
|
|
if InHref then DoAEnd;
|
|
while StackIndex > SaveIndex do
|
|
PopFont; {terminate any <font> introduced in table}
|
|
CurrentStyle := SaveStyle;
|
|
if Attributes.Find(NoWrapSy, T) and not Attributes.Find(WidthSy, T) then
|
|
NoBreak := True
|
|
else NoBreak := False;
|
|
if not Assigned(Row) then {in case <tr> is missing}
|
|
begin
|
|
Row := TCellList.Create;
|
|
RowJustify := NoJustify;
|
|
RowVAlign := AMiddle;
|
|
end
|
|
else AddSection;
|
|
if Sy = THSy then
|
|
begin
|
|
if RowJustify = NoJustify then
|
|
Justify := Centered {default <TH> is centered}
|
|
else Justify := RowJustify;
|
|
CurrentStyle := CurrentStyle + [fsBold];
|
|
end
|
|
else
|
|
begin
|
|
if RowJustify = NoJustify then
|
|
Justify := Left {default <TD> is Left}
|
|
else Justify := RowJustify;
|
|
CurrentStyle := CurrentStyle - [fsBold];
|
|
end;
|
|
TmpJustify := GetJustify; {see if there is Align override}
|
|
if TmpJustify <> NoJustify then
|
|
Justify := TmpJustify;
|
|
VAlign := GetVAlign(RowVAlign);
|
|
CellObj := TCellObj.Create(MasterList, VAlign, Attributes);
|
|
SectionList := CellObj.Cell;
|
|
SkipWhiteSpace;
|
|
Next;
|
|
NoPSpace := True;
|
|
DoBody(0, TableTermSet);
|
|
end;
|
|
CaptionSy:
|
|
begin
|
|
if InHref then DoAEnd;
|
|
while StackIndex > SaveIndex do
|
|
PopFont; {terminate any <font> introduced in table}
|
|
CurrentStyle := SaveStyle;
|
|
NoBreak := False;
|
|
AddSection;
|
|
if Attributes.Find(AlignSy, T) then
|
|
Table.TopCaption := Lowercase(T.Name) <> 'bottom';
|
|
SectionList := Table.Caption.Cell;
|
|
Justify := Centered;
|
|
Next;
|
|
DoBody(0, TableTermSet);
|
|
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
SectionList := Nil;
|
|
if Sy = CaptionEndSy then Next; {else it's TDSy, THSy, etc}
|
|
end;
|
|
TREndSy:
|
|
begin
|
|
if InHref then DoAEnd;
|
|
if Assigned(Row) then
|
|
begin
|
|
AddSection;
|
|
Table.Rows.Add(Row);
|
|
Row := Nil;
|
|
end;
|
|
Next;
|
|
end;
|
|
TRSy:
|
|
begin
|
|
if InHref then DoAEnd;
|
|
if Assigned(Row) then
|
|
begin
|
|
AddSection;
|
|
Table.Rows.Add(Row);
|
|
end;
|
|
Row := TCellList.Create;
|
|
RowJustify := GetJustify;
|
|
RowVAlign := GetVAlign(AMiddle);
|
|
Row.DoAttributes(Attributes);
|
|
Next;
|
|
end;
|
|
TDEndSy, THEndSy:
|
|
begin AddSection; Next; end;
|
|
TextSy:
|
|
begin
|
|
JunkSaveSectionList := SectionList;
|
|
SectionList := SaveSectionList; {the original one}
|
|
DoBody(0, TableTermSet);
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
SectionList := JunkSaveSectionList;
|
|
end;
|
|
else Next; {ignore all else}
|
|
end;
|
|
if InHref then DoAEnd;
|
|
while StackIndex > SaveIndex do
|
|
PopFont; {terminate any <font> introduced in table}
|
|
AddSection;
|
|
if Assigned(Row) then
|
|
Table.Rows.Add(Row);
|
|
SectionList := SaveSectionList;
|
|
SectionList.Add(Table);
|
|
CurrentStyle := SaveStyle;
|
|
NoBreak := SaveNoBreak;
|
|
Justify := SaveJustify;
|
|
Next;
|
|
end;
|
|
|
|
procedure ThlParser.GetOptions(Select: TListBoxFormControlObj);
|
|
{get the <option>s for Select form control}
|
|
var
|
|
Selected, InOption: boolean;
|
|
{$IFDEF HL_LAZARUS}
|
|
Answer, S: string[255];
|
|
{$ELSE}
|
|
Value, S: string[255];
|
|
{$ENDIF}
|
|
T: TAttribute;
|
|
SaveNoBreak: boolean;
|
|
begin
|
|
SaveNoBreak := NoBreak;
|
|
NoBreak := False;
|
|
Next;
|
|
{$IFDEF HL_LAZARUS}
|
|
S := ''; Answer := '';
|
|
{$ELSE}
|
|
S := ''; Value := '';
|
|
{$ENDIF}
|
|
Selected := False; InOption := False;
|
|
while not (Sy in[SelectEndSy, EofSy]) do
|
|
begin
|
|
case Sy of
|
|
OptionSy, OptionEndSy:
|
|
begin
|
|
S := Trim(S);
|
|
if S <> '' then
|
|
begin
|
|
if InOption then
|
|
{$IFDEF HL_LAZARUS}
|
|
Select.AddStr(S, Answer, Selected);
|
|
{$ELSE}
|
|
Select.AddStr(S, Value, Selected);
|
|
{$ENDIF}
|
|
S := '';
|
|
{$IFDEF HL_LAZARUS}
|
|
Answer := '';
|
|
{$ELSE}
|
|
Value := '';
|
|
{$ENDIF}
|
|
Selected := False;
|
|
end;
|
|
InOption := Sy = OptionSy;
|
|
if InOption then
|
|
begin
|
|
Selected := Attributes.Find(SelectedSy, T);
|
|
if Attributes.Find(ValueSy, T) then
|
|
{$IFDEF HL_LAZARUS}
|
|
Answer := T.Name;
|
|
{$ELSE}
|
|
Value := T.Name;
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
TextSy: if InOption then
|
|
S := S+LCToken.S;
|
|
end;
|
|
Next;
|
|
end;
|
|
if InOption then
|
|
begin
|
|
S := Trim(S);
|
|
if S <> '' then
|
|
{$IFDEF HL_LAZARUS}
|
|
Select.AddStr(S, Answer, Selected);
|
|
{$ELSE}
|
|
Select.AddStr(S, Value, Selected);
|
|
{$ENDIF}
|
|
end;
|
|
NoBreak := SaveNoBreak;
|
|
end;
|
|
|
|
function GetColor(S: String; Var Value: TColor): boolean;
|
|
const
|
|
ColorValues: array[1..16] of TColor =
|
|
(clBLACK, clMAROON, clGREEN, clOLIVE, clNAVY, clPURPLE, clTEAL, clGRAY,
|
|
clSILVER, clRED, clLIME, clYELLOW, clBLUE, clFUCHSIA, clAQUA, clWHITE);
|
|
|
|
const
|
|
Colors: array[1..16] of string[7] =
|
|
('BLACK', 'MAROON', 'GREEN', 'OLIVE', 'NAVY', 'PURPLE', 'TEAL', 'GRAY',
|
|
'SILVER', 'RED', 'LIME', 'YELLOW', 'BLUE', 'FUCHSIA', 'AQUA', 'WHITE');
|
|
var
|
|
Red, Blue: integer;
|
|
I: integer;
|
|
S1: string[10];
|
|
begin
|
|
GetColor := False;
|
|
if Length(S) > 0 then
|
|
begin
|
|
S1 := Uppercase(S);
|
|
for I := 1 to 16 do
|
|
if S1 = Colors[I] then
|
|
begin
|
|
Value := ColorValues[I];
|
|
GetColor := True;
|
|
Exit;
|
|
end;
|
|
try
|
|
I := Pos('#', S); {apparently # is allowed}
|
|
if I > 0 then Delete(S, I, 1);
|
|
while Length(S) < 6 do
|
|
S := S+'0';
|
|
Value := StrToInt('$'+S); {but bytes are backwards!}
|
|
Red := Value and $FF;
|
|
Blue := Value and $FF0000;
|
|
Value := (Value and $00FF00) + (Red shl 16) + (Blue shr 16);
|
|
GetColor := True;
|
|
except
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{----------------DoMap}
|
|
procedure ThlParser.DoMap;
|
|
var
|
|
Item: TMapItem;
|
|
T: TAttribute;
|
|
ErrorCnt: integer;
|
|
begin
|
|
Item := TMapItem.Create;
|
|
ErrorCnt := 0;
|
|
try
|
|
if Attributes.Find(NameSy, T) then
|
|
Item.MapName := Uppercase(T.Name);
|
|
Next;
|
|
while (Sy <> MapEndSy) and (Sy <> EofSy) and (ErrorCnt < 3) do
|
|
begin
|
|
if Sy = AreaSy then Item.AddArea(Attributes)
|
|
else if Sy <> TextSy then
|
|
Inc(ErrorCnt);
|
|
Next;
|
|
end;
|
|
if Sy = MapEndSy then MasterList.MapList.Add(Item)
|
|
else Item.Free;
|
|
except
|
|
Item.Free;
|
|
Raise;
|
|
end;
|
|
Next;
|
|
end;
|
|
|
|
procedure ThlParser.DoScript(Ascript: TScriptEvent);
|
|
const
|
|
Block = 32500;
|
|
var
|
|
Lang, AName: string;
|
|
T: TAttribute;
|
|
{$IFDEF HL_LAZARUS}
|
|
TempStore: PChar;
|
|
{$ELSE}
|
|
Buffer: PChar;
|
|
{$ENDIF}
|
|
Pos, Size: integer;
|
|
|
|
procedure AddText(const S: string);
|
|
begin
|
|
if Pos + Length(S) >= Size then
|
|
{$IFDEF HL_LAZARUS}
|
|
begin {Delphi 2,3, add to TempStore}
|
|
ReAllocMem(TempStore, Size+10000);
|
|
{$ELSE}
|
|
begin {Delphi 2,3, add to Buffer}
|
|
ReAllocMem(Buffer, Size+10000);
|
|
{$ENDIF}
|
|
Inc(Size, 10000);
|
|
end;
|
|
{$IFDEF HL_LAZARUS}
|
|
Move(S[1], TempStore[Pos], Length(S));
|
|
{$ELSE}
|
|
Move(S[1], Buffer[Pos], Length(S));
|
|
{$ENDIF}
|
|
Inc(Pos, Length(S));
|
|
end;
|
|
|
|
procedure Next1;
|
|
{Special Next routine to get the next token}
|
|
procedure GetTag1; {simplified 'Pick up a Tag' routine}
|
|
var
|
|
Count: integer;
|
|
begin
|
|
LCToken.AddChar('<', SIndex);
|
|
GetCh;
|
|
Sy := CommandSy; {catch all}
|
|
Count := 0;
|
|
while (Ch in ['A'..'Z', '/']) and (Count <= 6) do
|
|
begin
|
|
LCToken.AddChar(LCh, SIndex);
|
|
GetCh;
|
|
Inc(Count);
|
|
end;
|
|
if LCh = '>' then
|
|
begin
|
|
LCToken.AddChar(LCh, SIndex);
|
|
GetCh;
|
|
end;
|
|
if CompareText(LCToken.S, '</script>') = 0 then
|
|
Sy := ScriptEndSy;
|
|
end;
|
|
|
|
begin {already have fresh character loaded here}
|
|
LCToken.Clear;
|
|
if LCh = EofChar then Sy := EofSy
|
|
else if LCh = ^M then
|
|
begin
|
|
Sy := EolSy;
|
|
GetCh;
|
|
end
|
|
else if LCh = '<' then
|
|
GetTag1
|
|
else
|
|
begin
|
|
Sy := TextSy;
|
|
while (Length(LCToken.S) < 100) and not (LCh in [^M, '<', EofChar]) do
|
|
begin
|
|
LCToken.AddChar(LCh, SIndex);
|
|
GetCh;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
try
|
|
if Assigned(AScript) then
|
|
begin
|
|
InScript := True;
|
|
if Attributes.Find(LanguageSy, T) then
|
|
Lang := T.Name
|
|
else Lang := '';
|
|
if Attributes.Find(NameSy, T) then
|
|
AName := T.Name
|
|
else AName := '';
|
|
|
|
{$IFDEF HL_LAZARUS}
|
|
GetMem(TempStore, Block);
|
|
{$ELSE}
|
|
GetMem(Buffer, Block);
|
|
{$ENDIF}
|
|
Pos := 0;
|
|
Size := Block;
|
|
try
|
|
Next1;
|
|
while (Sy <> ScriptEndSy) and (Sy <> EofSy) do
|
|
begin
|
|
if Sy = EolSy then AddText(^M^J)
|
|
else
|
|
AddText(LCToken.S);
|
|
Next1;
|
|
end;
|
|
AddText(#0);
|
|
{$IFDEF HL_LAZARUS}
|
|
ReAllocMem(TempStore, Size);
|
|
AScript(CallingObject, AName, Lang, TempStore);
|
|
{$ELSE}
|
|
ReAllocMem(Buffer, Size);
|
|
AScript(CallingObject, AName, Lang, Buffer);
|
|
{$ENDIF}
|
|
except
|
|
FreeMem(TempStore);
|
|
Raise;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
repeat
|
|
Next1;
|
|
until Sy in [ScriptEndSy, EofSy];
|
|
end;
|
|
finally
|
|
InScript := False;
|
|
end;
|
|
end;
|
|
|
|
{----------------DoCommonSy}
|
|
procedure ThlParser.DoCommonSy(Lev: integer);
|
|
var
|
|
I: integer;
|
|
TxtArea: TTextAreaFormControlObj;
|
|
FormControl: TFormControlObj;
|
|
T: TAttribute;
|
|
TmpJustify, LastAlign: JustifyType;
|
|
Tmp: string;
|
|
|
|
function IncrementFont(Sy: Symb; Pre: boolean): boolean;
|
|
var
|
|
NewSize: integer;
|
|
|
|
function GetSizeIndex(Pre: boolean; Size: integer): integer;
|
|
begin
|
|
for Result := 1 to 7 do
|
|
if Pre and (Size = PreFontConv[Result]) then Exit
|
|
else if Size = FontConv[Result] then Exit;
|
|
Result := -1;
|
|
end;
|
|
|
|
begin
|
|
Result := False;
|
|
NewSize := GetSizeIndex(Pre, FontStack[StackIndex].NormalSize);
|
|
if (Sy = BigSy) then
|
|
begin
|
|
if (NewSize in [1..6]) then Inc(NewSize);
|
|
end
|
|
else
|
|
if NewSize in [2..7] then Dec(NewSize);
|
|
|
|
if PushNewFont then
|
|
begin
|
|
if Pre then NewSize := PreFontConv[NewSize]
|
|
else NewSize := FontConv[NewSize];
|
|
FontStack[StackIndex].SetNormalSize(MasterList, NewSize);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
function ChangeTheFont(Sy: Symb; Pre: boolean): boolean;
|
|
var
|
|
FaceName: string[50];
|
|
NewColor: TColor;
|
|
NewSize, I, K: integer;
|
|
FontResults: set of (Face, Colr, Siz);
|
|
begin
|
|
FontResults := [];
|
|
NewSize := 0; {get rid of warning}
|
|
for I := 0 to Attributes.Count-1 do
|
|
with TAttribute(Attributes[I]) do
|
|
case Which of
|
|
SizeSy:
|
|
begin
|
|
if (Length(Name) >= 2) and (Name[1] in ['+', '-']) then
|
|
Value := BaseFontSize + Value;
|
|
NewSize := IntMax(1, IntMin(7, Value)); {limit 1..7}
|
|
if (Sy = BaseFontSy) then BaseFontSize := NewSize;
|
|
Include(FontResults, Siz);
|
|
end;
|
|
ColorSy:
|
|
if (Sy <> BaseFontSy) and GetColor(Name, NewColor) then Include(FontResults, Colr);
|
|
FaceSy:
|
|
if (Sy <> BaseFontSy) and (Name <> '') then
|
|
begin
|
|
FaceName := Name;
|
|
K := Pos(',', FaceName);
|
|
if K > 0 then
|
|
Delete(FaceName, K, 255);
|
|
FaceName := Trim(FaceName);
|
|
if FaceName <> '' then
|
|
Include(FontResults, Face);
|
|
end;
|
|
end;
|
|
Result := False;
|
|
if ((Sy <> BasefontSy) or (SectionList.Count = 0) and
|
|
(SectionList = MasterList)) and {new font only if at start for Basefont}
|
|
PushNewFont and (FontResults <> []) then
|
|
with FontStack[StackIndex] do
|
|
begin
|
|
if Colr in FontResults then
|
|
Color := NewColor or $2000000;
|
|
if Siz in FontResults then
|
|
begin
|
|
if Pre then NewSize := PreFontConv[NewSize]
|
|
else NewSize := FontConv[NewSize];
|
|
SetNormalSize(MasterList, NewSize);
|
|
end;
|
|
if Face in FontResults then
|
|
Name := FaceName;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
procedure DoPreSy;
|
|
var
|
|
S: TokenObj;
|
|
Tmp: String;
|
|
Done: boolean;
|
|
I, InitialStackIndex: integer;
|
|
|
|
procedure NewSection;
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
S.Clear;
|
|
SectionList.Add(Section);
|
|
Section := TPreFormated.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, Left);
|
|
end;
|
|
|
|
begin
|
|
S := TokenObj.Create;
|
|
try
|
|
SectionList.Add(Section);
|
|
PushNewFont;
|
|
InitialStackIndex := StackIndex;
|
|
with FontStack[StackIndex] do
|
|
begin
|
|
Name := MasterList.PreFontName;
|
|
SetNormalSize(MasterList, 10);
|
|
Fixed := True;
|
|
end;
|
|
Section := TPreformated.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, Left);
|
|
S.Clear;
|
|
PreFormat := True;
|
|
Done := False;
|
|
while not Done do
|
|
case Ch of
|
|
'&': begin
|
|
Next;
|
|
S.Concat(LCToken);
|
|
end;
|
|
'<':
|
|
begin
|
|
Next;
|
|
case Sy of
|
|
PSy, BRSy:
|
|
begin
|
|
NewSection;
|
|
if Ch = ^M then GetCh;
|
|
end;
|
|
|
|
PreEndSy, TDEndSy, THEndSy:
|
|
Done := True;
|
|
|
|
BSy, ISy, BEndSy, IEndSy, EmSy, EmEndSy, StrongSy, StrongEndSy,
|
|
USy, UEndSy, CiteSy, CiteEndSy, VarSy, VarEndSy,
|
|
SSy, SEndSy, StrikeSy, StrikeEndSy:
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
S.Clear;
|
|
case Sy of
|
|
BSy, StrongSy: CurrentStyle := CurrentStyle + [fsBold];
|
|
BEndSy, StrongEndSy: CurrentStyle := CurrentStyle - [fsBold];
|
|
ISy, EmSy, CiteSy, VarSy: CurrentStyle := CurrentStyle + [fsItalic];
|
|
IEndSy, EmEndSy,
|
|
CiteEndSy, VarEndSy: CurrentStyle := CurrentStyle - [fsItalic];
|
|
USy: CurrentStyle := CurrentStyle + [fsUnderline];
|
|
UEndSy: CurrentStyle := CurrentStyle - [fsUnderline];
|
|
SSy, StrikeSy: CurrentStyle := CurrentStyle + [fsStrikeOut];
|
|
SEndSy, StrikeEndSy: CurrentStyle := CurrentStyle - [fsStrikeOut];
|
|
end;
|
|
|
|
TSection(Section).ChangeFont(MasterList, FontStack[StackIndex]);
|
|
end;
|
|
|
|
FontSy, BaseFontSy:
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
S.Clear;
|
|
if ChangeTheFont(Sy, True) then
|
|
TSection(Section).ChangeFont(MasterList, FontStack[StackIndex]);
|
|
end;
|
|
FontEndSy:
|
|
if StackIndex > InitialStackIndex then
|
|
begin
|
|
PopFont;
|
|
Section.AddTokenObj(S, NoBreak);
|
|
S.Clear;
|
|
TSection(Section).ChangeFont(MasterList, FontStack[StackIndex]);
|
|
end;
|
|
ASy:
|
|
for I := 0 to Attributes.Count-1 do
|
|
with TAttribute(Attributes[I]) do
|
|
case Which of
|
|
NameSy:
|
|
if Name <> '' then
|
|
begin
|
|
Tmp := UpperCase(Name);
|
|
{Author may have added '#' by mistake}
|
|
if (Length(Tmp) > 0) and (Tmp[1] = '#') then
|
|
Delete(Tmp, 1, 1);
|
|
NameList.AddObject(Tmp, Section);
|
|
end;
|
|
HRefSy:
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
S.Clear;
|
|
if InHref then DoAEnd;
|
|
if Name <> '' then {also have a string}
|
|
begin
|
|
if Attributes.Find(TargetSy, T) then
|
|
CurrentUrlTarget.Assign(Name, T.Name)
|
|
else CurrentUrlTarget.Assign(Name, '');
|
|
InHref := True;
|
|
PushNewFont;
|
|
with FontStack[StackIndex] do
|
|
begin
|
|
Style := Style + MasterList.UnLine;
|
|
Color := MasterList.HotSpotColor;
|
|
end;
|
|
end;
|
|
Section.HRef(HRefSy, MasterList, CurrentUrlTarget, FontStack[StackIndex]);
|
|
end;
|
|
end;
|
|
AEndSy:
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
S.Clear;
|
|
DoAEnd;
|
|
end;
|
|
ImageSy:
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
TSection(Section).AddImage(Attributes, SectionList, TagIndex, NoBreak);
|
|
S.Clear;
|
|
end;
|
|
InputSy, SelectSy:
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
FormControl := TSection(Section).AddFormControl(Sy, MasterList,
|
|
Attributes, SectionList, TagIndex, NoBreak);
|
|
if Sy = SelectSy then
|
|
GetOptions(FormControl as TListBoxFormControlObj);
|
|
S.Clear;;
|
|
end;
|
|
TextAreaSy:
|
|
Begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
TxtArea := TSection(Section).AddFormControl(TextAreaSy, MasterList,
|
|
Attributes, SectionList, TagIndex, NoBreak) as TTextAreaFormControlObj;
|
|
DoTextArea(TxtArea);
|
|
S.Clear;
|
|
end;
|
|
FormSy:
|
|
CurrentForm := ThtmlForm.Create(MasterList, Attributes);
|
|
FormEndSy:
|
|
CurrentForm := Nil;
|
|
MapSy: DoMap;
|
|
ScriptSy: DoScript(MasterList.ScriptEvent);
|
|
end;
|
|
end;
|
|
^M : begin NewSection; GetCh; end;
|
|
EofChar : Done := True;
|
|
else
|
|
begin {all other chars}
|
|
S.AddChar(LCh, SIndex);
|
|
if Length(S.S) > 200 then
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
S.Clear;
|
|
end;
|
|
GetCh;
|
|
end;
|
|
end;
|
|
Section.AddTokenObj(S, NoBreak);
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
PreFormat := False;
|
|
while StackIndex >= InitialStackIndex do
|
|
PopFont;
|
|
Next;
|
|
finally
|
|
S.Free;
|
|
end;
|
|
end;
|
|
|
|
function CreateFont(HeadNmb: integer; OldFont: TMyFont): TMyFont;
|
|
var
|
|
F : TMyFont;
|
|
Siz: integer;
|
|
begin
|
|
F := TMyFont.Create;
|
|
F.Assign(OldFont);
|
|
case HeadNmb of
|
|
0: Siz := 12; {0 is no heading}
|
|
1: Siz := 24;
|
|
2: Siz := 18;
|
|
3: Siz := 14;
|
|
4: Siz := 12;
|
|
5: Siz := 10;
|
|
6: Siz := 8;
|
|
else Siz := 12;
|
|
end;
|
|
if HeadNmb > 0 then
|
|
F.Style := F.Style + [fsBold];
|
|
F.SetNormalSize(MasterList, Siz);
|
|
Result := F;
|
|
end;
|
|
|
|
begin
|
|
writeln('ThlParser.DoCommonSy A ',SymbNames[Sy]);
|
|
case Sy of
|
|
TextSy :
|
|
begin
|
|
writeln('ThlParser.DoCommonSy B ',Assigned(Section),' ',LCToken.S);
|
|
if not Assigned(Section) then
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, Justify);
|
|
Section.AddTokenObj(LCToken, NoBreak);
|
|
Next;
|
|
end;
|
|
ImageSy:
|
|
begin
|
|
if not Assigned(Section) then
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, Justify);
|
|
TSection(Section).AddImage(Attributes, SectionList, TagIndex, NoBreak);
|
|
Next;
|
|
end;
|
|
InputSy, SelectSy:
|
|
begin
|
|
if not Assigned(Section) then
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, Justify);
|
|
FormControl := TSection(Section).AddFormControl(Sy, MasterList, Attributes, SectionList, TagIndex, NoBreak);
|
|
if Sy = SelectSy then
|
|
GetOptions(FormControl as TListBoxFormControlObj);
|
|
Next;
|
|
end;
|
|
TextAreaSy:
|
|
Begin
|
|
if not Assigned(Section) then
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, Justify);
|
|
TxtArea := TSection(Section).AddFormControl(TextAreaSy, MasterList,
|
|
Attributes, SectionList, TagIndex, NoBreak) as TTextAreaFormControlObj;
|
|
DoTextArea(TxtArea);
|
|
Next;
|
|
end;
|
|
TextAreaEndSy: {a syntax error but shouldn't hang}
|
|
Next;
|
|
FormSy:
|
|
begin
|
|
CurrentForm := ThtmlForm.Create(MasterList, Attributes);
|
|
Next;
|
|
end;
|
|
FormEndSy:
|
|
begin
|
|
CurrentForm := Nil;
|
|
Next;
|
|
end;
|
|
PSy, PEndSy:
|
|
begin
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
if Not NoPSpace then
|
|
SectionList.Add(TParagraphSpace.Create(MasterList));
|
|
SkipWhiteSpace;
|
|
LastAlign := FindAlignment;
|
|
NoPSpace := True;
|
|
Next;
|
|
while Sy in [PSy, PEndSy] do
|
|
begin {recognize only the first <p>}
|
|
LastAlign := FindAlignment; {if a series of <p>, get last alignment}
|
|
SkipWhiteSpace;
|
|
NoPSpace := True;
|
|
Next;
|
|
end;
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, LastAlign);
|
|
end;
|
|
BRSy:
|
|
begin
|
|
if Assigned(Section) then
|
|
TmpJustify := TSection(Section).BreakInfo(TagIndex, NoBreak) {so <br> doesn't change justification}
|
|
else TmpJustify := Justify;
|
|
SectionList.Add(Section);
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, TmpJustify);
|
|
Section.DoClearAttribute(Attributes); {check for clear attribute}
|
|
Next;
|
|
end;
|
|
NoBrSy, NoBrEndSy:
|
|
begin
|
|
NoBreak := Sy = NoBrSy;
|
|
if Assigned(Section) then
|
|
Section.AddTokenObj(LCToken, NoBreak);
|
|
Next;
|
|
end;
|
|
WbrSy:
|
|
begin
|
|
if Assigned(Section) and NoBreak then
|
|
Section.AddChar(' ', TagIndex, NoBreak);
|
|
Next;
|
|
end;
|
|
BSy, ISy, BEndSy, IEndSy, EmSy, EmEndSy, StrongSy, StrongEndSy,
|
|
USy, UEndSy, CiteSy, CiteEndSy, VarSy, VarEndSy,
|
|
SubSy, SubEndSy, SupSy, SupEndSy, SSy, SEndSy, StrikeSy, StrikeEndSy:
|
|
begin
|
|
case Sy of
|
|
BSy, StrongSy: CurrentStyle := CurrentStyle + [fsBold];
|
|
BEndSy, StrongEndSy: CurrentStyle := CurrentStyle - [fsBold];
|
|
ISy, EmSy, CiteSy, VarSy: CurrentStyle := CurrentStyle + [fsItalic];
|
|
IEndSy, EmEndSy,
|
|
CiteEndSy, VarEndSy: CurrentStyle := CurrentStyle - [fsItalic];
|
|
USy: CurrentStyle := CurrentStyle + [fsUnderline];
|
|
UEndSy: CurrentStyle := CurrentStyle - [fsUnderline];
|
|
SSy, StrikeSy: CurrentStyle := CurrentStyle + [fsStrikeOut];
|
|
SEndSy, StrikeEndSy: CurrentStyle := CurrentStyle - [fsStrikeOut];
|
|
SubEndSy, SupEndSy: CurrentSScript := Normal;
|
|
SubSy, SupSy:
|
|
begin
|
|
if not Assigned(Section) then
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, Justify);
|
|
if Sy = SubSy then CurrentSScript := SubSc
|
|
else CurrentSScript := SupSc;
|
|
end;
|
|
end;
|
|
|
|
if Assigned(Section) then {CurrentStyle used in ChangeFont}
|
|
TSection(Section).ChangeFont(MasterList, FontStack[StackIndex]);
|
|
Next;
|
|
end;
|
|
TTSy, CodeSy, KbdSy, SampSy:
|
|
begin
|
|
if PushNewFont then
|
|
begin
|
|
with FontStack[StackIndex] do
|
|
begin
|
|
Name := MasterList.PreFontName;
|
|
SetNormalSize(MasterList, 10);
|
|
Fixed := True;
|
|
end;
|
|
if Assigned(Section) then
|
|
TSection(Section).ChangeFont(MasterList, FontStack[StackIndex]);
|
|
end;
|
|
Next;
|
|
end;
|
|
TTEndSy, CodeEndSy, KbdEndSy, SampEndSy, FontEndSy, BigEndSy, SmallEndSy:
|
|
begin
|
|
PopFont;
|
|
if Assigned(Section) then
|
|
TSection(Section).ChangeFont(MasterList, FontStack[StackIndex]);
|
|
Next;
|
|
end;
|
|
FontSy, BaseFontSy:
|
|
begin
|
|
if ChangeTheFont(Sy, False) and Assigned(Section) then
|
|
TSection(Section).ChangeFont(MasterList, FontStack[StackIndex]);
|
|
Next;
|
|
end;
|
|
BigSy, SmallSy:
|
|
begin
|
|
if IncrementFont(Sy, False) and Assigned(Section) then
|
|
TSection(Section).ChangeFont(MasterList, FontStack[StackIndex]);
|
|
Next;
|
|
end;
|
|
AddressSy:
|
|
begin
|
|
SectionList.Add(Section);
|
|
PushNewFont;
|
|
with FontStack[StackIndex] do
|
|
Style := Style + [fsItalic];
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, Justify);
|
|
Next;
|
|
end;
|
|
AddressEndSy:
|
|
begin
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
PopFont;
|
|
Next;
|
|
end;
|
|
ASy:
|
|
begin
|
|
for I := 0 to Attributes.Count-1 do
|
|
with TAttribute(Attributes[I]) do
|
|
case Which of
|
|
NameSy:
|
|
if Name <> '' then
|
|
begin
|
|
if not Assigned(Section) then
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, Justify);
|
|
Tmp := UpperCase(Name);
|
|
{Author may have added '#' by mistake}
|
|
if (Length(Tmp) > 0) and (Tmp[1] = '#') then
|
|
Delete(Tmp, 1, 1);
|
|
NameList.AddObject(Tmp, Section);
|
|
end;
|
|
HRefSy:
|
|
begin
|
|
if InHref then DoAEnd;
|
|
if Name <> '' then {also have a string}
|
|
begin
|
|
if Attributes.Find(TargetSy, T) then
|
|
CurrentUrlTarget.Assign(Name, T.Name)
|
|
else CurrentUrlTarget.Assign(Name, '');
|
|
InHref := True;
|
|
PushNewFont;
|
|
with FontStack[StackIndex] do
|
|
begin
|
|
Style := Style + MasterList.UnLine;
|
|
Color := MasterList.HotSpotColor;
|
|
end;
|
|
if Assigned(Section) then
|
|
Section.HRef(HRefSy, MasterList, CurrentUrlTarget, FontStack[StackIndex]);
|
|
end;
|
|
end;
|
|
end;
|
|
Next;
|
|
end;
|
|
AEndSy:
|
|
begin
|
|
DoAEnd;
|
|
Next;
|
|
end;
|
|
HeadingSy:
|
|
begin
|
|
if StackIndex < MaxStack then
|
|
begin
|
|
SectionList.Add(Section);
|
|
Inc(StackIndex);
|
|
FontStack[StackIndex] := CreateFont(Value, FontStack[StackIndex-1]);
|
|
SectionList.Add(THeadingSpace.Create(MasterList, Value));
|
|
Section := TSection.Create(MasterList, Lev, FontStack[StackIndex],
|
|
CurrentUrlTarget, FindAlignment);
|
|
end;
|
|
Next;
|
|
end;
|
|
HeadingEndSy:
|
|
begin
|
|
if StackIndex > 1 then
|
|
begin
|
|
SectionList.Add(Section);
|
|
SectionList.Add(THeadingSpace.Create(MasterList, Value));
|
|
Section := Nil;
|
|
PopFont;
|
|
end;
|
|
Next;
|
|
end;
|
|
PreSy: DoPreSy;
|
|
TableSy: DoTable(Lev);
|
|
MapSy: DoMap;
|
|
ScriptSy: begin DoScript(MasterList.ScriptEvent); Next; end;
|
|
end;
|
|
end; {DoCommon}
|
|
|
|
{-------------DoLists}
|
|
procedure ThlParser.DoLists(Level: integer; Sym: Symb; const TermSet: SymbSet);
|
|
var
|
|
LineCount, CurrentLevel: integer;
|
|
T: TAttribute;
|
|
Plain: boolean;
|
|
Index: char;
|
|
|
|
begin
|
|
LineCount := 1;
|
|
Index := '1';
|
|
Plain := False;
|
|
if (Sym = OLSy) then
|
|
begin
|
|
if Attributes.Find(StartSy, T) then
|
|
if T.Value >= 0 then LineCount := T.Value;
|
|
if Attributes.Find(TypeSy, T) and (T.Name <> '') then
|
|
Index := T.Name[1];
|
|
end
|
|
else Plain := (Sym = ULSy) and Attributes.Find(PlainSy, T);
|
|
CurrentLevel := Level;
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
Next;
|
|
if Sy in [OLEndSy, ULEndSy, DirEndSy, MenuEndSy, DLEndSy, BlockQuoteEndSy] then
|
|
Exit; {guard against <ul></ul> and similar combinations}
|
|
repeat
|
|
case Sy of
|
|
LISy:
|
|
begin
|
|
SectionList.Add(Section);
|
|
if Sym = OLSy then
|
|
begin
|
|
Section := TOListItem.Create(MasterList, Level, LineCount, Index,
|
|
FontStack[StackIndex], CurrentUrlTarget);
|
|
Inc(LineCount);
|
|
end
|
|
else Section := TUlistItem.Create(MasterList, Level, FontStack[StackIndex],
|
|
CurrentUrlTarget);
|
|
if (Sym = ULSy) and Plain then
|
|
TUlistItem(Section).Plain := True;
|
|
CurrentLevel := Level;
|
|
SkipWhiteSpace;
|
|
Next;
|
|
if Sy = PSy then Next;
|
|
end;
|
|
DTSy, DDSy:
|
|
begin
|
|
SectionList.Add(Section);
|
|
if Sy = DTSy then
|
|
CurrentLevel := Level-1
|
|
else CurrentLevel := Level;
|
|
Section := TDListItem.Create(MasterList, CurrentLevel, FontStack[StackIndex],
|
|
CurrentUrlTarget);
|
|
Next;
|
|
end;
|
|
OLSy, ULSy, DirSy, MenuSy, DLSy:
|
|
begin
|
|
DoLists(Level+1, Sy, TermSet);
|
|
Next;
|
|
end;
|
|
BlockQuoteSy:
|
|
begin
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
DoLists(Level+1, Sy, TermSet);
|
|
Next;
|
|
end;
|
|
DivSy, CenterSy:
|
|
DoBody(CurrentLevel, [OLEndSy, ULEndSy, DirEndSy, MenuEndSy, DLEndSy,
|
|
BlockQuoteEndSy, EofSy]+TermSet);
|
|
HRSy:
|
|
begin
|
|
SectionList.Add(Section);
|
|
SectionList.Add(THorzLine.Create(MasterList, Attributes));
|
|
Section := Nil;
|
|
Next;
|
|
end;
|
|
TableSy:
|
|
begin
|
|
if Assigned(Section) then
|
|
TSection(Section).BreakInfo(TagIndex, NoBreak);
|
|
DoTable(CurrentLevel);
|
|
end;
|
|
|
|
TextSy, BRSy, PSy, PEndSy,
|
|
BSy, ISy, BEndSy, IEndSy, EmSy, EmEndSy, StrongSy, StrongEndSy,
|
|
USy, UEndSy, CiteSy, CiteEndSy, VarSy, VarEndSy,
|
|
SubSy, SubEndSy, SupSy, SupEndSy, SSy, SEndSy, StrikeSy, StrikeEndSy,
|
|
TTSy, CodeSy, KbdSy, SampSy, TTEndSy, CodeEndSy, KbdEndSy, SampEndSy,
|
|
NameSy, HRefSy, ASy, AEndSy,
|
|
HeadingSy, HeadingEndSy, AddressSy, AddressEndSy, PreSy,
|
|
InputSy, FormSy, FormEndSy, TextAreaSy, TextAreaEndSy, SelectSy,
|
|
ImageSy, FontSy, FontEndSy, BaseFontSy, BigSy, BigEndSy, SmallSy,
|
|
SmallEndSy, MapSy, ScriptSy, NoBrSy, NoBrEndSy, WbrSy:
|
|
DoCommonSy(CurrentLevel);
|
|
else if Sy in TermSet then Exit
|
|
else Next;
|
|
end;
|
|
Until (Sy in [OLEndSy, ULEndSy, DirEndSy, MenuEndSy, DLEndSy,
|
|
BlockQuoteEndSy, EofSy]);
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
end;
|
|
|
|
{----------------DoBase}
|
|
procedure ThlParser.DoBase;
|
|
var
|
|
I: integer;
|
|
begin
|
|
with Attributes do
|
|
for I := 0 to Count-1 do
|
|
with TAttribute(Attributes[I]) do
|
|
if Which = HrefSy then
|
|
Base := Name
|
|
else if Which = TargetSy then
|
|
BaseTarget := Name;
|
|
Next;
|
|
end;
|
|
|
|
procedure ThlParser.DoSoundEvent;
|
|
begin
|
|
SoundEvent(CallingObject, ATName, ALoop, False);
|
|
end;
|
|
|
|
{----------------DoSound}
|
|
procedure ThlParser.DoSound;
|
|
var
|
|
T, T1: TAttribute;
|
|
begin
|
|
if Assigned(SoundEvent) and Attributes.Find(SrcSy, T) then
|
|
begin
|
|
if Attributes.Find(LoopSy, T1) then ALoop := T1.Value
|
|
else ALoop := 1;
|
|
ATName := T.Name;
|
|
TParseThread(ParseThread).Synchronize(
|
|
{$IFDEF HL_LAZARUS}@{$ENDIF}DoSoundEvent);
|
|
end;
|
|
Next;
|
|
end;
|
|
|
|
function ThlParser.TranslateCharset(DefCharset: TFontCharset;
|
|
const {$IFDEF HL_LAZARUS}NewContent{$ELSE}Content{$ENDIF}: string): TFontCharset;
|
|
type
|
|
XRec = record S: string; CSet: TFontCharset; end;
|
|
const
|
|
MaxX = 14;
|
|
XTable: array[1..MaxX] of XRec =
|
|
((S:'1252'; CSet:ANSI_CHARSET),
|
|
(S:'8859-1'; CSet:ANSI_CHARSET),
|
|
(S:'1253'; CSet:GREEK_CHARSET),
|
|
(S:'8859-7'; CSet:GREEK_CHARSET),
|
|
(S:'1250'; CSet:EASTEUROPE_CHARSET),
|
|
(S:'8859-2'; CSet:EASTEUROPE_CHARSET),
|
|
(S:'1251'; CSet:RUSSIAN_CHARSET),
|
|
(S:'8859-5'; CSet:RUSSIAN_CHARSET),
|
|
(S:'koi8-r'; CSet:RUSSIAN_CHARSET),
|
|
(S:'1254'; CSet:TURKISH_CHARSET),
|
|
(S:'8859-3'; CSet:TURKISH_CHARSET),
|
|
(S:'8859-9'; CSet:TURKISH_CHARSET),
|
|
(S:'1257'; CSet:BALTIC_CHARSET),
|
|
(S:'8859-4'; CSet:BALTIC_CHARSET));
|
|
var
|
|
I: integer;
|
|
begin
|
|
Result := DefCharset;
|
|
for I := 1 to MaxX do
|
|
if Pos(XTable[I].S,
|
|
Lowercase({$IFDEF HL_LAZARUS}NewContent{$ELSE}Content{$ENDIF})) > 0
|
|
then
|
|
Begin
|
|
Result := XTable[I].CSet;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
procedure ThlParser.DoMetaEvent;
|
|
begin
|
|
MetaEvent(CallingObject, HttpEq, ATName, Content);
|
|
end;
|
|
|
|
{----------------DoMeta}
|
|
procedure ThlParser.DoMeta(Sender: TObject);
|
|
var
|
|
T: TAttribute;
|
|
{$ifdef ver100_plus}
|
|
Charset: TFontCharset;
|
|
{$endif}
|
|
begin
|
|
if Attributes.Find(HttpEqSy, T) then HttpEq := T.Name
|
|
else HttpEq := '';
|
|
if Attributes.Find(NameSy, T) then ATName := T.Name
|
|
else ATName := '';
|
|
if Attributes.Find(ContentSy, T) then Content := T.Name
|
|
else Content := '';
|
|
{$ifdef ver100_plus}
|
|
if (Sender is ThtmlLite) and (CompareText(HttpEq, 'content-type') = 0) then
|
|
begin
|
|
CharSet := TranslateCharset(TSectionList(SectionList).Charset, Content);
|
|
FontStack[StackIndex].Charset := Charset;
|
|
end;
|
|
{$endif}
|
|
if Assigned(MetaEvent) then
|
|
TParseThread(ParseThread).Synchronize({$IFDEF HL_LAZARUS}@{$ENDIF}DoMetaEvent);
|
|
Next;
|
|
end;
|
|
|
|
{----------------DoTitle}
|
|
procedure ThlParser.DoTitle;
|
|
begin
|
|
Title := '';
|
|
Next;
|
|
while Sy = TextSy do
|
|
begin
|
|
Title := Title+LCToken.S;
|
|
Next;
|
|
end;
|
|
end;
|
|
|
|
{-------------DoBody}
|
|
procedure ThlParser.DoBody(Level: integer; const TermSet: SymbSet);
|
|
var
|
|
I, SaveIndent: integer;
|
|
Val: TColor;
|
|
T: TAttribute;
|
|
SaveJustify: JustifyType;
|
|
S: string[10];
|
|
SaveSy: Symb;
|
|
|
|
begin
|
|
repeat
|
|
writeln('ThlParser.DoBody ',SymbNames[Sy]);
|
|
case Sy of
|
|
TextSy, BRSy, PSy, PEndSy,
|
|
NameSy, HRefSy, ASy, AEndSy,
|
|
BSy, ISy, BEndSy, IEndSy, EmSy, EmEndSy, StrongSy, StrongEndSy,
|
|
USy, UEndSy, CiteSy, CiteEndSy, VarSy, VarEndSy,
|
|
SubSy, SubEndSy, SupSy, SupEndSy, SSy, SEndSy, StrikeSy, StrikeEndSy,
|
|
TTSy, CodeSy, KbdSy, SampSy, TTEndSy, CodeEndSy, KbdEndSy, SampEndSy,
|
|
HeadingSy, HeadingEndSy, AddressSy, AddressEndSy, PreSy, TableSy,
|
|
InputSy, FormSy, FormEndSy, TextAreaSy, TextAreaEndSy, SelectSy,
|
|
ImageSy, FontSy, FontEndSy, BaseFontSy, BigSy, BigEndSy, SmallSy,
|
|
SmallEndSy, MapSy, ScriptSy, NoBrSy, NoBrEndSy, WbrSy:
|
|
DoCommonSy(Level);
|
|
BodySy:
|
|
begin
|
|
if SectionList.Count = 0 then {make sure we're at beginning}
|
|
begin
|
|
writeln('ThlParser.DoBody B ',SymbNames[Sy],' ');
|
|
Section.Free; {Will start with a new section}
|
|
for I := 0 to Attributes.Count-1 do
|
|
with TAttribute(Attributes[I]) do
|
|
case Which of
|
|
BackgroundSy: MasterList.SetBackgroundBitmap(Name);
|
|
TextSy: if GetColor(Name, Val) then
|
|
begin
|
|
FontStack[StackIndex].Color := Val or $2000000;
|
|
MasterList.FontColor := Val or $2000000;
|
|
end;
|
|
BGColorSy: if GetColor(Name, Val) then MasterList.SetBackGround(Val or $2000000);
|
|
LinkSy: if GetColor(Name, Val) then MasterList.HotSpotColor := Val or $2000000;
|
|
VLinkSy: if GetColor(Name, Val) then MasterList.LinkVisitedColor := Val or $2000000;
|
|
OLinkSy: if GetColor(Name, Val) then
|
|
begin
|
|
MasterList.LinkActiveColor := Val or $2000000;
|
|
MasterList.LinksActive := True;
|
|
end;
|
|
MarginWidthSy:
|
|
if CallingObject is ThtmlLite then
|
|
ThtmlLite(CallingObject).FMarginWidthX := IntMin(IntMax(0,Value), 200);
|
|
MarginHeightSy:
|
|
if CallingObject is ThtmlLite then
|
|
ThtmlLite(CallingObject).FMarginHeightX := IntMin(IntMax(0,Value), 200);
|
|
end;
|
|
Section := TSection.Create(MasterList, Level, FontStack[1], Nil, Justify);
|
|
end;
|
|
Next;
|
|
end;
|
|
HRSy:
|
|
begin
|
|
SectionList.Add(Section);
|
|
SectionList.Add(THorzLine.Create(MasterList, Attributes));
|
|
Section := Nil;
|
|
Next;
|
|
end;
|
|
OLSy, ULSy, DirSy, MenuSy, DLSy:
|
|
begin
|
|
DoLists(1, Sy, TermSet);
|
|
Next;
|
|
end;
|
|
LiSy:
|
|
if Level = 0 then
|
|
begin
|
|
SectionList.Add(Section);
|
|
SaveIndent := ListIndent;
|
|
ListIndent := SmallListIndent;
|
|
Section := TUlistItem.Create(MasterList, 1, FontStack[StackIndex],
|
|
CurrentUrlTarget);
|
|
SkipWhiteSpace;
|
|
Next;
|
|
while Sy in [TextSy, NoBrSy, NoBrEndSy, WbrSy, BSy, ISy, BEndSy, IEndSy,
|
|
EmSy, EmEndSy, StrongSy, StrongEndSy, USy, UEndSy, CiteSy,
|
|
CiteEndSy, VarSy, VarEndSy, SubSy, SubEndSy, SupSy, SupEndSy,
|
|
SSy, SEndSy, StrikeSy, StrikeEndSy, TTSy, CodeSy, KbdSy, SampSy,
|
|
TTEndSy, CodeEndSy, KbdEndSy, SampEndSy, FontEndSy, BigEndSy,
|
|
SmallEndSy, BigSy, SmallSy, ASy, AEndSy] do
|
|
begin
|
|
DoCommonSy(1);
|
|
end;
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
ListIndent := SaveIndent;
|
|
end
|
|
else Next;
|
|
BlockQuoteSy:
|
|
begin
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
DoLists(1, Sy, TermSet);
|
|
Next;
|
|
end;
|
|
DivSy, CenterSy:
|
|
begin
|
|
SaveSy := Sy;
|
|
SectionList.Add(Section);
|
|
SaveJustify := Justify;
|
|
if SaveSy = CenterSy then
|
|
Justify := Centered
|
|
else
|
|
if Attributes.Find(AlignSy, T) then
|
|
begin
|
|
S := LowerCase(T.Name);
|
|
if S = 'left' then Justify := Left
|
|
else if S = 'center' then Justify := Centered
|
|
else if S = 'right' then Justify := Right;
|
|
end;
|
|
Section := TSection.Create(MasterList, Level, FontStack[StackIndex],
|
|
CurrentUrlTarget, Justify);
|
|
Next;
|
|
DoBody(Level, [CenterEndSy, DivEndSy]+TermSet);
|
|
SectionList.Add(Section);
|
|
Justify := SaveJustify;
|
|
Section := TSection.Create(MasterList, Level, FontStack[StackIndex],
|
|
CurrentUrlTarget, Justify);
|
|
if Sy in [CenterEndSy, DivEndSy] then
|
|
Next;
|
|
end;
|
|
TitleSy:
|
|
DoTitle;
|
|
BgSoundSy:
|
|
DoSound;
|
|
MetaSy:
|
|
DoMeta(CallingObject);
|
|
BaseSy:
|
|
DoBase;
|
|
else if Sy in TermSet then Exit
|
|
else Next;
|
|
end;
|
|
Until (Sy = EofSy);
|
|
Next;
|
|
end;
|
|
|
|
procedure ThlParser.ParseInit(ASectionList: TList; ANameList: TStringList; AIncludeEvent: TIncludeType);
|
|
begin
|
|
SectionList := TSectionList(ASectionList);
|
|
MasterList := TSectionList(SectionList);
|
|
CallingObject := TSectionList(ASectionList).TheOwner;
|
|
IncludeEvent := AIncludeEvent;
|
|
NameList := ANameList;
|
|
PreFormat := False;
|
|
StackIndex := 1;
|
|
FontStack[1] := TMyFont.Create;
|
|
FontStack[1].Name := MasterList.FontName;
|
|
FontStack[1].Color := MasterList.FontColor;
|
|
FontStack[1].SetNormalSize(MasterList, 12);
|
|
{$ifdef ver100_plus}
|
|
FontStack[1].Charset := TSectionList(SectionList).Charset;
|
|
{$endif}
|
|
CurrentURLTarget := TUrlTarget.Create;
|
|
InHref := False;
|
|
BaseFontSize := 3;
|
|
|
|
Title := '';
|
|
Base := '';
|
|
BaseTarget := '';
|
|
Justify := Left;
|
|
CurrentStyle := [];
|
|
CurrentForm := Nil;
|
|
Section := TSection.Create(MasterList, 0, FontStack[1], Nil, Justify);
|
|
Attributes := TAttributeList.Create;
|
|
SIndex := -1;
|
|
InScript := False;
|
|
NoPSpace := False;
|
|
NoBreak := False;
|
|
end;
|
|
|
|
{----------------ThlParser.HtmlParseString}
|
|
procedure ThlParser.HtmlParseString(ASectionList: TList; ANameList: TStringList;
|
|
AIncludeEvent: TIncludeType; ASoundEvent: TSoundType;
|
|
AMetaEvent: TMetaType);
|
|
begin
|
|
LoadStyle := lsPrimary;
|
|
ParseInit(ASectionList, ANameList, AIncludeEvent);
|
|
SoundEvent := ASoundEvent;
|
|
MetaEvent := AMetaEvent;
|
|
Buffer := TParseThread(ParseThread).Buffer;
|
|
BuffEnd := TParseThread(ParseThread).BuffEnd;
|
|
try
|
|
try
|
|
GetCh; {get the reading started}
|
|
Next;
|
|
DoBody(0, []);
|
|
except
|
|
On EParseError do; {ignore this error}
|
|
end;
|
|
finally
|
|
Attributes.Free;
|
|
if Assigned(Section) then
|
|
SectionList.Add(Section);
|
|
while StackIndex >= 1 do
|
|
begin
|
|
FontStack[StackIndex].Free;
|
|
Dec(StackIndex);
|
|
end;
|
|
CurrentURLTarget.Free;
|
|
end;
|
|
end;
|
|
|
|
{----------------DoText}
|
|
procedure ThlParser.DoText;
|
|
var
|
|
S: TokenObj;
|
|
Done: boolean;
|
|
|
|
procedure NewSection;
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
S.Clear;
|
|
SectionList.Add(Section);
|
|
Section := TPreFormated.Create(MasterList, 0, FontStack[StackIndex], CurrentURLTarget, Left);
|
|
end;
|
|
|
|
begin
|
|
S := TokenObj.Create;
|
|
try
|
|
SectionList.Add(Section);
|
|
PushNewFont;
|
|
with FontStack[StackIndex] do
|
|
begin
|
|
Name := MasterList.PreFontName;
|
|
SetNormalSize(MasterList, 10);
|
|
Fixed := True;
|
|
end;
|
|
Section := TPreformated.Create(MasterList, 0, FontStack[StackIndex],
|
|
CurrentURLTarget, Left);
|
|
PreFormat := True;
|
|
Done := False;
|
|
while not Done do
|
|
case Ch of
|
|
^M : begin NewSection; GetCh; end;
|
|
EofChar : Done := True;
|
|
else
|
|
begin {all other chars}
|
|
S.AddChar(LCh, SIndex);
|
|
if Length(S.S) > 200 then
|
|
begin
|
|
Section.AddTokenObj(S, NoBreak);
|
|
S.Clear;
|
|
end;
|
|
GetCh;
|
|
end;
|
|
end;
|
|
Section.AddTokenObj(S, NoBreak);
|
|
SectionList.Add(Section);
|
|
Section := Nil;
|
|
PreFormat := False;
|
|
PopFont;
|
|
finally
|
|
S.Free;
|
|
end;
|
|
end;
|
|
|
|
{-------------HtmlParseTextString}
|
|
procedure ThlParser.HtmlParseTextString(ASectionList: TList; ANameList: TStringList);
|
|
begin
|
|
LoadStyle := lsPrimary;
|
|
ParseInit(ASectionList, ANameList, Nil);
|
|
SoundEvent := Nil;
|
|
MetaEvent := NIl;
|
|
Buffer := TParseThread(ParseThread).Buffer;
|
|
BuffEnd := TParseThread(ParseThread).BuffEnd;
|
|
|
|
try
|
|
try
|
|
GetCh; {get the reading started}
|
|
DoText;
|
|
except
|
|
On EParseError do; {ignore this error}
|
|
end;
|
|
|
|
finally
|
|
Attributes.Free;
|
|
if Assigned(Section) then
|
|
SectionList.Add(Section);
|
|
while StackIndex >= 1 do
|
|
begin
|
|
FontStack[StackIndex].Free;
|
|
Dec(StackIndex);
|
|
end;
|
|
end; {finally}
|
|
end;
|
|
|
|
constructor ThlParser.Create;
|
|
begin
|
|
inherited;
|
|
LCToken := TokenObj.Create;
|
|
end;
|
|
|
|
destructor ThlParser.Destroy;
|
|
begin
|
|
LCToken.Free;
|
|
inherited;
|
|
end;
|
|
|
|
|
|
end.
|
|
|