├── demo-delphi ├── HtmParser.dpr ├── Unit1.dfm ├── Unit1.pas └── HtmParser.dproj ├── README.md ├── htmtool.pas ├── demo-console └── project1.lpr ├── arrhtmlparser.pas ├── fasthtmlparser.pas └── htmutils.pas /demo-delphi/HtmParser.dpr: -------------------------------------------------------------------------------- 1 | program HtmParser; 2 | 3 | uses 4 | Vcl.Forms, 5 | Unit1 in 'Unit1.pas' {Form1}; 6 | 7 | {$R *.res} 8 | 9 | begin 10 | Application.Initialize; 11 | Application.MainFormOnTaskbar := True; 12 | Application.CreateForm(TForm1, Form1); 13 | Application.Run; 14 | end. 15 | -------------------------------------------------------------------------------- /demo-delphi/Unit1.dfm: -------------------------------------------------------------------------------- 1 | object Form1: TForm1 2 | Left = 0 3 | Top = 0 4 | Caption = 'Form1' 5 | ClientHeight = 507 6 | ClientWidth = 714 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -13 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | PixelsPerInch = 120 15 | TextHeight = 16 16 | object Button1: TButton 17 | Left = 486 18 | Top = 446 19 | Width = 189 20 | Height = 25 21 | Caption = 'Get Element By Name' 22 | TabOrder = 0 23 | end 24 | object Memo1: TMemo 25 | Left = 60 26 | Top = 26 27 | Width = 619 28 | Height = 409 29 | Lines.Strings = ( 30 | 'Memo1') 31 | TabOrder = 1 32 | end 33 | object bGetElementByID: TButton 34 | Left = 486 35 | Top = 474 36 | Width = 189 37 | Height = 25 38 | Caption = 'Get Element By ID' 39 | TabOrder = 2 40 | OnClick = bGetElementByIDClick 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /demo-delphi/Unit1.pas: -------------------------------------------------------------------------------- 1 | unit Unit1; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, 8 | fasthtmlparser; 9 | 10 | type 11 | TForm1 = class(TForm) 12 | Button1: TButton; 13 | Memo1: TMemo; 14 | bGetElementByID: TButton; 15 | procedure bGetElementByIDClick(Sender: TObject); 16 | private 17 | { Private declarations } 18 | public 19 | { Public declarations } 20 | end; 21 | 22 | var 23 | Form1: TForm1; 24 | 25 | implementation 26 | 27 | {$R *.dfm} 28 | 29 | procedure TForm1.bGetElementByIDClick(Sender: TObject); 30 | var 31 | s: string; 32 | Hp: THtmlParser; 33 | InnerHtml, Tag, TagEnd: string; 34 | begin 35 | s := '
some text
text about something
'; 36 | Hp := THtmlParser.Create(s); 37 | InnerHtml := Hp.GetElementById('divbox1', Tag, TagEnd); 38 | Memo1.Lines.Add('Element name: divbox1'); 39 | Memo1.Lines.Add('Element Inner HTML: '); 40 | Memo1.Lines.Add(InnerHtml); 41 | Memo1.Lines.Add('Tag: '); 42 | Memo1.Lines.Add(Tag); 43 | 44 | Hp.Free; Hp := nil; 45 | end; 46 | 47 | end. 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fast HTML Parser 2 | HTML Parser for FPC and Delphi originally written by Jazarsoft 3 | 4 | * Modified for use as a pure command line unit (no dialogs) for freepascal. 5 | * Also added UPPERCASE tags so that when you check for i.e. it returns 6 | all tags like < FONT > and < FoNt > and < font > 7 | 8 | ## Versions 9 | Revision 18 is Version 1 of this tool 10 | 11 | After revision 18 version 2 of the tool is being worked on with more object methods to access 12 | elements by Name or ID for example just like a DOM. 13 | 14 | ## Todo 15 | * keep the entire HTML file in an array for later usage: htmltags[] and text[] 16 | * parse like this: OnSection(opentag, text, closetag); as a different parser 17 | kind so that globals are not needed to keep track of InTag booleans, etc. 18 | so that all are together, tag, text, closing tag, in the same procedure 19 | * associate a number (open tag) with the text label using a record or such 20 | i.e. < body > < b >some text< / b >< / body > 21 | where < b > is tag "2" and some text is text "1" 22 | * turn into a DLL using FPC or C so that other languages can use a callback 23 | to parse html fast in that language (i.e. golang, python, etc.) 24 | 25 | Use this parser for what reasons: 26 | * make your own web browsers, 27 | * make your own text copies of web pages for caching purposes 28 | * Grab content from websites -without- using regular expressions 29 | * Seems to be MUCH MUCH FASTER than regular expressions, as it is after all 30 | a true parser 31 | * convert website tables into spreadsheets (parse TD and TR, turn in to 32 | CSV or similar) 33 | * convert websites into txt files 34 | * convert website tables into CSV/Database (parse TD and TR) 35 | * find certain info from a web page.. i.e. all the bold text or hyperlinks in 36 | a page. 37 | * Parse websites remotely from a CGI app using something like Sockets or 38 | Synapse and SynWrap to first get the HTML site. This would allow you to 39 | dynamically parse info from websites and display data on your site in real 40 | time. 41 | * HTML editor.. WYSIWYG or a partial WYSIWYG editor. Ambitious, but possible. 42 | * HTML property editor. Not completely wysiwyg but ability to edit proprties 43 | of tags. Work would need to be done to parse each property in a tag. 44 | 45 | 46 | -------------------------------------------------------------------------------- /htmtool.pas: -------------------------------------------------------------------------------- 1 | unit htmtool; {$IFDEF FPC}{$MODE OBJFPC}{$H+}{$ENDIF} 2 | 3 | interface 4 | 5 | function IsTag(TagType: string; Tag: string): boolean; 6 | function IsCloseTag(TagType: string; Tag: string): boolean; 7 | function Substr(sub, s: string): boolean; 8 | function StripTabs(s: string): string; 9 | function ReturnsToSpaces(s: string): string; 10 | function LessenSpaces(s: string): string; 11 | function CleanHtm1(s: string): string; 12 | 13 | implementation 14 | 15 | uses 16 | sysutils; 17 | { strips tabs, lessens spaces, converts returns to spaces } 18 | 19 | function CleanHtm1(s: string): string; 20 | begin 21 | result:= s; 22 | result:= stripTabs(result); 23 | result:= ReturnsToSpaces(result); 24 | result:= LessenSpaces(result); 25 | end; 26 | 27 | { strips double spaces into single spaces (recursively) } 28 | function LessenSpaces(s: string): string; 29 | var 30 | found: integer; 31 | begin 32 | result:= ''; 33 | result:= s; 34 | found:= 0; 35 | repeat 36 | result:= stringreplace(result, ' ', ' ', [rfReplaceAll]); 37 | found:= pos(' ', result); 38 | until found < 1; 39 | end; 40 | 41 | { strips tabs } 42 | function StripTabs(s: string): string; 43 | const 44 | TABCHAR = #9; 45 | begin 46 | result:= ''; 47 | result:= stringreplace(s, TABCHAR, '', [rfReplaceAll]); 48 | end; 49 | 50 | { strips returns but replaces them with spaces } 51 | function ReturnsToSpaces(s: string): string; 52 | const 53 | CR = #13; 54 | LF = #10; 55 | begin 56 | result:= ''; 57 | result:= s; 58 | result:= stringreplace(result, CR+LF, ' ', [rfReplaceAll]); 59 | result:= stringreplace(result, CR, ' ', [rfReplaceAll]); 60 | result:= stringreplace(result, LF, ' ', [rfReplaceAll]); 61 | end; 62 | 63 | // same as POS but returns boolean 64 | function Substr(sub, s: string): boolean; 65 | begin 66 | result:= false; 67 | if pos(sub, s) > 0 then result:= true; 68 | end; 69 | 70 | // is a '' 71 | function IsCloseTag(TagType: string; Tag: string): boolean; 72 | begin 73 | result:= false; 74 | if uppercase(Tag) = '' then result:= true; 75 | end; 76 | 77 | // is a '' or '', TagUp) > 0) or 87 | (pos('<' +TypeUp+' ', TagUp) > 0) 88 | then 89 | result:= true; 90 | 91 | end; 92 | 93 | end. 94 | -------------------------------------------------------------------------------- /demo-console/project1.lpr: -------------------------------------------------------------------------------- 1 | { Demo for fast html parser 2 | 3 | Try arrays } 4 | 5 | program project1; 6 | 7 | {$mode objfpc}{$H+} 8 | 9 | uses 10 | fasthtmlparser, // html parser 11 | arrhtmlparser, // same as fasthtmlparser but stores all tags/text in an array for later use 12 | sysutils; 13 | 14 | const 15 | HTMStringA = '

