home *** CD-ROM | disk | FTP | other *** search
/ Carousel / CAROUSEL.cdr / mactosh / unix / unpit.c < prev    next >
C/C++ Source or Header  |  1986-04-02  |  11KB  |  454 lines

  1. 31-Mar-86 22:42:01-PST,10912;000000000001
  2. Return-Path: <werner@ngp.UTEXAS.EDU>
  3. Received: from ngp.UTEXAS.EDU by SUMEX-AIM.ARPA with TCP; Mon 31 Mar 86 22:41:52-PST
  4. Date: Tue, 1 Apr 86 00:22:55 cst
  5. From: werner@ngp.UTEXAS.EDU (Werner Uhrig)
  6. Posted-Date: Tue, 1 Apr 86 00:22:55 cst
  7. Message-Id: <8604010622.AA04381@ngp.UTEXAS.EDU>
  8. Received: by ngp.UTEXAS.EDU (4.22/4.22)
  9.     id AA04381; Tue, 1 Apr 86 00:22:55 cst
  10. To: info-mac-request@sumex-aim
  11. Subject: from USENET: unpit2
  12.  
  13. [The Postman Strikes Twice .... (-: ---Werner]
  14. From weber@brand.UUCP  Wed Mar 26 10:52:28 1986
  15. Relay-Version: version B 2.10.2 9/18/84; site ut-ngp.UUCP
  16. Path: ut-ngp!ut-sally!seismo!lll-crg!lll-lcc!qantel!hplabs!sdcrdcf!oberon!brand!weber
  17. From: weber@brand.UUCP (Allan G. Weber)
  18. Newsgroups: net.sources.mac
  19. Subject: Unpit - Packit file unpacking program
  20. Message-ID: <194@brand.UUCP>
  21. Date: 26 Mar 86 16:52:28 GMT
  22. Date-Received: 28 Mar 86 13:22:23 GMT
  23. Distribution: na
  24. Organization: U. of So. Calif., Los Angeles
  25. Lines: 425
  26.  
  27. This is a Unix program for unpacking Mac Packit files into the component
  28. files.  See message in net.micro.mac for more info.
  29.  
  30.                     Allan Weber
  31.                     Arpa: Weber%Brand@USC-ECL
  32.                     Usenet: ...sdcrdcf!oberon!brand!weber
  33.  
  34. /*
  35.  
  36.         unpit - Macintosh PackIt file unpacker
  37.  
  38.         Version 2, for PackIt II
  39.  
  40. This program will unpack a Macintosh PackIt file into separate files.  The
  41. data fork of a PackIt file contains both the data and resource forks of the
  42. packed files.  The program will unpack each Mac file into separate .data,
  43. .rsrc., and .info files that can be downloaded to a Mac using macput.
  44.  
  45. The program syntax is much like macput/macget:
  46.  
  47.     unpit [-rdu] packit-file.data
  48.  
  49. The  -r and -d flags will cause only the resource and data forks to be
  50. written.  The -u flag will cause only the data fork to be written and
  51. to have carriage return characters changed to Unix newline characters.
  52.  
  53. Some of the program is borrowed from the macput.c/macget.c programs.
  54.  
  55.     Author: Allan G. Weber, (Weber%Brand@USC-ECL)        
  56.     Date:   September 30, 1985
  57.     Revised: January 24, 1986 - added CRC checking
  58.          March 25, 1986 - support compressed mode of PackIt II,
  59.                   check for illegal Unix file names
  60.  
  61. */
  62.  
  63. /* There is some confusion as to what to do with the "inited" flag in the
  64.    finder info bytes that are in the header of each file in the packit file.
  65.    If this flag bit is copied to the .info file, it seems to confuse
  66.    MacTerminal into placing the file icons in the upper left corner of the
  67.    window on top of each other.  Setting this bit to zero in the .info file
  68.    seems to fix that problem but may cause others.  I haven't been able to
  69.    find any .info files that have this flag set so making it zero may be OK.
  70.    Anyway, MacTerminal seems to set the flag when it create the file on the
  71.    Mac.  The "#define INITED_BUG" can be used to try both settings.  */
  72.  
  73. /*
  74. Format of a Packit file:
  75.  
  76. Repeat the following sequence for each file in the Packit file:
  77.  
  78.     4 byte identifier ("PMag" = not compressed, "Pma4" = compressed)
  79.     variable length compression data (if compressed file)
  80.     92 byte header (see struct pit_header below) *
  81.     2 bytes CRC number *
  82.     data fork (length from header) *
  83.     resource fork (length from header) *
  84.     2 bytes CRC number *
  85.  
  86. Last file is followed by the 4 byte Ascii string, "Pend", and then the EOF.
  87.  
  88. * these are in compressed form if compression is on for the file
  89.  
  90. */
  91.  
  92. #define DEBUG
  93.  
  94. #include <stdio.h>
  95.  
  96. typedef char byte;
  97. typedef short word;
  98.  
  99. struct pit_header {    /* Packit file header (92 bytes)
  100.     byte nlen;    /* number of characters in packed file name */
  101.     byte name[63];    /* name of packed file */
  102.     byte type[4];    /* file type */
  103.     byte auth[4];    /* file creator */
  104.     word flags;    /* file flags (?) */
  105.     word lock;    /* unknown */
  106.     long dlen;    /* number of bytes in data fork */
  107.     long rlen;    /* number of bytes in resource fork */
  108.     long ctim;    /* file creation time */
  109.     long mtim;    /* file modified time */
  110. };
  111.  
  112. #define HDRBYTES  92
  113. #define INFOBYTES 128
  114.  
  115. #define BYTEMASK 0xff
  116.  
  117. #define H_NAMELEN 63
  118.  
  119. #define H_NLENOFF 0
  120. #define H_NAMEOFF 1
  121. #define H_TYPEOFF 64
  122. #define H_AUTHOFF 68
  123. #define    H_LOCKOFF 70
  124. #define H_FLAGOFF 72
  125. #define H_DLENOFF 76
  126. #define H_RLENOFF 80
  127. #define H_CTIMOFF 84
  128. #define H_MTIMOFF 88
  129.  
  130. #define I_NAMELEN 69    /* H_NAMELEN + strlen(".info") + 1 */
  131.  
  132. /* The following are copied out of macput.c/macget.c */
  133. #define I_NLENOFF 1
  134. #define I_NAMEOFF 2
  135. /* 65 <-> 80 is the FInfo structure */
  136. #define I_TYPEOFF 65
  137. #define I_AUTHOFF 69
  138. #define I_FLAGOFF 73
  139. #define I_LOCKOFF 81
  140. #define I_DLENOFF 83
  141. #define I_RLENOFF 87
  142. #define I_CTIMOFF 91
  143. #define I_MTIMOFF 95
  144.  
  145. #define INITED_BUG
  146. #define INITED_OFF    I_FLAGOFF    /* offset to byte with Inited flag */
  147. #define INITED_MASK    (~1)        /* mask to '&' with byte to reset it */
  148.  
  149. #define TEXT 0
  150. #define DATA 1
  151. #define RSRC 2
  152. #define FULL 3
  153.  
  154. struct node {
  155.     int flag, byte;
  156.     struct node *one, *zero;
  157. } nodelist[512], *nodeptr, *read_tree();    /* 512 should be big enough */
  158.  
  159. char f_info[I_NAMELEN];
  160. char f_data[I_NAMELEN];
  161. char f_rsrc[I_NAMELEN];
  162.  
  163. char hdr[HDRBYTES];
  164. char info[INFOBYTES];
  165. char text[H_NAMELEN+1];
  166.  
  167. int mode, txtmode;
  168. int datalen, rsrclen;
  169. int decode, bit;
  170.  
  171. char usage[] = "usage: unpit [-rdu] filename\n";
  172.  
  173. main(ac, av)
  174. int ac;
  175. char **av;
  176. {
  177.     char temp[4], *name;
  178.     int crc, data_crc;
  179.  
  180.     mode = FULL;
  181.     name = "";
  182.     ac--; av++;
  183.     while (ac) {
  184.         if (av[0][0] == '-') {
  185.             switch (av[0][1]) {
  186.             case 'r':
  187.                 mode = RSRC;
  188.                 break;
  189.             case 'd':
  190.                 mode = DATA;
  191.                 break;
  192.             case 'u':
  193.                 mode = TEXT;
  194.                 break;
  195.             case '\0':
  196.                 name = av[0];
  197.                 break;
  198.             default:
  199.                 fprintf(stderr, usage);
  200.                 exit(1);
  201.             }
  202.         }
  203.         else {
  204.             name = av[0];
  205.         }
  206.         ac--; av++;
  207.     }
  208.  
  209.     if (strlen(name) == 0) {
  210.         fprintf(stderr, usage);
  211.         exit(1);
  212.     }
  213.     else {
  214.         if (freopen(name,"r",stdin) == NULL) {
  215.             fprintf(stderr,"Can't open input file \"%s\"\n",name);
  216.             exit(1);
  217.         }
  218.     }
  219.  
  220.     while (1) {
  221.         fread(temp, 1, 4, stdin);
  222.         if (strncmp(temp, "PMag", 4) == 0 ||
  223.             strncmp(temp, "PMa4", 4) == 0) {
  224.             if (temp[3] == '4') {
  225.                 nodeptr = nodelist;
  226.                 read_tree();
  227.                 decode = 1;
  228.             }
  229.             else
  230.                 decode = 0;
  231.             data_crc = read_hdr();
  232.             crc = getcrc();
  233.             if (crc != data_crc) {
  234.                 fprintf(stderr, "File header CRC mismatch\n");
  235.                 exit(1);
  236.             }
  237.             txtmode = (mode == TEXT);
  238.             data_crc = write_file(f_data, datalen, 0);
  239.             txtmode = 0;
  240.             data_crc = write_file(f_rsrc, rsrclen, data_crc);
  241.             crc = getcrc();
  242.             if (crc != data_crc) {
  243.                 fprintf(stderr,
  244.                     "File data/rsrc CRC mismatch\n");
  245.                 exit(1);
  246.             }
  247.             decode = 0;
  248.             bit = 0;    /* flush unused bits */
  249.         }
  250.         else if (strncmp(temp, "PEnd", 4) == 0)
  251.             break;
  252.         else {
  253.             fprintf(stderr, "Unrecognized Packit format\n");
  254.             exit(1);
  255.         }
  256.     }
  257. }
  258.  
  259. /* This routine recursively reads the compression decoding data.
  260.    It appears to be Huffman compression. */
  261. struct node *read_tree()
  262. {
  263.     struct node *np;
  264.     np = nodeptr++;
  265.     if (getbit() == 1) {
  266.         np->flag = 1;
  267.         np->byte = getbyte();
  268.     }
  269.     else {
  270.         np->flag = 0;
  271.         np->zero = read_tree();
  272.         np->one  = read_tree();
  273.     }
  274.     return(np);
  275. }
  276.  
  277. read_hdr()
  278. {
  279.     long get4();
  280.     register int i, n, crc;
  281.     FILE *fp;
  282.     char *np;
  283.  
  284.     for (n = 0; n < INFOBYTES; n++)
  285.         info[n] = '\0';
  286.     for (n = 0; n < HDRBYTES; n++)
  287.         hdr[n] = getbyte();
  288.     crc = 0;
  289.     for (n = 0; n < HDRBYTES; n++) {
  290.         crc = crc ^ ((int)hdr[n] << 8);
  291.         for (i = 0; i < 8; i++)
  292.             if (crc & 0x8000)
  293.                 crc = (crc << 1) ^ 0x1021;
  294.             else
  295.                 crc <<= 1;
  296.     }
  297.  
  298.     n = hdr[H_NLENOFF] & BYTEMASK;
  299.     if (n > H_NAMELEN)
  300.         n = H_NAMELEN;
  301.     info[I_NLENOFF] = n;
  302.     copy(info + I_NAMEOFF, hdr + H_NAMEOFF, n);
  303.     strncpy(text, hdr + H_NAMEOFF, n);
  304.     text[n] = '\0';
  305.     datalen = get4(hdr + H_DLENOFF);
  306.     rsrclen = get4(hdr + H_RLENOFF);
  307. #ifdef DEBUG
  308.     printf("name=\"%s\", type=%4.4s, author=%4.4s, data=%ld, rsrc=%ld\n",
  309.     text, hdr + H_TYPEOFF, hdr + H_AUTHOFF, datalen, rsrclen);
  310. #endif
  311.     /* check for illegal Unix characters in file name */
  312.     for (np = text; *np; np++)
  313.         if (*np <= ' ' || *np == '/' || *np > '~')
  314.             *np = '_';
  315.  
  316.     if (mode == FULL) {
  317.         sprintf(f_info, "%s.info", text);
  318.         sprintf(f_data, "%s.data", text);
  319.         sprintf(f_rsrc, "%s.rsrc", text);
  320.  
  321.         copy(info + I_TYPEOFF, hdr + H_TYPEOFF, 4);
  322.         copy(info + I_AUTHOFF, hdr + H_AUTHOFF, 4);
  323.         copy(info + I_FLAGOFF, hdr + H_FLAGOFF, 2);
  324. #ifdef INITED_BUG
  325.         info[INITED_OFF] &= INITED_MASK;    /* reset init bit */
  326. #endif
  327.         copy(info + I_LOCKOFF, hdr + H_LOCKOFF, 2);
  328.         copy(info + I_DLENOFF, hdr + H_DLENOFF, 4);
  329.         copy(info + I_RLENOFF, hdr + H_RLENOFF, 4);
  330.         copy(info + I_CTIMOFF, hdr + H_CTIMOFF, 4);
  331.         copy(info + I_MTIMOFF, hdr + H_MTIMOFF, 4);
  332.  
  333.         fp = fopen(f_info, "w");
  334.         if (fp == NULL) {
  335.             perror(f_info);
  336.             exit(1);
  337.         }
  338.         fwrite(info, 1, INFOBYTES, fp);
  339.         fclose(fp);
  340.     }
  341.     else if (mode == RSRC) {
  342.             sprintf(f_data, "/dev/null");
  343.             sprintf(f_rsrc, "%s.rsrc", text);
  344.     }
  345.     else {
  346.             sprintf(f_data, "%s", text);
  347.             sprintf(f_rsrc, "/dev/null");
  348.     }
  349.     return(crc & 0xffff);
  350. }
  351.  
  352. write_file(fname, bytes, crc)
  353. char *fname;
  354. long bytes;
  355. register int crc;
  356. {
  357.     register int b, i;
  358.     FILE *outf;
  359.  
  360.     outf = fopen(fname, "w");
  361.     if (outf == NULL) {
  362.         perror(fname);
  363.         exit(1);
  364.     }
  365.     while (bytes-- > 0) {
  366.         b = getbyte();
  367.         crc = crc ^ (b << 8);
  368.         for (i = 0; i < 8; i++)
  369.             if (crc & 0x8000)
  370.                 crc = (crc << 1) ^ 0x1021;
  371.             else
  372.                 crc <<= 1;
  373.         if (txtmode && (b & BYTEMASK) == '\r')
  374.             b = '\n';
  375.         putc(b, outf);
  376.     }
  377.     fclose(outf);
  378.     return(crc & 0xffff);
  379. }
  380.  
  381. long
  382. get4(bp)
  383. char *bp;
  384. {
  385.     register int i;
  386.     long value = 0;
  387.  
  388.     for (i = 0; i < 4; i++) {
  389.         value <<= 8;
  390.         value |= (*bp & BYTEMASK);
  391.         bp++;
  392.     }
  393.     return(value);
  394. }
  395.  
  396. getcrc()
  397. {
  398.     int value;
  399.     value = getbyte() & BYTEMASK;
  400.     return( value << 8 | (getbyte() & BYTEMASK) );
  401. }
  402.  
  403. copy(p1, p2, n)
  404. char *p1, *p2;
  405. int n;
  406. {
  407.     while (n-- > 0)
  408.         *p1++ = *p2++;
  409. }
  410.  
  411.  
  412. /* This routine returns the next bit in the input stream (MSB first) */
  413. getbit()
  414. {
  415.     static char b;
  416.     if (bit == 0) {
  417.         b = getchar() & 0xff;
  418.         bit = 8;
  419.     }
  420.     bit--;
  421.     return((b >> bit) & 1);
  422. }
  423.  
  424. /* This routine returns the next 8 bits.  If decoding is on, it finds the
  425. byte in the decoding tree based on the bits from the input stream.  If
  426. decoding is not on, it either gets it directly from the input stream or
  427. puts it together from 8 calls to getbit(), depending on whether or not we
  428. are currently on a byte boundary
  429. */
  430. getbyte()
  431. {
  432.     register struct node *np;
  433.     register int i, b;
  434.     if (decode) {
  435.         np = nodelist;
  436.         while (np->flag == 0)
  437.             np = (getbit()) ? np->one : np->zero;
  438.         b = np->byte;
  439.     }
  440.     else {
  441.         if (bit == 0)    /* on byte boundary? */
  442.             b = getc(stdin) & 0xff;
  443.         else {        /* no, put a byte together */
  444.             b = 0;
  445.             for (i = 8; i > 0; i--) {
  446.                 b = (b << 1) + getbit();
  447.             }
  448.         }
  449.     }
  450.     return(b);
  451. }
  452.  
  453.  
  454.