From: iacullwd@acasun.eckerd.edu (Walter D. Iacullo)
Newsgroups: alt.binaries.multimedia
Subject: Pascal Program for DeBinHexing (.hqx) files
Date: 4 Jan 1995 23:29:07 -0500
Organization: Eckerd College, St. Petersburg, Florida


The second part is a program for Turbo Pascal 7.0.  It ONLY WORKS WITH
7.0!!!  The following is more info on the program.

   Turbo Pascal 7.0 UnHQX Object    
   =============================
    - by Robert Rothenburg Walking-Owl <robert.rothenburg@asb.com> 
      CopyLeft, 1994


   How the UnHQX unit works:
   =========================

    - You must first locate where the "(This file must be converted..."
      message is in the file (raw FilePos) and pass that to Init.  Init
      reads the the initial header information and exits will the file-
      position at the start of the data fork. (Note: you must manually
      set FilePtr to 0 to signify relative position in each fork!)

      For example,

        var Filter: HQX;
            Origin: LongInt;
            f: file;
        begin
          Assign(f,'FileName.hqx');
          ReSet(f,1);
          repeat
            ...       { Search file for "(This file must be converted". }
            ...       { Set Origin to that position ...                 }
          until Found;
          Filter.Init(f,Origin);
          if Filter.Header.FileCRC <> Filter.Header.CRC
            then { Bad CRC! }
            else ...
            
            ...      { Filter.Header contains the header information   }
          
          Filter.FilePtr := 0;  { Initialize filepointer for fork      }
          Filter.CRC := 0;      { Initialize CRC for fork              }
          for i := 1 to Filter.Header.DataLen
            do ...   { Read Filter.Header.DataLen characters ...       }
          ActualCRC   := fCRC;          { What CRC actually was        }
          DataForkCRC := Filter.fGetW;  { What CRC is supposed to be   }

            ...      { Repeat the same for the Resource Fork           }

          Filter.Done;
        end;
    
      { Note: fCRC finalizes the CRC and returns the value.  You must  }
      {       then read the CRC, check if valid, and then reinitialize }
      {       the CRC to 0!                                            }

    - Use the public f-functions only to get characters from the file! 
      (ie. fGetC, fGetBlock, fGetW, fGetL, fSkip or fSeek, and fCRC).

    - fGetC is the root function, which handles the required bookkeeping,
      mainly because of the run-length encoding used by BinHex 4.0 files.


               ReadChar --> Fetch ---> Decode ----> PutBits
                             |                       |
        fSkip --> fSeek --> fGetC <-- UpdateCRC <-- Retrieve
                             |                       
                            fGetBlock  --->+        
                             |             +--> Init
                            fGetW, fGetL ->+

      If the Run-Length flag is set, fGetC continues to send the repeated 
      character when called for the specified number of times.

      If more characters need to be decoded, Fetch is called.  (Fetch
      gets raw characters from the file, then decodes them and adds them
      to the buffer for Retrieve.  ReadChar uses a Buffer to minimize
      disk-reads and speed the process up).

      fGetC then calls retrieve and sends the character unless it's 0x90
      (ASCII #144) which signifies a run-length code.  The number of
      repetitions is read in and the Run-Length flag is set.

      fGetC automatically calls UpdateCRC.  When you are done reading the
      fork, call fCRC to finalize the CRC.  (You must initialize the CRC
      before reading the fork!)
      
      fSeek and fGetBlock use fGetC.  The other functions use either fSeek
      or fGetBlock.

   Improvements?
   =============
      
    UnHQX is a bit slow for large files (about 15 seconds to decode a
    550k .sit.hqx file on a 486/33 machine).  Inline code has been used
    to improve performace--although the original Pascal source is left
    in {}-brackets for reference.

    I've played with various methods such as increasing the disk-buffer
    size or fetching more than four characters at a time... no notice-
    able effect on the speed has come of it, however.

   Other Important Stuff:
   ======================

    Remember to convert carriage-returns, line-feeds, spaces, slashes and
    periods in Mac filenames to other characters (usu. '_') which are acc-
    eptable to DOS as filenames!

    Mac date and time stamps are usu. stored in LSB Unix-time format PLUS
    0x7c25b080. (Get the time without using SwapLong, subtract $7C25B080,
    and then adjust for the time-zone, usu. stored in the TZ variable).

