wchmhwrap.pas 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. {
  2. This file is part of the Free Pascal Integrated Development Environment
  3. Copyright (c) 2008 by Marco van de Voort
  4. Wrapper for CHM reading to avoid having to import Delphi units into whtmlhlp,
  5. which can cause all kinds of namespace conflicts.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit wchmhwrap;
  13. interface
  14. {$Mode Delphi}
  15. Uses wutils,whelp,whtml,SysUtils,ChmReader,ChmSiteMap,Classes;
  16. Type
  17. // TopicLinks: PTopicLinkCollection;IndexEntries : PUnsortedIndexEntryCollection;
  18. TChmWrapper = Class
  19. private
  20. ffs : Classes.TFileStream;
  21. fchmr : TChmReader;
  22. findex: TChmSiteMap;
  23. ftopic: TChmSiteMap;
  24. floaded : boolean;
  25. public
  26. constructor Create(name:String);
  27. function LoadIndex(id:integer;TopicLinks: PTopicLinkCollection;IndexEntries : PUnsortedIndexEntryCollection;helpfacility:PHelpFacility):boolean;
  28. function GetTopic(name:string):PMemoryTextFile;
  29. destructor Destroy;override;
  30. end;
  31. function combinepaths(relpath,basepath:String):String;
  32. implementation
  33. function combinepaths(relpath,basepath:String):String;
  34. begin
  35. {$ifdef combinedebug}
  36. debugmessageS({$i %file%},'combine in "'+relpath+'" and "'+basepath+'"',{$i %line%},'1',0,0);
  37. {$endif}
  38. if relpath='' then exit;
  39. if relpath[length(relpath)]<>'/' Then
  40. basepath:=extractfiledir(basepath);
  41. while (length(relpath)>0) and (copy(relpath,1,3)='../') do
  42. begin
  43. basepath:=extractfiledir(basepath);
  44. delete(relpath,1,3);
  45. end;
  46. {$ifdef combinedebug}
  47. debugmessageS({$i %file%},'combine out "'+relpath+'" and "'+basepath+'"',{$i %line%},'1',0,0);
  48. {$endif}
  49. result:=basepath+relpath;
  50. end;
  51. Constructor TChmWrapper.Create(name:string);
  52. begin
  53. ffs:=Classes.TFileStream.create(name,fmOpenRead);
  54. fchmr:=TChmReader.Create(ffs,True); // owns ffs
  55. findex:=nil;
  56. if not fchmr.isvalidfile then
  57. begin
  58. freeandnil(fchmr);
  59. freeandnil(ffs);
  60. exit;
  61. end;
  62. {$ifdef wdebug}
  63. debugmessageS({$i %file%},'TCHMWrapper: before sitemap creation ',{$i %line%},'1',0,0);
  64. {$endif}
  65. findex:=TChmSiteMap.create(stindex);
  66. ftopic:=TChmSiteMap.create(sttoc);
  67. {$ifdef wdebug}
  68. debugmessageS({$i %file%},'TCHMWrapper: after sitemap creation ',{$i %line%},'1',0,0);
  69. {$endif}
  70. floaded:=false;
  71. end;
  72. function TChmWrapper.LoadIndex(id:integer;TopicLinks: PTopicLinkCollection;IndexEntries : PUnsortedIndexEntryCollection;helpfacility:PHelpFacility):boolean;
  73. function FormatAlias(Alias: string): string;
  74. begin
  75. if Assigned(HelpFacility) then
  76. if length(Alias)>HelpFacility^.IndexTabSize-4 then
  77. Alias:=Trim(copy(Alias,1,HelpFacility^.IndexTabSize-4-2))+'..';
  78. // if (length(alias)>0) and (alias[1]<>'/') then Alias:='/'+alias;
  79. FormatAlias:=Alias;
  80. end;
  81. var
  82. m : Classes.TMemoryStream;
  83. i,j : integer;
  84. item : TChmSiteMapItem;
  85. tli: integer;
  86. begin
  87. result:=false;
  88. if not assigned (fchmr) then exit;
  89. if floaded then exit;
  90. {$ifdef wdebug}
  91. debugmessageS({$i %file%},'TCHMWrapper: indexfilename:'+fchmr.indexfile,{$i %line%},'1',0,0);
  92. {$endif}
  93. m:=fchmr.getobject(fchmr.indexfile);
  94. try
  95. if assigned(m) then
  96. begin
  97. {$ifdef wdebug}
  98. debugmessageS({$i %file%},'TCHMWrapper: stream size loaded :'+inttostr(m.size),{$i %line%},'1',0,0);
  99. {$endif}
  100. findex.loadfromStream(m);
  101. end;
  102. finally
  103. freeandnil(m);
  104. end;
  105. {$ifdef wdebug}
  106. debugmessageS({$i %file%},'TCHMWrapper: loadindex after final ',{$i %line%},'1',0,0);
  107. {$endif}
  108. tli:=TopicLinks^.AddItem(fchmr.defaultpage);
  109. TLI:=EncodeHTMLCtx(ID,TLI+1);
  110. IndexEntries^.Insert(NewIndexEntry( FormatAlias('Table of contents'),ID,TLI));
  111. for i:=0 to findex.items.count-1 do
  112. begin
  113. item:=findex.items.item[i];
  114. tli:=TopicLinks^.AddItem('/'+item.local);
  115. TLI:=EncodeHTMLCtx(ID,TLI+1);
  116. IndexEntries^.Insert(NewIndexEntry( FormatAlias(item.text),ID,TLI));
  117. end;
  118. {$ifdef wdebug}
  119. debugmessageS({$i %file%},'TCHMWrapper: endloadindex ',{$i %line%},'1',0,0);
  120. {$endif}
  121. floaded:=true;
  122. result:=true;
  123. end;
  124. procedure splitline(idestream:PMemoryTextFile;s:ansistring);
  125. function scanvalue:integer; // searches for a possible breaking point left of char 255.
  126. var n,i : integer;
  127. lastpoint:integer;
  128. inquote : boolean;
  129. begin
  130. lastpoint:=-1;
  131. n:=length(s);
  132. if n>250 then n:=250;
  133. i:=1; inquote:=false;
  134. while (i<=n) do
  135. begin
  136. while (s[i]<>' ') and (s[i]<>'"') and (i<=n) do inc(i);
  137. if (s[i]=' ') and not inquote then lastpoint:=i;
  138. if (s[i]='"') then inquote:=not inquote;
  139. inc(i);
  140. end;
  141. scanvalue:=lastpoint;
  142. end;
  143. var position : longint;
  144. begin
  145. position:=0;
  146. while (length(s)>250) and (position<>-1) do
  147. begin
  148. position:=scanvalue;
  149. if position<>-1 then
  150. begin
  151. idestream.addline(copy(s,1,position-1));
  152. delete(s,1,position);
  153. end;
  154. end;
  155. if length(s)<>0 then
  156. idestream.addline(s);
  157. end;
  158. function TChmWrapper.GetTopic(name:string):PMemoryTextFile;
  159. var
  160. m : Classes.TMemorystream;
  161. linedata:Classes.TStringList;
  162. i : integer;
  163. begin
  164. result:=nil;
  165. if not assigned(fchmr) or (name='') then exit;
  166. If (name[1]<>'/') and (copy(name,1,7)<>'ms-its:') Then
  167. name:='/'+name;
  168. linedata:=Classes.TStringList.create;
  169. try
  170. {$ifdef wdebug}
  171. debugmessageS({$i %file%},'TCHMWrapper: Getting file '+name,{$i %line%},'1',0,0);
  172. {$endif}
  173. // if uppercase(name)='TABLE OF CONTENTS' Then
  174. // m:=fchmr.getobject(fchmr.tocfile)
  175. // else
  176. m:=fchmr.getobject(name);
  177. if not assigned(m) then exit;
  178. linedata.loadfromstream(m);
  179. result:=new(PMemoryTextFile,Init);
  180. for i:=0 to linedata.count-1 do
  181. begin
  182. if length(linedata[i])>250 Then
  183. splitline(result,linedata[i])
  184. else
  185. result.addline(linedata[i]);
  186. end;
  187. finally
  188. m.free;
  189. linedata.free;
  190. end;
  191. end;
  192. destructor TChmWrapper.Destroy;
  193. begin
  194. freeandnil(ftopic);
  195. freeandnil(findex);
  196. freeandnil(fchmr);
  197. end;
  198. // m:=r.getobject(r.indexfile);
  199. // siteindex.loadfromStream(m);
  200. end.