home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / suntar1.cpt / unpit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-02  |  10.0 KB  |  392 lines

  1. /*
  2. From weber@brand.UUCP (Allan G. Weber) Sat May  3 21:21:20 1986
  3. Path: ut-ngp!ut-sally!im4u!caip!topaz!uwvax!harvard!think!mit-eddie!genrad!decvax!ittatc!dcdwest!sdcsvax!sdcrdcf!usc-oberon!brand!weber
  4. From: weber@brand.UUCP (Allan G. Weber)
  5. Newsgroups: net.sources.mac
  6. Subject: unpit.c again
  7. Message-ID: <207@brand.UUCP>
  8. Date: 4 May 86 02:21:20 GMT
  9. Distribution: na
  10. Organization: U. of So. Calif., Los Angeles
  11. Lines: 438
  12.  
  13. A couple of people have requested that I send them copies of my program
  14. "unpit" that unpacks Packit-II files (normal or compressed) on a Unix system
  15. so I'm posting it again for anybody else who might find it useful.  A
  16. typical application of this program is for breaking apart a net.sources.mac
  17. file that contains a PackIt'ed executable program and the sources.  After
  18. using "xbin" to get the .data, .rsrc, and .info parts of the Packit file,
  19. run "unpit" on the .data file to break it into its component parts.  You can
  20. then use "tr" to change the carriage returns to new line characters in the
  21. data fork of the sources files, and print it out on your local line printer.
  22. Saves having to download the sources and watch your Imagewriter print it
  23. out.
  24.  
  25.                 Allan Weber
  26.                 Weber%Brand@USC-ECL.ARPA
  27.                 ...sdcrdcf!usc-oberon!brand!weber
  28.  
  29. */
  30.  
  31. /*
  32.  
  33.         unpit - Macintosh PackIt file unpacker
  34.  
  35.         Version 2, for PackIt II
  36.  
  37. This program will unpack a Macintosh PackIt file into separate files.  The
  38. data fork of a PackIt file contains both the data and resource forks of the
  39. packed files.  The program will unpack each Mac file.
  40.  
  41. Some of the program is borrowed from the macput.c/macget.c programs.
  42.  
  43.     Author: Allan G. Weber
  44.         Weber%Brand@USC-ECL.ARPA
  45.          ...sdcrdcf!usc-oberon!brand!weber
  46.     Date:   September 30, 1985
  47.     Revised: January 24, 1986 - added CRC checking
  48.          March 25, 1986 - support compressed mode of PackIt II,
  49.                   check for illegal Unix file names
  50.  
  51. */
  52.  
  53. /* adapted to become part of suntar: */
  54.  
  55. /*******************************************************************************\
  56.  
  57. PackIt extraction module
  58.  
  59. part of suntar, ⌐1991-92 Sauro & Gabriele Speranza
  60.  
  61. This program is public domain, feel free to use it or part of it for anything
  62.  
  63. \*******************************************************************************/
  64.  
  65.  
  66. /*
  67. Format of a Packit file:
  68.  
  69. Repeat the following sequence for each file in the Packit file:
  70.  
  71.     4 byte identifier ("PMag" = not compressed, "Pma4" = compressed)
  72.     variable length compression data (if compressed file)
  73.     92 byte header (see struct pit_header below) *
  74.     2 bytes CRC number *
  75.     data fork (length from header) *
  76.     resource fork (length from header) *
  77.     2 bytes CRC number *
  78.  
  79. Last file is followed by the 4 byte Ascii string, "Pend", and then the EOF.
  80.  
  81. * these are in compressed form if compression is on for the file
  82.  
  83. */
  84.  
  85. #include "PB_sync.h"
  86. #include "antiglue.h"
  87.  
  88. #include "suntar.h"
  89. #include "windows.h"
  90.  
  91. #ifndef NULL
  92.     #define NULL 0L
  93. #endif
  94.  
  95. /*#define DEBUG*/
  96.  
  97. typedef unsigned char byte;
  98. typedef short word;
  99.  
  100. #define H_NAMELEN 63
  101.  
  102. struct pit_header {            /* Packit file header (92 bytes)
  103.     byte nlen;                /* number of characters in packed file name */
  104.     byte name[H_NAMELEN];    /* name of packed file */
  105.     byte type[4];            /* file type */
  106.     byte creator[4];        /* file creator */
  107.     word flags;    /* File (finder) flags. */
  108.     word lock;    /* File locked if non-zero. */
  109.     long dlen;    /* number of bytes in data fork */
  110.     long rlen;    /* number of bytes in resource fork */
  111.     long ctim;    /* file creation time */
  112.     long mtim;    /* file modified time */
  113. };
  114.  
  115. #define HDRBYTES  sizeof(struct pit_header) /* 92 */
  116.  
  117. struct node {
  118.     unsigned char flag, byte;
  119.     struct node *one, *zero;
  120. } *nodelist=NULL, *nodeptr, *read_tree();
  121.  
  122. static Boolean decode;
  123. static unsigned char more_bits=0;
  124. static unsigned char current_bits;
  125. extern ParamBlockRec pb;
  126. #define ioDirID ioFlNum
  127. extern Boolean devo_chiudere_out;
  128.  
  129. struct node *read_tree(void);
  130. void read_hdr(void);
  131. void unpit_file(void);
  132. Boolean getcrc(void);
  133. short getbit(void);
  134. short getbyte(void);
  135.  
  136.  
  137. void my_unpit()
  138. {
  139.     OSType temp;
  140.     int crc, data_crc;
  141.     extern OSType filecreator,filetype;
  142.  
  143.     nodelist=NewPtr(512L*sizeof(struct node));    /* 512 is big enough:
  144.         a binary tree with n leaves, where no node has one son,  has 2n-1 nodes,
  145.         and n is at most 256 */
  146.  
  147.     while (1) {
  148.         if(readblock(&temp,4)) raise_error();
  149.  
  150.         if (temp=='PMag' || temp=='PMa4') {
  151.             if (temp=='PMa4') {
  152.                 nodeptr = nodelist;
  153.                 read_tree();
  154.                 decode = 1;
  155.                 }
  156.             else
  157.                 decode = 0;
  158.             current_crc=0;
  159.             read_hdr();
  160.             printf("File %p (",&macbinh.nlen);
  161.             if(decode) printf("compressed, ");
  162.             printf("data %ld+res %ld bytes)\n",macbinh.dflen,macbinh.rflen);
  163.             unpit_file();
  164.  
  165.             decode = 0;
  166.             more_bits = 0;    /* flush unused bits */
  167.         }
  168.         else if (temp=='PEnd'){
  169.             deall_tree();
  170.             return;
  171.             }
  172.         else if(temp=='PMa5' || temp=='PMa6' ){
  173.             error_message("Use PackIt III to unpack encrypted files !\n");
  174.             }
  175.         else {
  176.             error_message("Unrecognized Packit file header\n");
  177.         }
  178.     }
  179. }
  180.  
  181. void deall_tree()
  182. {
  183. if(nodelist!=NULL){
  184.     DisposPtr(nodelist);
  185.     nodelist=NULL;
  186.     }
  187. }
  188.  
  189. /* This routine recursively reads the compression decoding data.
  190.    It appears to be Huffman compression. See Knuth's Fundamental Algorithms
  191.    for a description of the Huffman tree, and how a prefix visit describes
  192.    a binary tree */
  193. static struct node *read_tree()
  194. {
  195.     struct node *np;
  196.     np = nodeptr++;
  197.     if (getbit() == 1) {
  198.         np->flag = 1;
  199.         np->byte = getbyte();
  200.     }
  201.     else {
  202.         np->flag = 0;
  203.         np->zero = read_tree();
  204.         np->one  = read_tree();
  205.     }
  206.     return(np);
  207. }
  208.  
  209. static void read_hdr()
  210. {
  211.     get_pit_bytes(&macbinh,74);        /* the MacBinary and PackIt headers are almost
  212.                                     identical, but MacBinary stores also fdLocation and
  213.                                     fdFldr, hence I must break the read into two pieces */
  214.     *(long*)&macbinh.finfo.fdLocation=0;
  215.     macbinh.finfo.fdFldr = 0;
  216.  
  217.     get_pit_bytes(&macbinh.protected,HDRBYTES-74);
  218. /*printf("protected=%d %d\n",macbinh.protected,macbinh.zero);*/
  219. }
  220.  
  221.  
  222. void unpit_file()
  223. /* this function is obviously inspired to the untar
  224. module of suntar, by Gail Zacharias and S&G Speranza  */
  225. {
  226. extern int openfile_vrefnum;
  227. extern long openfile_dirID;
  228. extern unsigned char mac_file_name[120];
  229.  
  230. if (getcrc()) {
  231.     printf("File header CRC mismatch\n");
  232.     if(!ignore_errors) raise_error();
  233.     }
  234. current_crc=0;
  235.  
  236. pStrcpy(tarh.name,&macbinh.nlen);
  237. p2cstr(tarh.name);
  238. filecreator=filetype='????';
  239.  
  240. #ifdef V_122
  241. if (! create_file(tarh.name,fsWrPerm,true)) {
  242.     controlla_spazio(macbinh.dflen,macbinh.rflen);
  243.     conferma_invisibili();
  244.     #if 0    /* Think C Marker.... */
  245.         }
  246.     #endif
  247. #else
  248.  
  249. if( ! crea_e_controlla(true) ){
  250. #endif
  251.     write_pit_fork(512,macbinh.dflen);
  252.  
  253.     pb.ioParam.ioVersNum = 0;
  254.     pb.ioParam.ioPermssn = fsWrPerm;
  255.     pb.ioParam.ioMisc = 0;
  256.  
  257.     if((pb.fileParam.ioDirID=openfile_dirID)!=0){
  258.         pb.ioParam.ioVRefNum=openfile_vrefnum;
  259.         pb.ioParam.ioNamePtr=mac_file_name;
  260.         }
  261.     if( PBHOpenRFSync(&pb)) pbsyserr(&pb);
  262.  
  263.     devo_chiudere_out=true;
  264.  
  265.     write_pit_fork(512,macbinh.rflen);
  266.     if (getcrc()) {
  267.         printf("File data/resource CRC mismatch\n");
  268.         if(!ignore_errors) raise_error();
  269.         }
  270.  
  271.     setmacbin();
  272.     }
  273. else    /* I should skip it, but I haven't a routine to do that, and to skip
  274.         a compressed file requires to perform the decompression anyway, since
  275.         the compressed size is not explicitly stored */
  276.     raise_error();
  277. }
  278.  
  279.  
  280.  
  281. static Boolean getcrc()
  282. {
  283.     int calc_crc,stored_crc;
  284.  
  285.     CalcCRC(0);
  286.     CalcCRC(0);
  287.     calc_crc=current_crc;
  288.  
  289.     stored_crc = getbyte();
  290.     stored_crc=(stored_crc << 8) | getbyte();
  291.  
  292.     /*printf("calc, letto=%x %x %x\n",calc_crc,stored_crc,current_crc);*/
  293.     return stored_crc!=calc_crc;
  294. }
  295.  
  296.  
  297. /* This routine returns the next bit in the input stream (MSB first) */
  298. static short getbit()
  299. {
  300.     if (more_bits == 0) {
  301.         if(readblock(¤t_bits,1)) raise_error();
  302.         more_bits = 8;
  303.     }
  304.     more_bits--;
  305.     return((current_bits >> more_bits) & 1);
  306. }
  307.  
  308. /* This routine returns the next 8 bits.  If decoding is on, it finds the
  309. byte in the decoding tree based on the bits from the input stream.  If
  310. decoding is not on, it either gets it directly from the input stream or
  311. puts it together from 8 calls to getbit(), depending on whether or not we
  312. are currently on a byte boundary
  313. */
  314. static short getbyte()
  315. {
  316.     register struct node *np;
  317.     register int i, b;
  318.     if (decode) {
  319.         np = nodelist;
  320.         while (np->flag == 0)
  321.             np = (getbit()) ? np->one : np->zero;
  322.         b = np->byte;
  323.     }
  324.     else {
  325.         if (more_bits == 0){    /* on byte boundary? */
  326.             unsigned char c;
  327.             if(readblock(&c,1)) raise_error();
  328.             b = c;
  329.             }
  330.         else {        /* no, put a byte together */
  331.             b = 0;
  332.             for (i = 8; i > 0; i--) {
  333.                 b = (b << 1) + getbit();
  334.             }
  335.         }
  336.     }
  337.     return(b);
  338. }
  339.  
  340. extern int more_in_bytes;
  341.  
  342. #define FAST_GET_PIT_BYTE(b)            \
  343. if(!more_in_bytes)                        \
  344.     {if(readblock(&b,1)) raise_error();}\
  345. else                                    \
  346.     b= disk_buffer[511-(--more_in_bytes)];
  347.  
  348.  
  349. void get_pit_bytes(buffer,len)
  350. /* by Speranza, 18 Jan 1992
  351.  An example of a simple but effective optimization: as in the dehqx module,
  352. move the loop from the caller to the callee, so that register variables 
  353. have a long life, and the stack frame creation/destruction is performed
  354. once rather than a few thousands times, and expand the body of some called
  355. functions to save the overhead of their calls.
  356.  That is, this one is an exception to the universally accepted rule that
  357. "function call overhead is usually negligible".
  358.  To code the bit extraction in assembly (with a fixed shift of 1 bit every time)
  359. and expanding the CRC computation would be the next step, but this routine
  360. is fast enough.
  361. */
  362. register char *buffer;
  363. register int len;
  364. {
  365.     if(!decode && ! more_bits){
  366.         if(readblock(buffer,len)) raise_error();
  367.         while(len--)
  368.             CalcCRC(*buffer++);
  369.         }
  370.     else if(!decode){    /* happens only in readtree, which does not call this function,
  371.                         but it's safer to handle all cases anyway */
  372.         while(len--)
  373.             CalcCRC(*buffer++ = getbyte());
  374.         }
  375.     else{        /* decode: optimize avoiding to call getbit so many times ! */
  376.         register struct node *np;
  377.         while(len--){
  378.             np = nodelist;        /* copy of the body of getbyte */
  379.             while (!np->flag){
  380.                 if (!more_bits) {        /* copy of the body of getbit, with one further
  381.                                         optimization */
  382.                     FAST_GET_PIT_BYTE(current_bits)
  383.                     more_bits = 8;
  384.                     }
  385.                 more_bits--;
  386.                 np = ((current_bits >> more_bits) & 1) ? np->one : np->zero;
  387.                 }
  388.             CalcCRC(*buffer++ = np->byte);
  389.             /*printf("byte %d=%d\n",n,buffer[-1]);*/
  390.             }
  391.         }
  392. }