home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progc / unzip_c.arj / UNZIP.C < prev    next >
C/C++ Source or Header  |  1990-03-18  |  39KB  |  1,710 lines

  1.  
  2. /*
  3.  * Copyright 1989 Samuel H. Smith;  All rights reserved
  4.  *
  5.  * Do not distribute modified versions without my permission.
  6.  * Do not remove or alter this notice or any other copyright notice.
  7.  * If you use this in your own program you must distribute source code.
  8.  * Do not use any of this in a commercial product.
  9.  *
  10.  */
  11.  
  12. /*
  13.  * UnZip - A simple zipfile extract utility
  14.  *
  15.  * To compile:
  16.  *      tcc -B -O -Z -G -mc unzip.c        ;turbo C 2.0, compact model
  17.  *
  18.  * Compile-time definitions:
  19.  *    HIGH_LOW    target machine is big-endian (68000 family)
  20.  *    ASM        critical functions are written in assembler
  21.  *    void=int    for compilers that don't implement void
  22.  *    UNIX        target o.s. is UNIX
  23.  *    BSD        UNIX is BSD
  24.  *    V7        UNIX is Version 7
  25.  *
  26.  * REVISION HISTORY
  27.  *
  28.  * 12/14/89  C. Mascott  2.0a    adapt for UNIX
  29.  *                ifdef HIGH_LOW swap bytes in time, date, CRC,
  30.  *                  version needed, bit flag
  31.  *                implement true s-f trees instead of table
  32.  *                don't pre-allocate output file space
  33.  *                implement -t, -v, member file specs
  34.  *                buffer all input
  35.  *                change hsize_array_integer to short
  36.  *                overlap storage used by different comp. methods
  37.  *                speed up unImplode
  38.  *                use insertion sort in SortLengths
  39.  *                define zipfile header structs in a way that
  40.  *                  avoids structure padding on 32-bit machines
  41.  *                fix "Bad CRC" msg: good/bad CRCs were swapped
  42.  *                check for write error on output file
  43.  *                added by John Cowan <cowan@magpie.masa.com>:
  44.  *                support -c option to expand to console
  45.  *                use stderr for messages
  46.  *                allow lowercase component name specs
  47.  *
  48.  */
  49.  
  50. #define VERSION  "UnZip:  Zipfile Extract v2.0a (C) of 12-14-89;  (C) 1989 Samuel H. Smith"
  51.  
  52. typedef unsigned char byte;    /* code assumes UNSIGNED bytes */
  53. typedef long longint;
  54. typedef unsigned short word;
  55. typedef char boolean;
  56.  
  57. #define STRSIZ 256
  58.  
  59. #include <stdio.h>
  60.  /* this is your standard header for all C compiles */
  61. #include <ctype.h>
  62.  
  63. #ifdef __STDC__
  64.  
  65. #include <stdlib.h>
  66.  /* this include defines various standard library prototypes */
  67.  
  68. #else
  69.  
  70. char *malloc();
  71.  
  72. #endif
  73.  
  74. #define min(a,b) ((a) < (b) ? (a) : (b))
  75.  
  76. /*
  77.  * SEE HOST OPERATING SYSTEM SPECIFICS SECTION STARTING NEAR LINE 180
  78.  *
  79.  */
  80.  
  81.  
  82. /* ----------------------------------------------------------- */
  83. /*
  84.  * Zipfile layout declarations
  85.  *
  86.  */
  87.  
  88. /* Macros for accessing the longint header fields.  These fields
  89.    are defined as array of char to prevent a 32-bit compiler from
  90.    padding the struct so that longints start on a 4-byte boundary.
  91.    This will not work on a machine that can access longints only
  92.    if they start on a 4-byte boundary. */
  93.  
  94. #define LONGIP(l) ((longint *) &((l)[0]))
  95. #define LONGI(l) (*(LONGIP(l)))
  96.  
  97. typedef longint signature_type;
  98.  
  99.  
  100. #define LOCAL_FILE_HEADER_SIGNATURE  0x04034b50L
  101.  
  102.  
  103. typedef struct local_file_header {
  104.     word version_needed_to_extract;
  105.         word general_purpose_bit_flag;
  106.     word compression_method;
  107.     word last_mod_file_time;
  108.     word last_mod_file_date;
  109.     byte crc32[4];
  110.     byte compressed_size[4];
  111.         byte uncompressed_size[4];
  112.     word filename_length;
  113.     word extra_field_length;
  114. } local_file_header;
  115.  
  116.  
  117. #define CENTRAL_FILE_HEADER_SIGNATURE  0x02014b50L
  118.  
  119.  
  120. typedef struct central_directory_file_header {
  121.     word version_made_by;
  122.     word version_needed_to_extract;
  123.     word general_purpose_bit_flag;
  124.     word compression_method;
  125.     word last_mod_file_time;
  126.     word last_mod_file_date;
  127.     byte crc32[4];
  128.     byte compressed_size[4];
  129.     byte uncompressed_size[4];
  130.     word filename_length;
  131.     word extra_field_length;
  132.     word file_comment_length;
  133.     word disk_number_start;
  134.     word internal_file_attributes;
  135.     byte external_file_attributes[4];
  136.     byte relative_offset_local_header[4];
  137. } central_directory_file_header;
  138.  
  139.  
  140. #define END_CENTRAL_DIR_SIGNATURE  0x06054b50L
  141.  
  142.  
  143. typedef struct end_central_dir_record {
  144.     word number_this_disk;
  145.     word number_disk_with_start_central_directory;
  146.     word total_entries_central_dir_on_this_disk;
  147.     word total_entries_central_dir;
  148.     byte size_central_directory[4];
  149.     byte offset_start_central_directory[4];
  150.     word zipfile_comment_length;
  151. } end_central_dir_record;
  152.  
  153.  
  154. char *fnames[2] = {    /* default filenames vector */
  155.     "*",
  156.     NULL
  157. };
  158. char **fnv = &fnames[0];
  159.  
  160. int tflag;        /* -t: test */
  161. int vflag;        /* -v: view directory */
  162. int cflag;        /* -c: output to stdout (JC) */
  163.  
  164. int members;
  165. longint csize;
  166. longint ucsize;
  167. longint tot_csize;
  168. longint tot_ucsize;
  169.  
  170.  
  171. /* ----------------------------------------------------------- */
  172. /*
  173.  * input file variables
  174.  *
  175.  */
  176.  
  177. #define INBUFSIZ BUFSIZ        /* same as stdio uses */
  178. byte *inbuf;            /* input file buffer - any size is legal */
  179. byte *inptr;
  180.  
  181. int incnt;
  182. word bitbuf;
  183. int bits_left;
  184. boolean zipeof;
  185.  
  186. int zipfd;
  187. char zipfn[STRSIZ];
  188. local_file_header lrec;
  189.  
  190.  
  191. /* ----------------------------------------------------------- */
  192. /*
  193.  * output stream variables
  194.  *
  195.  */
  196.  
  197. #define OUTBUFSIZ 0x2000        /* unImplode needs power of 2, >= 0x2000 */
  198. byte *outbuf;                   /* buffer for rle look-back */
  199. byte *outptr;
  200.  
  201. longint outpos;            /* absolute position in outfile */
  202. int outcnt;            /* current position in outbuf */
  203.  
  204. int outfd;
  205. char filename[STRSIZ];
  206. char extra[STRSIZ];
  207.  
  208. #define DLE 144
  209.  
  210.  
  211. /* ----------------------------------------------------------- */
  212. /*
  213.  * shrink/reduce working storage
  214.  *
  215.  */
  216.  
  217. int factor;
  218. /* really need only 256, but prefix_of, which shares the same
  219.    storage, is just over 16K */
  220. byte followers[257][64];    /* also lzw prefix_of, s-f lit_nodes */
  221. byte Slen[256];
  222.  
  223. #define max_bits 13
  224. #define init_bits 9
  225. #define hsize 8192
  226. #define first_ent 257
  227. #define clear 256
  228.  
  229. typedef short hsize_array_integer[hsize+1];    /* was used for prefix_of */
  230. typedef byte hsize_array_byte[hsize+1];
  231.  
  232. short *prefix_of = (short *) followers;    /* share reduce/shrink storage */
  233. hsize_array_byte suffix_of;        /* also s-f length_nodes */
  234. hsize_array_byte stack;            /* also s-f distance_nodes */
  235.  
  236. int codesize;
  237. int maxcode;
  238. int free_ent;
  239. int maxcodemax;
  240. int offset;
  241. int sizex;
  242.  
  243.  
  244.  
  245. /* ============================================================= */
  246. /*
  247.  * Host operating system details
  248.  *
  249.  */
  250.  
  251. #ifdef UNIX
  252.  
  253. /* On some systems the contents of sys/param.h duplicates the
  254.    contents of sys/types.h, so you don't need (and can't use)
  255.    sys/types.h. */
  256.  
  257. #include <sys/types.h>
  258. #include <sys/param.h>
  259. #include <time.h>
  260. struct tm *gmtime(), *localtime();
  261. #define ZSUFX ".zip"
  262.  
  263. #else
  264.  
  265. #define BSIZE 512    /* disk block size */
  266. #define ZSUFX ".ZIP"
  267.  
  268. #endif
  269.  
  270. #if defined(V7) || defined(BSD)
  271.  
  272. #define strchr index
  273. #define strrchr rindex
  274.  
  275. #endif
  276.  
  277. #ifdef __STDC__
  278.  
  279. #include <string.h>
  280.  /* this include defines strcpy, strcmp, etc. */
  281.  
  282. #else
  283.  
  284. char *strchr(), *strrchr();
  285.  
  286. #endif
  287.  
  288. long lseek();
  289.  
  290. #define SEEK_SET  0
  291. #define SEEK_CUR  1
  292. #define SEEK_END  2
  293.  
  294. #ifdef V7
  295.  
  296. #define O_RDONLY  0
  297. #define O_WRONLY  1
  298. #define O_RDWR    2
  299.  
  300. #else
  301.  
  302. #include <fcntl.h>
  303.  /*
  304.   * this include file defines
  305.   *             #define O_BINARY 0x8000  (* no cr-lf translation *)
  306.   * as used in the open() standard function
  307.   */
  308.  
  309. #endif
  310.  
  311. #ifndef UNIX
  312.  
  313. #include <sys/stat.h>
  314.  /*
  315.   * this include file defines
  316.   *             #define S_IREAD 0x0100  (* owner may read *)
  317.   *             #define S_IWRITE 0x0080 (* owner may write *)
  318.   * as used in the creat() standard function
  319.   */
  320.  
  321. #endif
  322.  
  323. void set_file_time()
  324.  /*
  325.   * set the output file date/time stamp according to information from the
  326.   * zipfile directory record for this file 
  327.   */
  328. {
  329. #ifndef UNIX
  330.     union {
  331.                 struct ftime ft;        /* system file time record */
  332.         struct {
  333.                         word ztime;     /* date and time words */
  334.                         word zdate;     /* .. same format as in .ZIP file */
  335.         } zt;
  336.     } td;
  337.  
  338.     /*
  339.      * set output file date and time - this is optional and can be
  340.      * deleted if your compiler does not easily support setftime() 
  341.      */
  342.  
  343.     td.zt.ztime = lrec.last_mod_file_time;
  344.     td.zt.zdate = lrec.last_mod_file_date;
  345.  
  346.     setftime(outfd, &td.ft);
  347.  
  348. #else
  349.  
  350.     time_t times[2];
  351.     struct tm *tmbuf;
  352.     long m_time;
  353.     int yr, mo, dy, hh, mm, ss, leap, days = 0;
  354.  
  355.     /*
  356.      * These date conversions look a little wierd, so I'll explain.
  357.      * UNIX bases all file modification times on the number of seconds
  358.      * elapsed since Jan 1, 1970, 00:00:00 GMT.  Therefore, to maintain
  359.      * compatibility with MS-DOS archives, which date from Jan 1, 1980,
  360.      * with NO relation to GMT, the following conversions must be made:
  361.      *         the Year (yr) must be incremented by 10;
  362.      *        the Date (dy) must be decremented by 1;
  363.      *        and the whole mess must be adjusted by TWO factors:
  364.      *            relationship to GMT (ie.,Pacific Time adds 8 hrs.),
  365.      *            and whether or not it is Daylight Savings Time.
  366.      * Also, the usual conversions must take place to account for leap years,
  367.      * etc.
  368.      *                                     C. Seaman
  369.      */
  370.  
  371.     yr = (((lrec.last_mod_file_date >> 9) & 0x7f) + 10);  /* dissect date */
  372.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f);
  373.     dy = ((lrec.last_mod_file_date & 0x1f) - 1);
  374.  
  375.     hh = ((lrec.last_mod_file_time >> 11) & 0x1f);        /* dissect time */
  376.     mm = ((lrec.last_mod_file_time >> 5) & 0x3f);
  377.     ss = ((lrec.last_mod_file_time & 0x1f) * 2);
  378.  
  379.     /* leap = # of leap years from 1970 up to but not including
  380.        the current year */
  381.  
  382.     leap = ((yr+1969)/4);              /* Leap year base factor */
  383.  
  384.     /* How many days from 1970 to this year? */
  385.     days = (yr * 365) + (leap - 492);
  386.  
  387.     switch(mo)                   /* calculate expired days this year */
  388.     {
  389.     case 12:
  390.         days += 30;
  391.     case 11:
  392.         days += 31;
  393.     case 10:
  394.         days += 30;
  395.     case 9:
  396.         days += 31;
  397.     case 8:
  398.         days += 31;
  399.     case 7:
  400.         days += 30;
  401.     case 6:
  402.         days += 31;
  403.     case 5:
  404.         days += 30;
  405.     case 4:
  406.         days += 31;
  407.     case 3:
  408.         days += 28;                    /* account for leap years */
  409.         if (((yr+1970) % 4 == 0) && (yr+1970) != 2000)
  410.             ++days;
  411.     case 2:
  412.         days += 31;
  413.     }
  414.  
  415.     /* convert date & time to seconds relative to 00:00:00, 01/01/1970 */
  416.     m_time = ((days + dy) * 86400) + (hh * 3600) + (mm * 60) + ss;
  417.  
  418. #ifdef BSD
  419.     struct timeval tv;
  420.     struct timezone tz;
  421.  
  422.     gettimeofday(&tv, &tz);
  423.  
  424.     if (tz.tz_dsttime != 0)
  425.         m_time -= 3600;
  426.  
  427.     m_time += tz.tz_minuteswest * 60;  /* account for timezone differences */
  428. #else
  429.     tmbuf = localtime(&m_time);
  430.     hh = tmbuf->tm_hour;
  431.     tmbuf = gmtime(&m_time);
  432.     hh = tmbuf->tm_hour - hh;
  433.     if (hh < 0)
  434.     hh += 24;
  435.     m_time += (hh * 3600);             /* account for timezone differences */
  436. #endif
  437.  
  438.     times[0] = m_time;             /* set the stamp on the file */
  439.     times[1] = m_time;
  440.     utime(filename, times);
  441. #endif
  442. }
  443.  
  444.  
  445. int create_output_file()
  446.  /* return non-0 if creat failed */
  447. {    /* create the output file with READ and WRITE permissions */
  448.     if (cflag) {        /* output to stdout (a copy of it, really) */
  449.         outfd = dup(1);
  450.         return 0;
  451.         }
  452. #ifndef UNIX
  453.     outfd = creat(filename, S_IWRITE | S_IREAD);
  454. #else
  455.     outfd = creat(filename, 0666);    /* let umask strip unwanted perm's */
  456. #endif
  457.  
  458.     if (outfd < 1) {
  459.         fprintf(stderr, "Can't create output: %s\n", filename);
  460.         return 1;
  461.     }
  462.  
  463.     /*
  464.      * close the newly created file and reopen it in BINARY mode to
  465.      * disable all CR/LF translations 
  466.      */
  467. #ifndef UNIX
  468.     close(outfd);
  469.     outfd = open(filename, O_RDWR | O_BINARY);
  470. #endif
  471.     return 0;
  472. }
  473.  
  474.  
  475. int open_input_file()
  476.  /* return non-0 if open failed */
  477. {
  478.     /*
  479.      * open the zipfile for reading and in BINARY mode to prevent cr/lf
  480.      * translation, which would corrupt the bitstreams 
  481.      */
  482.  
  483. #ifndef UNIX
  484.     zipfd = open(zipfn, O_RDONLY | O_BINARY);
  485. #else
  486.     zipfd = open(zipfn, O_RDONLY);
  487. #endif
  488.     if (zipfd < 1) {
  489.         fprintf(stderr, "Can't open input file: %s\n", zipfn);
  490.         return (1);
  491.     }
  492.     return 0;
  493. }
  494.  
  495.  
  496. #ifdef HIGH_LOW
  497.  
  498. void swap_bytes(wordp)
  499. word *wordp;
  500.  /* convert intel style 'short int' variable to host format */
  501. {
  502.     char *charp = (char *) wordp;
  503.     char temp;
  504.  
  505.     temp = charp[0];
  506.     charp[0] = charp[1];
  507.     charp[1] = temp;
  508. }
  509.  
  510. void swap_lbytes(longp)
  511. longint *longp;
  512.  /* convert intel style 'long' variable to host format */
  513. {
  514.     char *charp = (char *) longp;
  515.     char temp[4];
  516.  
  517.     temp[3] = charp[0];
  518.     temp[2] = charp[1];
  519.     temp[1] = charp[2];
  520.     temp[0] = charp[3];
  521.  
  522.     charp[0] = temp[0];
  523.     charp[1] = temp[1];
  524.     charp[2] = temp[2];
  525.     charp[3] = temp[3];
  526. }
  527.  
  528. #endif
  529.  
  530.  
  531.  
  532. /* ============================================================= */
  533.  
  534. int readbuf(fd, buf, size)
  535. int fd;
  536. char *buf;
  537. register unsigned size;
  538. {
  539.     register int count;
  540.     int n;
  541.  
  542.     n = size;
  543.     while (size)  {
  544.         if (incnt == 0)  {
  545.             if ((incnt = read(fd, inbuf, INBUFSIZ)) <= 0)
  546.                 return(incnt);
  547.             inptr = inbuf;
  548.         }
  549.         count = min(size, incnt);
  550.         memcpy(buf, inptr, count);
  551.         buf += count;
  552.         inptr += count;
  553.         incnt -= count;
  554.         size -= count;
  555.     }
  556.     return(n);
  557. }
  558.  
  559. int ReadByte(x)
  560. word *x;
  561.  /* read a byte; return 8 if byte available, 0 if not */
  562. {
  563.     if (csize-- <= 0)
  564.         return 0;
  565.     if (incnt == 0)  {
  566.         if ((incnt = read(zipfd, inbuf, INBUFSIZ)) <= 0)
  567.             return 0;
  568.         inptr = inbuf;
  569.     }
  570.     *x = *inptr++;
  571.     --incnt;
  572.     return 8;
  573. }
  574.  
  575.  
  576. /* ------------------------------------------------------------- */
  577. static word mask_bits[] =
  578.         {0,     0x0001, 0x0003, 0x0007, 0x000f,
  579.                 0x001f, 0x003f, 0x007f, 0x00ff,
  580.                 0x01ff, 0x03ff, 0x07ff, 0x0fff,
  581.                 0x1fff, 0x3fff, 0x7fff, 0xffff
  582.         };
  583.  
  584.  
  585. int FillBitBuffer(bits)
  586. register int bits;
  587. {
  588.     /* get the bits that are left and read the next word */
  589.         register int result = bitbuf;
  590.     word temp;
  591.     int sbits = bits_left;
  592.     bits -= bits_left;
  593.  
  594.     /* read next word of input */
  595.     bits_left = ReadByte(&bitbuf);
  596.     bits_left += ReadByte(&temp);
  597.     bitbuf |= (temp << 8);
  598.     if (bits_left == 0)
  599.         zipeof = 1;
  600.  
  601.     /* get the remaining bits */
  602.         result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
  603.         bitbuf >>= bits;
  604.         bits_left -= bits;
  605.         return result;
  606. }
  607.  
  608. #define READBIT(nbits,zdest) { if (nbits <= bits_left) { zdest = (int)(bitbuf & mask_bits[nbits]); bitbuf >>= nbits; bits_left -= nbits; } else zdest = FillBitBuffer(nbits);}
  609.  
  610. /*
  611.  * macro READBIT(nbits,zdest)
  612.  *  {
  613.  *      if (nbits <= bits_left) {
  614.  *          zdest = (int)(bitbuf & mask_bits[nbits]);
  615.  *          bitbuf >>= nbits;
  616.  *          bits_left -= nbits;
  617.  *      } else
  618.  *          zdest = FillBitBuffer(nbits);
  619.  *  }
  620.  *
  621.  */
  622.  
  623.  
  624. /* ------------------------------------------------------------- */
  625.  
  626. #include "crc32.h"
  627.  
  628.  
  629. /* ------------------------------------------------------------- */
  630.  
  631. void FlushOutput()
  632.  /* flush contents of output buffer */
  633. {
  634.     UpdateCRC(outbuf, outcnt);
  635.     if (!tflag)
  636.         if (write(outfd, outbuf, outcnt) != outcnt)  {
  637.             fprintf(stderr, " File write error\n");
  638.             exit(1);
  639.         }
  640.     outpos += outcnt;
  641.     outcnt = 0;
  642.     outptr = outbuf;
  643. }
  644.  
  645. #define OUTB(intc) { *outptr++=intc; if (++outcnt==OUTBUFSIZ) FlushOutput(); }
  646.  
  647. /*
  648.  *  macro OUTB(intc)
  649.  *  {
  650.  *      *outptr++=intc;
  651.  *      if (++outcnt==OUTBUFSIZ)
  652.  *          FlushOutput();
  653.  *  }
  654.  *
  655.  */
  656.  
  657.  
  658. /* ----------------------------------------------------------- */
  659.  
  660. void LoadFollowers()
  661. {
  662.         register int x;
  663.         register int i;
  664.  
  665.     for (x = 255; x >= 0; x--) {
  666.                 READBIT(6,Slen[x]);
  667.         for (i = 0; i < Slen[x]; i++) {
  668.                         READBIT(8,followers[x][i]);
  669.         }
  670.     }
  671. }
  672.  
  673.  
  674. /* ----------------------------------------------------------- */
  675. /*
  676.  * The Reducing algorithm is actually a combination of two
  677.  * distinct algorithms.  The first algorithm compresses repeated
  678.  * byte sequences, and the second algorithm takes the compressed
  679.  * stream from the first algorithm and applies a probabilistic
  680.  * compression method.
  681.  */
  682.  
  683. int L_table[] = {0, 0x7f, 0x3f, 0x1f, 0x0f};
  684.  
  685. int D_shift[] = {0, 0x07, 0x06, 0x05, 0x04};
  686. int D_mask[]  = {0, 0x01, 0x03, 0x07, 0x0f};
  687.  
  688. int B_table[] = {8, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5,
  689.          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
  690.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  691.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
  692.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  693.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  694.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  695.          7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  696.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  697.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  698.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  699.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  700.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  701.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  702.          8, 8, 8, 8};
  703.  
  704. /* ----------------------------------------------------------- */
  705.  
  706. void unReduce()
  707.  /* expand probablisticly reduced data */
  708. {
  709.         register int lchar;
  710.         int nchar;
  711.         int ExState;
  712.         int V;
  713.         int Len;
  714.  
  715.         factor = lrec.compression_method - 1;
  716.     ExState = 0;
  717.     lchar = 0;
  718.     LoadFollowers();
  719.  
  720.         while (((outpos+outcnt) < ucsize) && (!zipeof)) {
  721.         if (Slen[lchar] == 0)
  722.                         READBIT(8,nchar)      /* ; */
  723.                 else
  724.         {
  725.                         READBIT(1,nchar);
  726.                         if (nchar != 0)
  727.                                 READBIT(8,nchar)      /* ; */
  728.                         else
  729.             {
  730.                                 int follower;
  731.                                 int bitsneeded = B_table[Slen[lchar]];
  732.                                 READBIT(bitsneeded,follower);
  733.                                 nchar = followers[lchar][follower];
  734.             }
  735.         }
  736.  
  737.         /* expand the resulting byte */
  738.         switch (ExState) {
  739.  
  740.         case 0:
  741.                         if (nchar != DLE)
  742.                                 OUTB(nchar) /*;*/
  743.             else
  744.                 ExState = 1;
  745.             break;
  746.  
  747.         case 1:
  748.                         if (nchar != 0) {
  749.                                 V = nchar;
  750.                 Len = V & L_table[factor];
  751.                 if (Len == L_table[factor])
  752.                     ExState = 2;
  753.                 else
  754.                     ExState = 3;
  755.             }
  756.             else {
  757.                                 OUTB(DLE);
  758.                 ExState = 0;
  759.             }
  760.             break;
  761.  
  762.                 case 2: {
  763.                                 Len += nchar;
  764.                 ExState = 3;
  765.             }
  766.             break;
  767.  
  768.                 case 3: {
  769.                 register int i = Len + 3;
  770.                 int offset = (((V >> D_shift[factor]) &
  771.                                           D_mask[factor]) << 8) + nchar + 1;
  772.                                 longint op = (outpos+outcnt) - offset;
  773.  
  774.                 /* special case- before start of file */
  775.                 while ((op < 0L) && (i > 0)) {
  776.                     OUTB(0);
  777.                     op++;
  778.                     i--;
  779.                 }
  780.  
  781.                 /* normal copy of data from output buffer */
  782.                 {
  783.                     register int ix = (int) (op % OUTBUFSIZ);
  784.  
  785.                                         /* do a block memory copy if possible */
  786.                                         if ( ((ix    +i) < OUTBUFSIZ) &&
  787.                                              ((outcnt+i) < OUTBUFSIZ) ) {
  788.                                                 memcpy(outptr,&outbuf[ix],i);
  789.                                                 outptr += i;
  790.                                                 outcnt += i;
  791.                                         }
  792.  
  793.                                         /* otherwise copy byte by byte */
  794.                                         else while (i--) {
  795.                                                 OUTB(outbuf[ix]);
  796.                                                 if (++ix >= OUTBUFSIZ)
  797.                                                         ix = 0;
  798.                                         }
  799.                                 }
  800.  
  801.                 ExState = 0;
  802.             }
  803.             break;
  804.         }
  805.  
  806.                 /* store character for next iteration */
  807.                 lchar = nchar;
  808.         }
  809. }
  810.  
  811.  
  812. /* ------------------------------------------------------------- */
  813. /*
  814.  * Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
  815.  * with partial clearing.
  816.  *
  817.  */
  818.  
  819. void partial_clear()
  820. {
  821.         register int pr;
  822.         register int cd;
  823.  
  824.     /* mark all nodes as potentially unused */
  825.     for (cd = first_ent; cd < free_ent; cd++)
  826.         prefix_of[cd] |= 0x8000;
  827.  
  828.     /* unmark those that are used by other nodes */
  829.     for (cd = first_ent; cd < free_ent; cd++) {
  830.         pr = prefix_of[cd] & 0x7fff;    /* reference to another node? */
  831.                 if (pr >= first_ent)            /* flag node as referenced */
  832.             prefix_of[pr] &= 0x7fff;
  833.     }
  834.  
  835.     /* clear the ones that are still marked */
  836.     for (cd = first_ent; cd < free_ent; cd++)
  837.         if ((prefix_of[cd] & 0x8000) != 0)
  838.             prefix_of[cd] = -1;
  839.  
  840.     /* find first cleared node as next free_ent */
  841.         cd = first_ent;
  842.         while ((cd < maxcodemax) && (prefix_of[cd] != -1))
  843.                 cd++;
  844.         free_ent = cd;
  845. }
  846.  
  847.  
  848. /* ------------------------------------------------------------- */
  849.  
  850. void unShrink()
  851. {
  852. #define  GetCode(dest) READBIT(codesize,dest)
  853.  
  854.     register int code;
  855.     register int stackp;
  856.     int finchar;
  857.     int oldcode;
  858.     int incode;
  859.  
  860.  
  861.     /* decompress the file */
  862.     maxcodemax = 1 << max_bits;
  863.     codesize = init_bits;
  864.     maxcode = (1 << codesize) - 1;
  865.     free_ent = first_ent;
  866.     offset = 0;
  867.     sizex = 0;
  868.  
  869.     for (code = maxcodemax; code > 255; code--)
  870.         prefix_of[code] = -1;
  871.  
  872.     for (code = 255; code >= 0; code--) {
  873.         prefix_of[code] = 0;
  874.         suffix_of[code] = code;
  875.     }
  876.  
  877.     GetCode(oldcode);
  878.     if (zipeof)
  879.         return;
  880.     finchar = oldcode;
  881.  
  882.         OUTB(finchar);
  883.  
  884.         stackp = hsize;
  885.  
  886.     while (!zipeof) {
  887.         GetCode(code);
  888.         if (zipeof)
  889.             return;
  890.  
  891.         while (code == clear) {
  892.             GetCode(code);
  893.             switch (code) {
  894.  
  895.             case 1:{
  896.                     codesize++;
  897.                     if (codesize == max_bits)
  898.                         maxcode = maxcodemax;
  899.                     else
  900.                         maxcode = (1 << codesize) - 1;
  901.                 }
  902.                 break;
  903.  
  904.             case 2:
  905.                 partial_clear();
  906.                 break;
  907.             }
  908.  
  909.             GetCode(code);
  910.             if (zipeof)
  911.                 return;
  912.         }
  913.  
  914.  
  915.         /* special case for KwKwK string */
  916.         incode = code;
  917.         if (prefix_of[code] == -1) {
  918.                         stack[--stackp] = finchar;
  919.             code = oldcode;
  920.         }
  921.  
  922.  
  923.         /* generate output characters in reverse order */
  924.         while (code >= first_ent) {
  925.                         stack[--stackp] = suffix_of[code];
  926.             code = prefix_of[code];
  927.         }
  928.  
  929.         finchar = suffix_of[code];
  930.                 stack[--stackp] = finchar;
  931.  
  932.  
  933.                 /* and put them out in forward order, block copy */
  934.                 if ((hsize-stackp+outcnt) < OUTBUFSIZ) {
  935.                         memcpy(outptr,&stack[stackp],hsize-stackp);
  936.                         outptr += hsize-stackp;
  937.                         outcnt += hsize-stackp;
  938.                         stackp = hsize;
  939.                 }
  940.  
  941.                 /* output byte by byte if we can't go by blocks */
  942.                 else while (stackp < hsize)
  943.                         OUTB(stack[stackp++]);
  944.  
  945.  
  946.         /* generate new entry */
  947.         code = free_ent;
  948.         if (code < maxcodemax) {
  949.             prefix_of[code] = oldcode;
  950.             suffix_of[code] = finchar;
  951.  
  952.             do
  953.                 code++;
  954.             while ((code < maxcodemax) && (prefix_of[code] != -1));
  955.  
  956.             free_ent = code;
  957.         }
  958.  
  959.         /* remember previous code */
  960.         oldcode = incode;
  961.     }
  962.  
  963. }
  964.  
  965.  
  966. /* ------------------------------------------------------------- */ 
  967. /*
  968.  * Imploding
  969.  * ---------
  970.  *
  971.  * The Imploding algorithm is actually a combination of two distinct
  972.  * algorithms.  The first algorithm compresses repeated byte sequences
  973.  * using a sliding dictionary.  The second algorithm is used to compress
  974.  * the encoding of the sliding dictionary ouput, using multiple
  975.  * Shannon-Fano trees.
  976.  *
  977.  */ 
  978.  
  979. #define LITVALS        256
  980. #define DISTVALS    64
  981. #define LENVALS        64
  982. #define MAXSF        LITVALS
  983.  
  984.    typedef struct sf_entry { 
  985.                  byte         Value; 
  986.                  byte         BitLength; 
  987.               } sf_entry; 
  988.  
  989.    typedef struct sf_tree {   /* a shannon-fano "tree" (table) */
  990.       sf_entry     entry[MAXSF];
  991.       int          entries;
  992.       int          MaxLength;
  993.    } sf_tree; 
  994.  
  995.    typedef sf_tree      *sf_treep; 
  996.  
  997.    typedef struct sf_node {   /* node in a true shannon-fano tree */
  998.       word         left;    /* 0 means leaf node */
  999.       word         right;    /* or value if leaf node */
  1000.    } sf_node;
  1001.  
  1002.    sf_tree      lit_tree; 
  1003.    sf_tree      length_tree; 
  1004.    sf_tree      distance_tree; 
  1005.    /* s-f storage is shared with that used by other comp. methods */
  1006.    sf_node    *lit_nodes = (sf_node *) followers;    /* 2*LITVALS nodes */
  1007.    sf_node    *length_nodes = (sf_node *) suffix_of;    /* 2*LENVALS nodes */
  1008.    sf_node    *distance_nodes = (sf_node *) stack;    /* 2*DISTVALS nodes */
  1009.    boolean      lit_tree_present; 
  1010.    boolean      eightK_dictionary; 
  1011.    int          minimum_match_length;
  1012.    int          dict_bits;
  1013.  
  1014.  
  1015. void         SortLengths(tree)
  1016. sf_tree *tree;
  1017.   /* Sort the Bit Lengths in ascending order, while retaining the order
  1018.     of the original lengths stored in the file */ 
  1019.     register sf_entry *ejm1;    /* entry[j - 1] */
  1020.     register int j;
  1021.     register sf_entry *entry;
  1022.     register int i;
  1023.     sf_entry tmp;
  1024.     int entries;
  1025.     unsigned a, b;
  1026.  
  1027.     entry = &tree->entry[0];
  1028.     entries = tree->entries;
  1029.  
  1030.     for (i = 0; ++i < entries; )  {
  1031.         tmp = entry[i];
  1032.         b = tmp.BitLength;
  1033.         j = i;
  1034.         while ((j > 0)
  1035.         && ((a = (ejm1 = &entry[j - 1])->BitLength) >= b))  {
  1036.             if ((a == b) && (ejm1->Value <= tmp.Value))
  1037.                 break;
  1038.             *(ejm1 + 1) = *ejm1;    /* entry[j] = entry[j - 1] */
  1039.             --j;
  1040.         }
  1041.         entry[j] = tmp;
  1042.     }
  1043.  
  1044.  
  1045. /* ----------------------------------------------------------- */ 
  1046.  
  1047. void         ReadLengths(tree)
  1048. sf_tree *tree;
  1049.    int          treeBytes;
  1050.    int          i;
  1051.    int          num, len;
  1052.  
  1053.   /* get number of bytes in compressed tree */
  1054.    READBIT(8,treeBytes);
  1055.    treeBytes++; 
  1056.    i = 0; 
  1057.  
  1058.    tree->MaxLength = 0;
  1059.  
  1060.  /* High 4 bits: Number of values at this bit length + 1. (1 - 16)
  1061.     Low  4 bits: Bit Length needed to represent value + 1. (1 - 16) */
  1062.    while (treeBytes > 0)
  1063.    {
  1064.       READBIT(4,len); len++;
  1065.       READBIT(4,num); num++;
  1066.  
  1067.       while (num > 0)
  1068.       {
  1069.          if (len > tree->MaxLength)
  1070.             tree->MaxLength = len;
  1071.          tree->entry[i].BitLength = len;
  1072.          tree->entry[i].Value = i;
  1073.          i++;
  1074.          num--;
  1075.       }
  1076.  
  1077.       treeBytes--;
  1078.    } 
  1079.  
  1080.  
  1081. /* ----------------------------------------------------------- */ 
  1082.  
  1083. void         GenerateTrees(tree, nodes)
  1084. sf_tree *tree;
  1085. sf_node *nodes;
  1086.      /* Generate the Shannon-Fano trees */ 
  1087.     int codelen, i, j, lvlstart, next, parents;
  1088.  
  1089.     i = tree->entries - 1;    /* either 255 or 63 */
  1090.     lvlstart = next = 1;
  1091.  
  1092.     /* believe it or not, there may be a 1-bit code */
  1093.  
  1094.     for (codelen = tree->MaxLength; codelen >= 1; --codelen)  {
  1095.  
  1096.         /* create leaf nodes at level <codelen> */
  1097.  
  1098.         while ((i >= 0) && (tree->entry[i].BitLength == codelen))  {
  1099.             nodes[next].left = 0;
  1100.             nodes[next].right = tree->entry[i].Value;
  1101.             ++next;
  1102.             --i;
  1103.         }
  1104.  
  1105.         /* create parent nodes for all nodes at level <codelen>,
  1106.            but don't create the root node here */
  1107.  
  1108.         parents = next;
  1109.         if (codelen > 1)  {
  1110.             for (j = lvlstart; j <= parents-2; j += 2)  {
  1111.                 nodes[next].left = j;
  1112.                 nodes[next].right = j + 1;
  1113.                 ++next;
  1114.             }
  1115.         }
  1116.         lvlstart = parents;
  1117.     }
  1118.  
  1119.     /* create root node */
  1120.  
  1121.     nodes[0].left = next - 2;
  1122.     nodes[0].right = next - 1;
  1123.  
  1124.  
  1125. /* ----------------------------------------------------------- */ 
  1126.  
  1127. void         LoadTree(tree, treesize, nodes)
  1128. sf_tree *tree;
  1129. int treesize;
  1130. sf_node *nodes;
  1131.      /* allocate and load a shannon-fano tree from the compressed file */ 
  1132.    tree->entries = treesize; 
  1133.    ReadLengths(tree); 
  1134.    SortLengths(tree); 
  1135.    GenerateTrees(tree, nodes); 
  1136.  
  1137.  
  1138. /* ----------------------------------------------------------- */ 
  1139.  
  1140. void         LoadTrees()
  1141.    eightK_dictionary = (lrec.general_purpose_bit_flag & 0x02) != 0;   /* bit 1 */
  1142.    lit_tree_present = (lrec.general_purpose_bit_flag & 0x04) != 0;   /* bit 2 */
  1143.  
  1144.    if (eightK_dictionary) 
  1145.       dict_bits = 7;
  1146.    else 
  1147.       dict_bits = 6; 
  1148.  
  1149.    if (lit_tree_present) 
  1150.    { 
  1151.       minimum_match_length = 3; 
  1152.       LoadTree(&lit_tree,256,lit_nodes);
  1153.    } 
  1154.    else 
  1155.       minimum_match_length = 2; 
  1156.  
  1157.    LoadTree(&length_tree,64,length_nodes);
  1158.    LoadTree(&distance_tree,64,distance_nodes);
  1159.  
  1160.  
  1161. /* ----------------------------------------------------------- */ 
  1162.  
  1163. #ifndef ASM
  1164.  
  1165. void         ReadTree(nodes, dest)
  1166. register sf_node *nodes;
  1167. int *dest;
  1168.      /* read next byte using a shannon-fano tree */ 
  1169.     register int cur;
  1170.     register int left;
  1171.     word b;
  1172.  
  1173.     for (cur = 0; ; )  {
  1174.         if ((left = nodes[cur].left) == 0)  {
  1175.             *dest = nodes[cur].right;
  1176.             return;
  1177.         }
  1178.         READBIT(1, b);
  1179.         cur = (b ? nodes[cur].right : left);
  1180.     }
  1181.  
  1182. #endif
  1183.  
  1184. /* ----------------------------------------------------------- */ 
  1185.  
  1186. void         unImplode()
  1187.      /* expand imploded data */ 
  1188.    register int srcix;
  1189.    register int Length;
  1190.    register int limit;
  1191.    int          lout;
  1192.    int          Distance;
  1193.  
  1194.    LoadTrees(); 
  1195.  
  1196. #ifdef DEBUG
  1197.    printf("\n");
  1198. #endif
  1199.    while ((!zipeof) && ((outpos+outcnt) < ucsize))
  1200.    { 
  1201.       READBIT(1,lout);
  1202.  
  1203.       if (lout != 0)   /* encoded data is literal data */ 
  1204.       { 
  1205.          if (lit_tree_present)  /* use Literal Shannon-Fano tree */  {
  1206.             ReadTree(lit_nodes,&lout);
  1207. #ifdef DEBUG
  1208.         printf("lit=%d\n", lout);
  1209. #endif
  1210.      }
  1211.          else 
  1212.             READBIT(8,lout);
  1213.  
  1214.          OUTB(lout);
  1215.       } 
  1216.       else             /* encoded data is sliding dictionary match */
  1217.       {                
  1218.          READBIT(dict_bits,Distance);
  1219.  
  1220.          ReadTree(distance_nodes,&lout); 
  1221. #ifdef DEBUG
  1222.      printf("d=%5d (%2d,%3d)", (lout << dict_bits) | Distance, lout,
  1223.             Distance);
  1224. #endif
  1225.          Distance |= (lout << dict_bits);
  1226.          /* using the Distance Shannon-Fano tree, read and decode the
  1227.             upper 6 bits of the Distance value */ 
  1228.  
  1229.          ReadTree(length_nodes,&lout);
  1230.      Length = lout;
  1231. #ifdef DEBUG
  1232.      printf("\tl=%3d\n", Length);
  1233. #endif
  1234.          /* using the Length Shannon-Fano tree, read and decode the
  1235.             Length value */
  1236.  
  1237.          if (Length == 63)
  1238.          { 
  1239.             READBIT(8,lout);
  1240.             Length += lout; 
  1241.          } 
  1242.          Length += minimum_match_length; 
  1243.  
  1244.         /* move backwards Distance+1 bytes in the output stream, and copy
  1245.           Length characters from this position to the output stream.
  1246.           (if this position is before the start of the output stream,
  1247.           then assume that all the data before the start of the output
  1248.           stream is filled with zeros.  Requires initializing outbuf
  1249.       for each file.) */ 
  1250.  
  1251.     srcix = (outcnt - (Distance + 1)) & (OUTBUFSIZ-1);
  1252.     limit = OUTBUFSIZ - Length;
  1253.     if ((srcix <= limit) && (outcnt < limit))  {
  1254.         memcpy(outptr, &outbuf[srcix], Length);
  1255.         outptr += Length;
  1256.         outcnt += Length;
  1257.     }
  1258.     else {
  1259.         while (Length--)  {
  1260.             OUTB(outbuf[srcix++]);
  1261.             srcix &= OUTBUFSIZ-1;
  1262.         }
  1263.     }
  1264.  
  1265.       } 
  1266.    } 
  1267.  
  1268.  
  1269.  
  1270. /* ---------------------------------------------------------- */
  1271.  
  1272. /*
  1273.  Length  Method   Size  Ratio   Date    Time   CRC-32    Name
  1274.  ------  ------   ----- -----   ----    ----   ------    ----
  1275.   44004  Implode  13041  71%  11-02-89  19:34  88420727  DIFF3.C
  1276.  */
  1277.  
  1278. void dir_member()
  1279. {
  1280.     char *method;
  1281.     int ratio;
  1282.     int yr, mo, dy, hh, mm;
  1283.  
  1284.     yr = (((lrec.last_mod_file_date >> 9) & 0x7f) + 80);
  1285.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f);
  1286.     dy = (lrec.last_mod_file_date & 0x1f);
  1287.  
  1288.     hh = ((lrec.last_mod_file_time >> 11) & 0x1f);
  1289.     mm = ((lrec.last_mod_file_time >> 5) & 0x3f);
  1290.  
  1291.     switch (lrec.compression_method)  {
  1292.     case 0:
  1293.         method = "Stored";
  1294.         break;
  1295.     case 1:
  1296.         method = "Shrunk";
  1297.         break;
  1298.     case 2:
  1299.     case 3:
  1300.     case 4:
  1301.     case 5:
  1302.         method = "Reduced";
  1303.         break;
  1304.     case 6:
  1305.         method = "Implode";
  1306.         break;
  1307.     }
  1308.  
  1309.     if (ucsize != 0)  {
  1310.         ratio = (int) ((1000L * (ucsize    - csize)) / ucsize);
  1311.         if ((ratio % 10) >= 5)
  1312.             ratio += 10;
  1313.     }
  1314.     else
  1315.         ratio = 0;    /* can .zip contain 0-size file? */
  1316.  
  1317.     printf("%7ld  %-7s%7ld %3d%%  %02d-%02d-%02d  %02d:%02d  \
  1318. %08lx  %s\n", ucsize, method, csize,
  1319.         ratio / 10, mo, dy, yr, hh, mm,
  1320.         LONGI(lrec.crc32), filename);
  1321.     tot_ucsize += ucsize;
  1322.     tot_csize += csize;
  1323.     ++members;
  1324. }
  1325.  
  1326. /* ---------------------------------------------------------- */
  1327.  
  1328. void skip_member()
  1329. {
  1330.     register long pos;
  1331.     long endbuf;
  1332.     int offset;
  1333.  
  1334.     endbuf = lseek(zipfd, 0L, SEEK_CUR);    /* 1st byte beyond inbuf */
  1335.     pos = endbuf - incnt;            /* 1st compressed byte */
  1336.     pos += csize;        /* next header signature */
  1337.     if (pos < endbuf)  {
  1338.         incnt -= csize;
  1339.         inptr += csize;
  1340.     }
  1341.     else  {
  1342.         offset = pos % BSIZE;        /* offset within block */
  1343.         pos = (pos / BSIZE) * BSIZE;    /* block start */
  1344.             lseek(zipfd, pos, SEEK_SET);
  1345.         incnt = read(zipfd, inbuf, INBUFSIZ);
  1346.         incnt -= offset;
  1347.         inptr = inbuf + offset;
  1348.     }
  1349. }
  1350.  
  1351. /* ---------------------------------------------------------- */
  1352.  
  1353. void extract_member()
  1354. {
  1355.         word     b;
  1356.  
  1357.     bits_left = 0;
  1358.     bitbuf = 0;
  1359.     outpos = 0L;
  1360.     outcnt = 0;
  1361.     outptr = outbuf;
  1362.     zipeof = 0;
  1363.     crc32val = 0xFFFFFFFFL;
  1364.  
  1365.  
  1366.     memset(outbuf, 0, OUTBUFSIZ);
  1367.     if (tflag)
  1368.         fprintf(stderr, "Testing: %-12s ", filename);
  1369.     else
  1370.         /* create the output file with READ and WRITE permissions */
  1371.         if (create_output_file())
  1372.             exit(1);
  1373.  
  1374.         switch (lrec.compression_method) {
  1375.  
  1376.     case 0:        /* stored */
  1377.         {
  1378.             if (!tflag)
  1379.                 fprintf(stderr, " Extracting: %-12s ", filename);
  1380.             if (cflag) fprintf(stderr, "\n");
  1381.             while (ReadByte(&b))
  1382.                 OUTB(b);
  1383.         }
  1384.         break;
  1385.  
  1386.         case 1: {
  1387.             if (!tflag)
  1388.                 fprintf(stderr, "UnShrinking: %-12s ", filename);
  1389.             if (cflag) fprintf(stderr, "\n");
  1390.             unShrink();
  1391.         }
  1392.         break;
  1393.  
  1394.     case 2:
  1395.     case 3:
  1396.     case 4:
  1397.         case 5: {
  1398.             if (!tflag)
  1399.                 fprintf(stderr, "  Expanding: %-12s ", filename);
  1400.             if (cflag) fprintf(stderr, "\n");
  1401.             unReduce();
  1402.         }
  1403.         break;
  1404.  
  1405.         case 6: {
  1406.             if (!tflag)
  1407.                             fprintf(stderr, "  Exploding: %-12s ", filename);
  1408.             if (cflag) fprintf(stderr, "\n");
  1409.                         unImplode();
  1410.         }
  1411.         break;
  1412.  
  1413.         default:
  1414.         fprintf(stderr, "Unknown compression method.");
  1415.     }
  1416.  
  1417.  
  1418.     /* write the last partial buffer, if any */
  1419.     if (outcnt > 0) {
  1420.         UpdateCRC(outbuf, outcnt);
  1421.         if (!tflag)
  1422.             write(outfd, outbuf, outcnt);
  1423.     }
  1424.  
  1425.     if (!tflag)  {
  1426. #ifndef UNIX
  1427.         /* set output file date and time */
  1428.         set_file_time();
  1429.         close(outfd);
  1430. #else
  1431.         close(outfd);
  1432.         /* set output file date and time */
  1433.         set_file_time();
  1434. #endif
  1435.     }
  1436.  
  1437.     crc32val = ~crc32val;
  1438.         if (crc32val != LONGI(lrec.crc32))
  1439.                 fprintf(stderr, " Bad CRC %08lx  (should be %08lx)", crc32val,
  1440.             LONGI(lrec.crc32));
  1441.     else if (tflag)
  1442.         fprintf(stderr, " OK");
  1443.  
  1444.     fprintf(stderr, "\n");
  1445. }
  1446.  
  1447.  
  1448. /* ---------------------------------------------------------- */
  1449.  
  1450. void get_string(len, s)
  1451. int len;
  1452. char *s;
  1453. {
  1454.     readbuf(zipfd, s, len);
  1455.     s[len] = 0;
  1456. }
  1457.  
  1458.  
  1459. /* ---------------------------------------------------------- */
  1460.  
  1461. void process_local_file_header(fnamev)
  1462. char **fnamev;
  1463. {
  1464.     int extracted;
  1465.  
  1466.     readbuf(zipfd, &lrec, sizeof(lrec));
  1467.  
  1468. #ifdef HIGH_LOW
  1469.     swap_bytes(&lrec.filename_length);
  1470.     swap_bytes(&lrec.extra_field_length);
  1471.     swap_lbytes(LONGIP(lrec.compressed_size));
  1472.     swap_lbytes(LONGIP(lrec.uncompressed_size));
  1473.     swap_bytes(&lrec.compression_method);
  1474.     swap_bytes(&lrec.version_needed_to_extract);
  1475.         swap_bytes(&lrec.general_purpose_bit_flag);
  1476.     swap_bytes(&lrec.last_mod_file_time);
  1477.     swap_bytes(&lrec.last_mod_file_date);
  1478.         swap_lbytes(LONGIP(lrec.crc32));
  1479. #endif
  1480.     csize = LONGI(lrec.compressed_size);
  1481.     ucsize = LONGI(lrec.uncompressed_size);
  1482.  
  1483.     get_string(lrec.filename_length, filename);
  1484.     get_string(lrec.extra_field_length, extra);
  1485.  
  1486.     extracted = 0;
  1487.     for (--fnamev; *++fnamev; )  {
  1488.         if (match(filename, *fnamev))  {
  1489.             if (vflag)
  1490.                 dir_member();
  1491.             else  {
  1492.                 extract_member();
  1493.                 extracted = 1;
  1494.             }
  1495.             break;
  1496.         }
  1497.     }
  1498.     if (!extracted)
  1499.         skip_member();
  1500. }
  1501.  
  1502.  
  1503. /* ---------------------------------------------------------- */
  1504.  
  1505. void process_central_file_header()
  1506. {
  1507.     central_directory_file_header rec;
  1508.     char filename[STRSIZ];
  1509.     char extra[STRSIZ];
  1510.     char comment[STRSIZ];
  1511.  
  1512.     readbuf(zipfd, &rec, sizeof(rec));
  1513.  
  1514. #ifdef HIGH_LOW
  1515.     swap_bytes(&rec.filename_length);
  1516.     swap_bytes(&rec.extra_field_length);
  1517.     swap_bytes(&rec.file_comment_length);
  1518. #endif
  1519.  
  1520.         get_string(rec.filename_length, filename);
  1521.     get_string(rec.extra_field_length, extra);
  1522.     get_string(rec.file_comment_length, comment);
  1523. }
  1524.  
  1525.  
  1526. /* ---------------------------------------------------------- */
  1527.  
  1528. void process_end_central_dir()
  1529. {
  1530.     end_central_dir_record rec;
  1531.     char comment[STRSIZ];
  1532.  
  1533.     readbuf(zipfd, &rec, sizeof(rec));
  1534.  
  1535. #ifdef HIGH_LOW
  1536.     swap_bytes(&rec.zipfile_comment_length);
  1537. #endif
  1538.  
  1539.     /* There seems to be no limit to the zipfile
  1540.        comment length.  Some zipfiles have comments
  1541.        longer than 256 bytes.  Currently no use is
  1542.        made of the comment anyway.
  1543.      */
  1544. #if 0
  1545.     get_string(rec.zipfile_comment_length, comment);
  1546. #endif
  1547. }
  1548.  
  1549.  
  1550. /* ---------------------------------------------------------- */
  1551.  
  1552. void process_headers()
  1553. {
  1554.     int ratio;
  1555.     longint sig;
  1556.  
  1557.     if (vflag)  {
  1558.         members = 0;
  1559.         tot_ucsize = tot_csize = 0;
  1560.         printf("\n Length  Method   Size  Ratio   Date    Time   \
  1561. CRC-32    Name\n ------  ------   ----- -----   ----    ----   ------    \
  1562. ----\n");
  1563.     }
  1564.  
  1565.     while (1) {
  1566.         if (readbuf(zipfd, &sig, sizeof(sig)) != sizeof(sig))
  1567.             return;
  1568.  
  1569. #ifdef HIGH_LOW
  1570.         swap_lbytes(&sig);
  1571. #endif
  1572.  
  1573.                 if (sig == LOCAL_FILE_HEADER_SIGNATURE)
  1574.             process_local_file_header(fnv);
  1575.                 else if (sig == CENTRAL_FILE_HEADER_SIGNATURE)
  1576.             process_central_file_header();
  1577.                 else if (sig == END_CENTRAL_DIR_SIGNATURE) {
  1578.             process_end_central_dir();
  1579.             break;
  1580.         }
  1581.                 else {
  1582.             fprintf(stderr, "Invalid Zipfile Header\n");
  1583.             return;
  1584.         }
  1585.     }
  1586.     if (vflag)  {
  1587.         if (tot_ucsize != 0)  {
  1588.             ratio = (int) ((1000L * (tot_ucsize-tot_csize))
  1589.                     / tot_ucsize);
  1590.             if ((ratio % 10) >= 5)
  1591.                 ratio += 10;
  1592.         }
  1593.         else
  1594.             ratio = 0;
  1595.         printf(" ------          ------  \
  1596. ---                             -------\n\
  1597. %7ld         %7ld %3d%%                             %7d\n",
  1598.         tot_ucsize, tot_csize, ratio / 10, members);
  1599.     }
  1600. }
  1601.  
  1602.  
  1603. /* ---------------------------------------------------------- */
  1604.  
  1605. void process_zipfile()
  1606. {
  1607.     /*
  1608.      * open the zipfile for reading and in BINARY mode to prevent cr/lf
  1609.      * translation, which would corrupt the bitstreams 
  1610.      */
  1611.  
  1612.     if (open_input_file())
  1613.         exit(1);
  1614.  
  1615.     process_headers();
  1616.  
  1617.     close(zipfd);
  1618. }
  1619.  
  1620. /* ---------------------------------------------------------- */
  1621.  
  1622. usage()
  1623. {
  1624.     fprintf(stderr, "\n%s\nCourtesy of:  S.H.Smith  and  The Tool Shop BBS,  (602) 279-2673.\n\n",VERSION);
  1625.     fprintf(stderr, "Usage:  unzip [-tcv] file[.zip] [filespec...]\n\
  1626. \t-t\ttest member files\n\
  1627. \t-c\toutput to stdout\n\
  1628. \t-v\tview directory\n");
  1629.     exit(1);
  1630. }
  1631.  
  1632. /* ---------------------------------------------------------- */
  1633.  
  1634. /*
  1635.  * main program
  1636.  *
  1637.  */
  1638.  
  1639. void main(argc, argv)
  1640. int argc;
  1641. char **argv;
  1642. {
  1643.     char *s;
  1644.     int c;
  1645.  
  1646.     while (--argc > 0 && (*++argv)[0] == '-')  {
  1647.         s = argv[0] + 1;
  1648.         while (c = *s++)  {
  1649.             switch (tolower(c))  {
  1650.             case 't':
  1651.                 ++tflag;
  1652.                 break;
  1653.             case 'v':
  1654.                 ++vflag;
  1655.                 break;
  1656.             case 'c':
  1657.                 ++cflag;
  1658.                 break;
  1659.             default:
  1660.                 usage();
  1661.                 break;
  1662.             }
  1663.         }
  1664.     }
  1665.  
  1666.     if ((tflag && vflag) || (tflag && cflag) || (vflag && cflag))  {
  1667.         fprintf(stderr, "only one of -t, -c, or -v\n");
  1668.         exit(1);
  1669.     }
  1670.     if (argc-- == 0)
  1671.         usage();
  1672.  
  1673.     /* .ZIP default if none provided by user */
  1674.     strcpy(zipfn, *argv++);
  1675.     if (strchr(zipfn, '.') == NULL)
  1676.         strcat(zipfn, ZSUFX);
  1677.  
  1678.     /* if any member file specs on command line, set filename
  1679.        pointer to point to them. */
  1680.  
  1681.     if (argc != 0)
  1682.         fnv = argv;
  1683.  
  1684.         /* allocate i/o buffers */
  1685.     inbuf = (byte *) (malloc(INBUFSIZ));
  1686.     outbuf = (byte *) (malloc(OUTBUFSIZ));
  1687.     if ((inbuf == NULL) || (outbuf == NULL)) {
  1688.         fprintf(stderr, "Can't allocate buffers!\n");
  1689.         exit(1);
  1690.     }
  1691.  
  1692.         /* do the job... */
  1693.         process_zipfile();
  1694.     exit(0);
  1695. }
  1696.