123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- {%mainunit dw_html}
- {$IFDEF chmInterface}
- type
- { TCHMHTMLWriter }
- TCHMHTMLWriter = class(THTMLWriter)
- private
- FOutChm: TStream;
- FChm: TChmWriter;
- FTempUncompressed: TStream;
- FTempUncompressedName: String;
- FChmTitle: String;
- FTOCName,
- FIndexName,
- FDefaultPage: String;
- FMakeSearchable,
- FNoBinToc,
- FNoBinIndex,
- FAutoTOC,
- FAutoIndex: Boolean;
- FOtherFiles: String;
- procedure ProcessOptions;
- function RetrieveOtherFiles(const DataName: String; out PathInChm: String; out FileName: String; var Stream: TStream): Boolean;
- procedure LastFileAdded(Sender: TObject);
- procedure GenerateTOC;
- procedure GenerateIndex;
- public
- procedure WriteHTMLPages; override;
-
- function InterPretOption(const Cmd,Arg : String): boolean; override;
- class procedure Usage(List: TStrings); override;
- Class Function FileNameExtension : String; override;
- Class procedure SplitImport(var AFilename, ALinkPrefix: String); override;
- end;
- {$ELSE} // implementation
- { TCHMHTMLWriter }
- procedure TCHMHTMLWriter.ProcessOptions;
- var
- TempStream: TMemoryStream;
- begin
- if FDefaultPage = '' then
- FDefaultPage := 'index.html'
- else
- begin
- DoLog('Note: --index-page not assigned. Using default "index.html"');
- end;
-
- if FCSSFile <> '' then
- begin
- if not FileExists(FCSSFile) Then
- Raise Exception.CreateFmt('Can''t find CSS file "%S"',[FCSSFILE]);
- TempStream := TMemoryStream.Create;
- TempStream.LoadFromFile(FCSSFile);
- TempStream.Position := 0;
- FChm.AddStreamToArchive('fpdoc.css', '/', TempStream, True);
- TempStream.Free;
- end;
- FChm.DefaultPage := FDefaultPage;
-
- if FOtherFiles <> '' then
- begin
- FChm.FilesToCompress.LoadFromFile(FOtherFiles);
- end;
- FChm.FullTextSearch := FMakeSearchable;
- end;
- function TCHMHTMLWriter.RetrieveOtherFiles(const DataName: String; out
- PathInChm: String; out FileName: String; var Stream: TStream): Boolean;
- var
- Dir: String;
- begin
- if Stream <> nil then
- Stream.Free;
- Stream := TMemoryStream.Create;
- TMemoryStream(Stream).LoadFromFile(DataName);
- FileName := ExtractFileName(DataName);
-
- if ExtractFileDir(DataName) <> '' then
- PathInChm := ExtractRelativepath(GetCurrentDir, ExtractFileDir(DataName))
- else
- PathInChm := '/';
- FixHTMLpath(PathInChm);
- Stream.Position := 0;
- end;
- procedure TCHMHTMLWriter.LastFileAdded(Sender: TObject);
- var
- TmpStream: TMemoryStream;
- begin
- TmpStream := TMemoryStream.Create;
- if FAutoTOC then
- GenerateTOC
- else
- if FTOCName <> '' then
- begin
- TmpStream.LoadFromFile(FTOCName);
- TmpStream.Position := 0;
- FChm.AppendTOC(TmpStream);
- TmpStream.Size := 0;
- end;
-
- if FAutoIndex then
- GenerateIndex
- else
- if FIndexName <> '' then
- begin
- TmpStream.LoadFromFile(FIndexName);
- TmpStream.Position := 0;
- FChm.AppendIndex(TmpStream);
- end;
- TmpStream.Free;
- DoLog('Finishing compressing...');
- end;
- function TOCSort(Item1, Item2: TChmSiteMapItem): Integer;
- begin
- Result := CompareText(LowerCase(Item1.Text), LowerCase(Item2.Text));
- end;
- function GetAlphaItem(AItems: TChmSiteMapItems; AName: String): TChmSiteMapItem;
- var
- x: Integer;
- begin
- Result := nil;
- for x := 0 to AItems.Count-1 do
- begin
- if AItems.Item[x].Text = AName then
- Exit(AItems.Item[x]);
- end;
- Result := AItems.NewItem;
- Result.Text := AName;
- end;
-
- procedure TCHMHTMLWriter.GenerateTOC;
- var
- TOC: TChmSiteMap;
- Element: TPasElement;
- k: Integer;
- j: Integer;
- i: Integer;
- AModule: TPasModule;
- Member: TPasElement;
- Stream: TMemoryStream;
- TmpItem: TChmSiteMapItem;
- ObjByUnitItem,
- AlphaObjItem,
- ObjUnitItem,
- RoutinesByUnitItem,
- RoutinesUnitItem,
- AlphaRoutinesItem: TChmSiteMapItem;
- begin
- DoLog('Generating Table of contents...');
- if Assigned(Package) then
- begin
- Toc := TChmSiteMap.Create(stTOC);
- Stream := TMemoryStream.Create;
- ObjByUnitItem := TOC.Items.NewItem;
- ObjByUnitItem.Text := 'Classes and Objects, by Unit';
- AlphaObjItem := TOC.Items.NewItem;
- AlphaObjItem.Text := 'Alphabetical Classes and Objects List';
- RoutinesByUnitItem := TOC.Items.NewItem;
- RoutinesByUnitItem.Text := 'Routines, by Unit';
- AlphaRoutinesItem := TOC.Items.NewItem;
- AlphaRoutinesItem.Text := 'Alphabetical Routines List';
- // objects and classes
- for i := 0 to Package.Modules.Count - 1 do
- begin
- AModule := TPasModule(Package.Modules[i]);
- If not assigned(AModule.InterfaceSection) Then
- Continue;
- ObjUnitItem := ObjByUnitItem.Children.NewItem;
- ObjUnitItem.Text := AModule.Name;
- RoutinesUnitItem := RoutinesByUnitItem.Children.NewItem;
- RoutinesUnitItem.Text := AModule.Name;
- for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
- begin
- Element := TPasClassType(AModule.InterfaceSection.Classes[j]);
- // by unit
- TmpItem := ObjUnitItem.Children.NewItem;
- TmpItem.Text := Element.Name;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
-
- //alpha
- TmpItem := GetAlphaItem(AlphaObjItem.Children, UpperCase(Copy(Element.Name, 1, 2))).Children.NewItem;
- TmpItem.Text := Element.Name;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
-
- end;
-
- // non object procedures and functions
- for j := 0 to AModule.InterfaceSection.Functions.Count-1 do
- begin
- Element := TPasFunctionType(AModule.InterfaceSection.Functions[j]);
- // by unit
- TmpItem := RoutinesUnitItem.Children.NewItem;
- TmpItem.Text := Element.Name;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
-
- // alpha
- TmpItem := GetAlphaItem(AlphaRoutinesItem.Children, UpperCase(Element.Name[1])).Children.NewItem;
- TmpItem.Text := Element.Name;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
- end;
- end;
- end;
- // cleanup
- for i := ObjByUnitItem.Children.Count-1 downto 0 do
- begin
- if ObjByUnitItem.Children.Item[i].Children.Count = 0 then
- ObjByUnitItem.Children.Delete(i);
- end;
- for i := RoutinesByUnitItem.Children.Count-1 downto 0 do
- begin
- if RoutinesByUnitItem.Children.Item[i].Children.Count = 0 then
- RoutinesByUnitItem.Children.Delete(i);
- end;
-
- for i := TOC.Items.Count-1 downto 0 do
- begin
- if TOC.Items.Item[i].Children.Count = 0 then
- TOC.Items.Delete(i);
- end;
-
- // Sort
- for i := 0 to TOC.Items.Count-1 do
- begin
- TOC.Items.Item[i].Children.Sort(TListSortCompare(@TOCSort));
- for j := 0 to TOC.Items.Item[i].Children.Count-1 do
- begin
- TOC.Items.Item[i].Children.Item[j].Children.Sort(TListSortCompare(@TOCSort));
- end;
- end;
- if not fnobintoc then
- fchm.AppendBinaryTOCFromSiteMap(Toc);
- TOC.SaveToStream(Stream);
- TOC.Free;
- fchm.AppendTOC(Stream);
- Stream.Free;
- end;
- type
- TClassMemberType = (cmtProcedure, cmtFunction, cmtConstructor, cmtDestructor,
- cmtInterface, cmtProperty, cmtVariable, cmtUnknown);
-
- function ElementType(Element: TPasElement): TClassMemberType;
- var
- ETypeName: String;
- begin
- Result := cmtUnknown;
- ETypeName := Element.ElementTypeName;
- //overloaded we don't care
- if ETypeName[1] = 'o' then ETypeName := Copy(ETypeName, 11, Length(ETypeName));
-
- if ETypeName[1] = 'f' then Exit(cmtFunction);
- if ETypeName[1] = 'c' then Exit(cmtConstructor);
- if ETypeName[1] = 'v' then Exit(cmtVariable);
- if ETypeName[1] = 'i' then Exit(cmtInterface);
- // the p's
- if ETypeName[4] = 'c' then Exit(cmtProcedure);
- if ETypeName[4] = 'p' then Exit(cmtProperty);
-
- end;
- procedure TCHMHTMLWriter.GenerateIndex;
- var
- Index: TChmSiteMap;
- i, j, k: Integer;
- TmpItem: TChmSiteMapItem;
- ParentItem: TChmSiteMapItem;
- AModule: TPasModule;
- TmpElement: TPasElement;
- ParentElement: TPasElement;
- MemberItem: TChmSiteMapItem;
- Stream: TMemoryStream;
- begin
- DoLog('Generating Index...');
- if Assigned(Package) then
- begin
- Index := TChmSiteMap.Create(stIndex);
- Stream := TMemoryStream.Create;
- for i := 0 to Package.Modules.Count - 1 do
- begin
- AModule := TPasModule(Package.Modules[i]);
- if not assigned(AModule.InterfaceSection) then
- continue;
- ParentItem := Index.Items.NewItem;
- ParentItem.Text := AModule.Name;
- ParentItem.Local := FixHTMLpath(Allocator.GetFilename(AModule, 0));
- // classes
- for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
- begin
- ParentElement := TPasClassType(AModule.InterfaceSection.Classes[j]);
- ParentItem := Index.Items.NewItem;
- ParentItem.Text := ParentELement.Name;
- ParentItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
- for k := 0 to TPasClassType(ParentElement).Members.Count-1 do
- begin
- TmpElement := TPasElement(TPasClassType(ParentElement).Members.Items[k]);
- if Engine.HidePrivate and(TmpElement.Visibility = visPrivate) then
- continue;
- if Engine.HideProtected and(TmpElement.Visibility = visProtected) then
- continue;
- TmpItem := ParentItem.Children.NewItem;
- case ElementType(TmpElement) of
- cmtProcedure : TmpItem.Text := TmpElement.Name + ' procedure';
- cmtFunction : TmpItem.Text := TmpElement.Name + ' function';
- cmtConstructor : TmpItem.Text := TmpElement.Name + ' constructor';
- cmtDestructor : TmpItem.Text := TmpElement.Name + ' destructor';
- cmtProperty : TmpItem.Text := TmpElement.Name + ' property';
- cmtVariable : TmpItem.Text := TmpElement.Name + ' variable';
- cmtInterface : TmpItem.Text := TmpElement.Name + ' interface';
- cmtUnknown : TmpItem.Text := TmpElement.Name;
- end;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
- {
- ParentElement = Class
- TmpElement = Member
- }
- MemberItem := nil;
- MemberItem := GetAlphaItem(Index.Items, TmpElement.Name);
- // ahh! if MemberItem.Local is empty MemberType is not shown!
- MemberItem.Local := FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
- TmpItem := MemberItem.Children.NewItem;
- TmpItem.Text := ParentElement.Name;
- TmpITem.Local := FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
- end;
- end;
- // routines
- for j := 0 to AModule.InterfaceSection.Functions.Count-1 do
- begin
- ParentElement := TPasProcedureType(AModule.InterfaceSection.Functions[j]);
- TmpItem := Index.Items.NewItem;
- TmpItem.Text := ParentElement.Name + ' ' + ParentElement.ElementTypeName;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
- end;
- // consts
- for j := 0 to AModule.InterfaceSection.Consts.Count-1 do
- begin
- ParentElement := TPasElement(AModule.InterfaceSection.Consts[j]);
- TmpItem := Index.Items.NewItem;
- TmpItem.Text := ParentElement.Name;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
- end;
- // types
- for j := 0 to AModule.InterfaceSection.Types.Count-1 do
- begin
- ParentElement := TPasType(AModule.InterfaceSection.Types[j]);
- TmpItem := Index.Items.NewItem;
- TmpItem.Text := ParentElement.Name;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
- // enums
- if ParentELement is TPasEnumType then
- begin
- ParentItem := TmpItem;
- for k := 0 to TPasEnumType(ParentElement).Values.Count-1 do
- begin
- TmpElement := TPasType(TPasEnumType(ParentElement).Values.Items[k]);
- // subitem
- TmpItem := ParentItem.Children.NewItem;
- TmpItem.Text := TmpElement.Name;
- TmpItem.Local := ParentItem.Local;
- // root level
- TmpItem := Index.Items.NewItem;
- TmpItem.Text := TmpElement.Name;
- TmpItem.Local := ParentItem.Local;
- end;
- end;
- end;
- // variables
- for j := 0 to AModule.InterfaceSection.Variables.Count-1 do
- begin
- ParentElement := TPasElement(AModule.InterfaceSection.Variables[j]);
- TmpItem := Index.Items.NewItem;
- TmpItem.Text := ParentElement.Name + ' var';
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
- end;
- // declarations
- {
- for j := 0 to AModule.InterfaceSection.Declarations.Count-1 do
- begin
- ParentElement := TPasElement(AModule.InterfaceSection.Declarations[j]);
- TmpItem := Index.Items.NewItem;
- TmpItem.Text := ParentElement.Name;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
- end;
- // resource strings
- for j := 0 to AModule.InterfaceSection.ResStrings.Count-1 do
- begin
- ParentElement := TPasElement(AModule.InterfaceSection.ResStrings[j]);
- TmpItem := Index.Items.NewItem;
- TmpItem.Text := ParentElement.Name;
- TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
- end;
- }
- end;
- // Sort
- Index.Items.Sort(TListSortCompare(@TOCSort));
- for i := 0 to Index.Items.Count-1 do
- begin
- Index.Items.Item[i].Children.Sort(TListSortCompare(@TOCSort));
- end;
- // save
- Index.SaveToStream(Stream);
- if not fnobinindex then
- fchm.AppendBinaryindexFromSitemap(index,false);
- Index.Free;
- Stream.Position :=0 ;
- FChm.AppendIndex(Stream);
- Stream.Free;
- end;
- end;
- procedure TCHMHTMLWriter.WriteHTMLPages;
- var
- i: Integer;
- PageDoc: TXMLDocument;
- FileStream: TMemoryStream;
- FileName: String;
- FilePath: String;
- begin
- FileName := Engine.Output;
- if FileName = '' then
- Raise Exception.Create('Error: no --output option used.');
-
- if ExtractFileExt(FileName) <> FileNameExtension then
- FileName := ChangeFileExt(FileName, FileNameExtension);
- FOutChm := TFileStream.Create(FileName, fmOpenReadWrite or fmCreate);
- FTempUncompressedName := GetTempFileName+IntToStr(GetProcessID) +'.raw';
- FTempUncompressed := TFileStream.Create(FTempUncompressedName, fmOpenReadWrite or fmCreate);
- FChm := TChmWriter.Create(FOutChm, False);
- FChm.Title := FChmTitle;
- FChm.TempRawStream := FTempUncompressed;
- FChm.OnGetFileData := @RetrieveOtherFiles;
- FChm.OnLastFile := @LastFileAdded;
- fchm.hasbinarytoc:=not fnobintoc;;
- fchm.hasbinaryindex:=not fnobinindex;
- ProcessOptions;
- FileStream := TMemoryStream.Create;
- for i := 0 to PageInfos.Count - 1 do
- with TPageInfo(PageInfos[i]) do
- begin
- PageDoc := CreateHTMLPage(Element, SubpageIndex);
- try
- FileName := ExtractFileName(Allocator.GetFilename(Element, SubpageIndex));
- FilePath := '/'+FixHTMLpath(ExtractFilePath(Allocator.GetFilename(Element, SubpageIndex)));
- try
- WriteHTMLFile(PageDoc, FileStream);
- FChm.AddStreamToArchive(FileName, FilePath, FileStream, True);
- except
- on E: Exception do
- DoLog(Format(SErrCouldNotCreateFile, [FileName, e.Message]));
- end;
- finally
- PageDoc.Free;
- FileStream.Size := 0;
- end;
- end;
- FileStream.Free;
- DoLog('HTML Files written. Collecting other files and compressing...this could take some time');
- //write any found images to CHM stream
- FileStream := TMemoryStream.Create;
- for i := 0 to FImageFileList.Count - 1 do
- begin
- {$ifdef imagetest} DoLog(' adding image: '+FImageFileList[i]); {$endif}
- if FileExists(FImageFileList[i]) then
- begin
- {$ifdef imagetest} DoLog(' - found'); {$endif}
- FileName := ExtractFileName(FImageFileList[i]);
- FilePath := '/'+FixHTMLpath(ExtractFilePath(FImageFileList[i]));
- FileStream.LoadFromFile(FImageFileList[i]);
- FChm.AddStreamToArchive(FileName, FilePath, FileStream, True);
- FileStream.Size := 0;
- end
- else
- {$ifdef imagetest} DoLog(' - not found'){$endif};
- end;
- FileStream.Free;
- FChm.Execute;
- FChm.Free;
- // we don't need to free FTempUncompressed
- // FTempUncompressed.Free;
- FOutChm.Free;
- DeleteFile(FTempUncompressedName);
- end;
- function TCHMHTMLWriter.InterPretOption(const Cmd, Arg: String): boolean;
- begin
- Result:=True;
- FNoBinToc:=False;
- FnoBinIndex:=False;
- if Cmd = '--toc-file' then
- FTOCName := arg
- else if Cmd = '--index-file' then
- FIndexName := arg
- else if Cmd = '--default-page' then
- FDefaultPage := arg
- else if Cmd = '--other-files' then
- FOtherFiles := arg
- else if Cmd = '--auto-index' then
- FAutoIndex := True
- else if Cmd = '--auto-toc' then
- FAutoTOC := True
- else if Cmd = '--no-bintoc' then
- FNoBinToc := True
- else if Cmd = '--no-binindex' then
- FNoBinIndex := True
- else if Cmd = '--make-searchable' then
- FMakeSearchable := True
- else if Cmd = '--chm-title' then
- FChmTitle := arg
- else
- Result:=inherited InterPretOption(Cmd, Arg);
- if Length(FChmTitle) = 0 then
- FChmTitle := Copy(Package.Name, 2, Length(Package.Name));
- end;
- class procedure TCHMHTMLWriter.Usage(List: TStrings);
- begin
- THTMLWriter.Usage(List);
- List.add('--default-page');
- List.Add(SCHMUsageDefPage);
- List.add('--toc-file');
- List.Add(SCHMUsageTOC);
- List.add('--index-file');
- List.Add(SCHMUsageIndex);
- List.add('--other-files');
- List.Add(SCHMUsageOtrFiles);
- List.add('--css-file');
- List.Add(SCHMUsageCSSFile);
- List.add('--auto-index');
- List.Add(SCHMUsageAutoIDX);
- List.add('--auto-toc');
- List.Add(SCHMUsageAutoTOC);
- List.add('--make-searchable');
- List.Add(SCHMUsageMakeSearch);
- List.Add('--chm-title');
- List.Add(SCHMUsageChmTitle);
- end;
- Class Function TCHMHTMLWriter.FileNameExtension : String;
- begin
- result:='.chm';
- end;
- class procedure TCHMHTMLWriter.SplitImport(var AFilename, ALinkPrefix: String);
- var
- i: integer;
- begin
- i := Pos(',', AFilename);
- if i > 0 then
- begin //split into filename and prefix
- ALinkPrefix := Copy(AFilename,i+1,Length(AFilename));
- SetLength(AFilename, i-1);
- end
- else if ALinkPrefix = '' then
- begin //synthesize outdir\pgk.xct, ms-its:pkg.chm::/
- ALinkPrefix := 'ms-its:' + ChangeFileExt(ExtractFileName(AFilename), '.chm') + '::/';
- AFilename := ChangeFileExt(AFilename, '.xct');
- end;
- end;
- {$ENDIF}
|