some text

text in bold tag more text

more bold

and the end of html'; 16 | var 17 | InBold: boolean = false; 18 | 19 | procedure msg(s: string); 20 | begin writeln(s); 21 | end; 22 | 23 | procedure msg(s1,s2: string); 24 | begin writeln(s1,s2); 25 | end; 26 | 27 | procedure msg(s1: string; i: integer); 28 | begin writeln(s1,i); 29 | end; 30 | 31 | 32 | // TOnFoundTagP = procedure(NoCaseTag, ActualTag: string); 33 | // TOnFoundTextP = procedure(Text: string); 34 | 35 | procedure ExOnTag(NoCaseTag, ActualTag: string); 36 | begin 37 | if NoCaseTag = '' then begin 38 | InBold := true; 39 | msg('bold start'); 40 | end; 41 | 42 | if NoCaseTag = '' then begin 43 | InBold := false; 44 | msg('bold end'); 45 | end; 46 | end; 47 | 48 | procedure ExOnText(Text: string); 49 | begin 50 | if InBold then begin 51 | msg('Text tag: ', Text); 52 | end; 53 | end; 54 | 55 | procedure Example1; 56 | var 57 | hp: THTMLParser; 58 | begin 59 | hp := THTMLParser.create(HTMStringA); 60 | hp.OnFoundTagP := @ExOnTag; 61 | hp.OnFoundTextP := @ExOnText; 62 | hp.Exec; 63 | hp.free; hp := nil; 64 | end; 65 | 66 | procedure Example2; 67 | var 68 | ahp: TArrHTMLParser; 69 | i: integer; 70 | begin 71 | ahp := TArrHTMLParser.create(HTMStringA); 72 | ahp.OnFoundTagP := @ExOnTag; 73 | ahp.OnFoundTextP := @ExOnText; 74 | ahp.Exec; 75 | msg('Printing all tag items:'); 76 | msg('Length of Tags array: ',length(ahp.Tags)); 77 | // print out all tags in array 78 | for i := low(ahp.Tags) to high(ahp.Tags) do begin 79 | writeln(i,':',ahp.Tags[i]); 80 | end; 81 | msg('Printing all text items:'); 82 | msg('Length of Texts array: ', length(ahp.Texts)); 83 | // print out all texts in array 84 | for i := low(ahp.Texts) to high(ahp.Texts) do begin 85 | writeln(i,':',ahp.Texts[i]); 86 | end; 87 | ahp.free; ahp := nil; 88 | end; 89 | 90 | procedure Line; 91 | begin writeln('-----------------------------------------------'); 92 | end; 93 | 94 | begin 95 | Example1; 96 | Line; 97 | Example2; 98 | Line; 99 | ReadLn; // pause program on exit for to quit 100 | end. 101 | 102 | -------------------------------------------------------------------------------- /arrhtmlparser.pas: -------------------------------------------------------------------------------- 1 | {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | Array Html Parser 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | 5 | Original AUTHOR : James Azarja, http://www.jazarsoft.com/ 6 | 7 | CONTRIBUTORS : L505, http://z505.com 8 | 9 | NOTES: Same as FastHTMLParser but uses array to keep track of text and tags 10 | 11 | OTHER IDEAS: 12 | * associate start opening tag with text.. i.e. sometext 13 | where b is tag no. 2 associated to sometext is text no. 1 14 | 15 | LEGAL : Copyright (C) 2004 Jazarsoft, All Rights Reserved. 16 | Modified 2005 Lars (L505) 17 | -------------------------------------------------------------------------------- 18 | LICENSE/TERMS 19 | -------------------------------------------------------------------------------- 20 | 21 | This code may be used and modified by anyone so long as this header and 22 | copyright information remains intact. 23 | 24 | The code is provided "AS-IS" and without WARRANTY OF ANY KIND, 25 | expressed, implied or otherwise, including and without limitation, any 26 | warranty of merchantability or fitness for a particular purpose. 27 | 28 | In no event shall the author be liable for any special, incidental, 29 | indirect or consequential damages whatsoever (including, without 30 | limitation, damages for loss of profits, business interruption, loss 31 | of information, or any other loss), whether or not advised of the 32 | possibility of damage, and on any theory of liability, arising out of 33 | or in connection with the use or inability to use this software. 34 | } 35 | 36 | {$IFDEF FPC}{$MODE DELPHI}{$H+}{$ENDIF} 37 | 38 | // {$DEFINE DEBUGLN_ON} 39 | 40 | unit arrhtmlparser; 41 | 42 | interface 43 | 44 | uses 45 | {$IFDEF KOL_MCK}KOL;{$else}SysUtils;{$ENDIF} 46 | {$IFDEF DEBUGLN_ON} 47 | // dummy, default debugging 48 | procedure debugproc(s: string); 49 | // for custom debugging, assign this in your units 50 | var debugln: procedure(s: string) = debugproc; 51 | {$ENDIF} 52 | 53 | type 54 | 55 | // when tag content found in HTML, including names and values 56 | // case insensitive analysis available via NoCaseTag 57 | TOnFoundTag = procedure(NoCaseTag, ActualTag: string) of object; 58 | // procedural: 59 | TOnFoundTagP = procedure(NoCaseTag, ActualTag: string); 60 | 61 | // when text found in the HTML 62 | TOnFoundText = procedure(Text: string) of object; 63 | // procedural: 64 | TOnFoundTextP = procedure(Text: string); 65 | 66 | // Lars's modified html parser, case insensitive or case sensitive 67 | TArrHTMLParser = class(TObject) 68 | private 69 | procedure NilOnFoundTag(NoCaseTag, ActualTag: string); 70 | procedure NilOnFoundText(Text: string); 71 | public 72 | UseArrays: boolean; // store all html in tags[] and texts[] arrays for later access 73 | Tags: array of string; // keeps the whole file in an array of tags 74 | Texts: array of string; // and texts 75 | OnFoundTag: TOnFoundTag; 76 | OnFoundText: TOnFoundText; 77 | OnFoundTagP: TOnFoundTagP; 78 | OnFoundTextP: TOnFoundTextP; 79 | Raw: Pchar; 80 | constructor Create(sRaw: string);overload; 81 | constructor Create(pRaw: PChar);overload; 82 | procedure Exec; 83 | end; 84 | 85 | implementation 86 | 87 | // default debugging, do nothing, let user do his own by assigning DebugLn var 88 | procedure debugproc(s: string); 89 | begin 90 | end; 91 | 92 | function CopyBuffer(StartIndex: PChar; Length: Integer): string; 93 | var 94 | S: string; 95 | begin 96 | SetLength(S, Length); 97 | StrLCopy(@S[1], StartIndex, Length); 98 | Result:= S; 99 | end; 100 | 101 | 102 | { ************************ THTMLParser ************************************** } 103 | 104 | constructor TArrHTMLParser.Create(pRaw: Pchar); 105 | begin 106 | if pRaw = '' then exit; 107 | if pRaw = nil then exit; 108 | Raw:= pRaw; 109 | UseArrays := true; 110 | end; 111 | 112 | constructor TArrHTMLParser.Create(sRaw: string); 113 | begin 114 | // if sRaw = '' then exit; 115 | // Raw:= Pchar(sRaw); 116 | Create(pchar(sRaw)); 117 | end; 118 | 119 | { default dummy "do nothing" class events if unassigned } 120 | procedure TArrHTMLParser.NilOnFoundTag(NoCaseTag, ActualTag: string); 121 | begin 122 | end; 123 | 124 | procedure TArrHTMLParser.NilOnFoundText(Text: string); 125 | begin 126 | end; 127 | 128 | { default dummy "do nothing" procedural events if unassigned } 129 | procedure NilOnFoundTagP(NoCaseTag, ActualTag: string); 130 | begin 131 | end; 132 | 133 | procedure NilOnFoundTextP(Text: string); 134 | begin 135 | end; 136 | 137 | procedure TArrHTMLParser.Exec; 138 | var 139 | L, TL, I: integer; 140 | Done: Boolean; 141 | TagStart, TextStart, P: PChar; // Pointer to current char. 142 | C: Char; 143 | OldTagsLen, OldTextsLen: integer; 144 | begin 145 | {$IFDEF DEBUGLN_ON}debugln('FastHtmlParser Exec Begin');{$ENDIF} 146 | { set nil events once rather than checking for nil each time tag is found } 147 | if not assigned(OnFoundText) then OnFoundText:= NilOnFoundText; 148 | if not assigned(OnFoundTag) then OnFoundTag:= NilOnFoundTag; 149 | if not assigned(OnFoundTextP) then OnFoundTextP:= NilOnFoundTextP; 150 | if not assigned(OnFoundTagP) then OnFoundTagP:= NilOnFoundTagP; 151 | 152 | TL:= StrLen(Raw); 153 | I:= 0; 154 | P:= Raw; 155 | Done:= False; 156 | if P <> nil then 157 | begin 158 | TagStart:= nil; 159 | repeat 160 | TextStart:= P; 161 | { Get next tag position } 162 | while Not (P^ in [ '<', #0 ]) do 163 | begin 164 | Inc(P); Inc(I); 165 | if I >= TL then 166 | begin 167 | Done:= True; 168 | Break; 169 | end; 170 | end; 171 | if Done then Break; 172 | 173 | { Is there any text before ? } 174 | if (TextStart <> nil) and (P > TextStart) then 175 | begin 176 | L:= P - TextStart; 177 | { Yes, copy to buffer, OO event:} 178 | OnFoundText( CopyBuffer(TextStart, L) ); 179 | // procedural: 180 | OnFoundTextP( CopyBuffer(TextStart, L) ); 181 | if UseArrays then begin // new code 182 | OldTextsLen := length(Texts); 183 | setlength(Texts, OldTextsLen+1); 184 | Texts[OldTextsLen] := CopyBuffer(TextStart, L); 185 | end; 186 | end else 187 | begin 188 | TextStart:= nil; 189 | end; 190 | { No } 191 | 192 | TagStart:= P; 193 | while Not (P^ in [ '>', #0]) do 194 | begin 195 | // Find string in tag 196 | if (P^ = '"') or (P^ = '''') then 197 | begin 198 | C:= P^; 199 | Inc(P); Inc(I); // Skip current char " or ' 200 | 201 | // Skip until string end 202 | while Not (P^ in [C, #0]) do 203 | begin 204 | Inc(P);Inc(I); 205 | end; 206 | end; 207 | 208 | Inc(P);Inc(I); 209 | if I >= TL then 210 | begin 211 | Done:= True; 212 | Break; 213 | end; 214 | end; 215 | if Done then Break; 216 | 217 | { Copy this tag to buffer } 218 | L:= P - TagStart + 1; 219 | // OO event 220 | OnFoundTag(uppercase(CopyBuffer(TagStart, L)), CopyBuffer(TagStart, L ) ); //L505: added uppercase 221 | // procedural 222 | OnFoundTagP(uppercase(CopyBuffer(TagStart, L)), CopyBuffer(TagStart, L ) ); 223 | if UseArrays then begin // new code 224 | OldTagsLen := length(Tags); 225 | setlength(Tags, OldTagsLen+1); 226 | Tags[OldTagsLen] := CopyBuffer(TagStart, L); 227 | end; 228 | 229 | Inc(P); Inc(I); 230 | if I >= TL then Break; 231 | until (Done); 232 | end; 233 | {$IFDEF DEBUGLN_ON}debugln('FastHtmlParser Exec End');{$ENDIF} 234 | end; 235 | 236 | 237 | end. 238 | 239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /fasthtmlparser.pas: -------------------------------------------------------------------------------- 1 | {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | FastHTMLParser unit to parse HTML 3 | (disect html into its tags and text.) 4 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5 | 6 | Original AUTHOR : James Azarja, http://www.jazarsoft.com/ 7 | 8 | CONTRIBUTORS : L505, http://z505.com 9 | 10 | NOTES: Modified by Lars to work with both freepascal and delphi, and contains 11 | more features 12 | 13 | LEGAL : Copyright (C) 2004 Jazarsoft, All Rights Reserved. 14 | Modified 2005 Lars (L505) 15 | -------------------------------------------------------------------------------- 16 | LICENSE/TERMS 17 | -------------------------------------------------------------------------------- 18 | 19 | This code may be used and modified by anyone so long as this header and 20 | copyright information remains intact. 21 | 22 | The code is provided "AS-IS" and without WARRANTY OF ANY KIND, 23 | expressed, implied or otherwise, including and without limitation, any 24 | warranty of merchantability or fitness for a particular purpose. 25 | 26 | In no event shall the author be liable for any special, incidental, 27 | indirect or consequential damages whatsoever (including, without 28 | limitation, damages for loss of profits, business interruption, loss 29 | of information, or any other loss), whether or not advised of the 30 | possibility of damage, and on any theory of liability, arising out of 31 | or in connection with the use or inability to use this software. 32 | } 33 | 34 | {$IFDEF FPC}{$MODE DELPHI}{$H+}{$ENDIF} 35 | 36 | 37 | // {$DEFINE DEBUGLN_ON} 38 | 39 | unit fasthtmlparser; 40 | 41 | 42 | interface 43 | 44 | uses 45 | {$IFDEF KOL_MCK} 46 | KOL, 47 | {$else} 48 | SysUtils, 49 | {$ENDIF} 50 | Dialogs, //DEBUG REMOVE THIS LATER 51 | htmtool, htmutils; 52 | 53 | 54 | {$IFDEF DEBUGLN_ON} 55 | // dummy, default debugging 56 | procedure debugproc(s: string); 57 | // for custom debugging, assign this in your units 58 | var debugln: procedure(s: string) = debugproc; 59 | {$ENDIF} 60 | 61 | type 62 | 63 | // when tag content found in HTML, including names and values 64 | // case insensitive analysis available via NoCaseTag 65 | TOnFoundTag = procedure(NoCaseTag, ActualTag: string) of object; 66 | // procedural: 67 | TOnFoundTagP = procedure(NoCaseTag, ActualTag: string); 68 | 69 | // when text found in the HTML 70 | TOnFoundText = procedure(Text: string) of object; 71 | // procedural: 72 | TOnFoundTextP = procedure(Text: string); 73 | 74 | // Lars's modified html parser, case insensitive or case sensitive 75 | THTMLParser = class(TObject) 76 | private 77 | FElementFound: boolean; 78 | FElementTag: string; 79 | FElementTagEnd: string; 80 | FElementHtml: string; 81 | FElementName: string; 82 | FElementId: string; 83 | FFindingElementName: boolean; 84 | FFindingElementId: boolean; 85 | procedure NilOnFoundTag(NoCaseTag, ActualTag: string); 86 | procedure NilOnFoundText(Text: string); 87 | procedure ElementOnFoundTag(NoCaseTag, ActualTag: string); 88 | procedure ElementOnFoundText(Text: string); 89 | public 90 | UseTagTextArray: boolean; 91 | OnFoundTag: TOnFoundTag; 92 | OnFoundText: TOnFoundText; 93 | OnFoundTagP: TOnFoundTagP; 94 | OnFoundTextP: TOnFoundTextP; 95 | Raw: Pchar; 96 | constructor Create(sRaw: string);overload; 97 | constructor Create(pRaw: PChar);overload; 98 | procedure Exec; 99 | function GetElementByName(name: string; var Tag: string; var TagEnd: string): string; 100 | function GetElementById(id: string; var Tag: string; var TagEnd: string): string; 101 | end; 102 | 103 | 104 | implementation 105 | 106 | 107 | // default debugging, do nothing, let user do his own by assigning DebugLn var 108 | procedure debugproc(s: string); 109 | begin 110 | end; 111 | 112 | function CopyBuffer(StartIndex: PChar; Length: Integer): string; 113 | var 114 | S: string; 115 | begin 116 | SetLength(S, Length); 117 | StrLCopy(@S[1], StartIndex, Length); 118 | Result:= S; 119 | end; 120 | 121 | { ************************ THTMLParser ************************************** } 122 | 123 | constructor THTMLParser.Create(pRaw: Pchar); 124 | begin 125 | if pRaw = '' then exit; 126 | if pRaw = nil then exit; 127 | Raw:= pRaw; 128 | FElementFound := false; 129 | FElementTag := ''; 130 | FElementTagEnd := ''; 131 | FElementHtml := ''; 132 | FElementName := ''; 133 | FElementId := ''; 134 | FFindingElementName := false; 135 | FFindingElementId := false; 136 | end; 137 | 138 | constructor THTMLParser.Create(sRaw: string); 139 | begin 140 | if sRaw = '' then exit; 141 | Raw:= Pchar(sRaw); 142 | end; 143 | 144 | { default dummy "do nothing" class events if unassigned } 145 | procedure THTMLParser.NilOnFoundTag(NoCaseTag, ActualTag: string); 146 | begin 147 | end; 148 | 149 | procedure THTMLParser.NilOnFoundText(Text: string); 150 | begin 151 | end; 152 | 153 | procedure THTMLParser.ElementOnFoundTag(NoCaseTag, ActualTag: string); 154 | begin 155 | // tags inside 156 | if FElementFound then FElementHtml := FElementHtml + ActualTag; 157 | 158 | if (FElementId <> '') and (FFindingElementName) then begin 159 | if GetVal(ActualTag, 'name') = FElementName then begin 160 | FElementFound := true; 161 | FElementTag := ActualTag; 162 | // FElementName := ''; 163 | end; 164 | end; 165 | 166 | if (FElementId <> '') and (FFindingElementId) then begin 167 | if GetVal(ActualTag, 'id') = FElementId then begin 168 | FElementFound := true; 169 | FElementTag := ActualTag; 170 | // FElementId := ''; 171 | end; 172 | end; 173 | // closer tag 174 | if NoCaseTag[2] = '/' then FElementFound := false; 175 | end; 176 | 177 | procedure THTMLParser.ElementOnFoundText(Text: string); 178 | begin 179 | if FElementFound then begin 180 | FElementHtml := FElementHtml + Text; 181 | end; 182 | end; 183 | 184 | { default dummy "do nothing" procedural events if unassigned } 185 | procedure NilOnFoundTagP(NoCaseTag, ActualTag: string); 186 | begin 187 | end; 188 | 189 | procedure NilOnFoundTextP(Text: string); 190 | begin 191 | end; 192 | 193 | procedure THTMLParser.Exec; 194 | var 195 | L, TL, I: Integer; 196 | Done: Boolean; 197 | TagStart, TextStart, P: PChar; // Pointer to current char. 198 | C: Char; 199 | begin 200 | {$IFDEF DEBUGLN_ON}debugln('FastHtmlParser Exec Begin');{$ENDIF} 201 | { set nil events once rather than checking for nil each time tag is found } 202 | if not assigned(OnFoundText) then OnFoundText:= NilOnFoundText; 203 | if not assigned(OnFoundTag) then OnFoundTag:= NilOnFoundTag; 204 | if not assigned(OnFoundTextP) then OnFoundTextP:= NilOnFoundTextP; 205 | if not assigned(OnFoundTagP) then OnFoundTagP:= NilOnFoundTagP; 206 | 207 | TL:= StrLen(Raw); 208 | I:= 0; 209 | P:= Raw; 210 | Done:= False; 211 | if P <> nil then 212 | begin 213 | TagStart:= nil; 214 | repeat 215 | TextStart:= P; 216 | { Get next tag position } 217 | while Not (P^ in [ '<', #0 ]) do 218 | begin 219 | Inc(P); Inc(I); 220 | if I >= TL then 221 | begin 222 | Done:= True; 223 | Break; 224 | end; 225 | end; 226 | if Done then Break; 227 | 228 | { Is there any text before ? } 229 | if (TextStart <> nil) and (P > TextStart) then 230 | begin 231 | L:= P - TextStart; 232 | { Yes, copy to buffer, OO event:} 233 | OnFoundText( CopyBuffer(TextStart, L) ); 234 | // procedural: 235 | OnFoundTextP( CopyBuffer(TextStart, L) ); 236 | end else 237 | begin 238 | TextStart:= nil; 239 | end; 240 | { No } 241 | 242 | TagStart:= P; 243 | while Not (P^ in [ '>', #0]) do 244 | begin 245 | // Find string in tag 246 | if (P^ = '"') or (P^ = '''') then 247 | begin 248 | C:= P^; 249 | Inc(P); Inc(I); // Skip current char " or ' 250 | 251 | // Skip until string end 252 | while Not (P^ in [C, #0]) do 253 | begin 254 | Inc(P);Inc(I); 255 | end; 256 | end; 257 | 258 | Inc(P);Inc(I); 259 | if I >= TL then 260 | begin 261 | Done:= True; 262 | Break; 263 | end; 264 | end; 265 | if Done then Break; 266 | 267 | { Copy this tag to buffer } 268 | L:= P - TagStart + 1; 269 | // OO event 270 | OnFoundTag(uppercase(CopyBuffer(TagStart, L)), CopyBuffer(TagStart, L ) ); //L505: added uppercase 271 | // procedural 272 | OnFoundTagP(uppercase(CopyBuffer(TagStart, L)), CopyBuffer(TagStart, L ) ); 273 | 274 | Inc(P); Inc(I); 275 | if I >= TL then Break; 276 | until (Done); 277 | end; 278 | {$IFDEF DEBUGLN_ON}debugln('FastHtmlParser Exec End');{$ENDIF} 279 | end; 280 | 281 | function THTMLParser.GetElementByName(name: string; var Tag: string; var TagEnd: string): string; 282 | begin 283 | result := ''; 284 | FFindingElementName := true; 285 | OnFoundTag := ElementOnFoundTag; 286 | OnFoundText := ElementOnFoundText; 287 | FElementName := name; 288 | Exec; 289 | OnFoundTag := NilOnFoundTag; 290 | OnFoundText := NilOnFoundText; 291 | Tag := FElementTag; 292 | TagEnd := FElementTagEnd; 293 | result := FElementHtml; 294 | FFindingElementName := false; 295 | FElementTag := ''; 296 | FElementTagEnd := ''; 297 | FElementHtml := ''; 298 | FElementId := ''; 299 | FElementName := ''; 300 | end; 301 | 302 | function THTMLParser.GetElementById(id: string; var Tag: string; var TagEnd: string): string; 303 | begin 304 | result := ''; 305 | FFindingElementId := true; 306 | OnFoundTag := ElementOnFoundTag; 307 | OnFoundText := ElementOnFoundText; 308 | FElementId := id; 309 | Exec; 310 | OnFoundTag := NilOnFoundTag; 311 | OnFoundText := NilOnFoundText; 312 | Tag := FElementTag; 313 | TagEnd := FElementTagEnd; 314 | result := FElementHtml; 315 | FFindingElementId := false; 316 | FElementTag := ''; 317 | FElementTagEnd := ''; 318 | FElementHtml := ''; 319 | FElementId := ''; 320 | FElementName := ''; 321 | end; 322 | 323 | end. 324 | 325 | -------------------------------------------------------------------------------- /htmutils.pas: -------------------------------------------------------------------------------- 1 | { modified from jsFastHtmlParser for use with freepascal 2 | 3 | Original Author: 4 | James Azarja 5 | 6 | Contributor: 7 | Lars aka L505 8 | http://z505.com } 9 | 10 | unit HtmUtils; {$ifdef fpc} {$MODE OBJFPC} {$H+}{$endif} 11 | 12 | interface 13 | 14 | { most commonly used } 15 | function GetVal(const tag, attribname_ci: string): string; 16 | function GetTagName(const Tag: string): string; 17 | function GetUpTagName(const tag: string): string; 18 | 19 | { less commonly used, but useful } 20 | function GetNameValPair(const tag, attribname_ci: string): string; 21 | function GetValFromNameVal(const namevalpair: string): string; 22 | 23 | { rarely needed nAmE= case sensitivity } 24 | function GetNameValPair_cs(const tag, attribname: string): string; 25 | 26 | { old code with bugs from James } 27 | function GetVal_JAMES(const tag, attribname_ci: string): string; 28 | function GetNameValPair_JAMES(const tag, attribname_ci: string): string; 29 | 30 | { other utilities } 31 | function CopyBuffer(StartIndex: PChar; Len: integer): string; 32 | function Ucase(s: string): string; 33 | 34 | implementation 35 | 36 | // Note: use sysutils if you have problems with your Win64/other platform 37 | uses 38 | {$IFDEF FPC}CompactSysUtils{$ELSE}Sysutils{$ENDIF}; 39 | 40 | function CopyBuffer(StartIndex: PChar; Len: integer): string; 41 | var s : String; 42 | begin 43 | SetLength(s, Len); 44 | StrLCopy(@s[1], StartIndex, Len); 45 | result:= s; 46 | end; 47 | 48 | { upper case } 49 | function Ucase(s: string): string; 50 | begin 51 | {$IFDEF FPC}result:= upcase(s);{$ELSE}result:= uppercase(s);{$ENDIF} 52 | end; 53 | 54 | { return value of attrib, NAME case ignored, VALUE case preserved } 55 | function GetVal(const tag, attribname_ci: string): string; 56 | var nameval: string; 57 | begin 58 | result:= ''; 59 | if tag = '' then exit; 60 | if attribname_ci = '' then exit; 61 | // returns full name=value pair 62 | nameval:= GetNameValPair(tag, attribname_ci); 63 | // extracts value portion only 64 | result:= GetValFromNameVal(nameval); 65 | end; 66 | 67 | { Return tag name, case preserved } 68 | function GetTagName(const tag: string): string; 69 | var 70 | P : Pchar; 71 | S : Pchar; 72 | begin 73 | P := Pchar(tag); 74 | while P^ in ['<',' ',#9] do inc(P); 75 | S := P; 76 | while Not (P^ in [' ','>',#0]) do inc(P); 77 | if P > S then 78 | Result := CopyBuffer( S, P-S); 79 | end; 80 | 81 | { Return tag name in uppercase } 82 | function GetUpTagName(const tag: string): string; 83 | var 84 | P : Pchar; 85 | S : Pchar; 86 | begin 87 | result:= ''; 88 | if tag = '' then exit; 89 | P := Pchar(Ucase(tag)); 90 | while P^ in ['<',' ',#9] do inc(P); 91 | S := P; 92 | while Not (P^ in [' ','>',#0]) do inc(P); 93 | if P > S then 94 | Result := CopyBuffer( S, P-S); 95 | end; 96 | 97 | 98 | { Return name=value pair ignore case of NAME, preserve case of VALUE 99 | Lars' fixed version } 100 | function GetNameValPair(const tag, attribname_ci: string): string; 101 | var 102 | P : Pchar; 103 | S : Pchar; 104 | UpperTag, 105 | UpperAttrib : string; 106 | Start: integer; 107 | L : integer; 108 | C : char; 109 | begin 110 | result:= ''; 111 | if tag = '' then exit; 112 | if attribname_ci = '' then exit; 113 | // must be space before case insensitive NAME, i.e. nil then 120 | begin 121 | inc(S); // skip space 122 | P:= S; 123 | 124 | // Skip until hopefully equal sign 125 | while not (P^ in ['=', ' ', '>', #0]) do 126 | inc(P); 127 | 128 | if (P^ = '=') then inc(P); 129 | 130 | while not (P^ in [' ','>',#0]) do 131 | begin 132 | if (P^ in ['"','''']) then 133 | begin 134 | C:= P^; 135 | inc(P); { Skip quote } 136 | end else 137 | C:= ' '; 138 | 139 | { thanks to Dmitry [mail@vader.ru] } 140 | while not (P^ in [C, '>', #0]) do 141 | Inc(P); 142 | 143 | if (P^ <> '>') then inc(P); { Skip current character, except '>' } 144 | 145 | break; 146 | end; 147 | 148 | L:= P - S; 149 | Start:= S - Pchar(UpperTag); 150 | P:= Pchar(Tag); 151 | S:= P; 152 | inc(S, Start); 153 | 154 | result:= CopyBuffer(S, L); 155 | end; 156 | end; 157 | 158 | { Get value of attribute, e.g WIDTH=36 returns 36, preserves case of value } 159 | function GetValFromNameVal(const namevalpair: string): string; 160 | var 161 | P: Pchar; 162 | S: Pchar; 163 | C: Char; 164 | begin 165 | result:= ''; 166 | if namevalpair = '' then exit; 167 | P:= Pchar(namevalpair); 168 | S:= StrPos(P, '='); 169 | 170 | if S <> nil then 171 | begin 172 | inc(S); // skip equal 173 | P:= S; // set P to a character after = 174 | 175 | if (P^ in ['"','''']) then 176 | begin 177 | C:= P^; 178 | Inc(P); { Skip current character } 179 | end else 180 | C:= ' '; 181 | 182 | S:= P; 183 | while not (P^ in [C, #0]) do 184 | inc(P); 185 | 186 | if (P <> S) then { Thanks to Dave Keighan (keighand@yahoo.com) } 187 | Result:= CopyBuffer(S, P - S) 188 | else 189 | Result:= ''; 190 | end; 191 | end; 192 | 193 | { return name=value portion, case sensitive, case preserved, rarely useful } 194 | function GetNameValPair_cs(const Tag, attribname: string): string; 195 | var 196 | P : Pchar; 197 | S : Pchar; 198 | C : Char; 199 | begin 200 | result:= ''; 201 | if tag = '' then exit; 202 | if attribname = '' then exit; 203 | P := Pchar(Tag); 204 | S := StrPos(P, Pchar(attribname)); 205 | if S<>nil then 206 | begin 207 | P := S; 208 | 209 | // Skip attribute name 210 | while not (P^ in ['=',' ','>',#0]) do 211 | inc(P); 212 | 213 | if (P^ = '=') then inc(P); 214 | 215 | while not (P^ in [' ','>',#0]) do 216 | begin 217 | 218 | if (P^ in ['"','''']) then 219 | begin 220 | C:= P^; 221 | inc(P); { Skip current character } 222 | end else 223 | C:= ' '; 224 | 225 | { thanks to Dmitry [mail@vader.ru] } 226 | while not (P^ in [C, '>', #0]) do 227 | inc(P); 228 | 229 | if (P^<>'>') then inc(P); { Skip current character, except '>' } 230 | break; 231 | end; 232 | 233 | if P > S then 234 | Result:= CopyBuffer(S, P - S) 235 | else 236 | Result:= ''; 237 | end; 238 | end; 239 | 240 | 241 | { ---------------------------------------------------------------------------- 242 | BELOW FUNCTIONS ARE OBSOLETE OR RARELY NEEDED SINCE THEY EITHER CONTAIN BUGS 243 | OR THEY ARE TOO CASE SENSITIVE (FOR THE TAG NAME PORTION OF THE ATTRIBUTE } 244 | 245 | { James old buggy code for testing purposes. 246 | Bug: when finding 'ID', function finds "width", even though width <> "id" } 247 | function GetNameValPair_JAMES(const tag, attribname_ci: string): string; 248 | var 249 | P : Pchar; 250 | S : Pchar; 251 | UT, 252 | UA : string; 253 | Start: integer; 254 | L : integer; 255 | C : char; 256 | begin 257 | UA:= Ucase(attribname_ci); 258 | UT:= Ucase(Tag); 259 | P:= Pchar(UT); 260 | S:= StrPos(P, Pchar(UA)); 261 | if S <> nil then 262 | begin 263 | 264 | P := S; 265 | 266 | // Skip attribute name 267 | while not (P^ in ['=',' ','>',#0]) do 268 | inc(P); 269 | 270 | if (P^ = '=') then inc(P); 271 | 272 | while not (P^ in [' ','>',#0]) do 273 | begin 274 | 275 | if (P^ in ['"','''']) then 276 | begin 277 | C:= P^; 278 | inc(P); { Skip current character } 279 | end else 280 | C:= ' '; 281 | 282 | { thanks to Dmitry [mail@vader.ru] } 283 | while not (P^ in [C, '>', #0]) do 284 | Inc(P); 285 | 286 | if (P^ <> '>') then inc(P); { Skip current character, except '>' } 287 | break; 288 | end; 289 | 290 | L:= P - S; 291 | Start:= S - Pchar(UT); 292 | P:= Pchar(Tag); 293 | S:= P; 294 | inc(S, Start); 295 | result:= CopyBuffer(S, L); 296 | end; 297 | end; 298 | 299 | 300 | { James old buggy code for testing purposes } 301 | function GetVal_JAMES(const tag, attribname_ci: string): string; 302 | var namevalpair: string; 303 | begin 304 | namevalpair:= GetNameValPair_JAMES(tag, attribname_ci); 305 | result:= GetValFromNameVal(namevalpair); 306 | end; 307 | 308 | 309 | end. 310 | 311 | 312 | 313 | 314 | 315 | (* alternative, not needed 316 | 317 | { return value (case preserved) from a name=value pair, ignores case in given NAME= portion } 318 | function GetValFromNameVal(namevalpair: string): string; 319 | 320 | type 321 | TAttribPos = record 322 | startpos: longword; // start pos of value 323 | len: longword; // length of value 324 | end; 325 | 326 | { returns case insensitive start position and length of just the value 327 | substring in name=value pair} 328 | function ReturnPos(attribute: string): TAttribPos; 329 | var 330 | P : Pchar; 331 | S : Pchar; 332 | C : Char; 333 | begin 334 | result.startpos:= 0; 335 | result.len:= 0; 336 | P:= Pchar(uppercase(Attribute)); 337 | // get substring including and everything after equal 338 | S:= StrPos(P, '='); 339 | result.startpos:= pos('=', P); 340 | 341 | if S <> nil then 342 | begin 343 | inc(S); 344 | // set to character after = 345 | inc(result.startpos); 346 | P:= S; 347 | 348 | if (P^ in ['"','''']) then 349 | begin 350 | C:= P^; 351 | // skip quote 352 | inc(P); 353 | inc(result.startpos); 354 | end else 355 | C:= ' '; 356 | 357 | S:= P; 358 | // go to end quote or end of value 359 | while not (P^ in [C, #0]) do 360 | inc(P); 361 | 362 | if (P <> S) then 363 | begin 364 | result.len:= p - s; 365 | end; 366 | end; 367 | 368 | end; 369 | 370 | var 371 | found: TAttribPos; 372 | begin 373 | found:= ReturnPos(namevalpair); 374 | // extract using coordinates 375 | result:= MidStr(namevalpair, found.startpos, found.len); 376 | end; 377 | 378 | *) 379 | 380 | 381 | 382 | 383 | -------------------------------------------------------------------------------- /demo-delphi/HtmParser.dproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {B3B4203E-9C17-4618-9FE3-653DB7CBC04F} 4 | 18.1 5 | VCL 6 | HtmParser.dpr 7 | True 8 | Debug 9 | Win32 10 | 1 11 | Application 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Base 40 | true 41 | 42 | 43 | true 44 | Cfg_2 45 | true 46 | true 47 | 48 | 49 | $(BDS)\bin\delphi_PROJECTICON.ico 50 | HtmParser 51 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 52 | .\$(Platform)\$(Config) 53 | .\$(Platform)\$(Config) 54 | false 55 | false 56 | false 57 | false 58 | false 59 | 60 | 61 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 62 | $(BDS)\bin\default_app.manifest 63 | DBXSqliteDriver;bindcompdbx;IndyIPCommon;RESTComponents;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;PowStringGrids;vclimg;TeeDB;FireDAC;vcltouch;vcldb;bindcompfmx;svn;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;inetdb;ChromeTabs_R;SVGPackage;FMXTee;soaprtl;DbxCommonDriver;FmxTeeUI;ModScrCamDSeattle_Package;FireDACIBDriver;fmx;fmxdae;xmlrtl;soapmidas;Tee;fmxobj;vclwinx;InternetExplorerActiveX;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;speechlib;vclx;DCEF_DX10;bindcomp;appanalytics;dsnap;ModScrCamDSeattle_PackageDsgn;FireDACCommon;IndyIPClient;bindcompvcl;SynEdit_R;RESTBackendComponents;TeeUI;VCLRESTComponents;vclribbon;dbxcds;VclSmp;soapserver;adortl;FireDACODBCDriver;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;IndyProtocols;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) 64 | true 65 | 1033 66 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= 67 | 68 | 69 | DBXSqliteDriver;bindcompdbx;IndyIPCommon;RESTComponents;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;inetdb;ChromeTabs_R;FMXTee;soaprtl;DbxCommonDriver;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;xmlrtl;soapmidas;Tee;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;DCEF_DX10;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;SynEdit_R;RESTBackendComponents;TeeUI;VCLRESTComponents;vclribbon;dbxcds;VclSmp;soapserver;adortl;FireDACODBCDriver;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;IndyProtocols;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) 70 | 71 | 72 | DEBUG;$(DCC_Define) 73 | true 74 | false 75 | true 76 | true 77 | true 78 | 79 | 80 | true 81 | c:\important\fasthtmlparser\trunk\;$(DCC_UnitSearchPath) 82 | 1033 83 | true 84 | true 85 | false 86 | 87 | 88 | false 89 | RELEASE;$(DCC_Define) 90 | 0 91 | 0 92 | 93 | 94 | true 95 | true 96 | 97 | 98 | 99 | MainSource 100 | 101 | 102 |
Form1
103 | dfm 104 |
105 | 106 | Cfg_2 107 | Base 108 | 109 | 110 | Base 111 | 112 | 113 | Cfg_1 114 | Base 115 | 116 |
117 | 118 | Delphi.Personality.12 119 | Application 120 | 121 | 122 | 123 | HtmParser.dpr 124 | 125 | 126 | Microsoft Office 2000 Sample Automation Server Wrapper Components 127 | Microsoft Office XP Sample Automation Server Wrapper Components 128 | 129 | 130 | 131 | 132 | 133 | HtmParser.exe 134 | true 135 | 136 | 137 | 138 | 139 | 0 140 | .dll;.bpl 141 | 142 | 143 | 1 144 | .dylib 145 | 146 | 147 | Contents\MacOS 148 | 1 149 | .dylib 150 | 151 | 152 | 1 153 | .dylib 154 | 155 | 156 | 1 157 | .dylib 158 | 159 | 160 | 161 | 162 | Contents\Resources 163 | 1 164 | 165 | 166 | 167 | 168 | classes 169 | 1 170 | 171 | 172 | 173 | 174 | Contents\MacOS 175 | 0 176 | 177 | 178 | 1 179 | 180 | 181 | Contents\MacOS 182 | 1 183 | 184 | 185 | 186 | 187 | 1 188 | 189 | 190 | 1 191 | 192 | 193 | 1 194 | 195 | 196 | 197 | 198 | res\drawable-xxhdpi 199 | 1 200 | 201 | 202 | 203 | 204 | library\lib\mips 205 | 1 206 | 207 | 208 | 209 | 210 | 0 211 | 212 | 213 | 1 214 | 215 | 216 | Contents\MacOS 217 | 1 218 | 219 | 220 | 1 221 | 222 | 223 | library\lib\armeabi-v7a 224 | 1 225 | 226 | 227 | 1 228 | 229 | 230 | 231 | 232 | 0 233 | 234 | 235 | Contents\MacOS 236 | 1 237 | .framework 238 | 239 | 240 | 241 | 242 | 1 243 | 244 | 245 | 1 246 | 247 | 248 | 1 249 | 250 | 251 | 252 | 253 | 1 254 | 255 | 256 | 1 257 | 258 | 259 | 1 260 | 261 | 262 | 263 | 264 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 265 | 1 266 | 267 | 268 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 269 | 1 270 | 271 | 272 | 273 | 274 | library\lib\x86 275 | 1 276 | 277 | 278 | 279 | 280 | 1 281 | 282 | 283 | 1 284 | 285 | 286 | 1 287 | 288 | 289 | 290 | 291 | 1 292 | 293 | 294 | 1 295 | 296 | 297 | 1 298 | 299 | 300 | 301 | 302 | library\lib\armeabi 303 | 1 304 | 305 | 306 | 307 | 308 | 0 309 | 310 | 311 | 1 312 | 313 | 314 | Contents\MacOS 315 | 1 316 | 317 | 318 | 319 | 320 | 1 321 | 322 | 323 | 1 324 | 325 | 326 | 1 327 | 328 | 329 | 330 | 331 | res\drawable-normal 332 | 1 333 | 334 | 335 | 336 | 337 | res\drawable-xhdpi 338 | 1 339 | 340 | 341 | 342 | 343 | res\drawable-large 344 | 1 345 | 346 | 347 | 348 | 349 | 1 350 | 351 | 352 | 1 353 | 354 | 355 | 1 356 | 357 | 358 | 359 | 360 | ../ 361 | 1 362 | 363 | 364 | ../ 365 | 1 366 | 367 | 368 | 369 | 370 | res\drawable-hdpi 371 | 1 372 | 373 | 374 | 375 | 376 | library\lib\armeabi-v7a 377 | 1 378 | 379 | 380 | 381 | 382 | Contents 383 | 1 384 | 385 | 386 | 387 | 388 | ../ 389 | 1 390 | 391 | 392 | 393 | 394 | 1 395 | 396 | 397 | 1 398 | 399 | 400 | 1 401 | 402 | 403 | 404 | 405 | res\values 406 | 1 407 | 408 | 409 | 410 | 411 | res\drawable-small 412 | 1 413 | 414 | 415 | 416 | 417 | res\drawable 418 | 1 419 | 420 | 421 | 422 | 423 | 1 424 | 425 | 426 | 1 427 | 428 | 429 | 1 430 | 431 | 432 | 433 | 434 | 1 435 | 436 | 437 | 438 | 439 | res\drawable 440 | 1 441 | 442 | 443 | 444 | 445 | 0 446 | 447 | 448 | 0 449 | 450 | 451 | Contents\Resources\StartUp\ 452 | 0 453 | 454 | 455 | 0 456 | 457 | 458 | 0 459 | 460 | 461 | 0 462 | 463 | 464 | 465 | 466 | library\lib\armeabi-v7a 467 | 1 468 | 469 | 470 | 471 | 472 | 0 473 | .bpl 474 | 475 | 476 | 1 477 | .dylib 478 | 479 | 480 | Contents\MacOS 481 | 1 482 | .dylib 483 | 484 | 485 | 1 486 | .dylib 487 | 488 | 489 | 1 490 | .dylib 491 | 492 | 493 | 494 | 495 | res\drawable-mdpi 496 | 1 497 | 498 | 499 | 500 | 501 | res\drawable-xlarge 502 | 1 503 | 504 | 505 | 506 | 507 | res\drawable-ldpi 508 | 1 509 | 510 | 511 | 512 | 513 | 1 514 | 515 | 516 | 1 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | True 529 | False 530 | 531 | 532 | 12 533 | 534 | 535 | 536 | 537 |
538 | --------------------------------------------------------------------------------