home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / mcvertWOS.lha / mcvertppc / unpack.c < prev   
C/C++ Source or Header  |  1998-04-12  |  9KB  |  242 lines

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