home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / unix / hqxtobin.shr / unpack.c < prev   
C/C++ Source or Header  |  1989-04-10  |  6KB  |  184 lines

  1. #include "mactypes.h"
  2.  
  3. extern word magic[];
  4. extern FILE *verbose;
  5. extern char *dir, *ext;
  6.  
  7. ulong pit_datalen, pit_rsrclen;
  8. word hqx_crc, write_pit_fork(); 
  9. char pitfname[BINNAMELEN];              /* name of file being unpacked */
  10. FILE *pitfile;                          /* output file */
  11.  
  12. branch branchlist[255], *branchptr, *read_tree();
  13. leaf leaflist[256], *leafptr;
  14. word Huff_nibble, Huff_bit_count;
  15. byte (*read_char)(), get_crc_byte(), getHuffbyte();
  16.  
  17. word un_pit()
  18. {   char PitId[4];
  19.     int i;
  20.     word pit_crc;
  21.  
  22.     hqx_crc = 0;
  23.     /* Read and unpack until the PackIt End message is read */
  24.     for (;;) {
  25.         read_char = get_crc_byte;
  26.         for (i = 0; i < 4; i++) PitId[i] = (char) get_crc_byte();
  27.         if (!strncmp(PitId, "PEnd", 4)) break;
  28.  
  29.         if (strncmp(PitId, "PMag", 4) && strncmp(PitId, "PMa4", 4))
  30.             error("Unrecognized Packit format message %s", PitId);
  31.  
  32.         if (PitId[3] == '4') {          /* if this file is compressed */
  33.             branchptr = branchlist;     /* read the Huffman decoding  */
  34.             leafptr = leaflist;         /* tree that is on the input  */
  35.             Huff_bit_count = 0;         /* and use Huffman decoding   */
  36.             read_tree();                /* subsequently               */
  37.             read_char = getHuffbyte;
  38.             }
  39.  
  40.         read_pit_hdr();     /* also calculates datalen, rsrclen,
  41.                                pitfile, pitfname */
  42.         pit_crc = write_pit_fork(pit_datalen, 0);
  43.         pit_crc = write_pit_fork(pit_rsrclen, pit_crc);
  44.         check_pit_crc(pit_crc, "  File data/rsrc CRC mismatch in %s", pitfname);
  45.         fclose(pitfile);
  46.         }
  47.     hqx_crc = (hqx_crc << 8) ^ magic[hqx_crc >> 8];
  48.     hqx_crc = (hqx_crc << 8) ^ magic[hqx_crc >> 8];
  49.     return hqx_crc;
  50.     }
  51.  
  52. check_pit_crc(calc_crc, msg, name)
  53. word calc_crc;
  54. char msg[], name[];
  55. {   word read_crc;
  56.     read_crc = (*read_char)() << 8;
  57.     read_crc |= (*read_char)();
  58.     if (read_crc != calc_crc) error(msg, name);
  59.     }
  60.  
  61. /* This routine reads the header of a packed file and appropriately twiddles it,
  62.     determines if it has CRC problems, creates the .bin file, and puts the info
  63.     into the .bin file.
  64.     Output is pit_datalen, pit_rsrclen, pitfname, pitfile */
  65. read_pit_hdr()
  66. {   register int n;
  67.     register byte *pit_byte;
  68.     register ulong pit_crc;
  69.     pit_header pit;
  70.     info_header info;
  71.  
  72.     /* read the pit header and compute the CRC */
  73.     pit_crc = 0;
  74.     pit_byte = (byte *) &pit;
  75.     for (n = 0; n < sizeof(pit_header); n++) {
  76.         *pit_byte = (*read_char)();
  77.         pit_crc = ((pit_crc & 0xff) << 8)
  78.                     ^ magic[*pit_byte++ ^ (pit_crc >> 8)];
  79.         }
  80.  
  81.     /* stuff the pit header data into the info header */
  82.     bzero(&info, sizeof(info_header));
  83.     info.nlen = pit.nlen;
  84.     strncpy(info.name, pit.name, pit.nlen);     /* name */
  85.     bcopy(pit.type, info.type, 9);              /* type, author, flag */
  86.     bcopy(pit.dlen, info.dlen, 16);             /* (d,r)len, (c,m)tim */
  87.     info.flags  &= 0x7e;                        /* reset lock bit, init bit */
  88.     if (pit.protect & 0x40) info.protect = 1;   /* copy protect bit */
  89.  
  90.     /* Create the .bin file and write the info to it */
  91.     pit.name[pit.nlen] = '\0';
  92.     unixify(pit.name);
  93.     sprintf(pitfname, "%s/%s%s", dir, pit.name, ext);
  94.     fprintf(verbose,
  95.         " %-14s%-30s type = \"%4.4s\", author = \"%4.4s\"\n",
  96.         (read_char == get_crc_byte) ? "Unpacking" : "Decompressing",
  97.         pit.name, pit.type, pit.auth);
  98.     if ((pitfile = fopen(pitfname, "w")) == NULL)
  99.         error("  Cannot open %s", pitfname);
  100.     check_pit_crc(pit_crc, "  File header CRC mismatch in %s", pitfname);
  101.     fwrite(&info, sizeof(info_header), 1, pitfile);
  102.  
  103.     /* Get a couple of items we'll need later */
  104.     bcopy(pit.dlen, &pit_datalen, 4);
  105.     pit_datalen = mac2long(pit_datalen);
  106.     bcopy(pit.rlen, &pit_rsrclen, 4);
  107.     pit_rsrclen = mac2long(pit_rsrclen);
  108.     }
  109.  
  110. /* This routine copies bytes from the decoded input stream to the output
  111.     and calculates the CRC.  It also pads to a multiple of 128 bytes on the
  112.     output, which is part of the .bin format */
  113. word write_pit_fork(nbytes, calc_crc)
  114. register ulong nbytes;
  115. register ulong calc_crc;
  116. {   register ulong b;
  117.     int extra_bytes;
  118.  
  119.     extra_bytes = 127 - (nbytes+127)%128; /* pad fork to mult of 128 bytes */
  120.     while (nbytes--) {
  121.         b = (*read_char)();
  122.         calc_crc = ((calc_crc & 0xff) << 8) ^ magic[b ^ (calc_crc >> 8)];
  123.         putc(b, pitfile);
  124.         }
  125.     while (extra_bytes--) putc(0, pitfile);
  126.     return (word) calc_crc;
  127.     }
  128.  
  129. /* This routine recursively reads the compression decoding data.
  130.    It appears to be Huffman compression.  Every leaf is represented
  131.    by a 1 bit, then the byte it represents.  A branch is represented
  132.    by a 0 bit, then its zero and one sons */
  133. branch *read_tree()
  134. {   register branch *branchp;
  135.     register leaf *leafp;
  136.     register ulong b;
  137.     if (!Huff_bit_count--) {
  138.         Huff_nibble = get_crc_byte();
  139.         Huff_bit_count = 7;
  140.         }
  141.     if ((Huff_nibble<<=1) & 0x0100) {
  142.         leafp = leafptr++;
  143.         leafp->flag = 1;
  144.         b = get_crc_byte();
  145.         leafp->data = Huff_nibble | (b >> Huff_bit_count);
  146.         Huff_nibble = b << (8 - Huff_bit_count);
  147.         return (branch *) leafp;
  148.         }
  149.     else {
  150.         branchp = branchptr++;
  151.         branchp->flag = 0;
  152.         branchp->zero = read_tree();
  153.         branchp->one  = read_tree();
  154.         return branchp;
  155.         }
  156.     }
  157.  
  158. /* This routine returns the next 8 bits.  It finds the byte in the
  159.    Huffman decoding tree based on the bits from the input stream. */
  160. byte getHuffbyte()
  161. {   register branch *branchp;
  162.     branchp = branchlist;
  163.     while (!branchp->flag) {
  164.         if (!Huff_bit_count--) {
  165.             Huff_nibble = get_crc_byte();
  166.             Huff_bit_count = 7;
  167.             }
  168.         branchp = ((Huff_nibble<<=1) & 0x0100) ? branchp->one : branchp->zero;
  169.         }
  170.     return ((leaf *) branchp)->data;
  171.     }
  172.  
  173. /* This routine returns the next byte on the .hqx input stream, hiding
  174.     most file system details at a lower level.  .hqx CRC is maintained
  175.     here */
  176. byte get_crc_byte()
  177. {   register ulong c;
  178.     extern byte *buf_ptr, *buf_end;
  179.     if (buf_ptr == buf_end) fill_hqxbuf();
  180.     c = *buf_ptr++;
  181.     hqx_crc = ((hqx_crc << 8) | c) ^ magic[hqx_crc >> 8];
  182.     return (byte) c;
  183.     }
  184.