diff options
Diffstat (limited to 'docview/src/docdump')
-rw-r--r-- | docview/src/docdump/docdump.lpi | 114 | ||||
-rw-r--r-- | docview/src/docdump/docdump.lpr | 98 | ||||
-rw-r--r-- | docview/src/docdump/filestreamhelper.pas | 35 | ||||
-rw-r--r-- | docview/src/docdump/iterator_impl.pas | 480 | ||||
-rw-r--r-- | docview/src/docdump/iterator_intf.pas | 169 | ||||
-rw-r--r-- | docview/src/docdump/readcontrols.pas | 44 | ||||
-rw-r--r-- | docview/src/docdump/readextfiles.pas | 53 | ||||
-rw-r--r-- | docview/src/docdump/readfonts.pas | 47 | ||||
-rw-r--r-- | docview/src/docdump/readheader.pas | 135 | ||||
-rw-r--r-- | docview/src/docdump/readnlsdata.pas | 31 | ||||
-rw-r--r-- | docview/src/docdump/readstrings.pas | 56 | ||||
-rw-r--r-- | docview/src/docdump/readtoc.pas | 171 | ||||
-rw-r--r-- | docview/src/docdump/u_Tools.pas | 52 |
13 files changed, 1485 insertions, 0 deletions
diff --git a/docview/src/docdump/docdump.lpi b/docview/src/docdump/docdump.lpi new file mode 100644 index 00000000..440c482c --- /dev/null +++ b/docview/src/docdump/docdump.lpi @@ -0,0 +1,114 @@ +<?xml version="1.0"?> +<CONFIG> + <ProjectOptions> + <Version Value="7"/> + <General> + <SessionStorage Value="InIDEConfig"/> + <MainUnit Value="0"/> + <TargetFileExt Value=""/> + <UseAppBundle Value="False"/> + </General> + <VersionInfo> + <ProjectVersion Value=""/> + </VersionInfo> + <PublishOptions> + <Version Value="2"/> + <IgnoreBinaries Value="False"/> + <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> + <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> + </local> + </RunParams> + <Units Count="15"> + <Unit0> + <Filename Value="docdump.lpr"/> + <IsPartOfProject Value="True"/> + <UnitName Value="docdump"/> + </Unit0> + <Unit1> + <Filename Value="../IPFEscapeCodes.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="IPFEscapeCodes"/> + </Unit1> + <Unit2> + <Filename Value="../IPFFileFormatUnit.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="IPFFileFormatUnit"/> + </Unit2> + <Unit3> + <Filename Value="readheader.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="readheader"/> + </Unit3> + <Unit4> + <Filename Value="filestreamhelper.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="filestreamhelper"/> + </Unit4> + <Unit5> + <Filename Value="readextfiles.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="readextfiles"/> + </Unit5> + <Unit6> + <Filename Value="../../docs/inf04.txt"/> + <IsPartOfProject Value="True"/> + </Unit6> + <Unit7> + <Filename Value="readstrings.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="readstrings"/> + </Unit7> + <Unit8> + <Filename Value="iterator_impl.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="iterator_impl"/> + </Unit8> + <Unit9> + <Filename Value="iterator_intf.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="iterator_intf"/> + </Unit9> + <Unit10> + <Filename Value="readnlsdata.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="readnlsdata"/> + </Unit10> + <Unit11> + <Filename Value="readfonts.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="readfonts"/> + </Unit11> + <Unit12> + <Filename Value="readcontrols.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="readcontrols"/> + </Unit12> + <Unit13> + <Filename Value="readtoc.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="readtoc"/> + </Unit13> + <Unit14> + <Filename Value="u_Tools.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="u_Tools"/> + </Unit14> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="8"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)/"/> + <OtherUnitFiles Value="../"/> + <UnitOutputDirectory Value="units/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Other> + <CompilerPath Value="$(CompPath)"/> + </Other> + </CompilerOptions> +</CONFIG> diff --git a/docview/src/docdump/docdump.lpr b/docview/src/docdump/docdump.lpr new file mode 100644 index 00000000..84077608 --- /dev/null +++ b/docview/src/docdump/docdump.lpr @@ -0,0 +1,98 @@ +{ + Dumps the structure of an OS/2 IPF help file +} +program docdump; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UNIX}{$IFDEF UseCThreads} + cthreads, + {$ENDIF}{$ENDIF} + Classes, SysUtils, IPFFileFormatUnit, IPFEscapeCodes, CustApp, readheader, + filestreamhelper, readextfiles, readstrings, iterator_intf, iterator_impl, + readnlsdata, readfonts, readcontrols, readtoc, u_Tools; + +type + + { TDocDump } + + TDocDump = class(TCustomApplication) + private + FIn: TFileStream; + FOut: TFileTextStream; + protected + procedure DoRun; override; + public + constructor Create(TheOwner: TComponent); override; + destructor Destroy; override; + procedure WriteHelp; virtual; + end; + +{ TDocDump } + +procedure TDocDump.DoRun; +var + ErrorMsg: String; +begin + // quick check parameters + ErrorMsg:=CheckOptions('h','help'); + if ErrorMsg<>'' then begin + ShowException(Exception.Create(ErrorMsg)); + Terminate; + Exit; + end; + + // parse parameters + if HasOption('h','help') then begin + WriteHelp; + Terminate; + Exit; + end; + + FIn := TFileStream.Create(ParamStr(1), fmOpenRead); + FOut := TFileTextStream.Create(ExtractFileName(ParamStr(1))+'.txt', fmCreate); + try + FOut.WriteLn(Format('File name: %s (%d bytes)', [ExtractFileName(ParamStr(1)), FIn.Size])); + ProcessHeader(FIn, FOut); + ProcessExtFiles(FIn, FOut); + ProcessStringsTable(FIn, FOut); + ProcessNLSData(FIn, FOut); + ProcessFonts(FIn, FOut); + ProcessControls(FIn, FOut); + ProcessTOC(FIn, FOut); + finally + FIn.Free; + FOut.Free; + end; + // stop program loop + Terminate; +end; + +constructor TDocDump.Create(TheOwner: TComponent); +begin + inherited Create(TheOwner); + StopOnException:=True; +end; + +destructor TDocDump.Destroy; +begin + inherited Destroy; +end; + +procedure TDocDump.WriteHelp; +begin + { add your help code here } + writeln('Usage: ',ExeName,' -h'); +end; + +var + Application: TDocDump; + + +begin + Application:=TDocDump.Create(nil); + Application.Run; + Application.Free; +end. + diff --git a/docview/src/docdump/filestreamhelper.pas b/docview/src/docdump/filestreamhelper.pas new file mode 100644 index 00000000..ff831a91 --- /dev/null +++ b/docview/src/docdump/filestreamhelper.pas @@ -0,0 +1,35 @@ +unit filestreamhelper; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils; + +type + TFileTextStream = class(TFileStream) + public + procedure WriteLn(const fmt: String; const args: array of const); + procedure WriteLn(const s: String); + end; + +implementation + +{ TFileTextStream } + +procedure TFileTextStream.WriteLn(const fmt: String; const args: array of const); +var + temp: String; +begin + temp := Format(fmt, args) + LineEnding; + Write(temp[1], Length(temp)); +end; + +procedure TFileTextStream.WriteLn(const s: String); +begin + self.WriteLn('%s', [s]); +end; + +end. + diff --git a/docview/src/docdump/iterator_impl.pas b/docview/src/docdump/iterator_impl.pas new file mode 100644 index 00000000..4ad88052 --- /dev/null +++ b/docview/src/docdump/iterator_impl.pas @@ -0,0 +1,480 @@ +unit iterator_impl; + +{$mode objfpc}{$H+} + +interface + +uses + Classes + ,SysUtils + ,Regex { to be used with filtered string iterator } + ,iterator_intf + ,contnrs + ; + +type + + TTBStringsIterator = class(TInterfacedObject, ITBStringIterator, ITBStringAndObjectIterator) + private + FStrings: TStrings; + FCursor: Integer; + { Interface methods should always be private because + we will only ever access them via an Interface, + never via an Object instance } + + { Interface: ITBStringIterator and ITBStringAndObjectIterator } + function HasNext: Boolean; + function Next: string; + function HasPrevious: Boolean; + function Previous: string; + { Interface: ITBStringAndObjectIterator } + function HasNextObject: Boolean; + function NextObject: TObject; + function HasPreviousObject: Boolean; + function PreviousObject: TObject; + public + constructor CreateCustom(const ASource: TStrings); virtual; + end; + + + TTBListIterator = class(TInterfacedObject, ITBIterator) + private + FList: TList; + FCursor: Integer; + { Interface: ITBIterator } + function HasNext: Boolean; + function Next: TObject; + function HasPrevious: Boolean; + function Previous: TObject; + public + constructor CreateCustom(const ASource: TList); virtual; + end; + + + TTBCollectionIterator = class(TInterfacedObject, ITBIterator) + private + FCollection: TCollection; + FCursor: Integer; + { Interface: ITBIterator } + function HasNext: Boolean; + function Next: TObject; + function HasPrevious: Boolean; + function Previous: TObject; + public + constructor CreateCustom(const ASource: TCollection); virtual; + end; + + + TTBInterfaceListIterator = class(TInterfacedObject, ITBInterfaceIterator) + private + FList: TInterfaceList; + FCursor: integer; + { Interface: ITBinterfaceIterator } + function HasNext: Boolean; + function Next: IInterface; + function HasPrevious: Boolean; + function Previous: IInterface; + public + constructor CreateCustom(const ASource: TInterfaceList); virtual; + end; + + + TTBFilteredStringsIterator = class(TTBStringsIterator, ITBFilteredStringIterator) + private + FNextIndex: Integer; + FRegex: TRegexEngine; + { Interface: ITBFilteredStringIterator } + function GetFilter: string; + procedure SetFilter(const AValue: string); + { Interface: ITBStringIterator and ITBStringAndObjectIterator } + function HasNext: Boolean; + function Next: string; + function HasPrevious: Boolean; + function Previous: string; + public + constructor CreateCustom(const ASource: TStrings); override; + destructor Destroy; override; + end; + + + TTBObjectListIterator = class(TInterfacedObject, ITBIterator) + private + FList: TObjectList; + FCursor: Integer; + { Interface: ITBIterator } + function HasNext: Boolean; + function Next: TObject; + function HasPrevious: Boolean; + function Previous: TObject; + public + constructor CreateCustom(const ASource: TObjectList); virtual; + end; + + + +implementation + + +{ TTBStringsIterator } + +function TTBStringsIterator.HasNext: Boolean; +begin + Result := False; + if Assigned(FStrings) then + if FCursor < FStrings.Count - 1 then + Result := True; +end; + +function TTBStringsIterator.Next: string; +begin + Result := ''; + if HasNext then + begin + Inc(FCursor, 1); + Result := FStrings.Strings[FCursor]; + end; +end; + +function TTBStringsIterator.HasPrevious: Boolean; +begin + Result := False; + if Assigned(FStrings) then + if FCursor > 0 then + Result := True; +end; + +function TTBStringsIterator.Previous: string; +begin + Result := ''; + if HasPrevious then + begin + Dec(FCursor, 1); + Result := FStrings.Strings[FCursor]; + end; +end; + +function TTBStringsIterator.HasNextObject: Boolean; +begin + Result := False; + if Assigned(FStrings) then + if FCursor < FStrings.Count - 1 then + Result := FStrings.Objects[FCursor] <> nil; +end; + +function TTBStringsIterator.NextObject: TObject; +begin + Result := nil; + if HasNextObject then + // Note that Next(...) increments the FCursor + Result := FStrings.Objects[FCursor]; +end; + +function TTBStringsIterator.HasPreviousObject: Boolean; +begin + Result := False; + if Assigned(FStrings) then + if FCursor > 0 then + Result := FStrings.Objects[FCursor] <> nil; +end; + +function TTBStringsIterator.PreviousObject: TObject; +begin + Result := nil; + if HasPreviousObject then + // Note that Previous(...) decrements the FCursor + Result := FStrings.Objects[FCursor]; +end; + +constructor TTBStringsIterator.CreateCustom(const ASource: TStrings); +begin + inherited Create; + FStrings := ASource; + FCursor := -1; +end; + + +{ TTBListIterator } + +function TTBListIterator.HasNext: Boolean; +begin + Result := False; + if Assigned(FList) then + if FCursor < FList.Count - 1 then + Result := True; +end; + +function TTBListIterator.Next: TObject; +begin + Result := nil; + if HasNext then + begin + Inc(FCursor, 1); + result := TObject(FList.Items[FCursor]); + end; +end; + +function TTBListIterator.HasPrevious: Boolean; +begin + Result := False; + if Assigned(FList) then + begin + if FCursor > 0 then + Result := True; + end; +end; + +function TTBListIterator.Previous: TObject; +begin + Result := nil; + if HasPrevious then + begin + Dec(FCursor, 1); + Result := TObject(FList.Items[FCursor]); + end; +end; + +constructor TTBListIterator.CreateCustom(const ASource: TList); +begin + inherited Create; + FList := ASource; + FCursor := -1; +end; + + +{ TTBCollectionIterator } + +function TTBCollectionIterator.HasNext: Boolean; +begin + Result := False; + if Assigned(FCollection) then + if FCursor < FCollection.Count - 1 then + Result := True; +end; + +function TTBCollectionIterator.Next: TObject; +begin + Result := nil; + if HasNext then + begin + Inc(FCursor, 1); + result := FCollection.Items[FCursor]; + end; +end; + +function TTBCollectionIterator.HasPrevious: Boolean; +begin + Result := False; + if Assigned(FCollection) then + if FCursor > 0 then + Result := True; +end; + +function TTBCollectionIterator.Previous: TObject; +begin + Result := nil; + if HasPrevious then + begin + Dec(FCursor, 1); + Result := FCollection.Items[FCursor]; + end; +end; + +constructor TTBCollectionIterator.CreateCustom(const ASource: TCollection); +begin + inherited Create; + FCollection := ASource; + FCursor := -1; +end; + + +{ TTBFilteredStringsIterator } + +function TTBFilteredStringsIterator.GetFilter: string; +begin + Result := FRegex.RegexString; +end; + +procedure TTBFilteredStringsIterator.SetFilter(const AValue: string); +const + cFilterErr = 'Error in Filter string at position %d with ErrorCode %d. Filter string <%s>'; +var + LErrorCode: TRegexError; + LErrorPos: integer; +begin + if AValue <> FRegex.RegexString then + begin + FRegex.RegexString := AValue; + if not FRegex.Parse(LErrorPos, LErrorCode) then + raise Exception.CreateFmt(cFilterErr, [LErrorPos, Ord(LErrorCode), AValue]); + end; + FNextIndex := -1; +end; + +function TTBFilteredStringsIterator.HasNext: Boolean; +var + LIndex: integer; + LMatchPos: integer; + LOffset: integer; +begin + Result := False; + if GetFilter = '' then + begin + Result := inherited HasNext; + if Result then + FNextIndex := FCursor + 1; + end + else + begin + if FCursor < FStrings.Count - 1 then + begin + { If we haven't already calculated the next matching item } + if FNextIndex = -1 then + begin + LIndex := FCursor + 1; + { Peek ahead to find the next matching string } + while (LIndex < FStrings.Count) and (FNextIndex = -1) do + begin + { reset MatchString parameters } + LOffset := 0; + LMatchPos := 0; + if FRegex.MatchString(FStrings.Strings[LIndex], LMatchPos, LOffset) then + FNextIndex := LIndex; + Inc(LIndex); + end; + end; + if FNextIndex <> -1 then + Result := True; + end; + end; { if..else } +end; + +function TTBFilteredStringsIterator.Next: string; +begin + Result := ''; + if HasNext then + begin + FCursor := FNextIndex; + FNextIndex := -1; + Result := FStrings.Strings[FCursor]; + end; +end; + +function TTBFilteredStringsIterator.HasPrevious: Boolean; +begin + Result := False; // Filtered String is uni-directional +end; + +function TTBFilteredStringsIterator.Previous: string; +begin + Result := ''; + raise EUniDirectionalIterator.Create('Filtered String Iterator is uni-directional (forward) only.'); +end; + +constructor TTBFilteredStringsIterator.CreateCustom(const ASource: TStrings); +begin + inherited CreateCustom(ASource); + FRegex := TRegexEngine.Create(''); + FRegex.IgnoreCase := True; + FNextIndex := -1; +end; + +destructor TTBFilteredStringsIterator.Destroy; +begin + FRegex.Free; + inherited Destroy; +end; + + +{ TTBInterfaceListIterator } + +function TTBInterfaceListIterator.HasNext: Boolean; +begin + Result := False; + if Assigned(FList) then + if FCursor < FList.Count - 1 then + Result := True; +end; + +function TTBInterfaceListIterator.Next: IInterface; +begin + Result := nil; + if HasNext then + begin + Inc(FCursor, 1); + Result := FList.Items[FCursor]; + end; +end; + +function TTBInterfaceListIterator.HasPrevious: Boolean; +begin + Result := False; + if Assigned(FList) then + if FCursor > 0 then + Result := True; +end; + +function TTBInterfaceListIterator.Previous: IInterface; +begin + Result := nil; + if HasPrevious then + begin + Dec(FCursor, 1); + Result := FList.Items[FCursor]; + end; +end; + +constructor TTBInterfaceListIterator.CreateCustom(const ASource: TInterfaceList); +begin + inherited Create; + FList := ASource; + FCursor := -1; +end; + +{ TTBObjectListIterator } + +function TTBObjectListIterator.HasNext: Boolean; +begin + Result := False; + if Assigned(FList) then + if FCursor < FList.Count - 1 then + Result := True; +end; + +function TTBObjectListIterator.Next: TObject; +begin + result := nil; + if HasNext then + begin + Inc(FCursor); + result := FList.Items[FCursor]; + end; +end; + +function TTBObjectListIterator.HasPrevious: Boolean; +begin + Result := False; + if Assigned(FList) then + if FCursor > 0 then + Result := True; +end; + +function TTBObjectListIterator.Previous: TObject; +begin + result := nil; + if HasPrevious then + begin + Dec(FCursor); + result := FList.Items[FCursor]; + end; +end; + +constructor TTBObjectListIterator.CreateCustom(const ASource: TObjectList); +begin + inherited Create; + FList := ASource; + FCursor := -1; +end; + + +end. + diff --git a/docview/src/docdump/iterator_intf.pas b/docview/src/docdump/iterator_intf.pas new file mode 100644 index 00000000..e82b59a1 --- /dev/null +++ b/docview/src/docdump/iterator_intf.pas @@ -0,0 +1,169 @@ +unit iterator_intf; + +{$mode objfpc}{$H+} + +interface + +uses + Classes + ,SysUtils + ; + +type + { A custom exception class } + ENoIteratorImpl = class(Exception); + EUniDirectionalIterator = class(Exception); + + + { Standard iterators } + + ITBIterator = interface(IInterface) + ['{9C2BC10D-54C8-4B59-88B5-A564921CF0E3}'] + function HasNext: Boolean; + function Next: TObject; + function HasPrevious: Boolean; + function Previous: TObject; + end; + + + ITBStringIterator = interface(IInterface) + ['{B2A449B4-5D0A-4F14-AC11-CA055EDA3ED7}'] + function HasNext: Boolean; + function Next: string; + function HasPrevious: Boolean; + function Previous: string; + end; + + + ITBStringAndObjectIterator = interface(ITBStringIterator) + ['{287373DC-A90D-400E-BAEE-C85474C317A8}'] + function HasNextObject: Boolean; + function NextObject: TObject; + function HasPreviousObject: Boolean; + function PreviousObject: TObject; + end; + + + ITBInterfaceIterator = interface + ['{9B599C5B-4BBB-43F6-AF8E-09FEE9AE0E20}'] + function HasNext: Boolean; + function Next: IInterface; + function HasPrevious: Boolean; + function Previous: IInterface; + end; + + { TODO: + More interfaces could be added for collections like: + TTreeView, TStringGrid etc... } + + + { Filtered iterators } + + ITBFilteredStringIterator = interface(ITBStringIterator) + ['{CF1B9E2D-DD05-4D15-95C6-686EAFA4ED82}'] + function GetFilter: string; + procedure SetFilter(const AValue: string); + property Filter: string read GetFilter write SetFilter; + end; + + + { TODO: + More filtered versions of the standard iterators could + be added here... } + + + + { Iterator Factory } + + TTBIteratorFactory = class(TObject) + function Iterator(const ASource: TObject): ITBIterator; + function StringIterator(const ASource: TObject): ITBStringIterator; + function StringAndObjectIterator(const ASource: TObject): ITBStringAndObjectIterator; + function InterfaceIterator(const ASource: TObject): ITBInterfaceIterator; + function FilteredStringIterator(const ASource: TObject; const AFilter: string): ITBFilteredStringIterator; + end; + + +{ Global iterator factory singleton } +function gIteratorFactory: TTBIteratorFactory; + + +implementation + +uses + iterator_impl; + +var + uIteratorFactory: TTBIteratorFactory; + +const + cNoIteratorImpl = 'No Iterator implementation found for <%s>'; + + +{ The lazy mans singleton implementation, but it does the job just fine. } +function gIteratorFactory: TTBIteratorFactory; +begin + if not Assigned(uIteratorFactory) then + uIteratorFactory := TTBIteratorFactory.Create; + Result := uIteratorFactory; +end; + + +{ TTBIteratorFactory } + +function TTBIteratorFactory.Iterator(const ASource: TObject): ITBIterator; +begin + if ASource is TList then + Result := TTBListIterator.CreateCustom(TList(ASource)) + else if ASource is TCollection then + Result := TTBCollectionIterator.CreateCustom(TCollection(ASource)) + //else if ASource is TTreeNodes then + //Result := TTBTreeNodesIterator.CreateCustom(TTreeNodes(ASource)) + else + raise ENoIteratorImpl.CreateFmt(cNoIteratorImpl, [ASource.ClassName]); +end; + +function TTBIteratorFactory.StringIterator(const ASource: TObject): ITBStringIterator; +begin + if ASource is TStrings then + Result := TTBStringsIterator.CreateCustom(TStrings(ASource)) + else + raise ENoIteratorImpl.CreateFmt(cNoIteratorImpl, [ASource.ClassName]); +end; + +function TTBIteratorFactory.StringAndObjectIterator(const ASource: TObject): ITBStringAndObjectIterator; +begin + if ASource is TStrings then + Result := TTBStringsIterator.CreateCustom(TStrings(ASource)) + else + raise ENoIteratorImpl.CreateFmt(cNoIteratorImpl, [ASource.ClassName]); +end; + +function TTBIteratorFactory.InterfaceIterator(const ASource: TObject): ITBInterfaceIterator; +begin + if ASource is TInterfaceList then + Result := TTBInterfaceListIterator.CreateCustom(TInterfaceList(ASource)) + else + raise ENoIteratorImpl.CreateFmt(cNoIteratorImpl, [ASource.ClassName]); +end; + +function TTBIteratorFactory.FilteredStringIterator(const ASource: TObject; const AFilter: string): ITBFilteredStringIterator; +begin + if ASource is TStrings then + begin + Result := TTBFilteredStringsIterator.CreateCustom(TStrings(ASource)); + Result.Filter := AFilter; + end + else + raise ENoIteratorImpl.CreateFmt(cNoIteratorImpl, [ASource.ClassName]); +end; + + +initialization + uIteratorFactory := nil; + +finalization + uIteratorFactory.Free; + +end. + diff --git a/docview/src/docdump/readcontrols.pas b/docview/src/docdump/readcontrols.pas new file mode 100644 index 00000000..395a36db --- /dev/null +++ b/docview/src/docdump/readcontrols.pas @@ -0,0 +1,44 @@ +{ + Dump the controls data +} +unit readcontrols; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, filestreamhelper; + +procedure ProcessControls(AIn: TFileStream; AOut: TFileTextStream); + + +implementation + +uses + readheader, IPFFileFormatUnit; + +procedure ProcessControls(AIn: TFileStream; AOut: TFileTextStream); +var + ctrls: TPanelControls; + i: integer; +begin + AOut.WriteLn(''); + AOut.WriteLn('Panel Controls (Buttons)'); + if eHdr.CtrlOffset > 0 then + begin + AIn.Seek(eHdr.CtrlOffset, soBeginning); + AIn.Read(ctrls, SizeOf(TControlDef)); + AOut.WriteLn(Format(' PanelControls.ControlCount: %4.4x (%0:d)', [ctrls.ControlCount])); + AOut.WriteLn(Format(' PanelControls.GroupCount: %4.4x (%0:d)', [ctrls.GroupCount])); + AOut.WriteLn(Format(' PanelControls.GroupIndex: %4.4x (%0:d)', [ctrls.GroupIndex])); + AOut.WriteLn(Format(' PanelControls.Reserved: %4.4x (%0:d)', [ctrls.Reserved])); + AOut.WriteLn(' *****'); + AOut.WriteLn(' <todo - process CountrolCount and GroupCount data>'); + end + else + AOut.WriteLn(' No panel control found'); +end; + +end. + diff --git a/docview/src/docdump/readextfiles.pas b/docview/src/docdump/readextfiles.pas new file mode 100644 index 00000000..6ea979d9 --- /dev/null +++ b/docview/src/docdump/readextfiles.pas @@ -0,0 +1,53 @@ +{ + Dumps the names of external database (help) files referenced by this file +} +unit readextfiles; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, IPFFileFormatUnit, filestreamhelper; + +procedure ProcessExtFiles(AIn: TFileStream; AOut: TFileTextStream); + + +implementation + +uses + readheader; + +procedure ProcessExtFiles(AIn: TFileStream; AOut: TFileTextStream); +var + count: integer; + name: string; + pData: pointer; + p: pointer; + pLength: pByte; +begin + AOut.WriteLn(''); + AOut.WriteLn('External File References'); + + if eHdr.NumDataBase > 0 then + begin + pData := nil; + AIn.Seek(eHdr.DataBaseOffset, soBeginning); + GetMem(pData, eHdr.DataBaseSize); // allocate temp space for data + AIn.Read(pData^, eHdr.DataBaseSize); // read all data in one shot + p := pData; // p is our incrementing position in the data + for count := 0 to eHdr.NumDataBase-1 do + begin + pLength := p; // length byte, including itself + SetString(name, p+1, pLength^-1); // use length value minus the length byte to get the string length + AOut.WriteLn(Format(' File #%d: %s', [count, name])); + inc(p, pLength^); // skip to next entry using full length (including length byte) + end; + FreeMem(pData, eHdr.DataBaseSize); // free allocated space + end + else + AOut.WriteLn(' No external file references found'); +end; + +end. + diff --git a/docview/src/docdump/readfonts.pas b/docview/src/docdump/readfonts.pas new file mode 100644 index 00000000..6b684cac --- /dev/null +++ b/docview/src/docdump/readfonts.pas @@ -0,0 +1,47 @@ +{ + Dumps the font data +} +unit readfonts; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, filestreamhelper; + +procedure ProcessFonts(AIn: TFileStream; AOut: TFileTextStream); + + +implementation + +uses + readheader, IPFFileFormatUnit; + +procedure ProcessFonts(AIn: TFileStream; AOut: TFileTextStream); +var + fnt: THelpFontSpec; + pData: pointer; + i: integer; +begin + AOut.WriteLn(''); + AOut.WriteLn('Font Data'); + if eHdr.NumFontEntry > 0 then + begin + AIn.Seek(eHdr.FontTableOffset, soBeginning); + for i := 0 to eHdr.NumFontEntry-1 do + begin + AIn.Read(fnt, SizeOf(THelpFontSpec)); + AOut.WriteLn(Format(' Font Entry #%d', [i+1])); + AOut.WriteLn(Format(' FontSpec.FaceName: %s', [fnt.FaceName])); + AOut.WriteLn(Format(' FontSpec.Height: %4.4x (%0:d)', [fnt.Height])); + AOut.WriteLn(Format(' FontSpec.Width: %4.4x (%0:d)', [fnt.Width])); + AOut.WriteLn(Format(' FontSpec.CodePage: %4.4x (%0:d)', [fnt.Codepage])); + end; + end + else + AOut.WriteLn(' No font data is present'); +end; + +end. + diff --git a/docview/src/docdump/readheader.pas b/docview/src/docdump/readheader.pas new file mode 100644 index 00000000..201fcb86 --- /dev/null +++ b/docview/src/docdump/readheader.pas @@ -0,0 +1,135 @@ +{ + Dump the INF header & extended header structures to a text file +} +unit readheader; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, filestreamhelper, IPFFileFormatUnit; + +procedure ProcessHeader(AIn: TFileStream; AOut: TFileTextStream); + +var + hdr: THelpFileHeader; + eHdr: TExtendedHelpFileHeader; + + +implementation + + +type + TWord = record + b1: AnsiChar; + b2: AnsiChar; + end; + + TOverlayID = packed record + b1: Byte; + b2: Byte; + b3: Byte; + end; + + TOverlaySearchStart = bitpacked record + SearchOffset: Unsigned_31; + IsRec16bitSize: boolean; + end; + + +procedure ProcessHeader(AIn: TFileStream; AOut: TFileTextStream); +var + bytes: integer; + s: string; + w: TWord; + i: uint32; + t0: TOverlayID; + t1: TOverlaySearchStart; +begin + try + AIn.Seek(0, soBeginning); + bytes := AIn.Read(hdr, SizeOf(THelpFileHeader)); + if bytes <> SizeOf(THelpFileHeader) then + raise Exception.Create('Failed to read complete file header'); + + if hdr.ID <> INF_HEADER_ID then + raise Exception.Create('This is not an OS/2 help file'); + + AOut.WriteLn('Header Section'); + t0 := TOverlayID(hdr.ID); + s := hdr.ID; + AOut.WriteLn(Format(' ipfheader.id: %4.2x %2x %2x ("%s") : Magic word' ,[Byte(hdr.id[0]), Byte(hdr.id[1]), Byte(hdr.id[2]), s])); + if (hdr.flags and $01) > 0 then + s := 'INF' + else + s := 'HLP'; + AOut.WriteLn(Format(' ipfheader.flags: %8.2x (%s format) : File format' ,[hdr.flags, s])); + AOut.WriteLn(Format(' ipfheader.size: %8.4x (%0:7d bytes) : Size of this header structure', [hdr.hdrsize])); + AOut.WriteLn(Format(' ipfheader.version: %6d.%d : version of file format?', [hdr.version_hi, hdr.version_lo])); + AOut.WriteLn(Format(' ipfheader.ntoc: %8.4x (%0:13d) : No of TOC entries', [hdr.ntoc])); + AOut.WriteLn(Format(' ipfheader.tocstart: %8.8x (%0:7d bytes) : 32bit file offset to start of TOC', [hdr.tocstart])); + AOut.WriteLn(Format(' ipfheader.toclen: %8.8x (%0:7d bytes) : bytes occupied by TOC entries', [hdr.toclen])); + AOut.WriteLn(Format(' ipfheader.tocoffsetsstart: %8.8x (%0:7d bytes) : file offset to array of TOC offsets', [hdr.tocoffsetsstart])); + AOut.WriteLn(Format(' ipfheader.nres: %8.4x (%0:13d) : number of panels with resource numbers', [hdr.nres])); + AOut.WriteLn(Format(' ipfheader.resstart: %8.8x (%0:7d bytes) : 32bit file offset of ressource number table', [hdr.resstart])); + AOut.WriteLn(Format(' ipfheader.nname: %8.4x (%0:13d) : number of panels with textual name', [hdr.nname])); + AOut.WriteLn(Format(' ipfheader.namestart: %8.8x (%0:7d bytes) : 32bit file offset to panel name table', [hdr.namestart])); + AOut.WriteLn(Format(' ipfheader.nindex: %8.4x (%0:13d) : number of index entries', [hdr.nindex])); + AOut.WriteLn(Format(' ipfheader.indexstart: %8.8x (%0:7d bytes) : 32bit file offset to index table', [hdr.indexstart])); + AOut.WriteLn(Format(' ipfheader.indexlen: %8.8x (%0:7d bytes) : size of index table', [hdr.indexlen])); + AOut.WriteLn(Format(' ipfheader.icmdCount: %8.4x (%0:13d) : number of icmd index items', [hdr.icmdCount])); + AOut.WriteLn(Format(' ipfheader.icmdOffset: %8.8x (%0:7d bytes) : file offset to icmd index items', [hdr.icmdOffset])); + AOut.WriteLn(Format(' ipfheader.icmdSize: %8.8x (%0:7d bytes) : size of icmd index table', [hdr.icmdSize])); + t1 := TOverlaySearchStart(hdr.searchstart); + i := t1.SearchOffset; + AOut.WriteLn(Format(' ipfheader.searchstart :31 %8.8x (%0:7d bytes) : 31bit file offset of full text search table', [i, i])); + if t1.IsRec16bitSize then + s := 'search rec is 16bit size' + else + s := 'search rec is 8bit size'; + AOut.WriteLn(Format(' ipfheader.recSize :1 %s (%s) : if high bit set, search record size is 16bit', [BoolToStr(t1.IsRec16bitSize, True), s])); + AOut.WriteLn(Format(' ipfheader.searchlen: %8.8x (%0:7d bytes) : size of full text search table', [hdr.searchlen])); + AOut.WriteLn(Format(' ipfheader.nslots: %8.4x (%0:13d) : number of "slots"', [hdr.nslots])); + AOut.WriteLn(Format(' ipfheader.slotsstart: %8.8x (%0:7d bytes) : 32bit file offset of the slots array', [hdr.slotsstart])); + AOut.WriteLn(Format(' ipfheader.dictlen: %8.8x (%0:7d bytes) : bytes occupied by the "dictionary"', [hdr.dictlen])); + AOut.WriteLn(Format(' ipfheader.ndict: %8.4x (%0:13d) : number of entries in the dictionary', [hdr.ndict])); + AOut.WriteLn(Format(' ipfheader.dictstart: %8.8x (%0:7d bytes) : 32bit file offset to start of dictionary', [hdr.dictstart])); + AOut.WriteLn(Format(' ipfheader.imgstart: %8.8x (%0:7d bytes) : 32bit file offset to image data', [hdr.imgstart])); + AOut.WriteLn(Format(' ipfheader.maxCVTIndex: %8.2x (%0:13d) : highest index inside panel''s local dictionary', [hdr.maxCVTIndex])); + AOut.WriteLn(Format(' ipfheader.nlsstart: %8.8x (%0:7d bytes) : 32bit file offset of NLS table', [hdr.nlsstart, hdr.nlsstart])); + AOut.WriteLn(Format(' ipfheader.nlslen: %8.8x (%0:7d bytes) : size of NLS table', [hdr.nlslen])); + AOut.WriteLn(Format(' ipfheader.extstart: %8.8x (%0:7d bytes) : 32bit file offset of extended data block', [hdr.extstart])); + AOut.WriteLn(Format(' ipfheader.reserved: %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x : for future use. set to zero.', + [hdr.reserved[0], hdr.reserved[1], hdr.reserved[2], hdr.reserved[3], hdr.reserved[4], hdr.reserved[5], + hdr.reserved[6], hdr.reserved[7], hdr.reserved[8], hdr.reserved[9], hdr.reserved[10], hdr.reserved[11] ])); + AOut.WriteLn(Format(' ipfheader.title: "%s" : ASCII title of database', [hdr.title])); + + AOut.WriteLn(''); + AOut.WriteLn('Extended Header Section'); + AIn.Seek(hdr.extstart, soBeginning); + AIn.Read(eHdr, SizeOf(TExtendedHelpFileHeader)); + AOut.WriteLn(Format(' extheader.NumFontEntry %8.4x (%0:13d) : Font Table - number of entries', [eHdr.NumFontEntry])); + AOut.WriteLn(Format(' extheader.FontTableOffset %8.8x (%0:7d bytes) : Font Table - 32bit offset in file', [eHdr.FontTableOffset])); + AOut.WriteLn(Format(' extheader.NumDataBase %8.4x (%0:13d) : Data Base - No of files', [eHdr.NumDataBase])); + AOut.WriteLn(Format(' extheader.DataBaseOffset %8.8x (%0:7d bytes) : Data Base - 32bit offset in file', [eHdr.DataBaseOffset])); + AOut.WriteLn(Format(' extheader.DataBaseSize %8.8x (%0:7d bytes) : Data Base - Size in bytse', [eHdr.DataBaseSize])); + AOut.WriteLn(Format(' extheader.EntryInGNameTable %8.4x (%0:13d) : Global Names - No entries', [eHdr.EntryInGNameTable])); + AOut.WriteLn(Format(' extheader.HelpPanelGNameTblOffset %8.8x (%0:7d bytes) : Global Names - 32bit offset in file', [eHdr.HelpPanelGNameTblOffset])); + AOut.WriteLn(Format(' extheader.StringsOffset %8.8x (%0:7d bytes) : Strings - 32bit offset in file', [eHdr.StringsOffset])); + AOut.WriteLn(Format(' extheader.StringsSize %8.4x (%0:7d bytes) : Strings - Total bytes of all strings', [eHdr.StringsSize])); + AOut.WriteLn(Format(' extheader.ChildPagesOffset %8.8x (%0:7d bytes) : Child Pages - 32bit offset in file', [eHdr.ChildPagesOffset])); + AOut.WriteLn(Format(' extheader.ChildPagesSize %8.8x (%0:7d bytes) : Child Pages - Total bytes of all strings', [eHdr.ChildPagesSize])); + AOut.WriteLn(Format(' extheader.NumGIndexEntry %8.8x (%0:13d) : Total number of Global Index items', [eHdr.NumGIndexEntry])); + AOut.WriteLn(Format(' extheader.CtrlOffset %8.8x (%0:7d bytes) : Ctrl Buttons : offset in file', [eHdr.CtrlOffset])); + AOut.WriteLn(Format(' extheader.CtrlSize %8.8x (%0:7d bytes) : Ctrl Buttons : size in bytes', [eHdr.CtrlSize])); + AOut.WriteLn(Format(' extheader.reserved: %8.8x %8.8x %8.8x %8.8x : for future use. set to zero.', + [eHdr.reserved[0], eHdr.reserved[1], eHdr.reserved[2], eHdr.reserved[3]])); + + finally + // no nothing + end; +end; + +end. + diff --git a/docview/src/docdump/readnlsdata.pas b/docview/src/docdump/readnlsdata.pas new file mode 100644 index 00000000..68609235 --- /dev/null +++ b/docview/src/docdump/readnlsdata.pas @@ -0,0 +1,31 @@ +unit readnlsdata; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, filestreamhelper; + +procedure ProcessNLSData(AIn: TFileStream; AOut: TFileTextStream); + +implementation + +uses + readheader; + +procedure ProcessNLSData(AIn: TFileStream; AOut: TFileTextStream); +begin + AOut.WriteLn(''); + AOut.WriteLn('NLS Data'); + if hdr.nlslen > 0 then + begin + AOut.WriteLn(' <todo - process NLS data>'); + + end + else + AOut.WriteLn('NLS Data is not present'); +end; + +end. + diff --git a/docview/src/docdump/readstrings.pas b/docview/src/docdump/readstrings.pas new file mode 100644 index 00000000..7b397408 --- /dev/null +++ b/docview/src/docdump/readstrings.pas @@ -0,0 +1,56 @@ +{ + Dump the String table data +} +unit readstrings; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, filestreamhelper; + +procedure ProcessStringsTable(AIn: TFileStream; AOut: TFileTextStream); + + +implementation + +uses + readheader; + +procedure ProcessStringsTable(AIn: TFileStream; AOut: TFileTextStream); +var + name: string; + pData: pointer; + p: pointer; + pLength: pByte; + bytes: integer; +begin + AOut.WriteLn(''); + AOut.WriteLn('Strings Data'); + + if eHdr.StringsSize > 0 then + begin + pData := nil; + AIn.Seek(eHdr.StringsOffset, soBeginning); + GetMem(pData, eHdr.StringsSize); // allocate temp space for data + AIn.Read(pData^, eHdr.StringsSize); // read all data in one shot + p := pData; // p is our incrementing position in the data + bytes := 0; + while bytes < eHdr.StringsSize do; + begin + pLength := p; // length byte, including itself + bytes := bytes + pLength^; + SetString(name, p+1, pLength^-1); // use length value minus the length byte to get the string length + AOut.WriteLn(Format(' %s', [name])); + inc(p, pLength^); // skip to next entry using full length (including length byte) + end; + FreeMem(pData, eHdr.StringsSize); // free allocated space + end + else + AOut.WriteLn(' There are no strings'); + +end; + +end. + diff --git a/docview/src/docdump/readtoc.pas b/docview/src/docdump/readtoc.pas new file mode 100644 index 00000000..0cfae395 --- /dev/null +++ b/docview/src/docdump/readtoc.pas @@ -0,0 +1,171 @@ +{ + Dump the Table of Contents data +} +unit readtoc; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, filestreamhelper; + +procedure ProcessTOC(AIn: TFileStream; AOut: TFileTextStream); + +implementation + +uses + IPFFileFormatUnit, readheader, u_Tools; + +type + TTOCOverlay = bitpacked record + length: uint8; // length of the entry including this byte (but not including extended data) + nestlevel: Unsigned_4; + unknown: boolean; + extended: boolean; + hidden: boolean; + haschildren: boolean; + numSlots: uint8; // number of "slots" occupied by the text for this toc entry + end; + + + TTOCExtendedOverlay = bitpacked record + setPos: boolean; + setSize: boolean; + setView: boolean; + setStyle: boolean; + noSearch: boolean; + noPrint: boolean; + setCtrl: boolean; + setTutor: boolean; + clear: boolean; + unknown1: Unsigned_1; + setGroup: boolean; + isParent: boolean; + unknown2: Unsigned_4; + end; + + +procedure ProcessTOC(AIn: TFileStream; AOut: TFileTextStream); +var + Count: integer; + VisCount: integer; + pOffsets: UInt32ArrayPointer; + toc: TTOCEntryStart; + olay: TTOCOverlay; + tocextolay: TTOCExtendedOverlay; + pData: pointer; + pEntry: pTTOCEntryStart; + pExtendedInfo: pExtendedTOCEntry; + p: PByte; + i: integer; + titleLen: integer; + title: string; +begin + AOut.WriteLn(''); + AOut.WriteLn('Table of Contents'); + VisCount := 0; + GetMem(pOffsets, SizeOf(uint32) * hdr.ntoc); + AIn.Seek(hdr.tocoffsetsstart, soBeginning); + AIn.Read(pOffsets^, SizeOf(uint32) * hdr.ntoc); // now we have array of toc offsets + + AIn.Seek(hdr.tocstart, soBeginning); + GetMem(pData, hdr.toclen); + AIn.Read(pData^, hdr.toclen); + pEntry := pData; + for count := 1 to hdr.ntoc do + begin +// AIn.Read(toc, SizeOf(TTOCEntryStart)); +// FillChar(olay, SizeOf(TTOCOverlay), 0); + p := PByte(pEntry) + sizeof(TTOCEntryStart); + i := Longint(p^); + + olay.extended := (pEntry^.flags and TOCEntryExtended ) = TOCEntryExtended; + olay.nestlevel := (pEntry^.flags and TOCEntryLevelMask); + olay.hidden := (pEntry^.flags and TOCEntryHidden) = TOCEntryHidden; + olay.haschildren := (pEntry^.flags and TOCEntryHasChildren) = TOCEntryHasChildren; + + AOut.WriteLn(Format(' TOC Entry #%d at offset %8.8x (%d bytes)', [count, p^, i])); + AOut.WriteLn(Format(' tocentry.length: %2.2x (%0:d bytes)', [pEntry^.length])); + AOut.WriteLn(Format(' tocentry.nestlevel: %d', [olay.nestlevel])); + AOut.WriteLn(Format(' tocentry.unknown: %s', [iif(olay.unknown, 'set', 'clear')])); + AOut.WriteLn(Format(' tocentry.extended: %s', [iif(olay.extended, 'yes', 'no')])); + AOut.WriteLn(Format(' tocentry.hidden: %s', [iif(olay.hidden, 'yes', 'no')])); + AOut.WriteLn(Format(' tocentry.haschildren: %s', [iif(olay.haschildren, 'yes', 'no')])); + AOut.WriteLn(Format(' tocentry.numSlots: %d', [pEntry^.numSlots])); + if not olay.hidden then + inc(VisCount); + if olay.extended then + begin + pExtendedInfo := pExtendedTOCEntry( p ); // next data to follow must be Extended TOC Entry + + AOut.WriteLn(' Extended TOC Entry'); + tocextolay := TTOCExtendedOverlay(pExtendedInfo^); + + AOut.Writeln(Format(' ExtTocEntry.setPos: %s', [iif(tocextolay.setPos, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.setSize: %s', [iif(tocextolay.setSize, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.setView: %s', [iif(tocextolay.setView, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.setStyle: %s', [iif(tocextolay.setStyle, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.noSearch: %s', [iif(tocextolay.noSearch, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.noPrint: %s', [iif(tocextolay.noPrint, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.setCtrl: %s', [iif(tocextolay.setCtrl, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.setTutor: %s', [iif(tocextolay.setTutor, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.clear: %s', [iif(tocextolay.clear, 'clear', 'set')])); + AOut.Writeln(Format(' ExtTocEntry.unknown1: %1.1x', [tocextolay.unknown1])); + AOut.Writeln(Format(' ExtTocEntry.setGroup: %s', [iif(tocextolay.setGroup, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.isParent: %s', [iif(tocextolay.isParent, 'yes', 'no')])); + AOut.Writeln(Format(' ExtTocEntry.unknown2: %1.1x', [tocextolay.unknown2])); + + inc( p, sizeof( TExtendedTOCEntry ) ); // move p past two flag bytes + + if ( pExtendedInfo^.w1 and 1 ) > 0 then + // skip position + inc( p, sizeof( THelpXYPair ) ); + + if ( pExtendedInfo^.w1 and 2 ) > 0 then + // skip size + inc( p, sizeof( THelpXYPair ) ); + + if ( pExtendedInfo^.w1 and 8 ) > 0 then + // skip window controls + inc( p, sizeof(word) ); // increment by 2 + + if ( pExtendedInfo^.w1 and $40 ) > 0 then + // skip something else, unknown... style? 2 bytes + inc( p, sizeof(word) ); // increment by 2 + + if ( pExtendedInfo^.w2 and 4 ) > 0 then + begin +// _ContentsGroupIndex := pUInt16(p)^; + // read group + inc( p, sizeof( uint16 ) ); + end; + end; + + // skip slot numbers for now. +// _pSlotNumbers := pUInt16(p); + inc( p, pEntry^.numSlots * sizeof(uint16) ); + + // Calculate the remainder of the tocentry length - that is the bytes used for TOC topic (title) text + titleLen := pEntry^.length - ( longword( p ) - longword( pEntry ) ); + + // Read title + if TitleLen > 0 then + SetString(Title, Pointer(p), TitleLen) + else + Title := '<unknown>'; + AOut.WriteLn(Format(' toc Title: %s', [title])); + + + p := PByte(pEntry); + inc(p, pEntry^.Length); + pEntry := pTTOCEntryStart(p); + end; + + AOut.WriteLn(Format(' TOC visible count: %d', [VisCount])); + FreeMem(pOffsets, SizeOf(uint32) * hdr.ntoc); + FreeMem(pData, hdr.toclen); +end; + +end. + diff --git a/docview/src/docdump/u_Tools.pas b/docview/src/docdump/u_Tools.pas new file mode 100644 index 00000000..96192db9 --- /dev/null +++ b/docview/src/docdump/u_Tools.pas @@ -0,0 +1,52 @@ +{ + This unit will grow to include all handy functions that can be used in + different Lazarus projects. + + There may be no links to other non-standard units! +} +unit u_Tools; + +{$mode objfpc}{$H+} + +interface + + { Missing iif() known from Visual Basic - return a string } + function iif(fCon: Boolean; sTrue, sFalse: String): String; + { Missing iif() known from Visual Basic - return an Integer } + function iif(fCon: Boolean; iTrue, iFalse: Integer): Integer; + { Missing iif() known from Visual Basic - return an Extended } + function iif(fCon: Boolean; iTrue, iFalse: Extended): Extended; + + +implementation +uses + SysUtils; + + +function iif(fCon: Boolean; sTrue, sFalse: String): String; +begin + if fCon then + Result := sTrue + else + Result := sFalse; +end; + +function iif(fCon: Boolean; iTrue, iFalse: Integer): Integer; +begin + if fCon then + Result := iTrue + else + Result := iFalse; +end; + +function iif(fCon: Boolean; iTrue, iFalse: Extended): Extended; +begin + if fCon then + Result := iTrue + else + Result := iFalse; +end; + + +end. + |