home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 28 / amigaformatcd28.iso / -seriously_amiga- / archivers / mcvertppc / unpack.c < prev   
C/C++ Source or Header  |  1998-04-27  |  7KB  |  260 lines

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