home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 1996 March / PCPRO0396.ISO / code / prog / listing1.txt
Encoding:
Text File  |  1995-12-18  |  8.7 KB  |  317 lines

  1. unit HelpInfo;
  2.  
  3. interface
  4.  
  5. uses WinTypes, WinProcs, SysUtils;
  6.  
  7. const
  8.     HBadOpen = 1000;      { Can't open the help file   }
  9.     HIOError = 1001;      { I/O Error reading the file }
  10.     HBadSig  = 1002;      { Not a Windows Help file    }
  11.     HNoSys   = 1003;      { |SYSTEM file is missing!  }
  12.  
  13. function  OpenHelpFile (fileName: PChar; var hFile: Pointer): Integer;
  14. procedure CloseHelpFile (hFile: Pointer);
  15.  
  16. implementation
  17.  
  18. type
  19.     { Header for entire .HLP file }
  20.     THFileHeader 
  21.           = record
  22.               MagicNumber: LongInt;
  23.               WHIFSOffset: LongInt;
  24.               Negative: LongInt;
  25.               FileSize: LongInt;
  26.             end;
  27.  
  28.     { Header for each internal WHIFS file }
  29.     TFileHeader
  30.           = record
  31.           FilePlusHdr: LongInt;    { size with header }
  32.           FileSize:    LongInt;        { size without header }
  33.           NullByte: Byte;        { always zero... }
  34.         end;
  35.  
  36.     TWHIFSHeader 
  37.           = record
  38.               Magic: array [0..17] of Byte;
  39.               Junk: array [0..12] of Byte;
  40.               Zero, NSplits, RootPage, MinusOne: Integer;
  41.               TotPages, NLevels: Integer;
  42.               TotalWHIFSEntries: LongInt;
  43.             end;
  44.  
  45.     PSysHeader = ^TSysHeader;
  46.     TSysHeader 
  47.          = record
  48.              Magic, Version, Revision, Zero: Byte;
  49.              AlwaysOne: Word;
  50.              GenDate: LongInt;
  51.              Flags: Word;
  52.            end;
  53.  
  54.     PHelpHandle = ^THelpHandle;
  55.     THelpHandle 
  56.          = record
  57.              _fd: Integer;                       { handle of open help file     }
  58.              _fn: String;                        { full pathname of the file    }
  59.              _scratch1: array [0..255] of Char;  { scratch buffer             }
  60.              _WHIFSStart: LongInt;               { start of file system         }
  61.          _FirstLeaf: Integer;              { first leaf node number       }
  62.              _Title: array [0..255] of Char;     { help system title            }
  63.              _Copyright: array [0..255] of Char; { help system copyright        }
  64.              _MacroCount: Integer;               { number of startup macros     }
  65.              _MacroData: PChar;                  { pointer to macro data        }
  66.              _MacroDataSize: Word;               { size of _MacroData pointer   }
  67.              _FileCount: Integer;                { # of files in help system    }
  68.              _System: PSysHeader;                { pointer to in-memory |SYSTEM }
  69.              _FileDirectory: Pointer;            { pointer to file directory    }
  70.            end;
  71.  
  72. procedure GotoWHIFSPage (p: PHelpHandle; pageNum: LongInt);
  73. begin
  74.   with p^ do _llseek (_fd, _WHIFSStart + (pageNum * 1024), 0)
  75. end;
  76.  
  77. procedure ReadString (fd: Integer; dest: PChar);
  78. begin
  79.   while True do
  80.   begin
  81.     _lread (fd, dest, 1);
  82.     if dest^ = #0 then break;
  83.     Inc (dest)
  84.   end
  85. end;
  86.  
  87. function FindWHIFSFile (p: PHelpHandle; fileName: PChar): LongInt;
  88. var
  89.    count: Integer;
  90.    fEntry: ^PChar;
  91. begin
  92.   FindWHIFSFile := -1;
  93.   with p^ do
  94.   begin
  95.     fEntry := _FileDirectory;
  96.     for count := 0 to _FileCount - 1 do
  97.     begin
  98.       if lstrcmp (fileName, fEntry^) = 0 then
  99.       begin
  100.         FindWHIFSFile := PLongInt (fEntry^ + lstrlen (fEntry^) + 1)^;
  101.         Exit;
  102.       end;
  103.       Inc (fEntry)
  104.     end
  105.   end
  106. end;
  107.  
  108. procedure ReadFileDirectory (p: PHelpHandle);
  109. type
  110.     Node = record
  111.              Sig, Entries, Prev, Next: Integer;
  112.            end;
  113. var
  114.    f: Integer;
  115.    fEntry: ^PChar;
  116.    WHIFSNode: Node;
  117.    fname: array [0..255] of Char;
  118.  
  119. begin
  120.   with p^ do
  121.   begin
  122.     { Allocate memory for directory structure }
  123.  
  124.     _FileDirectory := AllocMem (_FileCount * sizeof (PChar));
  125.     fEntry := _FileDirectory;
  126.  
  127.     { Second pass - read the file directory }
  128.  
  129.     GotoWHIFSPage (p, _FirstLeaf);
  130.     while True do
  131.     begin
  132.       _lread (_fd, @WHIFSNode, sizeof (WHIFSNode));
  133.       for f := 1 to WHIFSNode.Entries do
  134.       begin
  135.         ReadString (_fd, fname);
  136.         fEntry^ := AllocMem (lstrlen (fname) + 1 + sizeof (LongInt));
  137.         lstrcpy (fEntry^, fname);
  138.         _lread (_fd, fEntry^ + lstrlen (fName) + 1, sizeof (LongInt));
  139.         Inc (fEntry)
  140.       end;
  141.  
  142.       if WHIFSNode.Next = -1 then break;
  143.       GotoWHIFSPage (p, WHIFSNode.Next)
  144.     end
  145.   end
  146. end;
  147.  
  148. function LoadSystem (p: PHelpHandle): Integer;
  149. const
  150.     hpj_Title     = 1;                { title string }
  151.     hpj_Copyright = 2;                { copyright string }
  152.     hpj_Contents  = 3;                { contents }
  153.     hpj_MacroData = 4;
  154.     hpj_IconData  = 5;
  155.     hpj_SecWindow = 6;
  156.     hpj_Citation  = 8;
  157. var
  158.    Data: array [0..1] of Word;
  159.    DataPtr: PChar;
  160.  
  161.    bytesRead: LongInt;
  162.    sysOffset: LongInt;
  163.    fhdr: TFileHeader;
  164.    szBuffer: array [0..255] of Char;
  165.  
  166.    procedure AddMacro (macro: PChar);
  167.    var
  168.       sz: Word;
  169.    begin
  170.      with p^ do
  171.      begin
  172.        sz := lstrlen (macro) + 1;
  173.        if _MacroData = Nil then _MacroData := AllocMem (sz)
  174.        else _MacroData 
  175.               := ReAllocMem (_MacroData, _MacroDataSize, _MacroDataSize + sz);
  176.        lstrcpy (_MacroData + _MacroDataSize, macro);
  177.        Inc (_MacroDataSize, sz);
  178.        Inc (_MacroCount)
  179.      end
  180.   end;
  181.  
  182. begin
  183.   LoadSystem := 0;
  184.   with p^ do
  185.   begin
  186.     sysOffset := FindWHIFSFile (p, '|SYSTEM');
  187.     if sysOffset = -1 then LoadSystem := HNoSys else
  188.     begin
  189.       { Read file header for |SYSTEM file }
  190.   
  191.       _llseek (_fd, sysOffset, 0);
  192.       _lread (_fd, @fhdr, sizeof (fhdr));
  193.       GetMem (_System, sizeof (TSysHeader));
  194.       _lread (_fd, PChar (_System), sizeof (TSysHeader));
  195.  
  196.       { Is it ancient ?  If so, title string only }
  197.       if _System^.Revision = $F then
  198.       begin
  199.         _lread (_fd, _Title, 33);
  200.        Exit
  201.       end;
  202.  
  203.       { Now, grab any stuff that follows system header }
  204.       { It's organised as <Type><Size><Data>,,,<Type><Size><Data> }
  205.  
  206.       bytesRead := sizeof (TSysHeader);
  207.       while fhdr.FileSize > bytesRead do
  208.       begin
  209.         _lread (_fd, @Data, sizeof (Data));
  210.         GetMem (DataPtr, Data [1]);
  211.         _lread (_fd, DataPtr, Data [1]);
  212.  
  213.        { Now case out on the data type }
  214.        case Data [0] of
  215.          hpj_Title:      lstrcpy (_Title, DataPtr);
  216.          hpj_Copyright:  if DataPtr^ <> #0 
  217.                          then lstrcpy (_Copyright, DataPtr)
  218.                          else lstrcpy (_Copyright, 'None');
  219.          hpj_MacroData:  AddMacro (DataPtr);
  220.         end;
  221.  
  222.         FreeMem (DataPtr, Data [1]);
  223.         Inc (bytesRead, Data [1] + sizeof (Data))
  224.       end
  225.     end
  226.   end
  227. end;
  228.  
  229. function OpenHelpFile (fileName: PChar; var hFile: Pointer): Integer;
  230. var
  231.    aPage: Word;
  232.    junk: LongInt;
  233.    hdr: THFileHeader;
  234.    whdr: TWHIFSHeader;
  235.    f, fd, ret: Integer;
  236.    p: PHelpHandle absolute hFile;
  237.  
  238. begin
  239.   ret := 0;
  240.   hFile := Nil;
  241.   fd := _lopen (fileName, 0);
  242.   if fd = -1 then ret := HBadOpen else
  243.   if _lread (fd, @hdr, sizeof (hdr)) <> sizeof (hdr) then ret := HIOError else
  244.   if hdr.MagicNumber <> $00035F3F then ret := HBadSig;
  245.  
  246.   if ret = 0 then
  247.   begin
  248.     CloseHelpFile (hFile);
  249.     p := AllocMem (sizeof (THelpHandle));
  250.     p^._fd := fd;
  251.     p^._fn := StrPas (fileName);
  252.     lstrcpy (p^._Title, 'None');
  253.     lstrcpy (p^._Copyright, 'None');
  254.     p^._WHIFSStart := hdr.WHIFSOffset + sizeof (whdr);
  255.  
  256.     { Read the WHIFS header }
  257.  
  258.     _llseek (fd, hdr.WHIFSOffset, 0);
  259.     _lread (fd, @whdr, sizeof (whdr));
  260.     p^._FileCount := whdr.TotalWHIFSEntries;
  261.  
  262.     { and find root page }
  263.  
  264.     f := 1;
  265.     aPage := 0;
  266.     GotoWHIFSPage (p, whdr.RootPage);
  267.     while f < whdr.NLevels do
  268.     begin
  269.       _lread (fd, @junk, sizeof (junk));
  270.       _lread (fd, @aPage, sizeof (aPage));
  271.       GotoWHIFSPage (p, aPage);
  272.       Inc (f);
  273.     end;
  274.  
  275.     p^._FirstLeaf := aPage;
  276.  
  277.     { Read directory and load the |SYSTEM file }
  278.  
  279.     ReadFileDirectory (p);
  280.     ret := LoadSystem (p);
  281.  
  282.   end
  283.   else if fd <> -1 then _lclose (fd);
  284.  
  285.   OpenHelpFile := ret
  286. end;
  287.  
  288. procedure CloseHelpFile (hFile: Pointer);
  289. var
  290.   count: Integer;
  291.   fEntry: ^PChar;
  292.   p: PHelpHandle absolute hFile;
  293. begin
  294.   if hFile <> Nil then with p^ do
  295.   begin
  296.     _lclose (_fd);
  297.     if _System <> Nil then FreeMem (_System, sizeof (TSysHeader));
  298.     if _MacroDataSize <> 0 then FreeMem (_MacroData, _MacroDataSize);
  299.  
  300.     if _FileDirectory <> Nil then
  301.     begin
  302.       fEntry := _FileDirectory;
  303.       { First kill individual entries }
  304.       for count := 0 to _FileCount - 1 do
  305.       begin
  306.         FreeMem (fEntry^, lstrlen (fEntry^) + 1 + sizeof (LongInt));
  307.         Inc (fEntry);
  308.       end;
  309.       { Then kill directory itself }
  310.       FreeMem (_FileDirectory, _FileCount * sizeof (PChar));
  311.     end;
  312.     FreeMem (hFile, sizeof (THelpHandle))
  313.   end
  314. end;
  315.  
  316. end.
  317.