wtphwrit.pas 7.1 KB

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