wtphwrit.pas 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. {
  2. This file is part of the Free Pascal Integrated Development Environment
  3. Copyright (c) 1998 by Berczi Gabor
  4. Routines to create .tph files
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit WTPHWriter;
  12. {$H-}
  13. interface
  14. uses
  15. Objects, WoaHelp, WHelp;
  16. const
  17. HelpStamp = 'TURBO PASCAL HelpFile.';
  18. DefFormatVersion = $34;
  19. type
  20. PHelpFileWriter = ^THelpFileWriter;
  21. THelpFileWriter = object(TOAHelpFile)
  22. constructor Init(AFileName: string; AID: word);
  23. function CreateTopic(HelpCtx: THelpCtx): PTopic; virtual;
  24. procedure AddTopicToIndex(IndexTag: string; P: PTopic); virtual;
  25. procedure AddLineToTopic(P: PTopic; Line: string); virtual;
  26. procedure AddLinkToTopic(P: PTopic; AHelpCtx: THelpCtx);
  27. procedure AddIndexEntry(Tag: string; P: PTopic); virtual;
  28. function WriteFile: boolean; virtual;
  29. destructor Done; virtual;
  30. private
  31. procedure CompleteContextNo;
  32. procedure CalcTopicOfs;
  33. procedure WriteHeader(var S: TStream);
  34. procedure WriteCompressionRecord(var S: TStream);
  35. procedure WriteContextTable(var S: TStream);
  36. procedure WriteIndexTable(var S: TStream);
  37. procedure WriteTopic(var S: TStream; T: PTopic);
  38. procedure WriteRecord(var S: TStream; RecType: byte; var Buf; Size: word);
  39. end;
  40. implementation
  41. constructor THelpFileWriter.Init(AFileName: string; AID: word);
  42. var OK: boolean;
  43. begin
  44. THelpFile.Init(AID);
  45. New(F, Init(AFileName, stCreate, HelpStreamBufSize));
  46. OK:=F<>nil;
  47. if OK then OK:=(F^.Status=stOK);
  48. if OK=false then Fail;
  49. end;
  50. function THelpFileWriter.CreateTopic(HelpCtx: THelpCtx): PTopic;
  51. var P: PTopic;
  52. begin
  53. if (HelpCtx<>0) and (SearchTopic(HelpCtx)<>nil) then
  54. P:=nil
  55. else
  56. begin
  57. P:=NewTopic(ID,HelpCtx,0,'');
  58. Topics^.Insert(P);
  59. end;
  60. CreateTopic:=P;
  61. end;
  62. procedure THelpFileWriter.AddTopicToIndex(IndexTag: string; P: PTopic);
  63. begin
  64. IndexEntries^.Insert(NewIndexEntry(IndexTag,P^.FileID,P^.HelpCtx));
  65. end;
  66. procedure THelpFileWriter.AddLineToTopic(P: PTopic; Line: string);
  67. var OldText: pointer;
  68. OldSize: word;
  69. begin
  70. if P=nil then Exit;
  71. OldText:=P^.Text; OldSize:=P^.TextSize;
  72. Inc(P^.TextSize,length(Line)+1);
  73. GetMem(P^.Text,P^.TextSize);
  74. if OldText<>nil then Move(OldText^,P^.Text^,OldSize);
  75. Move(Line[1],P^.Text^[OldSize],length(Line));
  76. P^.Text^[OldSize+length(Line)]:=0;
  77. if OldText<>nil then FreeMem(OldText,OldSize);
  78. end;
  79. procedure THelpFileWriter.AddLinkToTopic(P: PTopic; AHelpCtx: THelpCtx);
  80. var OldEntries: pointer;
  81. OldCount : word;
  82. OldSize : word;
  83. begin
  84. if P=nil then Exit;
  85. OldEntries:=P^.Links; OldCount:=P^.LinkCount; OldSize:=P^.LinkSize;
  86. Inc(P^.LinkCount);
  87. GetMem(P^.Links,P^.LinkSize);
  88. if OldEntries<>nil then Move(OldEntries^,P^.Links^,OldSize);
  89. with P^.Links^[P^.LinkCount-1] do
  90. begin
  91. FileID:=ID;
  92. Context:=AHelpCtx;
  93. end;
  94. if OldEntries<>nil then FreeMem(OldEntries,OldSize);
  95. end;
  96. procedure THelpFileWriter.AddIndexEntry(Tag: string; P: PTopic);
  97. begin
  98. if P=nil then Exit;
  99. IndexEntries^.Insert(NewIndexEntry(Tag,P^.FileID,P^.HelpCtx));
  100. end;
  101. function THelpFileWriter.WriteFile: boolean;
  102. var I: sw_integer;
  103. CtxStart: longint;
  104. begin
  105. CompleteContextNo;
  106. CalcTopicOfs;
  107. WriteHeader(F^);
  108. WriteCompressionRecord(F^);
  109. CtxStart:=F^.GetPos;
  110. WriteContextTable(F^);
  111. WriteIndexTable(F^);
  112. for I:=0 to Topics^.Count-1 do
  113. begin
  114. WriteTopic(F^,Topics^.At(I));
  115. end;
  116. F^.Seek(CtxStart);
  117. WriteContextTable(F^);
  118. end;
  119. procedure THelpFileWriter.WriteHeader(var S: TStream);
  120. var St: string;
  121. begin
  122. Version.FormatVersion:=DefFormatVersion;
  123. St:=HelpStamp+#0#$1a;
  124. F^.Write(St[1],length(St));
  125. St:=Signature;
  126. F^.Write(St[1],length(St));
  127. F^.Write(Version,SizeOf(Version));
  128. WriteRecord(F^,rtFileHeader,Header,SizeOf(Header));
  129. end;
  130. procedure THelpFileWriter.WriteCompressionRecord(var S: TStream);
  131. var CR: THLPCompression;
  132. begin
  133. FillChar(CR,SizeOf(CR),0);
  134. WriteRecord(F^,rtCompression,CR,SizeOf(CR));
  135. end;
  136. procedure THelpFileWriter.WriteIndexTable(var S: TStream);
  137. const BufSize = 65000;
  138. var P: ^THLPIndexTable;
  139. TableSize: word;
  140. procedure AddByte(B: byte);
  141. begin
  142. PByteArray(@P^.Entries)^[TableSize]:=B;
  143. Inc(TableSize);
  144. end;
  145. procedure AddEntry(Tag: string; HelpCtx: word);
  146. var Len,I: byte;
  147. begin
  148. Len:=length(Tag); if Len>31 then Len:=31;
  149. AddByte(Len);
  150. for I:=1 to Len do
  151. AddByte(ord(Tag[I]));
  152. AddByte(Lo(HelpCtx)); AddByte(Hi(HelpCtx));
  153. end;
  154. var I: sw_integer;
  155. begin
  156. if IndexEntries^.Count=0 then Exit;
  157. GetMem(P,BufSize);
  158. TableSize:=0;
  159. P^.IndexCount:=IndexEntries^.Count;
  160. for I:=0 to IndexEntries^.Count-1 do
  161. with IndexEntries^.At(I)^ do
  162. AddEntry(Tag^,HelpCtx);
  163. Inc(TableSize,SizeOf(P^.IndexCount));
  164. WriteRecord(F^,rtIndex,P^,TableSize);
  165. FreeMem(P,BufSize);
  166. end;
  167. procedure THelpFileWriter.WriteContextTable(var S: TStream);
  168. var Ctxs: ^THLPContexts;
  169. CtxSize,I: word;
  170. T: PTopic;
  171. MaxCtx: longint;
  172. begin
  173. if Topics^.Count=0 then MaxCtx:=1 else
  174. MaxCtx:=Topics^.At(Topics^.Count-1)^.HelpCtx;
  175. CtxSize:=SizeOf(Ctxs^.ContextCount)+SizeOf(Ctxs^.Contexts[0])*(MaxCtx+1);
  176. GetMem(Ctxs,CtxSize); FillChar(Ctxs^,CtxSize,0);
  177. Ctxs^.ContextCount:=MaxCtx+1;
  178. for I:=1 to Topics^.Count do
  179. begin
  180. T:=Topics^.At(I-1);
  181. with Ctxs^.Contexts[T^.HelpCtx] do
  182. begin
  183. LoW:=(T^.FileOfs and $ffff);
  184. HiB:=(T^.FileOfs shr 16) and $ff;
  185. end;
  186. end;
  187. WriteRecord(F^,rtContext,Ctxs^,CtxSize);
  188. FreeMem(Ctxs,CtxSize);
  189. end;
  190. procedure THelpFileWriter.WriteTopic(var S: TStream; T: PTopic);
  191. var TextBuf: PByteArray;
  192. TextSize: word;
  193. KWBuf: ^THLPKeywordRecord;
  194. I,KWBufSize: word;
  195. begin
  196. T^.FileOfs:=S.GetPos;
  197. TextBuf:=T^.Text; TextSize:=T^.TextSize;
  198. WriteRecord(F^,rtText,TextBuf^,TextSize);
  199. { write keyword record here }
  200. KWBufSize:=SizeOf(KWBuf^)+SizeOf(KWBuf^.Keywords[0])*T^.LinkCount;
  201. GetMem(KWBuf,KWBufSize); FillChar(KWBuf^,KWBufSize,0);
  202. KWBuf^.KeywordCount:=T^.LinkCount;
  203. for I:=0 to T^.LinkCount-1 do
  204. KWBuf^.Keywords[I].kwContext:=T^.Links^[I].Context;
  205. WriteRecord(F^,rtKeyword,KWBuf^,KWBufSize);
  206. FreeMem(KWBuf,KWBufSize);
  207. end;
  208. procedure THelpFileWriter.CompleteContextNo;
  209. var P: PTopic;
  210. NextTopicID: THelpCtx;
  211. function SearchNextFreeTopicID: THelpCtx;
  212. begin
  213. while Topics^.SearchTopic(NextTopicID)<>nil do
  214. Inc(NextTopicID);
  215. SearchNextFreeTopicID:=NextTopicID;
  216. end;
  217. begin
  218. NextTopicID:=1;
  219. repeat
  220. P:=Topics^.SearchTopic(0);
  221. if P<>nil then
  222. begin
  223. Topics^.Delete(P);
  224. P^.HelpCtx:=SearchNextFreeTopicID;
  225. Topics^.Insert(P);
  226. end;
  227. until P=nil;
  228. end;
  229. procedure THelpFileWriter.CalcTopicOfs;
  230. begin
  231. end;
  232. procedure THelpFileWriter.WriteRecord(var S: TStream; RecType: byte; var Buf; Size: word);
  233. var RH: THLPRecordHeader;
  234. begin
  235. RH.RecType:=RecType; RH.RecLength:=Size;
  236. S.Write(RH,SizeOf(RH));
  237. S.Write(Buf,Size);
  238. end;
  239. destructor THelpFileWriter.Done;
  240. begin
  241. inherited Done;
  242. end;
  243. END.