home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / util / unix / mcvert18.sha / unpack.c < prev   
Encoding:
C/C++ Source or Header  |  1992-11-05  |  6.2 KB  |  230 lines

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