* new bunch of Gabor's changes

This commit is contained in:
pierre 2000-06-26 07:29:22 +00:00
parent 1f902711f3
commit 0b75c6e4fd
7 changed files with 1296 additions and 119 deletions

View File

@ -1,3 +1,15 @@
Gabors's log to 26/6/2000 commits
========================= Already fixed ================================
[*] topics with the same name are now all shown on the Index page
========================== Other improvements ============================
[+] added support for "see also" entries of Norton Guide help topics
[+] coloring of NG help is now integrated with the common color managment
system of FV
[+] started implementing help support for Windows Help files
Gabors's log to 22/6/2000 commits
========================== Other improvements ============================

View File

@ -51,7 +51,8 @@ const
HTMLExt = '.htm';
TemplateExt = '.pt';
NGExt = '.ng';
HelpFileExts = '*.tph;*.htm*;*'+HTMLIndexExt+';*'+NGExt;
WinHelpExt = '.hlp';
HelpFileExts = '*.tph;*.htm*;*'+HTMLIndexExt+';*'+NGExt+';*'+WinHelpExt;
EnterSign = #17#196#217;
@ -406,7 +407,10 @@ implementation
END.
{
$Log$
Revision 1.41 2000-06-22 09:07:11 pierre
Revision 1.42 2000-06-26 07:29:22 pierre
* new bunch of Gabor's changes
Revision 1.41 2000/06/22 09:07:11 pierre
* Gabor changes: see fixes.txt
Revision 1.40 2000/06/16 08:50:40 pierre

View File

@ -66,7 +66,7 @@ const
implementation
uses Objects,Views,App,MsgBox,Commands,
WUtils,WHTMLHlp,
WUtils,WHTMLHlp,WNGHelp,
FPString,FPConst,FPVars,FPUtils;
const
@ -290,6 +290,14 @@ procedure InitHelpSystem;
{$IFDEF DEBUG}SetStatus(msg_LoadingHelpFile);{$ENDIF}
end;
procedure AddWinHelpFile(HelpFile: string);
begin
{$IFDEF DEBUG}SetStatus(msg_LoadingHelpFile+' ('+SmartPath(HelpFile)+')');{$ENDIF}
if HelpFacility^.AddWinHelpFile(HelpFile)=false then
ErrorBox(FormatStrStr(msg_failedtoloadhelpfile,HelpFile),nil);
{$IFDEF DEBUG}SetStatus(msg_LoadingHelpFile);{$ENDIF}
end;
procedure AddHTMLIndexFile(HelpFile: string);
begin
{$IFDEF DEBUG}SetStatus(msg_LoadingHelpFile+' ('+SmartPath(HelpFile)+')');{$ENDIF}
@ -317,6 +325,8 @@ begin
AddHTMLIndexFile(S) else
if UpcaseStr(ExtOf(S))=UpcaseStr(NGExt) then
AddNGFile(S) else
if UpcaseStr(ExtOf(S))=UpcaseStr(WinHelpExt) then
AddWinHelpFile(S) else
AddOAFile(S);
end;
PopStatus;
@ -461,9 +471,27 @@ begin
FPHTMLGetSectionColor:=OK;
end;
function FPNGGetAttrColor(Attr: char; var Color: byte): boolean;
var OK: boolean;
begin
OK:=false;
case Attr of
'A' : OK:=FPHTMLGetSectionColor(hsHeading1,Color);
'B' : OK:=FPHTMLGetSectionColor(hsHeading2,Color);
'b' : OK:=FPHTMLGetSectionColor(hsHeading5,Color);
'U' : OK:=FPHTMLGetSectionColor(hsHeading3,Color);
'N' : OK:=FPHTMLGetSectionColor(hsHeading4,Color);
{$ifdef DEBUGMSG}
else ErrorBox('Unknown attr encountered : "'+Attr+'"',nil);
{$endif}
end;
FPNGGetAttrColor:=OK;
end;
procedure InitHelpFiles;
begin
HTMLGetSectionColor:={$ifdef FPC}@{$endif}FPHTMLGetSectionColor;
NGGetAttrColor:={$ifdef FPC}@{$endif}FPNGGetAttrColor;
New(HelpFiles, Init(10,10));
end;
@ -490,7 +518,10 @@ end;
END.
{
$Log$
Revision 1.34 2000-06-22 09:07:12 pierre
Revision 1.35 2000-06-26 07:29:23 pierre
* new bunch of Gabor's changes
Revision 1.34 2000/06/22 09:07:12 pierre
* Gabor changes: see fixes.txt
Revision 1.33 2000/06/16 08:50:40 pierre

View File

@ -156,7 +156,7 @@ type
end;
PKeywordDescriptors = ^TKeywordDescriptors;
TKeywordDescriptors = array[0..10900] of TKeywordDescriptor;
TKeywordDescriptors = array[0..MaxBytes div sizeof(TKeywordDescriptor)-1] of TKeywordDescriptor;
PTopic = ^TTopic;
TTopic = object
@ -190,11 +190,17 @@ type
function Compare(Key1, Key2: Pointer): Sw_Integer; virtual;
end;
PUnsortedIndexEntryCollection = ^TUnsortedIndexEntryCollection;
TUnsortedIndexEntryCollection = object(TCollection)
function At(Index: Sw_Integer): PIndexEntry;
procedure FreeItem(Item: Pointer); virtual;
end;
PHelpFile = ^THelpFile;
THelpFile = object(TObject)
ID : word;
Topics : PTopicCollection;
IndexEntries : PIndexEntryCollection;
IndexEntries : PUnsortedIndexEntryCollection;
constructor Init(AID: word);
function LoadTopic(HelpCtx: THelpCtx): PTopic; virtual;
procedure AddTopic(HelpCtx: THelpCtx; Pos: longint; const Param: string);
@ -244,6 +250,7 @@ type
function AddOAHelpFile(const FileName: string): boolean;
function AddHTMLHelpFile(const FileName, TOCEntry: string): boolean;
function AddNGHelpFile(const FileName: string): boolean;
function AddWinHelpFile(const FileName: string): boolean;
function AddHTMLIndexHelpFile(const FileName: string): boolean;
function LoadTopic(SourceFileID: word; Context: THelpCtx): PTopic; virtual;
function TopicSearch(Keyword: string; var FileID: word; var Context: THelpCtx): boolean; virtual;
@ -279,7 +286,7 @@ uses
{$ifdef Linux}
linux,
{$endif Linux}
WConsts,WHTMLHlp,WNGHelp;
WConsts,WHTMLHlp,WNGHelp,WWinHelp;
Function GetDosTicks:longint; { returns ticks at 18.2 Hz, just like DOS }
@ -364,7 +371,7 @@ begin
end;
procedure RenderTopic(Lines: PUnsortedStringCollection; T: PTopic);
var Size,CurPtr,I: sw_word;
var Size,CurPtr,I,MSize: sw_word;
S: string;
begin
CurPtr:=0;
@ -379,8 +386,12 @@ begin
CurPtr:=0;
for I:=0 to Lines^.Count-1 do
begin
S:=GetStr(Lines^.At(I)); Size:=length(S);
Move(S[1],PByteArray(T^.Text)^[CurPtr],Size);
S:=GetStr(Lines^.At(I)); Size:=length(S); MSize:=Size;
if CurPtr+Size>=T^.TextSize then
MSize:=T^.TextSize-CurPtr;
Move(S[1],PByteArray(T^.Text)^[CurPtr],MSize);
if MSize<>Size then
Break;
Inc(CurPtr,Size);
PByteArray(T^.Text)^[CurPtr]:=ord(hscLineBreak);
Inc(CurPtr);
@ -392,7 +403,7 @@ procedure AddLinkToTopic(T: PTopic; AFileID: word; ACtx: THelpCtx);
var NewSize: word;
NewPtr: pointer;
begin
NewSize:=(T^.LinkCount+1)*sizeof(T^.Links^[0]);
NewSize:=longint(T^.LinkCount+1)*sizeof(T^.Links^[0]);
GetMem(NewPtr,NewSize);
if Assigned(T^.Links) then
begin
@ -488,6 +499,16 @@ begin
if Item<>nil then DisposeIndexEntry(Item);
end;
function TUnsortedIndexEntryCollection.At(Index: Sw_Integer): PIndexEntry;
begin
At:=inherited At(Index);
end;
procedure TUnsortedIndexEntryCollection.FreeItem(Item: Pointer);
begin
if Item<>nil then DisposeIndexEntry(Item);
end;
function TIndexEntryCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
var K1: PIndexEntry absolute Key1;
K2: PIndexEntry absolute Key2;
@ -497,6 +518,8 @@ begin
S1:=UpcaseStr(K1^.Tag^); S2:=UpcaseStr(K2^.Tag^);
if S1<S2 then R:=-1 else
if S1>S2 then R:=1 else
if K1^.FileID<K2^.FileID then R:=-1 else
if K1^.FileID>K2^.FileID then R:= 1 else
R:=0;
Compare:=R;
end;
@ -1006,6 +1029,13 @@ begin
AddNGHelpFile:=AddFile(H);;
end;
function THelpFacility.AddWinHelpFile(const FileName: string): boolean;
var H: PHelpFile;
begin
H:=New(PWinHelpFile, Init(FileName, LastID+1));
AddWinHelpFile:=AddFile(H);;
end;
function THelpFacility.AddHTMLIndexHelpFile(const FileName: string): boolean;
var H: PHelpFile;
begin
@ -1112,12 +1142,32 @@ begin
LastFirstChar:=FirstChar;
NLFlag:=0;
end;
function FormatAlias(Alias: string): string;
var StartP,EndP: sw_integer;
begin
repeat
StartP:=Pos(' ',Alias);
if StartP>0 then
begin
EndP:=StartP;
while (EndP+1<=length(Alias)) and (Alias[EndP+1]=' ') do Inc(EndP);
Alias:=copy(Alias,1,StartP-1)+' | '+copy(Alias,EndP+1,High(Alias));
end;
until StartP=0;
if Assigned(HelpFacility) then
if length(Alias)>IndexTabSize-4 then
Alias:=Trim(copy(Alias,1,IndexTabSize-4-2))+'..';
FormatAlias:=Alias;
end;
procedure AddKeyword(KWS: string);
begin
Inc(KWCount); if KWCount=1 then NLFlag:=0;
if (KWCount=1) or
( (Upcase(KWS[1])<>LastFirstChar) and ( (LastFirstChar>#64) or (KWS[1]>#64) ) ) then
NewSection(Upcase(KWS[1]));
KWS:=FormatAlias(KWS);
if (NLFlag mod 2)=0
then Line:=' '+#2+KWS+#2
else begin
@ -1141,14 +1191,15 @@ begin
begin
AddLine(' '+msg_helpindex);
KWCount:=0; Line:='';
T^.LinkCount:=Keywords^.Count;
T^.LinkCount:=Min(Keywords^.Count,MaxBytes div sizeof(T^.Links^[0])-1);
GetMem(T^.Links,T^.LinkSize);
for I:=0 to Keywords^.Count-1 do
for I:=0 to T^.LinkCount-1 do
begin
KW:=Keywords^.At(I);
AddKeyword(KW^.Tag^);
T^.Links^[I].Context:=longint(KW^.HelpCtx); T^.Links^[I].FileID:=KW^.FileID;
T^.Links^[I].Context:=longint(KW^.HelpCtx);
T^.Links^[I].FileID:=KW^.FileID;
end;
FlushLine;
AddLine('');
@ -1185,7 +1236,10 @@ end;
END.
{
$Log$
Revision 1.24 2000-06-22 09:07:14 pierre
Revision 1.25 2000-06-26 07:29:23 pierre
* new bunch of Gabor's changes
Revision 1.24 2000/06/22 09:07:14 pierre
* Gabor changes: see fixes.txt
Revision 1.23 2000/06/16 08:50:44 pierre

View File

@ -75,6 +75,7 @@ type
{ array of TNGSeeAlsoRec }
end;
PNGSeeAlsoRec = ^TNGSeeAlsoRec;
TNGSeeAlsoRec = packed record
EntryCount : word;
Entries : record end;
@ -89,6 +90,12 @@ type
Container: PNGContainerRecord;
end;
PLinkRec = ^TLinkRec;
TLinkRec = record
Name : string;
FilePos : longint;
end;
PNGHelpFile = ^TNGHelpFile;
TNGHelpFile = object(THelpFile)
constructor Init(AFileName: string; AID: word);
@ -99,17 +106,30 @@ type
private
F: PStream;
Header: TNGFileHeader;
FirstRecordPos: longint;
IndexLoaded: boolean;
{ NextHelpCtx: longint;}
function ReadHeader: boolean;
function ReadContainer(EnumProc: pointer): boolean;
function ReadTopicRec(Lines: PUnsortedStringCollection): boolean;
function ReadTopicRec(LineEnumProc: pointer; LinkEnumProc: pointer): boolean;
function ReadRecord(var R: TRecord; ReadData: boolean): boolean;
end;
TNGGetAttrColorProc = function(Attr: char; var Color: byte): boolean;
function DefNGGetAttrColor(Attr: char; var Color: byte): boolean;
const NGGetAttrColor : TNGGetAttrColorProc = DefNGGetAttrColor;
implementation
uses CallSpec;
function DefNGGetAttrColor(Attr: char; var Color: byte): boolean;
begin
DefNGGetAttrColor:=false;
end;
function NGDecompressStr(const S: string): string;
var NS: string;
I: sw_integer;
@ -134,6 +154,7 @@ function TranslateStr(const S: string): string;
var NS: string;
I: sw_integer;
InHiLite: boolean;
Color: byte;
begin
NS:=''; InHiLite:=false;
I:=1;
@ -144,25 +165,14 @@ begin
Inc(I);
case S[I] of
'^' : NS:=NS+'^';
'B' : begin
'A'..'Z',
'a'..'z' :
begin
if InHiLite then
NS:=NS+hscNormText
else
NS:=NS+hscTextColor+chr(15);
InHiLite:=not InHiLite;
end;
'b' : begin
if InHiLite then
NS:=NS+hscNormText
else
NS:=NS+hscTextColor+chr(11);
InHiLite:=not InHiLite;
end;
'U' : begin
if InHiLite then
NS:=NS+hscNormText
else
NS:=NS+hscTextColor+chr(3);
if NGGetAttrColor(S[I],Color) then
NS:=NS+hscTextColor+chr(Color);
InHiLite:=not InHiLite;
end;
else
@ -190,40 +200,7 @@ begin
end;
constructor TNGHelpFile.Init(AFileName: string; AID: word);
function FormatAlias(Alias: string): string;
var StartP,EndP: sw_integer;
begin
repeat
StartP:=Pos(' ',Alias);
if StartP>0 then
begin
EndP:=StartP;
while (EndP+1<=length(Alias)) and (Alias[EndP+1]=' ') do Inc(EndP);
Alias:=copy(Alias,1,StartP-1)+' | '+copy(Alias,EndP+1,High(Alias));
end;
until StartP=0;
if Assigned(HelpFacility) then
if length(Alias)>HelpFacility^.IndexTabSize-4 then
Alias:=Trim(copy(Alias,1,HelpFacility^.IndexTabSize-4-2))+'..';
FormatAlias:=Alias;
end;
procedure AddToIndex(P: PContainerItemRec); {$ifndef FPC}far;{$endif}
var S: string;
begin
S:=Trim(P^.Name);
S:=TranslateStr(S);
S:=Trim(FormatAlias(S));
if (S<>'') and (P^.FilePos<>-1) then
begin
{ Inc(NextHelpCtx);}
AddIndexEntry(S,P^.FilePos);
AddTopic(P^.FilePos,P^.FilePos,'');
end;
end;
var OK: boolean;
FS: longint;
R: TRecord;
L: longint;
begin
if inherited Init(AID)=false then Fail;
F:=New(PBufStream, Init(AFileName, stOpenRead, HelpStreamBufSize));
@ -231,38 +208,10 @@ begin
if OK then OK:=(F^.Status=stOK);
if OK then
begin
FS:=F^.GetSize;
OK:=ReadHeader;
if OK then
FirstRecordPos:=F^.GetPos;
end;
while OK do
begin
L:=F^.GetPos;
if (L>=FS) then Break;
OK:=ReadRecord(R,false);
if (OK=false) then Break;
case R.SClass of
ng_rtContainer : begin F^.Seek(L); OK:=ReadContainer(@AddToIndex); end;
{ ng_rtTopic : begin F^.Seek(L); OK:=ReadTopicRec; end;}
else
begin
{$ifdef DEBUGMSG}
ClearFormatParams;
AddFormatParamInt(R.SClass);
AddFormatParamInt(L);
AddFormatParamInt(R.Size);
ErrorBox('Uknown help record tag %x encountered, '+
'offset %x, size %d',@FormatParams);
{$else}
{Skip};
{$endif}
end;
end;
if OK then
begin
Inc(L, sizeof(TNGRecordHeader)+R.Size); F^.Seek(L);
OK:=(F^.Status=stOK);
end;
end;
if OK=false then
begin
Done;
@ -279,22 +228,10 @@ begin
ReadHeader:=OK;
end;
function KillSpecChars(const S: string): string;
var I: sw_integer;
RS: string;
begin
RS:='';
for I:=1 to length(S) do
if S[I]>=#32 then
RS:=RS+S[I];
KillSpecChars:=RS;
end;
function TNGHelpFile.ReadContainer(EnumProc: pointer): boolean;
var OK: boolean;
R: TRecord;
I,L: longint;
CI: TNGContainerItem;
I: longint;
P: pointer;
CIR: TContainerItemRec;
begin
@ -322,23 +259,45 @@ begin
ReadContainer:=OK;
end;
function TNGHelpFile.ReadTopicRec(Lines: PUnsortedStringCollection): boolean;
function TNGHelpFile.ReadTopicRec(LineEnumProc, LinkEnumProc: pointer): boolean;
var OK: boolean;
R: TRecord;
I: sw_integer;
LineP: pointer;
S: string;
ParamS: string;
NextLinkOfsPtr,NextLinkNamePtr: pointer;
SeeAlso: PNGSeeAlsoRec;
LR: TLinkRec;
begin
OK:=ReadRecord(R, true);
if OK then
with TNGTopicRecord(R.Data^) do
begin
LineP:=@TopicLines;
if Assigned(LineEnumProc) then
for I:=1 to NumberOfLines do
begin
S:=StrPas(LineP);
Lines^.InsertStr(NGDecompressStr(S));
LineP:=pointer(longint(LineP)+length(S)+1);
ParamS:=NGDecompressStr(S);
CallPointerLocal(LineEnumProc,PreviousFramePointer,@ParamS);
Inc(longint(LineP),length(S)+1);
end;
if Assigned(LinkEnumProc) and (SeeAlsoOfs>0) then
begin
SeeAlso:=@PByteArray(R.Data)^[NGMinRecordSize-sizeof(TNGRecordHeader)+SeeAlsoOfs];
NextLinkOfsPtr:=@SeeAlso^.Entries;
NextLinkNamePtr:=@PByteArray(NextLinkOfsPtr)^[SeeAlso^.EntryCount*4];
for I:=1 to SeeAlso^.EntryCount do
begin
FillChar(LR,sizeof(LR),0);
S:=StrPas(NextLinkNamePtr);
LR.Name:=S;
Move(NextLinkOfsPtr^,LR.FilePos,4);
CallPointerLocal(LinkEnumProc,PreviousFramePointer,@LR);
Inc(longint(NextLinkNamePtr),length(S)+1);
Inc(longint(NextLinkOfsPtr),4);
end;
end;
end;
DisposeRecord(R);
@ -374,20 +333,142 @@ begin
end;
function TNGHelpFile.LoadIndex: boolean;
{function FormatAlias(Alias: string): string;
var StartP,EndP: sw_integer;
begin
LoadIndex:=false;
repeat
StartP:=Pos(' ',Alias);
if StartP>0 then
begin
EndP:=StartP;
while (EndP+1<=length(Alias)) and (Alias[EndP+1]=' ') do Inc(EndP);
Alias:=copy(Alias,1,StartP-1)+' | '+copy(Alias,EndP+1,High(Alias));
end;
until StartP=0;
if Assigned(HelpFacility) then
if length(Alias)>HelpFacility^.IndexTabSize-4 then
Alias:=Trim(copy(Alias,1,HelpFacility^.IndexTabSize-4-2))+'..';
FormatAlias:=Alias;
end;}
procedure AddToIndex(P: PContainerItemRec); {$ifndef FPC}far;{$endif}
var S: string;
begin
S:=Trim(P^.Name);
S:=TranslateStr(S);
S:=Trim({FormatAlias}(S));
if (S<>'') and (P^.FilePos<>-1) then
begin
{ Inc(NextHelpCtx);}
AddIndexEntry(S,P^.FilePos);
AddTopic(P^.FilePos,P^.FilePos,'');
end;
end;
var OK: boolean;
FS: longint;
R: TRecord;
L: longint;
begin
if IndexLoaded then OK:=true else
begin
FS:=F^.GetSize;
OK:=FirstRecordPos<>0;
while OK do
begin
L:=F^.GetPos;
if (L>=FS) then Break;
OK:=ReadRecord(R,false);
if (OK=false) then Break;
case R.SClass of
ng_rtContainer : begin F^.Seek(L); OK:=ReadContainer(@AddToIndex); end;
ng_rtTopic : ;
else
begin
{$ifdef DEBUGMSG}
ClearFormatParams;
AddFormatParamInt(R.SClass);
AddFormatParamInt(L);
AddFormatParamInt(R.Size);
ErrorBox('Uknown help record tag %x encountered, '+
'offset %x, size %d',@FormatParams);
{$else}
{Skip};
{$endif}
end;
end;
if OK then
begin
Inc(L, sizeof(TNGRecordHeader)+R.Size); F^.Seek(L);
OK:=(F^.Status=stOK);
end;
end;
IndexLoaded:=OK;
end;
LoadIndex:=OK;
end;
function TNGHelpFile.ReadTopic(T: PTopic): boolean;
function ExtractStr(var Buf; BufSize: word): string;
var S: string;
I,Size: integer;
StartP,EndP: sw_integer;
begin
S:='';
Size:=BufSize;
while (PByteArray(@Buf)^[Size-1]=0) and (Size>0) do
Dec(Size);
S:=MemToStr(Buf,Size);
S:=NGDecompressStr(S);
for I:=1 to length(S) do
if S[I]=#0 then S[I]:=#32;
{ kill long spaces }
repeat
StartP:=Pos(' ',S);
if StartP>0 then
begin
EndP:=StartP;
while (EndP+1<=length(S)) and (S[EndP+1]=' ') do Inc(EndP);
S:=copy(S,1,StartP-1)+hscLineBreak+copy(S,EndP+1,High(S));
end;
until StartP=0;
S:=Trim(S);
ExtractStr:=S;
end;
var Lines: PUnsortedStringCollection;
procedure AddLine(const S: string);
begin
Lines^.InsertStr(S);
end;
procedure AddToTopic(P: PContainerItemRec); {$ifndef FPC}far;{$endif}
begin
Lines^.InsertStr(hscLink+P^.Name+hscLink);
AddLine(hscLink+Trim(P^.Name)+hscLink);
AddLinkToTopic(T,ID,P^.FilePos);
end;
procedure AddTopicLine(P: PString); {$ifndef FPC}far;{$endif}
begin
AddLine(' '+GetStr(P));
end;
var LinkCount: sw_integer;
procedure AddLink(P: PLinkRec); {$ifndef FPC}far;{$endif}
begin
Inc(LinkCount);
if LinkCount=1 then
begin
AddLine('');
AddLine(' See also :');
end;
AddLine(' '+hscLink+Trim(P^.Name)+hscLink);
AddLinkToTopic(T,ID,P^.FilePos);
end;
var OK: boolean;
R: TRecord;
begin
LinkCount:=0;
New(Lines, Init(100,100));
F^.Seek(T^.FileOfs); OK:=F^.Status=stOK;
if OK then OK:=ReadRecord(R,false);
@ -395,17 +476,21 @@ begin
ng_rtContainer :
begin
F^.Seek(T^.FileOfs);
Lines^.InsertStr(' ');
AddLine('');
OK:=ReadContainer(@AddToTopic);
RenderTopic(Lines,T);
end;
ng_rtTopic :
begin
F^.Seek(T^.FileOfs);
Lines^.InsertStr(' ');
OK:=ReadTopicRec(Lines);
AddLine('');
OK:=ReadTopicRec(@AddTopicLine,@AddLink);
TranslateLines(Lines);
Lines^.InsertStr(' ');
AddLine('');
{ include copyright info }
{ AddLine(CharStr('Ä',80));
AddLine(ExtractStr(Header.GuideName,sizeof(Header.GuideName)));
AddLine(ExtractStr(Header.Credits,sizeof(Header.Credits)));}
RenderTopic(Lines,T);
end;
else OK:=false;
@ -423,7 +508,10 @@ end;
END.
{
$Log$
Revision 1.1 2000-06-22 09:07:15 pierre
Revision 1.2 2000-06-26 07:29:23 pierre
* new bunch of Gabor's changes
Revision 1.1 2000/06/22 09:07:15 pierre
* Gabor changes: see fixes.txt
}

View File

@ -66,12 +66,27 @@ type
S : PStream;
end;
PFastBufStream = ^TFastBufStream;
TFastBufStream = object(TBufStream)
procedure Seek(Pos: Longint); virtual;
private
BasePos: longint;
end;
PTextCollection = ^TTextCollection;
TTextCollection = object(TStringCollection)
function LookUp(const S: string; var Idx: sw_integer): string;
function Compare(Key1, Key2: Pointer): sw_Integer; virtual;
end;
PIntCollection = ^TIntCollection;
TIntCollection = object(TSortedCollection)
function Compare(Key1, Key2: Pointer): sw_Integer; virtual;
procedure FreeItem(Item: Pointer); virtual;
procedure Add(Item: longint);
function Contains(Item: longint): boolean;
end;
{$ifdef TPUNIXLF}
procedure readln(var t:text;var s:string);
{$endif}
@ -609,6 +624,33 @@ begin
S.WriteStr(Item);
end;
function TIntCollection.Contains(Item: longint): boolean;
var Index: sw_integer;
begin
Contains:=Search(pointer(Item),Index);
end;
procedure TIntCollection.Add(Item: longint);
begin
Insert(pointer(Item));
end;
function TIntCollection.Compare(Key1, Key2: Pointer): sw_Integer;
var K1: longint absolute Key1;
K2: longint absolute Key2;
R: integer;
begin
if K1<K2 then R:=-1 else
if K1>K2 then R:= 1 else
R:=0;
Compare:=R;
end;
procedure TIntCollection.FreeItem(Item: Pointer);
begin
{ do nothing here }
end;
constructor TNulStream.Init;
begin
inherited Init;
@ -684,6 +726,26 @@ begin
S^.Write(Buf,Count);
end;
procedure TFastBufStream.Seek(Pos: Longint);
function BufStartPos: longint;
begin
BufStartPos:=Position-BufPtr;
end;
var RelOfs: longint;
begin
RelOfs:=Pos-{BufStartPos}BasePos;
if (RelOfs<0) or (RelOfs>=BufEnd) or (BufEnd=0) then
begin
inherited Seek(Pos);
BasePos:=Pos;
end
else
begin
BufPtr:=RelOfs;
Position:=Pos;
end;
end;
function TTextCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
var K1: PString absolute Key1;
K2: PString absolute Key2;
@ -972,7 +1034,10 @@ end;
END.
{
$Log$
Revision 1.25 2000-06-22 09:07:15 pierre
Revision 1.26 2000-06-26 07:29:23 pierre
* new bunch of Gabor's changes
Revision 1.25 2000/06/22 09:07:15 pierre
* Gabor changes: see fixes.txt
Revision 1.24 2000/06/16 21:16:41 pierre

923
ide/text/wwinhelp.pas Normal file
View File

@ -0,0 +1,923 @@
{
$Id$
This file is part of the Free Pascal Integrated Development Environment
Copyright (c) 2000 by Berczi Gabor
Help support for Windows Help (.HLP) files
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
{$R-}
unit WWinHelp;
interface
uses Objects,
WUtils,WHelp;
const
WinHelpMagicNo = $00035F3F;
WinHelpBTreeHeaderMagicNo = $293B;
WinHelpSystemHeaderMagicNo = $036c;
{ WinHelp Btree dataformat descriptors }
wh_bdf_Long = 'L';
wh_bdf_ASCIIZ = 'F';
wh_bdf_ASCIIZ2 = 'i';
wh_bdf_Short = '2';
wh_bdf_Long2 = '4';
wh_bdf_ASCIIZ3 = 'z';
{ WinHelp system record type }
wh_srt_Title = 1;
wh_srt_Copyright = 2;
wh_srt_Contents = 3;
wh_srt_Config = 4;
wh_srt_Icon = 5;
wh_srt_Window = 6;
wh_srt_Citation = 8;
wh_srt_LangID = 9;
wh_srt_Content = 10;
wh_srt_DefFont = 11;
wh_srt_FtIndex = 12;
wh_srt_Groups = 13;
wh_srt_KeyIndex = 14;
wh_srt_Language = 18;
wh_srt_DLLMaps = 19;
type
PInteger = ^integer;
TWinHelpHeader = packed record
MagicNo : longint;
DirectoryStart : longint;
NonDirectoryStart: longint;
EntireFileSize : longint;
end;
TWinHelpFileEntryHeader = packed record
ReservedSpace : longint;
UsedSpace : longint;
FileFlags : byte;
end;
TWinHelpRecordHeader = packed record
RecordType : word;
DataSize : word;
end;
TWinHelpBTreeHeader = packed record
Magic : word;
Flags : word; { 0x0002 always set, 0x0400 set if directory }
PageSize : word;
DataFormat : array[1..16] of char;
MustBeZero : word; { $0000 }
PageSplits : word;
RootPage : word;
MustBeNegOne : integer; { $ffff }
TotalPages : word;
NumLevels : word;
TotalEntries : word;
Pages : record end;
end;
TWinHelpBTreeIndexHeader = packed record
Unknown : longint;
NumEntries : word; { no of index-entries }
PrevPage : integer;
end;
{
TWinHelpBTreeIndexEntry = packed record
FileName : STRINGZ;
PageNumber : word;
end;
}
TWinHelpBTreeNodeHeader = packed record
Unknown : longint;
NumEntries : word; { no of index-entries }
PrevPage : integer;
NextPage : integer;
end;
TWinHelpSystemHeader = packed record
Magic : word;
Version : word;
Always1 : word;
GenDate : longint;
Flags : word;
end;
TWinHelpTopicBlockHeader = packed record
LastTopicLink : longint;
FirstTopicLink : longint;
LastTopicHeader : longint;
end;
TWinHelpTopicBlock = packed record
Header : TWinHelpTopicBlockHeader;
Data : record end;
end;
TTopicBlock = record
Header : TWinHelpTopicBlockHeader;
DataSize : longint;
DataPtr : pointer;
end;
PWinHelpFile = ^TWinHelpFile;
TWinHelpFile = object(THelpFile)
constructor Init(AFileName: string; AID: word);
destructor Done; virtual;
public
function LoadIndex: boolean; virtual;
function ReadTopic(T: PTopic): boolean; virtual;
private
F: PStream;
Header: TWinHelpHeader;
SysHeader: TWinHelpSystemHeader;
Title: string;
CNTFileName: string;
PhrasesStart: longint;
TTLBTreeStart: longint;
TopicFileStart: longint;
Phrases: PUnsortedStringCollection;
TreeDone: boolean;
IndexLoaded: boolean;
function ReadHeader: boolean;
function ReadInternalDirectory: boolean;
function ProcessLeafPage(PagesBase: longint; PageSize,PageNo,TotalPages: word;
ReadLeafEntryMethod: pointer; ScannedPages: PIntCollection): boolean;
function ProcessIndexPage(CurLevel,MaxLevel: integer; PagesBase: longint; PageSize: word; PageNo,
TotalPages: word; ReadIndexEntryMethod, ReadLeafEntryMethod: pointer;
ScannedPages: PIntCollection): boolean;
function ProcessTree(ReadIndexEntryMethod, ReadLeafEntryMethod: pointer; NoDuplicates: boolean): boolean;
function IDIRReadIndexEntry(SubPageNo: PInteger): boolean;
function IDIRReadLeafEntry(P: pointer): boolean;
function IDIRProcessFile(const FileName: string; FileOfs: longint): boolean;
function TTLBReadIndexEntry(SubPageNo: PInteger): boolean;
function TTLBReadLeafEntry(P: pointer): boolean;
function TTLBProcessTopicEntry(const TopicTitle: string; FileOfs: longint): boolean;
function ReadSystemFile: boolean;
function ReadPhraseFile: boolean;
function ReadTTLBTree: boolean;
function TopicBlockSize: word;
function LZ77Compressed: boolean;
procedure ExtractTopicOffset(TopicOffset: longint; var TopicBlockNo, TopicBlockOffset: word);
function ReadTopicBlock(BlockNo: word; var T: TTopicBlock; ReadData: boolean): boolean;
end;
implementation
uses Crt,CallSpec;
function ReadString(F: PStream): string;
var S: string;
C: char;
begin
S:='';
if Assigned(F) then
repeat
F^.Read(C,sizeof(C));
if (F^.Status=stOK) and (C<>#0) then
S:=S+C;
until (C=#0) or (F^.Status<>stOK);
ReadString:=S;
end;
constructor TWinHelpFile.Init(AFileName: string; AID: word);
var OK: boolean;
begin
if inherited Init(AID)=false then Fail;
New(Phrases, Init(1000,1000));
F:=New(PFastBufStream, Init(AFileName, stOpenRead, HelpStreamBufSize));
OK:=F<>nil;
if OK then OK:=(F^.Status=stOK);
if OK then
begin
OK:=ReadHeader;
end;
if OK=false then
begin
Done;
Fail;
end;
end;
function TWinHelpFile.ReadHeader: boolean;
var OK: boolean;
begin
F^.Read(Header,sizeof(Header));
OK:=(F^.Status=stOK);
OK:=OK and (Header.MagicNo=WinHelpMagicNo);
if OK then
begin
F^.Seek(Header.DirectoryStart);
OK:=(F^.Status=stOK);
end;
if OK then
OK:=ReadInternalDirectory;
ReadHeader:=OK;
end;
function TWinHelpFile.TopicBlockSize: word;
var Size: word;
begin
if (SysHeader.Version<=16) then
Size:=2048 else
if (SysHeader.Flags in[0,4]) then
Size:=4096
else
Size:=2048;
TopicBlockSize:=Size;
end;
function TWinHelpFile.LZ77Compressed: boolean;
begin
LZ77Compressed:=(SysHeader.Version>16) and (SysHeader.Flags<>0);
end;
function TWinHelpFile.ReadSystemFile: boolean;
var OK: boolean;
FH: TWinHelpFileEntryHeader;
RH: TWinHelpRecordHeader;
StartOfs,RecStartOfs: longint;
begin
F^.Read(FH,sizeof(FH));
OK:=(F^.Status=stOK);
StartOfs:=F^.GetPos;
F^.Read(SysHeader,sizeof(SysHeader));
OK:=OK and (F^.Status=stOK);
OK:=OK and (SysHeader.Magic=WinHelpSystemHeaderMagicNo);
if OK then
if SysHeader.Version>16 then
begin
repeat
F^.Read(RH,sizeof(RH));
OK:=(F^.Status=stOK);
RecStartOfs:=F^.GetPos;
if OK then
begin
case RH.RecordType of
wh_srt_Title : Title:=ReadString(F);
wh_srt_Content : CNTFileName:=ReadString(F);
end;
if F^.GetPos<>RecStartOfs+RH.DataSize then
F^.Seek(RecStartOfs+RH.DataSize);
OK:=(F^.Status=stOK);
end;
until (OK=false) or (F^.GetPos>=StartOfs+FH.UsedSpace);
end
else
Title:=ReadString(F);
OK:=OK and (F^.Status=stOK);
ReadSystemFile:=OK;
end;
function LZ77Decompress(SrcBufP: pointer; SrcSize: longint; DestBufP: pointer; DestSize: longint): longint;
var SrcBuf: PByteArray absolute SrcBufP;
DestBuf: PByteArray absolute DestBufP;
var SrcOfs: longint;
function GetByte: byte;
begin
GetByte:=PByteArray(SrcBuf)^[SrcOfs];
Inc(SrcOfs);
end;
var DestOfs: longint;
procedure PutByte(B: byte);
begin
PByteArray(DestBuf)^[DestOfs]:=B;
Inc(DestOfs);
end;
var B,Mask: byte;
Len,J: word;
I: integer;
const N = 4096; F=16;
begin
SrcOfs:=0; DestOfs:=0; I:=N-F;
while (SrcOfs<SrcSize) do
begin
B:=GetByte;
for Mask:=0 to 7 do
begin
if SrcOfs=SrcSize then Break;
if (B and (1 shl Mask))<>0 then
begin
J:=GetByte;
Len:=GetByte;
J:=J+(Len and $0f) shl 8;
Len:=(Len and $f0) shr 4+3;
while (Len>0) do
begin
PutByte(PByteArray(DestBuf)^[DestOfs-J-1]);
{Inc(J); }Inc(I);
Dec(Len);
end;
end
else
begin
PutByte(GetByte);
I:=(I+1) and (N-1);
end;
end;
end;
LZ77Decompress:=DestOfs;
end;
function TWinHelpFile.ReadPhraseFile: boolean;
var OK: boolean;
FH: TWinHelpFileEntryHeader;
NumPhrases: word;
DecompSize: longint;
W: word;
PhraseOfss: PWordArray;
PhraseOfssSize: word;
PhraseBuf: PByteArray;
TempBuf: pointer;
TempSize: longint;
I,PhraseBufSize,PhraseOfs,PhraseSize: longint;
S: string;
begin
F^.Read(FH,sizeof(FH));
OK:=(F^.Status=stOK);
F^.Read(NumPhrases,sizeof(NumPhrases));
F^.Read(W,sizeof(W));
OK:=(F^.Status=stOK) and (W=$0100);
if OK then
begin
PhraseOfssSize:=(NumPhrases+1)*sizeof(word);
GetMem(PhraseOfss,PhraseOfssSize);
F^.Read(W,sizeof(W));
if W=2*(NumPhrases+1) then
begin
{ uncompressed data }
PhraseOfss^[0]:=W;
F^.Read(PhraseOfss^[1],PhraseOfssSize-sizeof(word)*1);
DecompSize:=FH.UsedSpace-(PhraseOfssSize+2+2+2);
PhraseBufSize:=DecompSize;
GetMem(PhraseBuf,PhraseBufSize);
F^.Read(PhraseBuf^,DecompSize);
end
else
begin
DecompSize:=W;
F^.Read(W,sizeof(W));
DecompSize:=DecompSize+longint(W) shl 16;
Inc(DecompSize);
PhraseOfss^[0]:=DecompSize;
F^.Read(PhraseOfss^[1],PhraseOfssSize);
PhraseBufSize:=DecompSize+10;
GetMem(PhraseBuf,PhraseBufSize); FillChar(PhraseBuf^,DecompSize,0);
TempSize:=FH.UsedSpace-(PhraseOfssSize+2+2+2);
GetMem(TempBuf,TempSize);
F^.Read(TempBuf^,TempSize);
LZ77Decompress(TempBuf,TempSize,PhraseBuf,DecompSize);
FreeMem(TempBuf,TempSize);
end;
for I:=1 to NumPhrases do
begin
PhraseOfs:=PhraseOfss^[I]-PhraseOfss^[1];
if I=NumPhrases then
PhraseSize:=DecompSize-PhraseOfs
else
PhraseSize:=PhraseOfss^[I+1]-PhraseOfss^[I];
S:=MemToStr(PhraseBuf^[PhraseOfs],PhraseSize);
Phrases^.InsertStr(S);
end;
FreeMem(PhraseOfss,PhraseOfssSize);
FreeMem(PhraseBuf,PhraseBufSize);
end;
ReadPhraseFile:=OK;
end;
function TWinHelpFile.ProcessLeafPage(PagesBase: longint; PageSize,PageNo,TotalPages: word;
ReadLeafEntryMethod: pointer; ScannedPages: PIntCollection): boolean;
var OK: boolean;
BNH: TWinHelpBTreeNodeHeader;
Count: longint;
PageOfs: longint;
CurPage: longint;
begin
CurPage:=PageNo;
repeat
PageOfs:=PagesBase+longint(PageSize)*CurPage;
F^.Seek(PageOfs);
OK:=(F^.Status=stOK);
if OK then
begin
F^.Read(BNH,sizeof(BNH));
OK:=(F^.Status=stOK);
end;
if OK then
if (ScannedPages<>nil) and ScannedPages^.Contains(CurPage) then
Break
else
begin
if Assigned(ScannedPages) then ScannedPages^.Add(CurPage);
Count:=0;
repeat
TreeDone:=not (longint(CallPointerMethod(ReadLeafEntryMethod,@Self,nil))<>0);
Inc(Count);
until (OK=false) or (F^.Status<>stOK) or TreeDone or (Count>=BNH.NumEntries){ or
(F^.GetPos>=PageOfs+PageSize-BNH.NumEntries)};
end;
if (BNH.PrevPage<>-1) and (TreeDone=false) then
CurPage:=BNH.PrevPage;
until (OK=false) or TreeDone or (BNH.PrevPage=-1);
ProcessLeafPage:=OK;
end;
function TWinHelpFile.ProcessIndexPage(CurLevel,MaxLevel: integer; PagesBase: longint; PageSize: word; PageNo,
TotalPages: word; ReadIndexEntryMethod, ReadLeafEntryMethod: pointer; ScannedPages: PIntCollection): boolean;
var BIH: TWinHelpBTreeIndexHeader;
I: integer;
SubPageNo: integer;
OK: boolean;
OldPos: longint;
CurPage: longint;
begin
CurPage:=PageNo;
repeat
F^.Seek(PagesBase+longint(PageSize)*CurPage);
OK:=(F^.Status=stOK);
if OK then
begin
F^.Read(BIH,sizeof(BIH));
OK:=(F^.Status=stOK);
end;
if OK then
if (ScannedPages<>nil) and ScannedPages^.Contains(CurPage) then
Break
else
begin
if Assigned(ScannedPages) then ScannedPages^.Add(CurPage);
for I:=1 to BIH.NumEntries do
begin
SubPageNo:=-1;
OK:=(longint(CallPointerMethod(ReadIndexEntryMethod,@Self,@SubPageNo))<>0);
OK:=OK and (F^.Status=stOK);
if OK then
if CurLevel<MaxLevel-1 then
begin
if (0<=SubPageNo) then
if (ScannedPages=nil) or (ScannedPages^.Contains(SubPageNo)=false) then
begin
OldPos:=F^.GetPos;
OK:=ProcessIndexPage(CurLevel+1,MaxLevel,PagesBase,PageSize,SubPageNo,TotalPages,
ReadIndexEntryMethod,ReadLeafEntryMethod,ScannedPages);
if F^.GetPos<>OldPos then
F^.Seek(OldPos);
end
end
else
{ process leaf page }
if (0<=SubPageNo) then
if (ScannedPages=nil) or (ScannedPages^.Contains(SubPageNo)=false) then
begin
OldPos:=F^.GetPos;
OK:=ProcessLeafPage(PagesBase,PageSize,SubPageNo,TotalPages,ReadLeafEntryMethod,ScannedPages);
if F^.GetPos<>OldPos then
F^.Seek(OldPos);
end;
if TreeDone then
Break;
end;
end;
if (BIH.PrevPage>0) and (TreeDone=false) then
CurPage:=BIH.PrevPage
else
Break;
until (OK=false) or TreeDone;
ProcessIndexPage:=OK;
end;
function TWinHelpFile.ProcessTree(ReadIndexEntryMethod, ReadLeafEntryMethod: pointer; NoDuplicates: boolean): boolean;
var BTH: TWinHelpBTreeHeader;
OK: boolean;
PagesBase: longint;
ScannedPages: PIntCollection;
begin
ScannedPages:=nil;
TreeDone:=false;
F^.Read(BTH,sizeof(BTH));
OK:=(F^.Status=stOK);
PagesBase:=F^.GetPos;
if OK then
begin
OK:=(BTH.Magic=WinHelpBTreeHeaderMagicNo) and
(BTH.MustBeZero=0) and
(BTH.MustBeNegOne=-1);
end;
if OK then
begin
if NoDuplicates then
New(ScannedPages, Init(500,100));
if BTH.NumLevels>1 then
begin
OK:=ProcessIndexPage(1,BTH.NumLevels,PagesBase,BTH.PageSize,BTH.RootPage,BTH.TotalPages,
ReadIndexEntryMethod,ReadLeafEntryMethod,ScannedPages);
end
else
OK:=ProcessLeafPage(PagesBase,BTH.PageSize,BTH.RootPage,BTH.TotalPages,ReadLeafEntryMethod,ScannedPAges);
if Assigned(ScannedPages) then
Dispose(ScannedPages, Done);
end;
ProcessTree:=OK;
end;
(*function TWinHelpFile.IDIRProcessFile(const FileName: string; FileOfs: longint): boolean;
var OK: boolean;
begin
OK:=true;
if FileName='|SYSTEM' then
begin
F^.Seek(FileOfs); OK:=(F^.Status=stOK);
if OK then OK:=ReadSystemFile;
end else
if (FileName='|Phrases') then
begin
PhrasesStart:=FileOfs;
end else
;
IDIRProcessFile:=OK;
end;
function TWinHelpFile.IDIRProcessLeafPage(PagesBase: longint; PageSize,PageNo,TotalPages: word): boolean;
var OK: boolean;
BNH: TWinHelpBTreeNodeHeader;
FileOfs: longint;
Count: integer;
S: string;
CurOfs,PageOfs,OldPos: longint;
begin
PageOfs:=PagesBase+PageSize*PageNo;
F^.Seek(PageOfs);
OK:=(F^.Status=stOK);
repeat
if OK then
begin
F^.Read(BNH,sizeof(BNH));
OK:=(F^.Status=stOK);
end;
if OK then
begin
Count:=0;
repeat
S:=ReadString(F);
F^.Read(FileOfs,sizeof(FileOfs)); { longint }
OK:=OK and (F^.Status=stOK);
if OK then
begin
OldPos:=F^.GetPos;
OK:=IDIRProcessFile(S,FileOfs);
if F^.GetPos<>OldPos then
F^.Seek(OldPos);
end;
Inc(Count);
until (OK=false) or (Count=BNH.NumEntries){ or (F^.GetPos>=PageOfs+PageSize-BNH.NumEntries)};
end;
if BNH.PrevPage<>-1 then
begin
F^.Seek(PagesBase+PageSize*BNH.PrevPage);
OK:=(F^.Status=stOK);
end;
until (OK=false) or (BNH.PrevPage=-1);
IDIRProcessLeafPage:=OK;
end;
function TWinHelpFile.IDIRProcessIndexPage(CurLevel,MaxLevel: integer; PagesBase: longint; PageSize: word; PageNo,
TotalPages: word): boolean;
var BIH: TWinHelpBTreeIndexHeader;
I: integer;
SubPageNo: integer;
OK: boolean;
S: string;
OldPos: longint;
begin
F^.Seek(PagesBase+PageSize*PageNo);
OK:=(F^.Status=stOK);
repeat
if OK then
begin
F^.Read(BIH,sizeof(BIH));
OK:=(F^.Status=stOK);
end;
if OK then
for I:=1 to BIH.NumEntries do
begin
S:=ReadString(F);
F^.Read(SubPageNo,sizeof(SubPageNo)); { word }
OK:=OK and (F^.Status=stOK);
if OK then
if CurLevel<MaxLevel-1 then
begin
if (0<=SubPageNo) then
begin
OldPos:=F^.GetPos;
OK:=IDIRProcessIndexPage(CurLevel+1,MaxLevel,PagesBase,PageSize,SubPageNo,TotalPages);
if F^.GetPos<>OldPos then
F^.Seek(OldPos);
end
end
else
{ process leaf page }
if (0<=SubPageNo) then
OK:=IDIRProcessLeafPage(PagesBase,PageSize,SubPageNo,TotalPages);
end;
if (BIH.PrevPage>0) then
begin
F^.Seek(PagesBase+PageSize*BIH.PrevPage);
OK:=(F^.Status=stOK);
end
else
Break;
until (OK=false);
IDIRProcessIndexPage:=OK;
end;
function TWinHelpFile.ReadInternalDirectory: boolean;
var BTH: TWinHelpBTreeHeader;
OK: boolean;
PagesBase: longint;
begin
F^.Read(BTH,sizeof(BTH));
OK:=(F^.Status=stOK);
PagesBase:=F^.GetPos;
if OK then
begin
OK:=(BTH.Magic=WinHelpBTreeHeaderMagicNo) and
(BTH.MustBeZero=0) and
(BTH.MustBeNegOne=-1);
end;
if BTH.NumLevels>1 then
OK:=IDIRProcessIndexPage(1,BTH.NumLevels,PagesBase,BTH.PageSize,BTH.RootPage,BTH.TotalPages)
else
OK:=IDIRProcessLeafPage(PagesBase,BTH.PageSize,BTH.RootPage,BTH.TotalPages);
ReadInternalDirectory:=OK;
end;
*)
function TWinHelpFile.IDIRProcessFile(const FileName: string; FileOfs: longint): boolean;
var OK: boolean;
begin
OK:=true;
if FileName='|SYSTEM' then
begin
F^.Seek(FileOfs); OK:=(F^.Status=stOK);
if OK then OK:=ReadSystemFile;
end else
if (FileName='|Phrases') then
begin
PhrasesStart:=FileOfs;
end else
;
if (FileName='|TOPIC') then
begin
TopicFileStart:=FileOfs;
end else
;
if (FileName='|TTLBTREE') then
begin
TTLBTreeStart:=FileOfs;
end else
;
IDIRProcessFile:=OK;
end;
function TWinHelpFile.IDIRReadIndexEntry(SubPageNo: PInteger): boolean;
var {S: string;}
OK: boolean;
begin
{S:=}ReadString(F);
F^.Read(SubPageNo^,sizeof(SubPageNo^));
OK:=(F^.Status=stOK);
IDIRReadIndexEntry:=OK;
end;
function TWinHelpFile.IDIRReadLeafEntry(P: pointer): boolean;
var OK: boolean;
S: string;
FileOfs,OldPos: longint;
begin
S:=ReadString(F);
F^.Read(FileOfs,sizeof(FileOfs)); { longint }
OK:=(F^.Status=stOK);
if OK then
begin
OldPos:=F^.GetPos;
OK:=IDIRProcessFile(S,FileOfs);
if F^.GetPos<>OldPos then
F^.Seek(OldPos);
OK:=OK and (F^.Status=stOK);
end;
IDIRReadLeafEntry:=OK;
end;
function TWinHelpFile.ReadInternalDirectory: boolean;
var OK: boolean;
FH: TWinHelpFileEntryHeader;
begin
F^.Read(FH,sizeof(FH));
OK:=(F^.Status=stOK);
if OK then
OK:=ProcessTree(@TWinHelpFile.IDIRReadIndexEntry,@TWinHelpFile.IDIRReadLeafEntry,true);
ReadInternalDirectory:=OK;
end;
function TWinHelpFile.TTLBReadIndexEntry(SubPageNo: PInteger): boolean;
var TopicOffset: longint;
OK: boolean;
begin
F^.Read(TopicOffset,sizeof(TopicOffset));
F^.Read(SubPageNo^,sizeof(SubPageNo^));
OK:=(F^.Status=stOK);
TTLBReadIndexEntry:=OK;
end;
function TWinHelpFile.TTLBReadLeafEntry(P: pointer): boolean;
var OK: boolean;
S: string;
TopicOfs,OldPos: longint;
begin
F^.Read(TopicOfs,sizeof(TopicOfs)); { longint }
S:=ReadString(F);
OK:=(F^.Status=stOK);
if OK then
begin
OldPos:=F^.GetPos;
OK:=TTLBProcessTopicEntry(S,TopicOfs);
if F^.GetPos<>OldPos then
F^.Seek(OldPos);
OK:=OK and (F^.Status=stOK);
end;
TTLBReadLeafEntry:=OK;
end;
function TWinHelpFile.TTLBProcessTopicEntry(const TopicTitle: string; FileOfs: longint): boolean;
var OK: boolean;
const Count: longint = 0;
begin
Inc(Count);
if (Count mod 100)=1 then
begin
gotoxy(1,1); write(Count,' - ',IndexEntries^.Count,' - ',Topics^.Count);
end;
OK:=(IndexEntries^.Count<MaxCollectionSize-10);
if OK then
begin
if (TopicTitle<>'') and (FileOfs>=0) then
begin
AddIndexEntry(TopicTitle,FileOfs);
AddTopic(FileOfs,FileOfs,'');
end;
end;
TTLBProcessTopicEntry:=OK;
end;
function TWinHelpFile.ReadTTLBTree: boolean;
var OK: boolean;
FH: TWinHelpFileEntryHeader;
begin
F^.Read(FH,sizeof(FH));
OK:=(F^.Status=stOK);
if OK then
OK:=ProcessTree(@TWinHelpFile.TTLBReadIndexEntry,@TWinHelpFile.TTLBReadLeafEntry,true);
ReadTTLBTree:=OK;
end;
function TWinHelpFile.LoadIndex: boolean;
var OK: boolean;
begin
if IndexLoaded then OK:=true else
begin
if PhrasesStart<>0 then
begin
F^.Seek(PhrasesStart); OK:=(F^.Status=stOK);
if OK then OK:=ReadPhraseFile;
end;
if TTLBTreeStart<>0 then
begin
F^.Seek(TTLBTreeStart); OK:=(F^.Status=stOK);
if OK then OK:=ReadTTLBTree;
end;
IndexLoaded:=OK;
end;
LoadIndex:=OK;
end;
procedure TWinHelpFile.ExtractTopicOffset(TopicOffset: longint; var TopicBlockNo, TopicBlockOffset: word);
var {OfsBitCount: longint;
OfsMask: longint;}
BS: longint;
begin
if LZ77Compressed then
BS:=16384
else
BS:=TopicBlockSize;
{ for OfsBitCount:=0 to 31 do
if (1 shl OfsBitCount)=BS then
Break;
OfsMask:=(1 shl OfsBitCount)-1;
TopicBlockNo:=(TopicOffset and not OfsMask) shr OfsBitCount;
TopicBlockOffset:=(TopicOffset and OfsMask);}
TopicBlockNo:=TopicOffset div BS;
TopicBlockOffset:=TopicOffset mod BS;
end;
function TWinHelpFile.ReadTopicBlock(BlockNo: word; var T: TTopicBlock; ReadData: boolean): boolean;
var TempBuf: pointer;
BlockBuf: ^TWinHelpTopicBlock;
OK: boolean;
RS,DecompSize: longint;
const TempBufSize = 16384;
begin
FillChar(T,sizeof(T),0);
F^.Seek(TopicFileStart+sizeof(TWinHelpFileEntryHeader)+longint(BlockNo)*TopicBlockSize);
OK:=(F^.Status=stOK);
if OK then
if ReadData=false then
begin
F^.Read(T.Header,sizeof(T.Header));
OK:=(F^.Status=stOK);
end
else
begin
GetMem(BlockBuf, TopicBlockSize);
F^.Read(BlockBuf^,TopicBlockSize);
OK:=(F^.Status=stOK);
if OK then
begin
Move(BlockBuf^.Header,T.Header,sizeof(T.Header));
if LZ77Compressed then
begin
GetMem(TempBuf,TempBufSize);
DecompSize:=LZ77Decompress(@BlockBuf^.Data,TopicBlockSize-sizeof(BlockBuf^.Header),TempBuf,TempBufSize);
T.DataSize:=DecompSize;
GetMem(T.DataPtr,T.DataSize);
Move(TempBuf^,T.DataPtr^,T.DataSize);
FreeMem(TempBuf,TempBufSize);
end
else
begin
T.DataSize:=TopicBlockSize-sizeof(BlockBuf^.Header);
GetMem(T.DataPtr,T.DataSize);
Move(BlockBuf^.Data,T.DataPtr^,T.DataSize);
end;
end;
FreeMem(BlockBuf,TopicBlockSize);
end;
ReadTopicBlock:=OK;
end;
procedure FreeTopicBlock(T: TTopicBlock);
begin
if (T.DataSize>0) and (T.DataPtr<>nil) then
begin
FreeMem(T.DataPtr,T.DataSize);
T.DataPtr:=nil;
end;
end;
function TWinHelpFile.ReadTopic(T: PTopic): boolean;
var OK: boolean;
BlockNo,BlockOfs: word;
TB: TTopicBlock;
begin
OK:=(TopicFileStart<>0) and (T<>nil);
if OK then
begin
ExtractTopicOffset(T^.FileOfs,BlockNo,BlockOfs);
OK:=ReadTopicBlock(BlockNo,TB,true);
end;
if OK then
begin
FreeTopicBlock(TB);
end;
ReadTopic:=OK;
end;
destructor TWinHelpFile.Done;
begin
if Assigned(F) then Dispose(F, Done); F:=nil;
if Assigned(Phrases) then Dispose(Phrases, Done); Phrases:=nil;
inherited Done;
end;
END.
{
$Log$
Revision 1.1 2000-06-26 07:29:23 pierre
* new bunch of Gabor's changes
}