dw_chm.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. unit dw_chm;
  2. interface
  3. uses Classes, DOM, DOM_HTML,
  4. dGlobals, PasTree, dwriter, dw_html, chmwriter, chmtypes, chmsitemap;
  5. type
  6. { TFpDocChmWriter }
  7. TFpDocChmWriter = class (TChmWriter)
  8. protected
  9. procedure FileAdded(AStream: TStream; const AEntry: TFileEntryRec); override;
  10. end;
  11. { TCHMHTMLWriter }
  12. TCHMHTMLWriter = class(THTMLWriter)
  13. private
  14. FOutChm: TStream;
  15. FChm: TFpDocChmWriter;
  16. FTempUncompressed: TStream;
  17. FTempUncompressedName: String;
  18. FChmTitle: String;
  19. FTOCName,
  20. FIndexName,
  21. FDefaultPage: String;
  22. FMakeSearchable,
  23. FNoBinToc,
  24. FNoBinIndex,
  25. FAutoTOC,
  26. FAutoIndex: Boolean;
  27. FOtherFiles: String;
  28. procedure ProcessOptions;
  29. function ResolveLinkIDAbs(const Name: String; Level : Integer = 0): DOMString;
  30. function RetrieveOtherFiles(const DataName: String; out PathInChm: String;
  31. out FileName: String; var Stream: TStream): Boolean;
  32. procedure LastFileAdded(Sender: TObject);
  33. function FindAlphaItem(AItems: TChmSiteMapItems; AName: String): TChmSiteMapItem;
  34. function GetAlphaItem(AItems: TChmSiteMapItems; AName: String): TChmSiteMapItem;
  35. procedure MultiAlphaItem(AItems: TChmSiteMapItems; AName: String;
  36. APasEl: TPasElement; Prefix:String);
  37. procedure GenerateTOC;
  38. procedure GenerateIndex;
  39. public
  40. procedure WriteHTMLPages; override;
  41. function InterPretOption(const Cmd,Arg : String): boolean; override;
  42. class procedure Usage(List: TStrings); override;
  43. Class Function FileNameExtension : String; override;
  44. Class procedure SplitImport(var AFilename, ALinkPrefix: String); override;
  45. end;
  46. implementation
  47. uses SysUtils, HTMWrite;
  48. { TFpDocChmWriter }
  49. procedure TFpDocChmWriter.FileAdded ( AStream: TStream;
  50. const AEntry: TFileEntryRec ) ;
  51. begin
  52. // Exclude Full text index for files starting from the dot
  53. if Pos('.', AEntry.Name) <> 1 then
  54. inherited FileAdded(AStream, AEntry);
  55. end;
  56. { TCHMHTMLWriter }
  57. function TCHMHTMLWriter.ResolveLinkIDAbs(const Name: String; Level : Integer = 0): DOMString;
  58. begin
  59. Result:=UTF8Decode(FixHTMLpath(Engine.ResolveLink(Module,Name, True)));
  60. // for global index: don't make it relative to the current document.
  61. end;
  62. procedure TCHMHTMLWriter.ProcessOptions;
  63. var
  64. TempStream: TMemoryStream;
  65. begin
  66. if FDefaultPage = '' then
  67. FDefaultPage := 'index.html'
  68. else
  69. begin
  70. DoLog('Note: --index-page not assigned. Using default "index.html"');
  71. end;
  72. if FCSSFile <> '' then
  73. begin
  74. if not FileExists(FCSSFile) Then
  75. Raise Exception.CreateFmt('Can''t find CSS file "%S"',[FCSSFILE]);
  76. TempStream := TMemoryStream.Create;
  77. TempStream.LoadFromFile(FCSSFile);
  78. TempStream.Position := 0;
  79. FChm.AddStreamToArchive('fpdoc.css', '/', TempStream, True);
  80. TempStream.Free;
  81. end;
  82. FChm.DefaultPage := FDefaultPage;
  83. if FOtherFiles <> '' then
  84. begin
  85. FChm.FilesToCompress.LoadFromFile(FOtherFiles);
  86. end;
  87. FChm.FullTextSearch := FMakeSearchable;
  88. end;
  89. function TCHMHTMLWriter.RetrieveOtherFiles(const DataName: String; out
  90. PathInChm: String; out FileName: String; var Stream: TStream): Boolean;
  91. begin
  92. Result:=True;
  93. if Stream <> nil then
  94. Stream.Free;
  95. Stream := TMemoryStream.Create;
  96. TMemoryStream(Stream).LoadFromFile(DataName);
  97. FileName := ExtractFileName(DataName);
  98. if ExtractFileDir(DataName) <> '' then
  99. PathInChm := ExtractRelativepath(GetCurrentDir, ExtractFileDir(DataName))
  100. else
  101. PathInChm := '/';
  102. FixHTMLpath(PathInChm);
  103. Stream.Position := 0;
  104. end;
  105. procedure TCHMHTMLWriter.LastFileAdded(Sender: TObject);
  106. var
  107. TmpStream: TMemoryStream;
  108. begin
  109. TmpStream := TMemoryStream.Create;
  110. if FAutoTOC then
  111. GenerateTOC
  112. else
  113. if FTOCName <> '' then
  114. begin
  115. TmpStream.LoadFromFile(FTOCName);
  116. TmpStream.Position := 0;
  117. FChm.AppendTOC(TmpStream);
  118. TmpStream.Size := 0;
  119. end;
  120. if FAutoIndex then
  121. GenerateIndex
  122. else
  123. if FIndexName <> '' then
  124. begin
  125. TmpStream.LoadFromFile(FIndexName);
  126. TmpStream.Position := 0;
  127. FChm.AppendIndex(TmpStream);
  128. end;
  129. TmpStream.Free;
  130. DoLog('Finishing compressing...');
  131. end;
  132. function TOCSort(Item1, Item2: TChmSiteMapItem): Integer;
  133. begin
  134. Result := CompareText(LowerCase(Item1.Text), LowerCase(Item2.Text));
  135. end;
  136. function TCHMHTMLWriter.FindAlphaItem(AItems: TChmSiteMapItems; AName: String
  137. ): TChmSiteMapItem;
  138. var
  139. x: Integer;
  140. begin
  141. Result := nil;
  142. for x := 0 to AItems.Count-1 do
  143. begin
  144. if AItems.Item[x].Text = AName then
  145. Exit(AItems.Item[x]);
  146. end;
  147. end;
  148. function TCHMHTMLWriter.GetAlphaItem(AItems: TChmSiteMapItems; AName: String
  149. ): TChmSiteMapItem;
  150. begin
  151. Result := FindAlphaItem(AItems, AName);
  152. if Result <> nil then Exit;
  153. Result := AItems.NewItem;
  154. Result.Text := AName;
  155. end;
  156. procedure TCHMHTMLWriter.MultiAlphaItem(AItems: TChmSiteMapItems; AName: String;
  157. APasEl: TPasElement; Prefix: String);
  158. var
  159. AChmItem, AChmChld: TChmSiteMapItem;
  160. begin
  161. AChmItem:= FindAlphaItem(AItems, AName);
  162. if AChmItem = nil then
  163. begin
  164. // add new
  165. AChmItem := AItems.NewItem;
  166. AChmItem.Text := AName;
  167. AChmItem.addLocal(FixHTMLpath(Allocator.GetFilename(APasEl, 0)));
  168. end
  169. else
  170. begin
  171. // add as child
  172. AChmChld := AChmItem.Children.NewItem;
  173. AChmChld.Text := Prefix + '.' + AName;
  174. AChmChld.addLocal(FixHTMLpath(Allocator.GetFilename(APasEl, 0)));
  175. end;
  176. end;
  177. procedure TCHMHTMLWriter.GenerateTOC;
  178. var
  179. TOC: TChmSiteMap;
  180. Element: TPasElement;
  181. j: Integer;
  182. i: Integer;
  183. AModule: TPasModule;
  184. Stream: TMemoryStream;
  185. TmpItem: TChmSiteMapItem;
  186. ObjByUnitItem,
  187. AlphaObjItem,
  188. ObjUnitItem,
  189. RoutinesByUnitItem,
  190. RoutinesUnitItem,
  191. AlphaRoutinesItem: TChmSiteMapItem;
  192. begin
  193. DoLog('Generating Table of contents...');
  194. if Assigned(Package) then
  195. begin
  196. Toc := TChmSiteMap.Create(stTOC);
  197. Stream := TMemoryStream.Create;
  198. ObjByUnitItem := TOC.Items.NewItem;
  199. ObjByUnitItem.Text := 'Classes and Objects, by Unit';
  200. AlphaObjItem := TOC.Items.NewItem;
  201. AlphaObjItem.Text := 'Alphabetical Classes and Objects List';
  202. RoutinesByUnitItem := TOC.Items.NewItem;
  203. RoutinesByUnitItem.Text := 'Routines, by Unit';
  204. AlphaRoutinesItem := TOC.Items.NewItem;
  205. AlphaRoutinesItem.Text := 'Alphabetical Routines List';
  206. // objects and classes
  207. for i := 0 to Package.Modules.Count - 1 do
  208. begin
  209. AModule := TPasModule(Package.Modules[i]);
  210. If not assigned(AModule.InterfaceSection) Then
  211. Continue;
  212. ObjUnitItem := ObjByUnitItem.Children.NewItem;
  213. ObjUnitItem.Text := AModule.Name;
  214. RoutinesUnitItem := RoutinesByUnitItem.Children.NewItem;
  215. RoutinesUnitItem.Text := AModule.Name;
  216. for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
  217. begin
  218. Element := TPasClassType(AModule.InterfaceSection.Classes[j]);
  219. // by unit
  220. TmpItem := ObjUnitItem.Children.NewItem;
  221. TmpItem.Text := Element.Name;
  222. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
  223. //alpha
  224. TmpItem := GetAlphaItem(AlphaObjItem.Children, UpperCase(Copy(Element.Name, 1, 2))).Children.NewItem;
  225. TmpItem.Text := Element.Name;
  226. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
  227. end;
  228. // non object procedures and functions
  229. for j := 0 to AModule.InterfaceSection.Functions.Count-1 do
  230. begin
  231. Element := TPasFunctionType(AModule.InterfaceSection.Functions[j]);
  232. // by unit
  233. TmpItem := RoutinesUnitItem.Children.NewItem;
  234. TmpItem.Text := Element.Name;
  235. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
  236. // alpha
  237. TmpItem := GetAlphaItem(AlphaRoutinesItem.Children, UpperCase(Element.Name[1])).Children.NewItem;
  238. TmpItem.Text := Element.Name;
  239. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
  240. end;
  241. end;
  242. end;
  243. // cleanup
  244. for i := ObjByUnitItem.Children.Count-1 downto 0 do
  245. begin
  246. if ObjByUnitItem.Children.Item[i].Children.Count = 0 then
  247. ObjByUnitItem.Children.Delete(i);
  248. end;
  249. for i := RoutinesByUnitItem.Children.Count-1 downto 0 do
  250. begin
  251. if RoutinesByUnitItem.Children.Item[i].Children.Count = 0 then
  252. RoutinesByUnitItem.Children.Delete(i);
  253. end;
  254. for i := TOC.Items.Count-1 downto 0 do
  255. begin
  256. if TOC.Items.Item[i].Children.Count = 0 then
  257. TOC.Items.Delete(i);
  258. end;
  259. // Sort
  260. for i := 0 to TOC.Items.Count-1 do
  261. begin
  262. TOC.Items.Item[i].Children.Sort(TListSortCompare(@TOCSort));
  263. for j := 0 to TOC.Items.Item[i].Children.Count-1 do
  264. begin
  265. TOC.Items.Item[i].Children.Item[j].Children.Sort(TListSortCompare(@TOCSort));
  266. end;
  267. end;
  268. if not fnobintoc then
  269. fchm.AppendBinaryTOCFromSiteMap(Toc);
  270. TOC.SaveToStream(Stream);
  271. TOC.Free;
  272. fchm.AppendTOC(Stream);
  273. Stream.Free;
  274. DoLog('Generating TOC done');
  275. end;
  276. type
  277. TClassMemberType = (cmtProcedure, cmtFunction, cmtConstructor, cmtDestructor,
  278. cmtInterface, cmtProperty, cmtVariable, cmtOperator, cmtConstant, cmtUnknown);
  279. function ElementType(Element: TPasElement): TClassMemberType;
  280. var
  281. ETypeName: String;
  282. begin
  283. Result := cmtUnknown;
  284. if not Assigned(Element) then Exit;
  285. ETypeName := Element.ElementTypeName;
  286. if Length(ETypeName) = 0 then Exit;
  287. // opearator
  288. if ETypeName[2] = 'p' then Exit(cmtOperator);
  289. if ETypeName[3] = 'n' then Exit(cmtConstant);
  290. // overloaded we don't care
  291. if ETypeName[1] = 'o' then ETypeName := Copy(ETypeName, 12, Length(ETypeName));
  292. if ETypeName[1] = 'f' then Exit(cmtFunction);
  293. if ETypeName[1] = 'c' then Exit(cmtConstructor);
  294. if ETypeName[1] = 'v' then Exit(cmtVariable);
  295. if ETypeName[1] = 'i' then Exit(cmtInterface);
  296. // the p's
  297. if ETypeName[4] = 'c' then Exit(cmtProcedure);
  298. if ETypeName[4] = 'p' then Exit(cmtProperty);
  299. // Unknown
  300. // WriteLn(' Warning El name: '+ Element.Name+' path: '+Element.PathName+' TypeName: '+Element.ElementTypeName);
  301. end;
  302. procedure TCHMHTMLWriter.GenerateIndex;
  303. var
  304. Index: TChmSiteMap;
  305. i, j, k: Integer;
  306. TmpItem: TChmSiteMapItem;
  307. ParentItem: TChmSiteMapItem;
  308. AModule: TPasModule;
  309. TmpElement: TPasElement;
  310. ParentElement: TPasElement;
  311. MemberItem: TChmSiteMapItem;
  312. Stream: TMemoryStream;
  313. RedirectUrl,Urls,SName: String;
  314. begin
  315. DoLog('Generating Index...');
  316. if Assigned(Package) then
  317. begin
  318. Index := TChmSiteMap.Create(stIndex);
  319. Stream := TMemoryStream.Create;
  320. for i := 0 to Package.Modules.Count - 1 do
  321. begin
  322. AModule := TPasModule(Package.Modules[i]);
  323. if not assigned(AModule.InterfaceSection) then
  324. continue;
  325. ParentItem := Index.Items.NewItem;
  326. ParentItem.Text := AModule.Name;
  327. ParentItem.addLocal(FixHTMLpath(Allocator.GetFilename(AModule, 0)));
  328. // classes
  329. for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
  330. begin
  331. ParentElement := TPasClassType(AModule.InterfaceSection.Classes[j]);
  332. ParentItem := Index.Items.NewItem;
  333. ParentItem.Text := ParentELement.Name;
  334. ParentItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
  335. for k := 0 to TPasClassType(ParentElement).Members.Count-1 do
  336. begin
  337. TmpElement := TPasElement(TPasClassType(ParentElement).Members.Items[k]);
  338. if Engine.HidePrivate and(TmpElement.Visibility = visPrivate) then
  339. continue;
  340. if Engine.HideProtected and(TmpElement.Visibility = visProtected) then
  341. continue;
  342. Urls:=FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
  343. RedirectUrl:='';
  344. if TmpElement is TPasEnumValue then
  345. RedirectUrl := UTF8Encode(ResolveLinkIDAbs(tmpElement.Parent.PathName))
  346. else
  347. RedirectUrl := UTF8Encode(ResolveLinkIDAbs(tmpElement.PathName));
  348. if(trim(RedirectUrl)<>'') and (RedirectUrl<>urls) then
  349. begin
  350. //writeln('Hint: Index Resolved:',urls,' to ',RedirectUrl);
  351. urls:=RedirectUrl;
  352. end;
  353. TmpItem := ParentItem.Children.NewItem;
  354. case ElementType(TmpElement) of
  355. cmtProcedure : TmpItem.Text := TmpElement.Name + ' procedure';
  356. cmtFunction : TmpItem.Text := TmpElement.Name + ' function';
  357. cmtConstructor : TmpItem.Text := TmpElement.Name + ' constructor';
  358. cmtDestructor : TmpItem.Text := TmpElement.Name + ' destructor';
  359. cmtProperty : TmpItem.Text := TmpElement.Name + ' property';
  360. cmtVariable : TmpItem.Text := TmpElement.Name + ' variable';
  361. cmtInterface : TmpItem.Text := TmpElement.Name + ' interface';
  362. cmtOperator : TmpItem.Text := TmpElement.Name + ' operator';
  363. cmtConstant : TmpItem.Text := TmpElement.Name + ' const';
  364. cmtUnknown : TmpItem.Text := TmpElement.Name;
  365. end;
  366. TmpItem.addLocal(Urls);
  367. {
  368. ParentElement = Class
  369. TmpElement = Member
  370. }
  371. MemberItem := nil;
  372. MemberItem := GetAlphaItem(Index.Items, TmpElement.Name);
  373. // ahh! if MemberItem.Local is empty MemberType is not shown!
  374. MemberItem.addLocal(Urls);
  375. TmpItem := MemberItem.Children.NewItem;
  376. TmpItem.Text := ParentElement.Name;
  377. TmpItem.AddLocal(Urls);
  378. end;
  379. end;
  380. // routines
  381. for j := 0 to AModule.InterfaceSection.Functions.Count-1 do
  382. begin
  383. // routine name
  384. ParentElement := TPasElement(AModule.InterfaceSection.Functions[j]);
  385. case ElementType(ParentElement) of
  386. cmtProcedure : SName:= ' procedure';
  387. cmtFunction : SName:= ' function';
  388. cmtOperator : SName:= ' operator';
  389. //cmtConstant : SName:= ' const';
  390. else SName:= ' unknown'
  391. end;
  392. SName:= ParentElement.Name + ' ' + SName;
  393. MultiAlphaItem(Index.Items, SName, ParentElement, AModule.Name);
  394. end;
  395. // consts
  396. for j := 0 to AModule.InterfaceSection.Consts.Count-1 do
  397. begin
  398. ParentElement := TPasElement(AModule.InterfaceSection.Consts[j]);
  399. SName:= ParentElement.Name + ' const';
  400. MultiAlphaItem(Index.Items, SName, ParentElement, AModule.Name);
  401. end;
  402. // types
  403. for j := 0 to AModule.InterfaceSection.Types.Count-1 do
  404. begin
  405. ParentElement := TPasType(AModule.InterfaceSection.Types[j]);
  406. TmpItem := Index.Items.NewItem;
  407. TmpItem.Text := ParentElement.Name;
  408. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
  409. // enums
  410. if ParentELement is TPasEnumType then
  411. begin
  412. ParentItem := TmpItem;
  413. for k := 0 to TPasEnumType(ParentElement).Values.Count-1 do
  414. begin
  415. TmpElement := TPasType(TPasEnumType(ParentElement).Values.Items[k]);
  416. // subitem
  417. TmpItem := ParentItem.Children.NewItem;
  418. TmpItem.Text := TmpElement.Name;
  419. TmpItem.addLocal(ParentItem.Local);
  420. // root level
  421. TmpItem := Index.Items.NewItem;
  422. TmpItem.Text := TmpElement.Name;
  423. TmpItem.addLocal(ParentItem.Local);
  424. end;
  425. end;
  426. end;
  427. // variables
  428. for j := 0 to AModule.InterfaceSection.Variables.Count-1 do
  429. begin
  430. ParentElement := TPasElement(AModule.InterfaceSection.Variables[j]);
  431. SName:= ParentElement.Name + ' variable';
  432. MultiAlphaItem(Index.Items, SName, ParentElement, AModule.Name);
  433. end;
  434. // declarations
  435. {
  436. for j := 0 to AModule.InterfaceSection.Declarations.Count-1 do
  437. begin
  438. ParentElement := TPasElement(AModule.InterfaceSection.Declarations[j]);
  439. TmpItem := Index.Items.NewItem;
  440. TmpItem.Text := ParentElement.Name;
  441. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  442. end;
  443. // resource strings
  444. for j := 0 to AModule.InterfaceSection.ResStrings.Count-1 do
  445. begin
  446. ParentElement := TPasElement(AModule.InterfaceSection.ResStrings[j]);
  447. TmpItem := Index.Items.NewItem;
  448. TmpItem.Text := ParentElement.Name;
  449. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  450. end;
  451. }
  452. end;
  453. // Sort
  454. Index.Items.Sort(TListSortCompare(@TOCSort));
  455. for i := 0 to Index.Items.Count-1 do
  456. begin
  457. Index.Items.Item[i].Children.Sort(TListSortCompare(@TOCSort));
  458. end;
  459. // save
  460. Index.SaveToStream(Stream);
  461. if not fnobinindex then
  462. fchm.AppendBinaryindexFromSitemap(index,false);
  463. Index.Free;
  464. Stream.Position :=0 ;
  465. FChm.AppendIndex(Stream);
  466. Stream.Free;
  467. end;
  468. DoLog('Generating Index Done');
  469. end;
  470. procedure TCHMHTMLWriter.WriteHTMLPages;
  471. var
  472. i: Integer;
  473. PageDoc: TXMLDocument;
  474. FileStream: TMemoryStream;
  475. IFileName,FileName: String;
  476. FilePath: String;
  477. begin
  478. FileName := Engine.Output;
  479. if FileName = '' then
  480. Raise Exception.Create('Error: no --output option used.');
  481. if ExtractFileExt(FileName) <> FileNameExtension then
  482. FileName := ChangeFileExt(FileName, FileNameExtension);
  483. FOutChm := TFileStream.Create(FileName, fmOpenReadWrite or fmCreate);
  484. FTempUncompressedName := GetTempFileName+IntToStr(GetProcessID) +'.raw';
  485. FTempUncompressed := TFileStream.Create(FTempUncompressedName, fmOpenReadWrite or fmCreate);
  486. FChm := TFpDocChmWriter.Create(FOutChm, False);
  487. FChm.Title := FChmTitle;
  488. FChm.TempRawStream := FTempUncompressed;
  489. FChm.OnGetFileData := @RetrieveOtherFiles;
  490. FChm.OnLastFile := @LastFileAdded;
  491. fchm.hasbinarytoc:=not fnobintoc;;
  492. fchm.hasbinaryindex:=not fnobinindex;
  493. ProcessOptions;
  494. FileStream := TMemoryStream.Create;
  495. for i := 0 to PageInfos.Count - 1 do
  496. with TPageInfo(PageInfos[i]) do
  497. begin
  498. PageDoc := CreateHTMLPage(Element, SubpageIndex);
  499. try
  500. FileName := ExtractFileName(Allocator.GetFilename(Element, SubpageIndex));
  501. FilePath := '/'+FixHTMLpath(ExtractFilePath(Allocator.GetFilename(Element, SubpageIndex)));
  502. try
  503. WriteHTMLFile(PageDoc, FileStream);
  504. FChm.AddStreamToArchive(FileName, FilePath, FileStream, True);
  505. except
  506. on E: Exception do
  507. DoLog(Format(SErrCouldNotCreateFile, [FileName, e.Message]));
  508. end;
  509. finally
  510. PageDoc.Free;
  511. FileStream.Size := 0;
  512. end;
  513. end;
  514. FileStream.Free;
  515. DoLog('HTML Files written. Collecting other files and compressing...this could take some time');
  516. //write any found images to CHM stream
  517. FileStream := TMemoryStream.Create;
  518. for iFilename in ImageFileList do
  519. begin
  520. {$ifdef imagetest} DoLog(' adding image: '+iFileName); {$endif}
  521. if FileExists(iFileName) then
  522. begin
  523. {$ifdef imagetest} DoLog(' - found'); {$endif}
  524. FileName := ExtractFileName(iFileName);
  525. FilePath := '/'+FixHTMLpath(ExtractFilePath(iFileName));
  526. FileStream.LoadFromFile(iFileName);
  527. FChm.AddStreamToArchive(FileName, FilePath, FileStream, True);
  528. FileStream.Size := 0;
  529. end
  530. else
  531. {$ifdef imagetest} DoLog(' - not found'){$endif};
  532. end;
  533. FileStream.Free;
  534. FChm.Execute;
  535. FChm.Free;
  536. DoLog('Collecting done');
  537. // we don't need to free FTempUncompressed
  538. // FTempUncompressed.Free;
  539. FOutChm.Free;
  540. DeleteFile(FTempUncompressedName);
  541. end;
  542. function TCHMHTMLWriter.InterPretOption(const Cmd, Arg: String): boolean;
  543. begin
  544. Result:=True;
  545. FNoBinToc:=False;
  546. FnoBinIndex:=False;
  547. if Cmd = '--toc-file' then
  548. FTOCName := arg
  549. else if Cmd = '--index-file' then
  550. FIndexName := arg
  551. else if Cmd = '--default-page' then
  552. FDefaultPage := arg
  553. else if Cmd = '--other-files' then
  554. FOtherFiles := arg
  555. else if Cmd = '--auto-index' then
  556. FAutoIndex := True
  557. else if Cmd = '--auto-toc' then
  558. FAutoTOC := True
  559. else if Cmd = '--no-bintoc' then
  560. FNoBinToc := True
  561. else if Cmd = '--no-binindex' then
  562. FNoBinIndex := True
  563. else if Cmd = '--make-searchable' then
  564. FMakeSearchable := True
  565. else if Cmd = '--chm-title' then
  566. FChmTitle := arg
  567. else
  568. Result:=inherited InterPretOption(Cmd, Arg);
  569. if Length(FChmTitle) = 0 then
  570. FChmTitle := Copy(Package.Name, 2, Length(Package.Name));
  571. end;
  572. class procedure TCHMHTMLWriter.Usage(List: TStrings);
  573. begin
  574. THTMLWriter.Usage(List);
  575. List.add('--default-page');
  576. List.Add(SCHMUsageDefPage);
  577. List.add('--toc-file');
  578. List.Add(SCHMUsageTOC);
  579. List.add('--index-file');
  580. List.Add(SCHMUsageIndex);
  581. List.add('--other-files');
  582. List.Add(SCHMUsageOtrFiles);
  583. List.add('--css-file');
  584. List.Add(SCHMUsageCSSFile);
  585. List.add('--auto-index');
  586. List.Add(SCHMUsageAutoIDX);
  587. List.add('--auto-toc');
  588. List.Add(SCHMUsageAutoTOC);
  589. List.add('--make-searchable');
  590. List.Add(SCHMUsageMakeSearch);
  591. List.Add('--chm-title');
  592. List.Add(SCHMUsageChmTitle);
  593. end;
  594. Class Function TCHMHTMLWriter.FileNameExtension : String;
  595. begin
  596. result:='.chm';
  597. end;
  598. class procedure TCHMHTMLWriter.SplitImport(var AFilename, ALinkPrefix: String);
  599. var
  600. i: integer;
  601. begin
  602. i := Pos(',', AFilename);
  603. if i > 0 then
  604. begin //split into filename and prefix
  605. ALinkPrefix := Copy(AFilename,i+1,Length(AFilename));
  606. SetLength(AFilename, i-1);
  607. if copy(ALinkPrefix,1,2)='..' then // workaround for project files.
  608. begin
  609. ALinkPrefix := 'ms-its:' + ChangeFileExt(ExtractFileName(AFilename), '.chm') + '::/';
  610. AFilename := ChangeFileExt(AFilename, '.xct');
  611. end;
  612. end
  613. else if ALinkPrefix = '' then
  614. begin //synthesize outdir\pgk.xct, ms-its:pkg.chm::/
  615. ALinkPrefix := 'ms-its:' + ChangeFileExt(ExtractFileName(AFilename), '.chm') + '::/';
  616. AFilename := ChangeFileExt(AFilename, '.xct');
  617. end;
  618. end;
  619. initialization
  620. RegisterWriter(TCHMHTMLWriter,'chm','Compressed HTML file output using fpdoc.css stylesheet.');
  621. finalization
  622. UnRegisterWriter('chm');
  623. end.