| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 | {    This file is part of the Free Pascal Integrated Development Environment    Copyright (c) 1998 by Berczi Gabor    Routines to create .tph files    See the file COPYING.FPC, included in this distribution,    for details about the copyright.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************}unit WTPHWriter;interfaceuses    Objects, WoaHelp, WHelp;const     HelpStamp = 'TURBO PASCAL HelpFile.';     DefFormatVersion = $34;type    PHelpFileWriter = ^THelpFileWriter;    THelpFileWriter = object(TOAHelpFile)      constructor Init(AFileName: string; AID: word);      function    CreateTopic(HelpCtx: THelpCtx): PTopic; virtual;      procedure   AddTopicToIndex(IndexTag: string; P: PTopic); virtual;      procedure   AddLineToTopic(P: PTopic; Line: string); virtual;      procedure   AddLinkToTopic(P: PTopic; AHelpCtx: THelpCtx);      procedure   AddIndexEntry(Tag: string; P: PTopic); virtual;      function    WriteFile: boolean; virtual;      destructor  Done; virtual;    private      procedure   CompleteContextNo;      procedure   CalcTopicOfs;      procedure   WriteHeader(var S: TStream);      procedure   WriteCompressionRecord(var S: TStream);      procedure   WriteContextTable(var S: TStream);      procedure   WriteIndexTable(var S: TStream);      procedure   WriteTopic(var S: TStream; T: PTopic);      procedure   WriteRecord(var S: TStream; RecType: byte; var Buf; Size: word);    end;implementationconstructor THelpFileWriter.Init(AFileName: string; AID: word);var OK: boolean;begin  THelpFile.Init(AID);  New(F, Init(AFileName, stCreate, HelpStreamBufSize));  OK:=F<>nil;  if OK then OK:=(F^.Status=stOK);  if OK=false then Fail;end;function THelpFileWriter.CreateTopic(HelpCtx: THelpCtx): PTopic;var P: PTopic;begin  if (HelpCtx<>0) and (SearchTopic(HelpCtx)<>nil) then    P:=nil  else    begin      P:=NewTopic(ID,HelpCtx,0,'');      Topics^.Insert(P);    end;  CreateTopic:=P;end;procedure THelpFileWriter.AddTopicToIndex(IndexTag: string; P: PTopic);begin  IndexEntries^.Insert(NewIndexEntry(IndexTag,P^.FileID,P^.HelpCtx));end;procedure THelpFileWriter.AddLineToTopic(P: PTopic; Line: string);var OldText: pointer;    OldSize: word;begin  if P=nil then Exit;  OldText:=P^.Text; OldSize:=P^.TextSize;  Inc(P^.TextSize,length(Line)+1);  GetMem(P^.Text,P^.TextSize);  if OldText<>nil then Move(OldText^,P^.Text^,OldSize);  Move(Line[1],P^.Text^[OldSize],length(Line));  P^.Text^[OldSize+length(Line)]:=0;  if OldText<>nil then FreeMem(OldText,OldSize);end;procedure THelpFileWriter.AddLinkToTopic(P: PTopic; AHelpCtx: THelpCtx);var OldEntries: pointer;    OldCount  : word;    OldSize   : word;begin  if P=nil then Exit;  OldEntries:=P^.Links; OldCount:=P^.LinkCount; OldSize:=P^.LinkSize;  Inc(P^.LinkCount);  GetMem(P^.Links,P^.LinkSize);  if OldEntries<>nil then Move(OldEntries^,P^.Links^,OldSize);  with P^.Links^[P^.LinkCount-1] do    begin      FileID:=ID;      Context:=AHelpCtx;    end;  if OldEntries<>nil then FreeMem(OldEntries,OldSize);end;procedure THelpFileWriter.AddIndexEntry(Tag: string; P: PTopic);begin  if P=nil then Exit;  IndexEntries^.Insert(NewIndexEntry(Tag,P^.FileID,P^.HelpCtx));end;function THelpFileWriter.WriteFile: boolean;var I: sw_integer;    CtxStart: longint;begin  CompleteContextNo;  CalcTopicOfs;  WriteHeader(F^);  WriteCompressionRecord(F^);  CtxStart:=F^.GetPos;  WriteContextTable(F^);  WriteIndexTable(F^);  for I:=0 to Topics^.Count-1 do    begin      WriteTopic(F^,Topics^.At(I));    end;  F^.Seek(CtxStart);  WriteContextTable(F^);end;procedure THelpFileWriter.WriteHeader(var S: TStream);var St: string;begin  Version.FormatVersion:=DefFormatVersion;  St:=HelpStamp+#0#$1a;  F^.Write(St[1],length(St));  St:=Signature;  F^.Write(St[1],length(St));  F^.Write(Version,SizeOf(Version));  WriteRecord(F^,rtFileHeader,Header,SizeOf(Header));end;procedure THelpFileWriter.WriteCompressionRecord(var S: TStream);var CR: THLPCompression;begin  FillChar(CR,SizeOf(CR),0);  WriteRecord(F^,rtCompression,CR,SizeOf(CR));end;procedure THelpFileWriter.WriteIndexTable(var S: TStream);const BufSize = 65000;var P: ^THLPIndexTable;    TableSize: word;procedure AddByte(B: byte);begin  PByteArray(@P^.Entries)^[TableSize]:=B;  Inc(TableSize);end;procedure AddEntry(Tag: string; HelpCtx: word);var Len,I: byte;begin  Len:=length(Tag); if Len>31 then Len:=31;  AddByte(Len);  for I:=1 to Len do    AddByte(ord(Tag[I]));  AddByte(Lo(HelpCtx)); AddByte(Hi(HelpCtx));end;var I: sw_integer;begin  if IndexEntries^.Count=0 then Exit;  GetMem(P,BufSize);  TableSize:=0;  P^.IndexCount:=IndexEntries^.Count;  for I:=0 to IndexEntries^.Count-1 do    with IndexEntries^.At(I)^ do    AddEntry(Tag^,HelpCtx);  Inc(TableSize,SizeOf(P^.IndexCount));  WriteRecord(F^,rtIndex,P^,TableSize);  FreeMem(P,BufSize);end;procedure THelpFileWriter.WriteContextTable(var S: TStream);var Ctxs: ^THLPContexts;    CtxSize,I: word;    T: PTopic;    MaxCtx: longint;begin  if Topics^.Count=0 then MaxCtx:=1 else    MaxCtx:=Topics^.At(Topics^.Count-1)^.HelpCtx;  CtxSize:=SizeOf(Ctxs^.ContextCount)+SizeOf(Ctxs^.Contexts[0])*(MaxCtx+1);  GetMem(Ctxs,CtxSize); FillChar(Ctxs^,CtxSize,0);  Ctxs^.ContextCount:=MaxCtx+1;  for I:=1 to Topics^.Count do    begin      T:=Topics^.At(I-1);      with Ctxs^.Contexts[T^.HelpCtx] do       begin         LoW:=(T^.FileOfs and $ffff);         HiB:=(T^.FileOfs shr 16) and $ff;       end;    end;  WriteRecord(F^,rtContext,Ctxs^,CtxSize);  FreeMem(Ctxs,CtxSize);end;procedure THelpFileWriter.WriteTopic(var S: TStream; T: PTopic);var TextBuf: PByteArray;    TextSize: word;    KWBuf: ^THLPKeywordRecord;    I,KWBufSize: word;begin  T^.FileOfs:=S.GetPos;  TextBuf:=T^.Text; TextSize:=T^.TextSize;  WriteRecord(F^,rtText,TextBuf^,TextSize);  { write keyword record here }  KWBufSize:=SizeOf(KWBuf^)+SizeOf(KWBuf^.Keywords[0])*T^.LinkCount;  GetMem(KWBuf,KWBufSize); FillChar(KWBuf^,KWBufSize,0);  KWBuf^.KeywordCount:=T^.LinkCount;  for I:=0 to T^.LinkCount-1 do    KWBuf^.Keywords[I].kwContext:=T^.Links^[I].Context;  WriteRecord(F^,rtKeyword,KWBuf^,KWBufSize);  FreeMem(KWBuf,KWBufSize);end;procedure THelpFileWriter.CompleteContextNo;var P: PTopic;    NextTopicID: THelpCtx;function SearchNextFreeTopicID: THelpCtx;begin  while Topics^.SearchTopic(NextTopicID)<>nil do    Inc(NextTopicID);  SearchNextFreeTopicID:=NextTopicID;end;begin  NextTopicID:=1;  repeat    P:=Topics^.SearchTopic(0);    if P<>nil then      begin        Topics^.Delete(P);        P^.HelpCtx:=SearchNextFreeTopicID;        Topics^.Insert(P);      end;  until P=nil;end;procedure THelpFileWriter.CalcTopicOfs;beginend;procedure THelpFileWriter.WriteRecord(var S: TStream; RecType: byte; var Buf; Size: word);var RH: THLPRecordHeader;begin  RH.RecType:=RecType; RH.RecLength:=Size;  S.Write(RH,SizeOf(RH));  S.Write(Buf,Size);end;destructor THelpFileWriter.Done;begin  inherited Done;end;END.
 |