home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume8 / unzipbsd / unzipbsd.c < prev   
Encoding:
C/C++ Source or Header  |  1989-10-01  |  41.3 KB  |  1,717 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.  */
  19.  
  20. #include "patchlevel.h"
  21. #define VERSION  "2.0"
  22.  
  23. typedef unsigned char byte;    /* code assumes UNSIGNED bytes */
  24. typedef long longint;
  25. typedef unsigned word;
  26. typedef char boolean;
  27.  
  28. #define STRSIZ 256
  29.  
  30. #include <stdio.h>
  31.  /* this is your standard header for all C compiles */
  32. #include <ctype.h>
  33.  
  34. #ifdef MSDOS || M_XENIX
  35. #include <stdlib.h>
  36.  /* this include defines various standard library prototypes */
  37. #endif
  38.  
  39.  
  40. /*
  41.  * SEE HOST OPERATING SYSTEM SPECIFICS SECTION STARTING NEAR LINE 180
  42.  *
  43.  */
  44.  
  45.  
  46. /* ----------------------------------------------------------- */
  47. /*
  48.  * Zipfile layout declarations
  49.  *
  50.  */
  51.  
  52.  
  53. char local_file_header_signature[] = {0x50,0x4b,0x03,0x04};
  54.  
  55.  
  56. typedef struct local_file_header {
  57.     word version_needed_to_extract;
  58.     word general_purpose_bit_flag;
  59.     word compression_method;
  60.     word last_mod_file_time;
  61.     word last_mod_file_date;
  62.     longint crc32;
  63.     longint compressed_size;
  64.     longint uncompressed_size;
  65.     word filename_length;
  66.     word extra_field_length;
  67. } local_file_header;
  68.  
  69.  
  70. char central_file_header_signature[] = {0x50,0x4b,0x01,0x02};
  71.  
  72.  
  73. typedef struct central_directory_file_header {
  74.     word version_made_by;
  75.     word version_needed_to_extract;
  76.     word general_purpose_bit_flag;
  77.     word compression_method;
  78.     word last_mod_file_time;
  79.     word last_mod_file_date;
  80.     longint crc32;
  81.     longint compressed_size;
  82.     longint uncompressed_size;
  83.     word filename_length;
  84.     word extra_field_length;
  85.     word file_comment_length;
  86.     word disk_number_start;
  87.     word internal_file_attributes;
  88.     longint external_file_attributes;
  89.     longint relative_offset_local_header;
  90. } central_directory_file_header;
  91.  
  92.  
  93. char end_central_dir_signature[] = {0x50,0x4b,0x05,0x06};
  94.  
  95.  
  96. typedef struct end_central_dir_record {
  97.     word number_this_disk;
  98.     word number_disk_with_start_central_directory;
  99.     word total_entries_central_dir_on_this_disk;
  100.     word total_entries_central_dir;
  101.     longint size_central_directory;
  102.     longint offset_start_central_directory;
  103.     word zipfile_comment_length;
  104. } end_central_dir_record;
  105.  
  106.  
  107.  
  108. /* ----------------------------------------------------------- */
  109. /*
  110.  * input file variables
  111.  *
  112.  */
  113.  
  114. #define INBUFSIZ 0x2000
  115. byte *inbuf;            /* input file buffer - any size is legal */
  116. byte *inptr;
  117. byte *comment;
  118.  
  119. int incnt;
  120. unsigned bitbuf;
  121. int bits_left;
  122. boolean zipeof;
  123.  
  124. int zipfd;
  125. char zipfn[STRSIZ];
  126. local_file_header lrec;
  127.  
  128.  
  129. /* ----------------------------------------------------------- */
  130. /*
  131.  * output stream variables
  132.  *
  133.  */
  134.  
  135. #define OUTBUFSIZ 0x6000
  136. byte *outbuf;                   /* buffer for rle look-back */
  137. byte *outptr;
  138.  
  139. longint outpos;            /* absolute position in outfile */
  140. int outcnt;            /* current position in outbuf */
  141.  
  142. int outfd;
  143. char filename[STRSIZ];
  144. char extra[STRSIZ];
  145.  
  146. #define DLE 144
  147.  
  148.  
  149. /* ----------------------------------------------------------- */
  150. /*
  151.  * shrink/reduce working storage
  152.  *
  153.  */
  154.  
  155. int factor;
  156. byte followers[256][64];
  157. byte Slen[256];
  158.  
  159. #define max_bits 13
  160. #define init_bits 9
  161. #define hsize 8192
  162. #define first_ent 257
  163. #define clear 256
  164.  
  165. typedef int hsize_array_integer[hsize+1];
  166. typedef byte hsize_array_byte[hsize+1];
  167.  
  168. hsize_array_integer prefix_of;
  169. hsize_array_byte suffix_of;
  170. hsize_array_byte stack;
  171.  
  172. int codesize;
  173. int maxcode;
  174. int free_ent;
  175. int maxcodemax;
  176. int offset;
  177. int sizex;
  178.  
  179.  
  180.  
  181. /* ============================================================= */
  182. /*
  183.  * Host operating system details
  184.  *
  185.  */
  186.  
  187. #include <string.h>
  188.  /* this include defines strcpy, strcmp, etc. */
  189.  
  190. #include <time.h>
  191.  
  192. #ifdef MSDOS || M_XENIX
  193. #include <io.h>
  194.  /*
  195.   * this include file defines
  196.   *             struct ftime ...        (* file time/date stamp info *)
  197.   *             int setftime (int handle, struct ftime *ftimep);
  198.   *             #define SEEK_CUR  1     (* lseek() modes *)
  199.   *             #define SEEK_END  2
  200.   *             #define SEEK_SET  0
  201.   */
  202. #else
  203. #include <sys/file.h>
  204.  /*
  205.   * this include file defines
  206.   *             #define L_SET 0  (* Seek to absolute record *)
  207.   */
  208. #define SEEK_SET L_SET
  209. #endif
  210.  
  211.  
  212.  
  213. #ifdef MSDOS || M_XENIX
  214. #include <fcntl.h>
  215.  /*
  216.   * this include file defines
  217.   *             #define O_BINARY 0x8000  (* no cr-lf translation *)
  218.   * as used in the open() standard function
  219.   */
  220. #ifndef L_SET
  221. #define L_SET 1
  222. #endif
  223. #endif
  224.  
  225. #ifndef O_BINARY
  226. #define O_BINARY 0        /* BSD don't have a Open_BINARY mode */
  227. #endif
  228.  
  229. #include <sys/types.h>
  230. #include <sys/stat.h>
  231.  /*
  232.   * this include file defines
  233.   *             #define S_IREAD 0x0100  (* owner may read *)
  234.   *             #define S_IWRITE 0x0080 (* owner may write *)
  235.   * as used in the creat() standard function
  236.   */
  237.  
  238. void set_file_time()
  239.  /*
  240.   * set the output file date/time stamp according to information from the
  241.   * zipfile directory record for this file 
  242.   */
  243. {
  244.     /*
  245.      * set output file date and time - this is optional and can be
  246.      * deleted
  247.      */
  248.  
  249. #define leap(y)     (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
  250. #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
  251.  
  252.     byte    yr, mo, dy;    /* parts of a date */
  253.     byte    hh, mm, ss;    /* parts of a time */
  254.     static char month_lengths[] =
  255.         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  256.     int day_of_year, year;
  257.     struct utimbuf {
  258.         time_t actime;        /* file accessed time */
  259.         time_t modtime;        /* file updated time */
  260.     } times;
  261.  
  262.     yr = (lrec.last_mod_file_date >> 9) & 0x7f;    /* dissect the date */
  263.     mo = (lrec.last_mod_file_date >> 5) & 0x0f;
  264.     dy = lrec.last_mod_file_date & 0x1f;
  265.  
  266.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;    /* dissect the time */
  267.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  268.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  269.     yr = (yr + 80) % 100;
  270.     year = yr + 1900;
  271.  
  272.     /*
  273.      * this is the standard Unix implementation (also fully
  274.      * compatible with MSC)
  275.      */
  276.  
  277.     close(outfd);
  278.     if (mo < 1 || mo > 12 || dy < 1 || dy > month_lengths[mo-1]
  279.         && !(mo == 2 && dy == 29 && leap (year))
  280.         || hh > 23 || mm > 59 || ss > 59)
  281.         return;
  282.  
  283.     day_of_year = dy - 1;
  284.     if (mo > 2 && leap(year))
  285.         ++day_of_year;
  286.  
  287.     while (--mo > 0)
  288.         day_of_year += month_lengths[mo - 1];
  289.  
  290.     times.modtime = (86400 * (long)(day_of_year + 365 * (year - 1970) 
  291.         + nleap (year)) + 3600 * (hh-1) + 60 * mm + ss);
  292.  
  293. #ifdef    HAVE_TZ
  294.     tzset();
  295.     times.modtime += timezone;
  296. #endif    /* HAVE_TZ */
  297.     times.actime = times.modtime;
  298.     utime(filename, ×);
  299. }
  300.  
  301. /*
  302.  * Some defines to use the GETOPT functions
  303.  * that are on most systems, even TURBO-C has these.
  304.  */
  305. #define USE_GETOPT        /* Use the GETOPT package */
  306. int extract   = 1;        /* Extract contents */
  307. int debugging = 0;        /* debug enable */
  308. int verbose   = 0;        /* be verbose */
  309. int list_zip  = 0;        /* list contents only */
  310. int test_zip  = 0;        /* test CRC's only */
  311. int unixfy    = 1;        /* Convert filename to lowercase */
  312. int dsp_comment  = 1;        /* Display comments */
  313.  
  314. long crc32val;            /* The CRC value we calculate */
  315. int numbad =0;
  316. int Total_files =0;
  317. long Total_bytes =0;
  318. long Total_length =0;
  319.  
  320. /* ============================================================= */
  321.  
  322. int create_output_file()
  323.  /* return non-0 if creat failed */
  324. {
  325.     if (!extract)
  326.         return 0;
  327.  
  328.     /* create the output file with READ and WRITE permissions */
  329.     outfd = creat(filename, S_IWRITE | S_IREAD);
  330.     if (outfd < 1) {
  331.         printf("Can't create output: %s\n", filename);
  332.         return 1;
  333.     }
  334.  
  335.     /*
  336.      * close the newly created file and reopen it in BINARY mode to
  337.      * disable all CR/LF translations 
  338.      */
  339.     close(outfd);
  340.     outfd = open(filename, O_RDWR | O_BINARY);
  341.  
  342.     /* write a single byte at EOF to pre-allocate the file */
  343.         lseek(outfd, lrec.uncompressed_size - 1L, SEEK_SET);
  344.     write(outfd, "?", 1);
  345.     lseek(outfd, 0L, SEEK_SET);
  346.     return 0;
  347. }
  348.  
  349.  
  350. int open_input_file()
  351.  /* return non-0 if creat failed */
  352. {
  353.     /*
  354.      * open the zipfile for reading and in BINARY mode to prevent cr/lf
  355.      * translation, which would corrupt the bitstreams 
  356.      */
  357.  
  358.     zipfd = open(zipfn, O_RDONLY | O_BINARY);
  359.     if (zipfd < 1) {
  360.         printf("Can't open input file: %s\n", zipfn);
  361.         return (1);
  362.     }
  363.     return 0;
  364. }
  365.  
  366.  
  367. int FillBuffer()
  368.  /* fill input buffer if possible */
  369. {
  370.     int readsize;
  371.  
  372.         if (lrec.compressed_size <= 0)
  373.         return incnt = 0;
  374.  
  375.         if (lrec.compressed_size > INBUFSIZ)
  376.         readsize = INBUFSIZ;
  377.     else
  378.                 readsize = (int) lrec.compressed_size;
  379.     incnt = read(zipfd, inbuf, readsize);
  380.  
  381.         lrec.compressed_size -= incnt;
  382.     inptr = inbuf;
  383.     return incnt--;
  384. }
  385.  
  386. int ReadByte(x)
  387. unsigned *x;
  388.  /* read a byte; return 8 if byte available, 0 if not */
  389. {
  390.     if (incnt-- == 0)
  391.         if (FillBuffer() == 0)
  392.             return 0;
  393.  
  394.     *x = *inptr++;
  395.     return 8;
  396. }
  397.  
  398.  
  399. /* ------------------------------------------------------------- */
  400. static unsigned mask_bits[] =
  401.         {0,     0x0001, 0x0003, 0x0007, 0x000f,
  402.                 0x001f, 0x003f, 0x007f, 0x00ff,
  403.                 0x01ff, 0x03ff, 0x07ff, 0x0fff,
  404.                 0x1fff, 0x3fff, 0x7fff, 0xffff
  405.         };
  406.  
  407.  
  408. int FillBitBuffer(bits)
  409. register int bits;
  410. {
  411.     /* get the bits that are left and read the next word */
  412.     unsigned temp;
  413.         register int result = bitbuf;
  414.     int sbits = bits_left;
  415.     bits -= bits_left;
  416.  
  417.     /* read next word of input */
  418.     bits_left = ReadByte(&bitbuf);
  419.     bits_left += ReadByte(&temp);
  420.     bitbuf |= (temp << 8);
  421.     if (bits_left == 0)
  422.         zipeof = 1;
  423.  
  424.     /* get the remaining bits */
  425.         result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
  426.         bitbuf >>= bits;
  427.         bits_left -= bits;
  428.         return result;
  429. }
  430.  
  431. #define READBIT(nbits,zdest,ztype) \
  432.     { if (nbits <= bits_left) \
  433.         { zdest = ztype(bitbuf & mask_bits[nbits]);\
  434.         bitbuf >>= nbits; bits_left -= nbits; }\
  435.     else zdest = ztype(FillBitBuffer(nbits));}
  436.  
  437. /*
  438.  * macro READBIT(nbits,zdest,ztype)
  439.  *  {
  440.  *      if (nbits <= bits_left) {
  441.  *          zdest = ztype(bitbuf & mask_bits[nbits]);
  442.  *          bitbuf >>= nbits;
  443.  *          bits_left -= nbits;
  444.  *      } else
  445.  *          zdest = ztype(FillBitBuffer(nbits));
  446.  *  }
  447.  *
  448.  */
  449.  
  450.  
  451. /* ------------------------------------------------------------- */
  452.  
  453. void Write_file()
  454. {
  455.     if (extract)
  456.         write(outfd, outbuf, outcnt);
  457. }
  458.  
  459. /* ------------------------------------------------------------- */
  460.  
  461. void FlushOutput()
  462.  /* flush contents of output buffer */
  463. {
  464.     UpdateCRC(outbuf, outcnt);
  465.     Write_file();
  466.     outpos += outcnt;
  467.     outcnt = 0;
  468.     outptr = outbuf;
  469. }
  470.  
  471. #define OUTB(intc) { *outptr++=intc; if (++outcnt==OUTBUFSIZ) FlushOutput(); }
  472.  
  473. /*
  474.  *  macro OUTB(intc)
  475.  *  {
  476.  *      *outptr++=intc;
  477.  *      if (++outcnt==OUTBUFSIZ)
  478.  *          FlushOutput();
  479.  *  }
  480.  *
  481.  */
  482.  
  483.  
  484. /* ----------------------------------------------------------- */
  485.  
  486. void LoadFollowers()
  487. {
  488.         register int x;
  489.         register int i;
  490.  
  491.     for (x = 255; x >= 0; x--) {
  492.                 READBIT(6,Slen[x],(byte));
  493.         for (i = 0; i < Slen[x]; i++) {
  494.                         READBIT(8,followers[x][i],(byte));
  495.         }
  496.     }
  497. }
  498.  
  499. /* ----------------------------------------------------------- */
  500. /*
  501.  * The Reducing algorithm is actually a combination of two
  502.  * distinct algorithms.  The first algorithm compresses repeated
  503.  * byte sequences, and the second algorithm takes the compressed
  504.  * stream from the first algorithm and applies a probabilistic
  505.  * compression method.
  506.  */
  507.  
  508. int L_table[] = {0, 0x7f, 0x3f, 0x1f, 0x0f};
  509.  
  510. int D_shift[] = {0, 0x07, 0x06, 0x05, 0x04};
  511. int D_mask[]  = {0, 0x01, 0x03, 0x07, 0x0f};
  512.  
  513. int B_table[] = {8, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5,
  514.          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
  515.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  516.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
  517.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  518.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  519.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  520.          7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  521.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  522.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  523.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  524.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  525.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  526.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  527.          8, 8, 8, 8};
  528.  
  529. /* ----------------------------------------------------------- */
  530.  
  531. void unReduce()
  532.  /* expand probablisticly reduced data */
  533. {
  534.         register int lchar;
  535.         int nchar;
  536.         int ExState;
  537.         int V;
  538.         int Len;
  539.  
  540.         factor = lrec.compression_method - 1;
  541.     ExState = 0;
  542.     lchar = 0;
  543.     LoadFollowers();
  544.  
  545.         while (((outpos + outcnt) < lrec.uncompressed_size) && (!zipeof)) {
  546.         if (Slen[lchar] == 0)
  547.                         READBIT(8,nchar,(int))      /* ; */
  548.                 else
  549.         {
  550.                         READBIT(1,nchar,(int));
  551.                         if (nchar != 0)
  552.                                 READBIT(8,nchar,(int))      /* ; */
  553.                         else
  554.             {
  555.                                 int follower;
  556.                                 int bitsneeded = B_table[Slen[lchar]];
  557.                                 READBIT(bitsneeded,follower,(int));
  558.                                 nchar = followers[lchar][follower];
  559.             }
  560.         }
  561.  
  562.         /* expand the resulting byte */
  563.         switch (ExState) {
  564.  
  565.         case 0:
  566.                         if (nchar != DLE)
  567.                                 OUTB(nchar) /*;*/
  568.             else
  569.                 ExState = 1;
  570.             break;
  571.  
  572.         case 1:
  573.                         if (nchar != 0) {
  574.                                 V = nchar;
  575.                 Len = V & L_table[factor];
  576.                 if (Len == L_table[factor])
  577.                     ExState = 2;
  578.                 else
  579.                     ExState = 3;
  580.             }
  581.             else {
  582.                                 OUTB(DLE);
  583.                 ExState = 0;
  584.             }
  585.             break;
  586.  
  587.                 case 2: {
  588.                                 Len += nchar;
  589.                 ExState = 3;
  590.             }
  591.             break;
  592.  
  593.                 case 3: {
  594.                 register int i = Len + 3;
  595.                 int offset = (((V >> D_shift[factor]) &
  596.                                           D_mask[factor]) << 8) + nchar + 1;
  597.                 longint op = outpos + outcnt - offset;
  598.  
  599.                 /* special case- before start of file */
  600.                 while ((op < 0L) && (i > 0)) {
  601.                     OUTB(0);
  602.                     op++;
  603.                     i--;
  604.                 }
  605.  
  606.                 /* normal copy of data from output buffer */
  607.                 {
  608.                     register int ix = (int) (op % OUTBUFSIZ);
  609.  
  610.                                         /* do a block memory copy if possible */
  611.                                         if ( ((ix    +i) < OUTBUFSIZ) &&
  612.                                              ((outcnt+i) < OUTBUFSIZ) ) {
  613.                                                 memcpy(outptr,&outbuf[ix],i);
  614.                                                 outptr += i;
  615.                                                 outcnt += i;
  616.                                         }
  617.  
  618.                                         /* otherwise copy byte by byte */
  619.                                         else while (i--) {
  620.                                                 OUTB(outbuf[ix]);
  621.                                                 if (++ix >= OUTBUFSIZ)
  622.                                                         ix = 0;
  623.                                         }
  624.                                 }
  625.  
  626.                 ExState = 0;
  627.             }
  628.             break;
  629.         }
  630.  
  631.                 /* store character for next iteration */
  632.                 lchar = nchar;
  633.         }
  634. }
  635.  
  636.  
  637. /* ------------------------------------------------------------- */
  638. /*
  639.  * Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
  640.  * with partial clearing.
  641.  *
  642.  */
  643.  
  644. void partial_clear()
  645. {
  646.         register int pr;
  647.         register int cd;
  648.  
  649.     /* mark all nodes as potentially unused */
  650.     for (cd = first_ent; cd < free_ent; cd++)
  651.         prefix_of[cd] |= 0x8000;
  652.  
  653.     /* unmark those that are used by other nodes */
  654.     for (cd = first_ent; cd < free_ent; cd++) {
  655.         pr = prefix_of[cd] & 0x7fff;    /* reference to another node? */
  656.                 if (pr >= first_ent)            /* flag node as referenced */
  657.             prefix_of[pr] &= 0x7fff;
  658.     }
  659.  
  660.     /* clear the ones that are still marked */
  661.     for (cd = first_ent; cd < free_ent; cd++)
  662.         if ((prefix_of[cd] & 0x8000) != 0)
  663.             prefix_of[cd] = -1;
  664.  
  665.     /* find first cleared node as next free_ent */
  666.         cd = first_ent;
  667.         while ((cd < maxcodemax) && (prefix_of[cd] != -1))
  668.                 cd++;
  669.         free_ent = cd;
  670. }
  671.  
  672.  
  673. /* ------------------------------------------------------------- */
  674.  
  675. void unShrink()
  676. {
  677. #define  GetCode(dest) READBIT(codesize,dest,(int))
  678.  
  679.     register int code;
  680.     register int stackp;
  681.     int finchar;
  682.     int oldcode;
  683.     int incode;
  684.  
  685.  
  686.     /* decompress the file */
  687.     maxcodemax = 1 << max_bits;
  688.     codesize = init_bits;
  689.     maxcode = (1 << codesize) - 1;
  690.     free_ent = first_ent;
  691.     offset = 0;
  692.     sizex = 0;
  693.  
  694.     for (code = maxcodemax; code > 255; code--)
  695.         prefix_of[code] = -1;
  696.  
  697.     for (code = 255; code >= 0; code--) {
  698.         prefix_of[code] = 0;
  699.         suffix_of[code] = code;
  700.     }
  701.  
  702.     GetCode(oldcode);
  703.     if (zipeof)
  704.         return;
  705.     finchar = oldcode;
  706.  
  707.         OUTB(finchar);
  708.  
  709.         stackp = hsize;
  710.  
  711.     while (!zipeof) {
  712.         GetCode(code);
  713.         if (zipeof)
  714.             return;
  715.  
  716.         while (code == clear) {
  717.             GetCode(code);
  718.             switch (code) {
  719.  
  720.             case 1:{
  721.                     codesize++;
  722.                     if (codesize == max_bits)
  723.                         maxcode = maxcodemax;
  724.                     else
  725.                         maxcode = (1 << codesize) - 1;
  726.                 }
  727.                 break;
  728.  
  729.             case 2:
  730.                 partial_clear();
  731.                 break;
  732.             }
  733.  
  734.             GetCode(code);
  735.             if (zipeof)
  736.                 return;
  737.         }
  738.  
  739.  
  740.         /* special case for KwKwK string */
  741.         incode = code;
  742.         if (prefix_of[code] == -1) {
  743.                         stack[--stackp] = finchar;
  744.             code = oldcode;
  745.         }
  746.  
  747.  
  748.         /* generate output characters in reverse order */
  749.         while (code >= first_ent) {
  750.                         stack[--stackp] = suffix_of[code];
  751.             code = prefix_of[code];
  752.         }
  753.  
  754.         finchar = suffix_of[code];
  755.                 stack[--stackp] = finchar;
  756.  
  757.  
  758.                 /* and put them out in forward order, block copy */
  759.                 if ((hsize-stackp+outcnt) < OUTBUFSIZ) {
  760.                         memcpy(outptr,&stack[stackp],hsize-stackp);
  761.                         outptr += hsize-stackp;
  762.                         outcnt += hsize-stackp;
  763.                         stackp = hsize;
  764.                 }
  765.  
  766.                 /* output byte by byte if we can't go by blocks */
  767.                 else while (stackp < hsize)
  768.                         OUTB(stack[stackp++]);
  769.  
  770.  
  771.         /* generate new entry */
  772.         code = free_ent;
  773.         if (code < maxcodemax) {
  774.             prefix_of[code] = oldcode;
  775.             suffix_of[code] = finchar;
  776.  
  777.             do
  778.                 code++;
  779.             while ((code < maxcodemax) && (prefix_of[code] != -1));
  780.  
  781.             free_ent = code;
  782.         }
  783.  
  784.         /* remember previous code */
  785.         oldcode = incode;
  786.     }
  787.  
  788. }
  789.  
  790. /* ------------------------------------------------------------- */ 
  791. /*
  792.  * Imploding
  793.  * ---------
  794.  *
  795.  * The Imploding algorithm is actually a combination of two distinct
  796.  * algorithms.  The first algorithm compresses repeated byte sequences
  797.  * using a sliding dictionary.  The second algorithm is used to compress
  798.  * the encoding of the sliding dictionary ouput, using multiple
  799.  * Shannon-Fano trees.
  800.  *
  801.  */ 
  802.  
  803. #define maxSF 256
  804.  
  805.    typedef struct sf_entry { 
  806.                  word         Code; 
  807.                  byte         Value; 
  808.                  byte         BitLength; 
  809.               } sf_entry; 
  810.  
  811.    typedef struct sf_tree {   /* a shannon-fano tree */ 
  812.       sf_entry     entry[maxSF];
  813.       int          entries;
  814.       int          MaxLength;
  815.    } sf_tree; 
  816.  
  817.    typedef sf_tree      *sf_treep; 
  818.  
  819.    sf_tree      lit_tree; 
  820.    sf_tree      length_tree; 
  821.    sf_tree      distance_tree; 
  822.    boolean      lit_tree_present; 
  823.    boolean      eightK_dictionary; 
  824.    int          minimum_match_length;
  825.    int          dict_bits;
  826.  
  827.  
  828. void SortLengths(tree)
  829. sf_tree *tree;
  830.   /* Sort the Bit Lengths in ascending order, while retaining the order
  831.     of the original lengths stored in the file */ 
  832.    int          x;
  833.    int          gap;
  834.    sf_entry     t; 
  835.    boolean      noswaps;
  836.    int          a, b;
  837.  
  838.    gap = tree->entries / 2; 
  839.  
  840.    do { 
  841.       do { 
  842.          noswaps = 1;
  843.          for (x = 0; x <= (tree->entries - 1) - gap; x++) 
  844.          { 
  845.             a = tree->entry[x].BitLength; 
  846.             b = tree->entry[x + gap].BitLength; 
  847.             if ((a > b) || ((a == b) && (tree->entry[x].Value > tree->entry[x + gap].Value))) 
  848.             { 
  849.                t = tree->entry[x]; 
  850.                tree->entry[x] = tree->entry[x + gap]; 
  851.                tree->entry[x + gap] = t; 
  852.                noswaps = 0;
  853.             } 
  854.          } 
  855.       }  while (!noswaps);
  856.  
  857.       gap = gap / 2; 
  858.    }  while (gap > 0);
  859.  
  860.  
  861. /* ----------------------------------------------------------- */ 
  862.  
  863. void ReadLengths(tree)
  864. sf_tree *tree;
  865.    int          treeBytes;
  866.    int          i;
  867.    int          num, len;
  868.  
  869.   /* get number of bytes in compressed tree */
  870.    READBIT(8,treeBytes,(int));
  871.    treeBytes++; 
  872.    i = 0; 
  873.  
  874.    tree->MaxLength = 0;
  875.  
  876.  /* High 4 bits: Number of values at this bit length + 1. (1 - 16)
  877.     Low  4 bits: Bit Length needed to represent value + 1. (1 - 16) */
  878.    while (treeBytes > 0)
  879.    {
  880.       READBIT(4,len,(int)); len++;
  881.       READBIT(4,num,(int)); num++;
  882.  
  883.       while (num > 0)
  884.       {
  885.          if (len > tree->MaxLength)
  886.             tree->MaxLength = len;
  887.          tree->entry[i].BitLength = (byte) len;
  888.          tree->entry[i].Value = (byte) i;
  889.          i++;
  890.          num--;
  891.       }
  892.  
  893.       treeBytes--;
  894.    } 
  895.  
  896.  
  897. /* ----------------------------------------------------------- */ 
  898.  
  899. void GenerateTrees(tree)
  900. sf_tree *tree;
  901.      /* Generate the Shannon-Fano trees */ 
  902.    word         Code;
  903.    int          CodeIncrement;
  904.    int          LastBitLength;
  905.    int          i;
  906.  
  907.  
  908.    Code = 0;
  909.    CodeIncrement = 0; 
  910.    LastBitLength = 0; 
  911.  
  912.    i = tree->entries - 1;   /* either 255 or 63 */ 
  913.    while (i >= 0) 
  914.    { 
  915.       Code += CodeIncrement; 
  916.       if (tree->entry[i].BitLength != (byte) LastBitLength) 
  917.       { 
  918.          LastBitLength = tree->entry[i].BitLength; 
  919.          CodeIncrement = 1 << (16 - LastBitLength); 
  920.       } 
  921.  
  922.       tree->entry[i].Code = Code; 
  923.       i--; 
  924.    } 
  925.  
  926.  
  927. /* ----------------------------------------------------------- */ 
  928.  
  929. void ReverseBits(tree)
  930. sf_tree *tree;
  931.  /* Reverse the order of all the bits in the above ShannonCode[]
  932.     vector, so that the most significant bit becomes the least
  933.     significant bit. For example, the value 0x1234 (hex) would become
  934.     0x2C48 (hex). */ 
  935.    int          i;
  936.    word         mask;
  937.    word         revb;
  938.    word         v;
  939.    word         o;
  940.    int          b;
  941.  
  942.  
  943.    for (i = 0; i <= tree->entries - 1; i++) 
  944.    { 
  945.         /* get original code */ 
  946.       o = tree->entry[i].Code; 
  947.  
  948.         /* reverse each bit */ 
  949.       mask = 0x0001;
  950.       revb = 0x8000;
  951.       v = 0;
  952.       for (b = 0; b <= 15; b++) 
  953.       { 
  954.            /* if bit set in mask, then substitute reversed bit */ 
  955.          if ((o & mask) != 0) 
  956.             v = v | revb; 
  957.  
  958.            /* advance to next bit */ 
  959.          revb = (revb >> 1);
  960.          mask = (mask << 1);
  961.       } 
  962.  
  963.         /* store reversed bits */ 
  964.       tree->entry[i].Code = v; 
  965.    } 
  966.  
  967.  
  968. /* ----------------------------------------------------------- */ 
  969.  
  970. void LoadTree(tree, treesize)
  971. sf_tree *tree;
  972. int treesize;
  973.      /* allocate and load a shannon-fano tree from the compressed file */ 
  974.    tree->entries = treesize; 
  975.    ReadLengths(tree); 
  976.    SortLengths(tree); 
  977.    GenerateTrees(tree); 
  978.    ReverseBits(tree); 
  979.  
  980.  
  981. /* ----------------------------------------------------------- */ 
  982.  
  983. void LoadTrees()
  984.    /* bit 1... */
  985.    eightK_dictionary = (boolean) ((lrec.general_purpose_bit_flag & 0x02) != 0);
  986.    /* bit 2... */
  987.    lit_tree_present = (boolean) ((lrec.general_purpose_bit_flag & 0x04) != 0);
  988.  
  989.    if (eightK_dictionary) 
  990.       dict_bits = 7;
  991.    else 
  992.       dict_bits = 6; 
  993.  
  994.    if (lit_tree_present) 
  995.    { 
  996.       minimum_match_length = 3; 
  997.       LoadTree(&lit_tree,256); 
  998.    } 
  999.    else 
  1000.       minimum_match_length = 2; 
  1001.  
  1002.    LoadTree(&length_tree,64); 
  1003.    LoadTree(&distance_tree,64); 
  1004.  
  1005.  
  1006. /* ----------------------------------------------------------- */ 
  1007.  
  1008. void ReadTree(tree, dest)
  1009. sf_tree *tree;
  1010. int *dest;
  1011.      /* read next byte using a shannon-fano tree */ 
  1012.    int          bits = 0;
  1013.    word         cv = 0;
  1014.    int          cur = 0;
  1015.    int          b;
  1016.  
  1017.    *dest = -1;   /* in case of error */ 
  1018.  
  1019.    for (;;)
  1020.    { 
  1021.       READBIT(1,b,(int));
  1022.       cv = cv | (b << bits);
  1023.       bits++; 
  1024.  
  1025.       /* this is a very poor way of decoding shannon-fano.  two quicker
  1026.          methods come to mind:
  1027.             a) arrange the tree as a huffman-style binary tree with
  1028.                a "leaf" indicator at each node,
  1029.          and
  1030.             b) take advantage of the fact that s-f codes are at most 8
  1031.                bits long and alias unused codes for all bits following
  1032.                the "leaf" bit.
  1033.       */
  1034.  
  1035.       while (tree->entry[cur].BitLength < (byte) bits) 
  1036.       { 
  1037.          cur++; 
  1038.          if (cur >= tree->entries) 
  1039.             return; /* data error */
  1040.       } 
  1041.  
  1042.       while (tree->entry[cur].BitLength == (byte) bits) 
  1043.       { 
  1044.          if (tree->entry[cur].Code == cv) 
  1045.          { 
  1046.             *dest = tree->entry[cur].Value; 
  1047.             return; 
  1048.          } 
  1049.  
  1050.          cur++; 
  1051.          if (cur >= tree->entries) 
  1052.             return; /* data error */
  1053.       } 
  1054.    } 
  1055.  
  1056.  
  1057. /* ----------------------------------------------------------- */ 
  1058.  
  1059. void unImplode()
  1060.      /* expand imploded data */ 
  1061.  
  1062.    int          lout;
  1063.    longint      op;
  1064.    int          Length;
  1065.    int          Distance;
  1066.  
  1067.    LoadTrees(); 
  1068.  
  1069.    while ((!zipeof) && ((outpos+outcnt) < lrec.uncompressed_size))
  1070.    { 
  1071.       READBIT(1,lout,(int));
  1072.  
  1073.       if (lout != 0)   /* encoded data is literal data */ 
  1074.       { 
  1075.          if (lit_tree_present)  /* use Literal Shannon-Fano tree */
  1076.             ReadTree(&lit_tree,&lout);
  1077.          else 
  1078.             READBIT(8,lout,(int));
  1079.  
  1080.          OUTB((byte) lout);
  1081.       } 
  1082.       else             /* encoded data is sliding dictionary match */
  1083.       {                
  1084.          READBIT(dict_bits,lout,(int));
  1085.          Distance = lout; 
  1086.  
  1087.          ReadTree(&distance_tree,&lout); 
  1088.          Distance |= (lout << dict_bits);
  1089.          /* using the Distance Shannon-Fano tree, read and decode the
  1090.             upper 6 bits of the Distance value */ 
  1091.  
  1092.          ReadTree(&length_tree,&Length); 
  1093.          /* using the Length Shannon-Fano tree, read and decode the
  1094.             Length value */
  1095.  
  1096.          Length += minimum_match_length; 
  1097.          if (Length == (63 + minimum_match_length)) 
  1098.          { 
  1099.             READBIT(8,lout,(int));
  1100.             Length += lout; 
  1101.          } 
  1102.  
  1103.         /* move backwards Distance+1 bytes in the output stream, and copy
  1104.           Length characters from this position to the output stream.
  1105.           (if this position is before the start of the output stream,
  1106.           then assume that all the data before the start of the output
  1107.           stream is filled with zeros) */ 
  1108.  
  1109.          op = (outpos+outcnt) - Distance - 1L;
  1110.  
  1111.           /* special case- before start of file */
  1112.           while ((op < 0L) && (Length > 0)) {
  1113.                   OUTB(0);
  1114.                   op++;
  1115.                   Length--;
  1116.           }
  1117.  
  1118.           /* normal copy of data from output buffer */
  1119.           {
  1120.                   register int ix = (int) (op % OUTBUFSIZ);
  1121.  
  1122.                   /* do a block memory copy if possible */
  1123.                   if ( ((ix    +Length) < OUTBUFSIZ) &&
  1124.                        ((outcnt+Length) < OUTBUFSIZ) ) {
  1125.                           memcpy(outptr,&outbuf[ix],Length);
  1126.                           outptr += Length;
  1127.                           outcnt += Length;
  1128.                   }
  1129.  
  1130.                   /* otherwise copy byte by byte */
  1131.                   else while (Length--) {
  1132.                           OUTB(outbuf[ix]);
  1133.                           if (++ix >= OUTBUFSIZ)
  1134.                                   ix = 0;
  1135.                   }
  1136.          }
  1137.       } 
  1138.    } 
  1139.  
  1140. /* ---------------------------------------------------------- */
  1141.  
  1142. void extract_member()
  1143. {
  1144.     unsigned b;
  1145.  
  1146.     bits_left = 0;
  1147.     bitbuf = 0;
  1148.     incnt = 0;
  1149.     outpos = 0L;
  1150.     outcnt = 0;
  1151.     outptr = outbuf;
  1152.     zipeof = 0;
  1153.     crc32val = 0xFFFFFFFFL;
  1154.  
  1155.  
  1156.     /* create the output file with READ and WRITE permissions */
  1157.     if (create_output_file())
  1158.         exit(1);
  1159.  
  1160.         switch (lrec.compression_method) {
  1161.  
  1162.     case 0:        /* stored */
  1163.         {
  1164.             if (test_zip)
  1165.                 printf("Testing: %-12s ", filename);
  1166.             if (extract)
  1167.                 printf(" Extracting: %-12s ", filename);
  1168.             while (ReadByte(&b))
  1169.                 OUTB(b);
  1170.         }
  1171.         break;
  1172.  
  1173.         case 1: {    /* shrunk */
  1174.             if (test_zip)
  1175.                 printf("Testing: %-12s ", filename);
  1176.             if (extract)
  1177.                 printf("UnShrinking: %-12s ", filename);
  1178.             unShrink();
  1179.         }
  1180.         break;
  1181.  
  1182.     case 2:        /* reduced, factor:1 */
  1183.     case 3:        /* reduced, factor:2 */
  1184.     case 4:        /* reduced, factor:3 */
  1185.         case 5: {    /* reduced, factor:4 */
  1186.             if (test_zip)
  1187.                 printf("Testing: %-12s ", filename);
  1188.             if (extract)
  1189.                 printf("  Expanding: %-12s ", filename);
  1190.             unReduce();
  1191.         }
  1192.         break;
  1193.  
  1194.     case 6: {    /* imploded */
  1195.             if (test_zip)
  1196.                 printf("Testing: %-12s ", filename);
  1197.             if (extract)
  1198.                 printf("  Exploding: %-12s ", filename);
  1199.             unImplode();
  1200.         }
  1201.         break;
  1202.  
  1203.  
  1204.     default:
  1205.         printf("Unknown compression method.");
  1206.     }
  1207.  
  1208.  
  1209.     /* write the last partial buffer, if any */
  1210.     if (outcnt > 0) {
  1211.         UpdateCRC(outbuf, outcnt);
  1212.         Write_file();
  1213.     }
  1214.  
  1215.     /* set output file date and time */
  1216.     set_file_time();
  1217.  
  1218.     close(outfd);
  1219.  
  1220.     crc32val = -1 - crc32val;
  1221.     if (!list_zip) {
  1222.       if (crc32val != lrec.crc32) {
  1223.         numbad++;
  1224.         printf(" Bad");
  1225.         if(verbose)
  1226.         printf(", CRC %08lx  (should be %08lx)", lrec.crc32, crc32val);
  1227.       } else {
  1228.         printf(" Ok");
  1229.         if (verbose)
  1230.         printf(", CRC = %08lx", lrec.crc32);
  1231.       }
  1232.     printf("\n");
  1233.     }
  1234. }
  1235.  
  1236.  
  1237. /* ---------------------------------------------------------- */
  1238.  
  1239. void get_string(len, s)
  1240. int len;
  1241. char *s;
  1242. {
  1243.     read(zipfd, s, len);
  1244.     s[len] = 0;
  1245. }
  1246.  
  1247. /* UNIX support routines: Michael Enkelis */
  1248. get_byte()
  1249. {
  1250.     byte nibble;
  1251.     read(zipfd,&nibble,1);
  1252.     return (byte) (nibble & 0xff);
  1253. }
  1254.  
  1255. get_word()
  1256. {
  1257.     byte nibble[2];
  1258.         nibble[0] = get_byte();
  1259.         nibble[1] = get_byte();
  1260.     return (word) (nibble[0] | nibble[1] << 8);
  1261. }
  1262.  
  1263. get_long()
  1264. {
  1265.     byte nibble[4];
  1266.         nibble[0] = get_byte();
  1267.         nibble[1] = get_byte();
  1268.         nibble[2] = get_byte();
  1269.         nibble[3] = get_byte();
  1270.     return (longint)    ((unsigned long) nibble[0] |
  1271.             ((unsigned long) nibble[1] << 8)  |
  1272.             ((unsigned long) nibble[2] << 16) |
  1273.             ((unsigned long) nibble[3] << 24));
  1274. }
  1275. /** End of added support routines **/
  1276.  
  1277.  
  1278. /* ---------------------------------------------------------- */
  1279.  
  1280. void process_local_file_header()
  1281. {
  1282.     byte    Temp;
  1283.     byte    yr, mo, dy;    /* parts of a date */
  1284.     byte    hh, mm, ss;    /* parts of a time */
  1285.  
  1286.     static char    *mon[] =    /* month abbreviations */
  1287.     {
  1288.      "Jan", "Feb", "Mar", "Apr",
  1289.      "May", "Jun", "Jul", "Aug",
  1290.      "Sep", "Oct", "Nov", "Dec"
  1291.     };
  1292.  
  1293.     lrec.version_needed_to_extract = get_word();
  1294.     lrec.general_purpose_bit_flag = get_word();
  1295.     lrec.compression_method = get_word();
  1296.     lrec.last_mod_file_time = get_word();
  1297.     lrec.last_mod_file_date = get_word();
  1298.     lrec.crc32 = get_long();
  1299.     lrec.compressed_size = get_long();
  1300.     lrec.uncompressed_size = get_long();
  1301.     lrec.filename_length = get_word();
  1302.     lrec.extra_field_length = get_word();
  1303.  
  1304.     get_string(lrec.filename_length,filename);
  1305.     if (unixfy) {
  1306.         char *cp;
  1307.         for (cp = filename; *cp; ++cp)
  1308.             if (isupper(*cp)) *cp = tolower(*cp);
  1309.     }
  1310.  
  1311.     get_string(lrec.extra_field_length,extra);
  1312.  
  1313.     yr = (lrec.last_mod_file_date >> 9) & 0x7f;    /* dissect the date */
  1314.     mo = (lrec.last_mod_file_date >> 5) & 0x0f;
  1315.     dy = lrec.last_mod_file_date & 0x1f;
  1316.  
  1317.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;    /* dissect the time */
  1318.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  1319.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  1320.  
  1321.     if (debugging) {
  1322.     printf("\n\nProcess LOCAL file header.\n");
  1323.     Temp = lrec.version_needed_to_extract;
  1324.     printf("Version used    : %d.%d\n",Temp/10,Temp%10);
  1325.     printf("Bit flags    : ");
  1326.     Temp = (lrec.general_purpose_bit_flag & 3);
  1327.     if (Temp & 1)
  1328.         printf("Encrypted\n");
  1329.     if (lrec.compression_method == 6) {
  1330.         printf("%dK sliding dictionary, ", (Temp & 2)? 8 : 4);
  1331.         printf("%d Shannon-Fano trees", (Temp & 4)? 3 : 2);
  1332.     }
  1333.     printf("\n");
  1334.  
  1335.     printf("Compression     : %d\n",lrec.compression_method);
  1336.     printf("Mod time    :");
  1337.         printf("%2d:%02d%cm\n",
  1338.                (hh > 12 ? hh - 12 : hh), mm, (hh > 11 ? 'p' : 'a'));
  1339.     printf("Mod date    :");
  1340.         printf("%2d %3s %02d\n", dy, mon[mo - 1], (yr + 80) % 100);
  1341.     printf("Crc32        : %d\n",~lrec.crc32);
  1342.     printf("Compressed size    : %d\n",lrec.compressed_size);
  1343.     printf("Normal file size: %d\n",lrec.uncompressed_size);
  1344.     printf("File name    : %s.%s\n",filename,extra);
  1345.     }
  1346.  
  1347.     extract_member();
  1348. }
  1349.  
  1350.  
  1351. /* ---------------------------------------------------------- */
  1352.  
  1353. void process_central_file_header()
  1354. {
  1355.     central_directory_file_header rec;
  1356.     char filename[STRSIZ];
  1357.     char extra[STRSIZ];
  1358.  
  1359.     byte    Temp;
  1360.     byte    yr, mo, dy;    /* parts of a date */
  1361.     byte    hh, mm, ss;    /* parts of a time */
  1362.  
  1363.     static char    *mon[] =    /* month abbreviations */
  1364.     {
  1365.      "Jan", "Feb", "Mar", "Apr",
  1366.      "May", "Jun", "Jul", "Aug",
  1367.      "Sep", "Oct", "Nov", "Dec"
  1368.     };
  1369.  
  1370.     rec.version_made_by = get_word();
  1371.     rec.version_needed_to_extract = get_word();
  1372.     rec.general_purpose_bit_flag = get_word();
  1373.     rec.compression_method = get_word();
  1374.     rec.last_mod_file_time = get_word();
  1375.     rec.last_mod_file_date = get_word();
  1376.     rec.crc32 = get_long();
  1377.     rec.compressed_size = get_long();
  1378.     rec.uncompressed_size = get_long();
  1379.     rec.filename_length = get_word();
  1380.     rec.extra_field_length = get_word();
  1381.     rec.file_comment_length = get_word();
  1382.     rec.disk_number_start = get_word();
  1383.     rec.internal_file_attributes = get_word();
  1384.     rec.external_file_attributes = get_long();
  1385.     rec.relative_offset_local_header = get_long();
  1386.  
  1387.     get_string(rec.filename_length,filename); 
  1388.     if (unixfy) {
  1389.         char *cp;
  1390.         for (cp = filename; *cp; ++cp)
  1391.             if (isupper(*cp)) *cp = tolower(*cp);
  1392.     }
  1393.  
  1394.     get_string(rec.extra_field_length,extra); 
  1395.     comment = (byte *) (realloc(comment, rec.file_comment_length));
  1396.     get_string(rec.file_comment_length,comment); 
  1397.  
  1398.     yr = (rec.last_mod_file_date >> 9) & 0x7f;    /* dissect the date */
  1399.     mo = (rec.last_mod_file_date >> 5) & 0x0f;
  1400.     dy = rec.last_mod_file_date & 0x1f;
  1401.  
  1402.     hh = (rec.last_mod_file_time >> 11) & 0x1f;    /* dissect the time */
  1403.     mm = (rec.last_mod_file_time >> 5) & 0x3f;
  1404.     ss = (rec.last_mod_file_time & 0x1f) * 2;
  1405.  
  1406.     if (debugging) {
  1407.     printf("\n\nProcess CENTRAL file header.\n");
  1408.     printf("Version made by : ");
  1409.     Temp = rec.version_made_by;
  1410.     switch ((Temp >> 8) & 7) {
  1411.         case 0:    printf("MS-DOS");break;
  1412.         case 1:    printf("Amiga");break;
  1413.         case 2:    printf("VMS");break;
  1414.         case 3:    printf("Unix");break;
  1415.         case 4:    printf("VM/CMS");break;
  1416.         case 5:    printf("Atari");break;
  1417.         case 6:    printf("OS/2");break;
  1418.         case 7:    printf("Macintosh");break;
  1419.         default:
  1420.             printf("Unknown");
  1421.     }
  1422.     printf(" Version %d.%d\n",(Temp & 255)/10,(Temp & 255) % 10);
  1423.  
  1424.     printf("Ver to extract    : %d\n",rec.version_needed_to_extract);
  1425.     printf("Bit flags    : ");
  1426.     Temp = (rec.general_purpose_bit_flag & 3);
  1427.     if (Temp & 1)
  1428.         printf("Encrypted\n");
  1429.     if (rec.compression_method == 6) {
  1430.         printf("%dK sliding dictionary, ", (Temp & 2)? 8 : 4);
  1431.         printf("%d Shannon-Fano trees", (Temp & 4)? 3 : 2);
  1432.     }
  1433.     printf("\n");
  1434.  
  1435.     printf("Compression     : %d\n",rec.compression_method);
  1436.     printf("Mod time    :");
  1437.         printf("%2d:%02d%cm\n",
  1438.                (hh > 12 ? hh - 12 : hh), mm, (hh > 11 ? 'p' : 'a'));
  1439.     printf("Mod date    :");
  1440.         printf("%2d %3s %02d\n", dy, mon[mo - 1], (yr + 80) % 100);
  1441.     printf("Crc32        : %d\n",~rec.crc32);
  1442.     printf("Compressed size    : %d\n",rec.compressed_size);
  1443.     printf("Normal file size: %d\n",rec.uncompressed_size);
  1444.     printf("File name    : %s.%s\n",filename,extra);
  1445.     printf("Comment size    : %d\n",rec.file_comment_length);
  1446.     printf("Disk start #    : %d\n",rec.disk_number_start);
  1447.     printf("File attributes : %d\n",rec.internal_file_attributes);
  1448.     printf("Os attributes   : %d\n",rec.external_file_attributes);
  1449.     printf("Offset to header: %d\n",rec.relative_offset_local_header);
  1450.     printf("Comment         : %s\n",comment); 
  1451.     }
  1452.  
  1453.     if (list_zip) {
  1454.     Total_files++;
  1455.     Total_bytes += rec.uncompressed_size;
  1456.     Total_length += rec.compressed_size;
  1457.  
  1458.     printf("%-12s  %8d  ", filename,rec.uncompressed_size);
  1459.     if (verbose) {
  1460.         printf("%8d  ",rec.compressed_size);
  1461.         if (rec.compressed_size)
  1462.             printf("%3d%%  ",100L - (100L * rec.compressed_size)/
  1463.                 rec.uncompressed_size);
  1464.         else
  1465.             printf("---   ");
  1466.     }
  1467.  
  1468.     printf("%2d %3s %02d", dy, mon[mo - 1], (yr + 80) % 100);
  1469.  
  1470.     if (verbose)
  1471.         printf("  %2d:%02d%cm",
  1472.                (hh > 12 ? hh - 12 : hh), mm, (hh > 11 ? 'p' : 'a'));
  1473.     printf("\n");
  1474.     }
  1475.  
  1476. }
  1477.  
  1478.  
  1479. /* ---------------------------------------------------------- */
  1480.  
  1481. void process_end_central_dir()
  1482. {
  1483.     end_central_dir_record rec;
  1484.  
  1485.     rec.number_this_disk = get_word();
  1486.     rec.number_disk_with_start_central_directory = get_word();
  1487.     rec.total_entries_central_dir_on_this_disk = get_word();
  1488.     rec.total_entries_central_dir = get_word();
  1489.     rec.size_central_directory = get_long(); 
  1490.     rec.offset_start_central_directory = get_long();
  1491.     rec.zipfile_comment_length = get_word();
  1492.  
  1493.     comment = (byte *) (realloc(comment, rec.zipfile_comment_length));
  1494.     get_string(rec.zipfile_comment_length,comment); 
  1495.  
  1496.     if (debugging) {
  1497.     printf("\n\nProcess END_CENTRAL directory header.\n");
  1498.     printf("This disk       : %d\n",rec.number_this_disk);
  1499.     printf("Starting disk    : %d\n",
  1500.         rec.number_disk_with_start_central_directory);
  1501.     printf("Total this disk    : %d\n",
  1502.         rec.total_entries_central_dir_on_this_disk);
  1503.     printf("Total entries    : %d\n",rec.total_entries_central_dir);
  1504.     printf("Central dir size: %d\n",rec.size_central_directory);
  1505.     printf("Offset to dir   : %d\n",rec.offset_start_central_directory);
  1506.     printf("Comment size    : %d\n",rec.zipfile_comment_length);
  1507.     printf("Comment         : %s\n",comment); 
  1508.     }
  1509. }
  1510.  
  1511.  
  1512. /* ---------------------------------------------------------- */
  1513.  
  1514. void process_headers()
  1515.     int i;
  1516.     char sig[4];
  1517.  
  1518.     if (list_zip) {
  1519.      if (verbose) {
  1520.      printf("\nName          Length    Size now   SF   Date       Time");
  1521.      printf("\n============  ========  ========  ====  =========  ========\n");
  1522.      } else {
  1523.      printf("\nName          Length    Date");
  1524.      printf("\n============  ========  =========\n");
  1525.      }
  1526.     }
  1527.  
  1528.     while (1)
  1529.     { 
  1530.     for (i=0; i<4; i++)        /* Read the ZIP file sig */
  1531.         sig[i] = get_byte();
  1532.  
  1533.     if (strncmp(sig,local_file_header_signature,4) == 0)
  1534.         process_local_file_header();
  1535.     else
  1536.     if (strncmp(sig,central_file_header_signature,4) == 0)
  1537.         process_central_file_header();
  1538.     else
  1539.     if (strncmp(sig,end_central_dir_signature,4) == 0)
  1540.         {
  1541.             process_end_central_dir(); 
  1542.             if (test_zip) {
  1543.              if (numbad < 1)
  1544.                 printf("No errors detected\n");
  1545.              else
  1546.              if (numbad == 1)
  1547.                 printf("One error detected\n");
  1548.              else
  1549.                 printf("%d errors detected\n",numbad);
  1550.             }
  1551.             if (list_zip) {
  1552.              if (verbose) {
  1553.               printf("        ====  ========  ========  ====  \n");
  1554.              printf("Total:  %4d  %8d  %8d  ",
  1555.                 Total_files,Total_bytes,Total_length);
  1556.              if (Total_length)
  1557.                 printf("%3d%%\n", 100 - (100 * Total_length)/
  1558.                     Total_bytes);
  1559.             else
  1560.                 printf("---\n");
  1561.              } else {
  1562.              printf("        ====  ========\n");
  1563.              printf("Total:  %4d  %8d\n",
  1564.                 Total_files,Total_bytes);
  1565.              }
  1566.             }
  1567.             if (strlen(comment) && dsp_comment)
  1568.                 printf("%s\n",comment); 
  1569.             return;
  1570.         } 
  1571.     else 
  1572.         { 
  1573.             printf("Invalid Zipfile Header\n"); 
  1574.             return;
  1575.         } 
  1576.     } 
  1577. }
  1578.  
  1579.  
  1580.  
  1581. /* ---------------------------------------------------------- */
  1582.  
  1583. void extract_zipfile()
  1584. {
  1585.     /*
  1586.      * open the zipfile for reading and in BINARY mode to prevent cr/lf
  1587.      * translation, which would corrupt the bitstreams 
  1588.      */
  1589.  
  1590.     if (open_input_file())
  1591.         exit(1);
  1592.  
  1593.     process_headers();
  1594.  
  1595.     close(zipfd);
  1596. }
  1597.  
  1598.  
  1599. /* ---------------------------------------------------------- */
  1600. /*
  1601.  * main program
  1602.  *
  1603.  */
  1604.  
  1605. void main(argc, argv)
  1606. int argc;
  1607. char **argv;
  1608. {
  1609.  
  1610. #ifdef USE_GETOPT
  1611.     int c;                /* next option letter */
  1612.     int count = 0;            /* count of required options seen */
  1613.  
  1614.     extern int optind;        /* from getopt: next arg to process */
  1615.     extern int opterr;        /* used by getopt */
  1616.     extern char *optarg;
  1617.  
  1618.     opterr = 0;            /* so getopt won't print err msg */
  1619.  
  1620.     while ((c = getopt (argc, argv, "cdltuv")) != EOF)
  1621.     {
  1622.     switch (c) {
  1623.         case 'c':    dsp_comment =0; break;
  1624.         case 'd':    debugging++;dsp_comment =0; break;
  1625.         case 'l':    list_zip =1;extract =0; break;
  1626.         case 't':    test_zip =1;extract =0; break;
  1627.         case 'u':    unixfy =0; break;
  1628.         case 'v':    verbose++; break;
  1629.         default:    short_help();
  1630.         }
  1631.     }
  1632.  
  1633.     if (argv[optind] != NULL)
  1634.         strcpy(zipfn,argv[optind]);
  1635.     else
  1636.         long_help();
  1637.  
  1638.     /* .ZIP default if none provided by user */
  1639.     if (strchr(zipfn,'.') == NULL)
  1640.     strcat(zipfn,".zip");
  1641. #else
  1642.     if (argc != 2)
  1643.         long_help();
  1644.  
  1645.     /* .ZIP default if none provided by user */
  1646.     strcpy(zipfn, argv[1]);
  1647.     if (strchr(zipfn, '.') == NULL)
  1648.         strcat(zipfn, ".zip");
  1649. #endif
  1650.  
  1651.         /* allocate i/o buffers */
  1652.     inbuf = (byte *) (malloc(INBUFSIZ));
  1653.     outbuf = (byte *) (malloc(OUTBUFSIZ));
  1654.     comment = (byte *) (malloc(STRSIZ));
  1655.     if ((inbuf == NULL) || (outbuf == NULL) || (comment == NULL)) {
  1656.         printf("Can't allocate buffers!\n");
  1657.         exit(1);
  1658.     }
  1659.  
  1660.         /* do the job... */
  1661.         extract_zipfile();
  1662.     exit(0);
  1663. }
  1664.  
  1665. long_help()
  1666. {
  1667. printf("\nUnZip:  Zipfile Extract Version:%s Patchlevel:%d",VERSION,PATCH);
  1668. printf(";  (C) 1989 Samuel H. Smith\n");
  1669. printf("Courtesy of:  S.H.Smith and The Tool Shop BBS, (602) 279-2673.");
  1670. printf("\n\n");
  1671. printf("UNIX mods by: Michael Enkelis\n\n");
  1672. printf("You may copy and distribute this program freely, provided that:\n");
  1673. printf("    1)   No fee is charged for such copying and distribution, and\n");
  1674. printf("    2)   It is distributed ONLY in its original, unmodified state.");
  1675. printf("\n\n");
  1676. printf("If you wish to distribute a modified version of this program, you MUST\n");
  1677. printf("include the source code.\n\n");
  1678. printf("If you modify this program, I would appreciate a copy of the  new source\n");
  1679. printf("code.   I am holding the copyright on the source code, so please don't\n");
  1680. printf("delete my name from the program files or from the documentation.\n\n");
  1681. printf("IN NO EVENT WILL I BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY LOST\n");
  1682. printf("PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES\n");
  1683. printf("ARISING OUT OF YOUR USE OR INABILITY TO USE THE PROGRAM, OR FOR ANY\n");
  1684. printf("CLAIM BY ANY OTHER PARTY.\n\n");
  1685. short_help();
  1686. exit(1);
  1687. }
  1688.  
  1689. short_help()
  1690. {
  1691.     printf("Usage:    UnZip -chltuv FILE[.zip]\n\n");
  1692.     printf("  -c    Don't display coments.\n");
  1693.     printf("  -h    This help listing.\n");
  1694.     printf("  -l    List zip archive.\n");
  1695.     printf("  -t    Test zip archive.\n");
  1696.     printf("  -u    Don't convert filenames to lowercase.\n");
  1697.     printf("  -v    Verbose output.\n\n");
  1698.     exit(1);
  1699. }
  1700.