mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-02 16:03:39 +02:00
342 lines
8.9 KiB
ObjectPascal
342 lines
8.9 KiB
ObjectPascal
{ Copyright (C) <2005> <Andrew Haines> chmspecialparser.pas
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; if not, write to the Free Software Foundation,
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
}
|
|
{
|
|
See the file COPYING.modifiedLGPL, included in this distribution,
|
|
for details about the copyright.
|
|
}
|
|
unit ChmSpecialParser;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, Forms, SysUtils, Controls, ComCtrls;
|
|
|
|
type
|
|
|
|
TContentTreeNode = class(TTreeNode)
|
|
private
|
|
fUrl: String;
|
|
public
|
|
property Url:String read fUrl write fUrl;
|
|
end;
|
|
|
|
TContentNode = record
|
|
Name: String;
|
|
Url: String;
|
|
LineCount: Integer;
|
|
end;
|
|
|
|
TIndexItem = class(TListITem)
|
|
private
|
|
fUrl: String;
|
|
public
|
|
property Url:String read fUrl write fUrl;
|
|
end;
|
|
|
|
|
|
{ TContentsFiller }
|
|
|
|
TContentsFiller = class(TObject)
|
|
private
|
|
fTreeView: TTreeView;
|
|
fStream: TStream;
|
|
fText: TStringList;
|
|
fBranchCount: DWord;
|
|
fStop: PBoolean;
|
|
fULList: Array of Integer;
|
|
procedure CustomCreateContentTreeItem(Sender: TCustomTreeView;
|
|
var ATreeNode: TTreenode);
|
|
function AddULTree(StartLine, EndLine: Integer; ParentNode: TTreeNode): Boolean;
|
|
function GetULEnd(StartLine: Integer): Integer;
|
|
function GetLIData(StartLine: Integer): TContentNode;
|
|
procedure FillULIndices;
|
|
public
|
|
constructor Create(ATreeView: TTreeView; AStream: TStream; StopBoolean: PBoolean);
|
|
procedure DoFill(ParentNode: TTreeNode);
|
|
|
|
|
|
end;
|
|
|
|
{ TIndexFiller }
|
|
|
|
TIndexFiller = class(TObject)
|
|
private
|
|
fListView: TListView;
|
|
fStream: TStream;
|
|
fText: TStringList;
|
|
function GetLIEnd(StartLine: Integer): Integer;
|
|
function GetNextLI(StartLine: Integer): Integer;
|
|
function AddLIObjects(StartLine: Integer): Integer;
|
|
function LineHasLI(ALine: Integer): Boolean;
|
|
public
|
|
constructor Create(AListView: TListView; AStream: TStream);
|
|
procedure DoFill;
|
|
|
|
end;
|
|
|
|
implementation
|
|
|
|
function FixURL(URL: String):String;
|
|
var
|
|
X: LongInt;
|
|
begin
|
|
X := Pos('%20', Url);
|
|
while X > 0 do begin
|
|
Delete(Url, X, 3);
|
|
Insert(' ', Url, X);
|
|
X := Pos('%20', Url);
|
|
end;
|
|
Result := Url;
|
|
end;
|
|
|
|
{ TContentsFiller }
|
|
|
|
procedure TContentsFiller.CustomCreateContentTreeItem(Sender: TCustomTreeView;
|
|
var ATreeNode: TTreenode);
|
|
begin
|
|
ATreeNode := TContentTreeNode.Create(TTreeView(Sender).Items);
|
|
end;
|
|
|
|
function TContentsFiller.AddULTree(StartLine, EndLine: Integer; ParentNode: TTreeNode): Boolean;
|
|
var
|
|
X: LongInt;
|
|
TreeNode: TContentTreeNode = nil;
|
|
NodeInfo: TContentNode;
|
|
ULEnd: Integer;
|
|
begin
|
|
// NOTE: this doesn't truly parse the html'ish content here. So things like
|
|
// entries spread on multiple lines won't work. Patches are welcome :)
|
|
Result := True;
|
|
Inc(fBranchCount);
|
|
X := StartLine-1;
|
|
while X < EndLine do begin
|
|
Inc(X);
|
|
if Pos('<LI>', fText.Strings[X]) > 0 then begin
|
|
try
|
|
NodeInfo := GetLIData(X);
|
|
TreeNode := TContentTreeNode(fTreeView.Items.AddChild(ParentNode, NodeInfo.Name));
|
|
TreeNode.Url := NodeInfo.Url;
|
|
Inc(X, NodeInfo.LineCount);
|
|
except
|
|
// an exception can occur if we have closed the file while the toc is still being read
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
end;
|
|
if (X <> StartLine) and (fULList[X-1] < fULList[X]) then begin
|
|
ULEnd := GetULEnd(X);
|
|
if not AddULTree(X, ULEnd, TreeNode) then exit(False);
|
|
Inc(X, ULEnd-X);
|
|
end;
|
|
end;
|
|
if fBranchCount mod 400 = 0 then begin
|
|
Application.ProcessMessages;
|
|
if fStop^ = True then Exit(False);
|
|
end;
|
|
end;
|
|
|
|
function TContentsFiller.GetULEnd(StartLine: Integer): Integer;
|
|
var
|
|
X: LongInt;
|
|
begin
|
|
for X := StartLine+1 to fText.Count-1 do begin
|
|
if fULList[X] < fULList[StartLine] then begin
|
|
Result := X;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TContentsFiller.GetLIData(StartLine: Integer): TContentNode;
|
|
var
|
|
X: Integer;
|
|
NameCount: Integer = 0;
|
|
fLength: Integer;
|
|
fPos: Integer;
|
|
Line: String;
|
|
begin
|
|
FillChar(Result, SizeOf(Result), 0);
|
|
for X := StartLine to fText.Count-1 do begin
|
|
Line := fText.Strings[X];
|
|
fPos := Pos('<param name="name" value="', LowerCase(Line));
|
|
if fPos > 0 then begin
|
|
fLength := Length('<param name="name" value="');
|
|
Result.Name := Copy(Line, fPos+fLength, Length(Line)-(fLength+fPos));
|
|
Result.Name := Copy(Result.Name, 1, Pos('"', Result.Name)-1);
|
|
end
|
|
else begin
|
|
fPos := Pos('<param name="local" value="', LowerCase(Line));
|
|
if fPos > 0 then begin
|
|
fLength := Length('<param name="local" value="');
|
|
Result.Url := Copy(Line, fPos+fLength, Length(Line)-(fLength+fPos));
|
|
Result.Url := '/'+Copy(Result.Url, 1, Pos('"', Result.Url)-1);
|
|
end
|
|
else if Pos('</OBJECT>', UpperCase(Line)) > 0 then begin
|
|
Result.LineCount := X-StartLine;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
Result.Url := FixURL(Result.Url);
|
|
end;
|
|
|
|
procedure TContentsFiller.FillULIndices;
|
|
var
|
|
ULDepth: Integer = 0;
|
|
X: Integer;
|
|
begin
|
|
for X := 0 to fText.Count-1 do begin
|
|
if Pos('<UL>', fText.Strings[X]) > 0 then Inc(ULDepth);
|
|
if Pos('</UL>', fText.Strings[X]) > 0 then Dec(ULDepth);
|
|
fULList[X] := ULDepth;
|
|
end;
|
|
end;
|
|
|
|
|
|
constructor TContentsFiller.Create(ATreeView: TTreeView; AStream: TStream; StopBoolean: PBoolean);
|
|
begin
|
|
inherited Create;
|
|
fTreeView := ATreeView;
|
|
fStream := AStream;
|
|
fStop := StopBoolean;
|
|
end;
|
|
|
|
procedure TContentsFiller.DoFill(ParentNode: TTreeNode);
|
|
var
|
|
OrigEvent: TTVCustomCreateNodeEvent;
|
|
X: Integer;
|
|
begin
|
|
OrigEvent := fTreeView.OnCustomCreateItem;
|
|
fTreeView.OnCustomCreateItem := @CustomCreateContentTreeItem;
|
|
|
|
fText := TStringList.Create;
|
|
fStream.Position := 0;
|
|
fTreeView.BeginUpdate;
|
|
fText.LoadFromStream(fStream);
|
|
SetLength(fULList, fText.Count);
|
|
FillULIndices;
|
|
for X := 0 to fText.Count-1 do begin
|
|
if Pos('<UL>', UpperCase(fText.Strings[X])) > 0 then begin
|
|
if not AddULTree(X, GetULEnd(X), ParentNode) then begin
|
|
//then we have either closed the file or are exiting the program
|
|
fTreeView.Items.Clear;
|
|
end;
|
|
Break;
|
|
end;
|
|
end;
|
|
fTreeView.OnCustomCreateItem := OrigEvent;
|
|
fText.Free;
|
|
fTreeView.EndUpdate;
|
|
end;
|
|
|
|
{ TIndexFiller }
|
|
|
|
function TIndexFiller.GetLIEnd(StartLine: Integer): Integer;
|
|
begin
|
|
// for X := StartLine to
|
|
end;
|
|
|
|
function TIndexFiller.GetNextLI(StartLine: Integer): Integer;
|
|
begin
|
|
|
|
end;
|
|
|
|
function TIndexFiller.AddLIObjects(StartLine: Integer): Integer;
|
|
var
|
|
NeedsUrl: Boolean = True;
|
|
NeedsName: Boolean = True;
|
|
ItemNAme: String;
|
|
ItemUrl: String;
|
|
Line: String;
|
|
fPos: Integer;
|
|
fLength: Integer;
|
|
Item: TIndexItem;
|
|
X: LongInt;
|
|
begin
|
|
for X:= StartLine to fText.Count-1 do begin
|
|
Line := fText.Strings[X];
|
|
if NeedsName then begin
|
|
fPos := Pos('<param name="name" value="', LowerCase(Line));
|
|
if fPos > 0 then begin
|
|
fLength := Length('<param name="name" value="');
|
|
ItemName := Copy(Line, fPos+fLength, Length(Line)-(fLength+fPos));
|
|
ItemName := Copy(ItemNAme, 1, Pos('"', ItemName)-1);
|
|
NeedsName := False;
|
|
NeedsUrl := True;
|
|
end;
|
|
end
|
|
else if NeedsUrl then begin
|
|
fPos := Pos('<param name="local" value="', LowerCase(Line));
|
|
if fPos > 0 then begin
|
|
fLength := Length('<param name="Local" value="');
|
|
ItemUrl := Copy(Line, fPos+fLength, Length(Line)-(fLength+fPos));
|
|
ItemUrl := FixUrl('/'+Copy(ItemUrl, 1, Pos('"', ItemUrl)-1));
|
|
NeedsName := False;
|
|
NeedsUrl := False;
|
|
Item := TIndexItem.Create(fListView.Items);
|
|
fListView.Items.AddItem(Item);
|
|
Item.Caption := ItemName;
|
|
Item.Url := ItemUrl;
|
|
//WriteLn('Added IndexItem. Caption = ', ItemName,' Url = ',ItemUrl);
|
|
ItemName := '';
|
|
ItemUrl := '';
|
|
end;
|
|
end;
|
|
if Pos('</OBJECT>', UpperCase(Line)) > 0 then begin
|
|
Result := X-StartLine;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TIndexFiller.LineHasLI(ALine: Integer): Boolean;
|
|
begin
|
|
Result := Pos('<LI>', UpperCase(fText.Strings[ALine])) > 0;
|
|
end;
|
|
|
|
constructor TIndexFiller.Create(AListView: TListView; AStream: TStream);
|
|
begin
|
|
inherited Create;
|
|
fListView := AListView;
|
|
fStream := AStream;
|
|
end;
|
|
|
|
procedure TIndexFiller.DoFill;
|
|
var
|
|
X: Integer;
|
|
begin
|
|
fStream.Position := 0;
|
|
fText := TStringList.Create;
|
|
fText.LoadFromStream(fStream);
|
|
fListView.BeginUpdate;
|
|
fListView.Items.Clear;
|
|
X := -1;
|
|
while X < fText.Count-1 do begin
|
|
Inc(X);
|
|
if LineHasLI(X) then Inc(X, AddLIObjects(X));
|
|
end;
|
|
fText.Free;
|
|
fListView.EndUpdate;
|
|
end;
|
|
|
|
end.
|
|
|