home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 249.lha / UnZip_v1.2 / UNZIP.c < prev    next >
C/C++ Source or Header  |  1989-05-29  |  24KB  |  1,046 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. /*
  21.  * Amiga Notes:
  22.  *
  23.  * Compiled with Lattice C 5.02
  24.  * Large Memory model (-b0)
  25.  * 16 bit ints        (-w)
  26.  *
  27.  * Macroed out the setftime call
  28.  * Added swap_bytes and swap_lbytes to all structure fields read from file
  29.  * Changed includes and system defines for Amiga/Lattice C 5.02
  30.  * HIGH_LOW is defined
  31.  * AMIGA is defined automatically by Lattice C
  32.  *
  33.  * Compile with:
  34.  *    lc >errs -b0 -L -M -w UNZIP.c CRC32.c
  35.  */
  36.  
  37. #define VERSION  "UnZip:  Zipfile Extract v1.2.A of 03-15-89;  (C) 1989 Samuel H. Smith"
  38.  
  39. typedef unsigned char byte;    /* code assumes UNSIGNED bytes */
  40. typedef long longint;
  41. typedef unsigned word;
  42. typedef char boolean;
  43.  
  44. #define STRSIZ 256
  45.  
  46. #include <stdio.h>
  47.  /* this is your standard header for all C compiles */
  48.  
  49. #include <stdlib.h>
  50.  /* this include defines various standard library prototypes */
  51.  
  52.  
  53. /*
  54.  * SEE HOST OPERATING SYSTEM SPECIFICS SECTION STARTING NEAR LINE 180
  55.  *
  56.  */
  57.  
  58.  
  59. /* ----------------------------------------------------------- */
  60. /*
  61.  * Zipfile layout declarations
  62.  *
  63.  */
  64.  
  65. typedef longint signature_type;
  66.  
  67.  
  68. #define LOCAL_FILE_HEADER_SIGNATURE  0x04034b50L
  69.  
  70.  
  71. typedef struct local_file_header {
  72.     word version_needed_to_extract;
  73.     word general_purpose_bit_flag;
  74.     word compression_method;
  75.     word last_mod_file_time;
  76.     word last_mod_file_date;
  77.     longint crc32;
  78.     longint compressed_size;
  79.     longint uncompressed_size;
  80.     word filename_length;
  81.     word extra_field_length;
  82. } local_file_header;
  83.  
  84.  
  85. #define CENTRAL_FILE_HEADER_SIGNATURE  0x02014b50L
  86.  
  87.  
  88. typedef struct central_directory_file_header {
  89.     word version_made_by;
  90.     word version_needed_to_extract;
  91.     word general_purpose_bit_flag;
  92.     word compression_method;
  93.     word last_mod_file_time;
  94.     word last_mod_file_date;
  95.     longint crc32;
  96.     longint compressed_size;
  97.     longint uncompressed_size;
  98.     word filename_length;
  99.     word extra_field_length;
  100.     word file_comment_length;
  101.     word disk_number_start;
  102.     word internal_file_attributes;
  103.     longint external_file_attributes;
  104.     longint relative_offset_local_header;
  105. } central_directory_file_header;
  106.  
  107.  
  108. #define END_CENTRAL_DIR_SIGNATURE  0x06054b50L
  109.  
  110.  
  111. typedef struct end_central_dir_record {
  112.     word number_this_disk;
  113.     word number_disk_with_start_central_directory;
  114.     word total_entries_central_dir_on_this_disk;
  115.     word total_entries_central_dir;
  116.     longint size_central_directory;
  117.     longint offset_start_central_directory;
  118.     word zipfile_comment_length;
  119. } end_central_dir_record;
  120.  
  121.  
  122.  
  123. /* ----------------------------------------------------------- */
  124. /*
  125.  * input file variables
  126.  *
  127.  */
  128.  
  129. #define INBUFSIZ 0x2000
  130. byte *inbuf;            /* input file buffer - any size is legal */
  131. byte *inptr;
  132.  
  133. int incnt;
  134. unsigned bitbuf;
  135. int bits_left;
  136. boolean zipeof;
  137.  
  138. int zipfd;
  139. char zipfn[STRSIZ];
  140. local_file_header lrec;
  141.  
  142.  
  143. /* ----------------------------------------------------------- */
  144. /*
  145.  * output stream variables
  146.  *
  147.  */
  148.  
  149. #define OUTBUFSIZ 0x6000
  150. byte *outbuf;                   /* buffer for rle look-back */
  151. byte *outptr;
  152.  
  153. longint outpos;            /* absolute position in outfile */
  154. int outcnt;            /* current position in outbuf */
  155.  
  156. int outfd;
  157. char filename[STRSIZ];
  158. char extra[STRSIZ];
  159.  
  160. #define DLE 144
  161.  
  162.  
  163. /* ----------------------------------------------------------- */
  164. /*
  165.  * shrink/reduce working storage
  166.  *
  167.  */
  168.  
  169. int factor;
  170. byte followers[256][64];
  171. byte Slen[256];
  172.  
  173. #define max_bits 13
  174. #define init_bits 9
  175. #define hsize 8192
  176. #define first_ent 257
  177. #define clear 256
  178.  
  179. typedef int hsize_array_integer[hsize+1];
  180. typedef byte hsize_array_byte[hsize+1];
  181.  
  182. hsize_array_integer prefix_of;
  183. hsize_array_byte suffix_of;
  184. hsize_array_byte stack;
  185.  
  186. int codesize;
  187. int maxcode;
  188. int free_ent;
  189. int maxcodemax;
  190. int offset;
  191. int sizex;
  192.  
  193.  
  194.  
  195. /* ============================================================= */
  196. /*
  197.  * Host operating system details
  198.  *
  199.  */
  200.  
  201. #include <string.h>
  202.  /* this include defines strcpy, strcmp, etc. */
  203.  
  204. #ifndef AMIGA
  205. #include <io.h>
  206. #endif
  207. #ifdef AMIGA
  208. #define SEEK_CUR 1
  209. #define SEEK_END 2
  210. #define SEEK_SET 0
  211. struct ftime {
  212.     unsigned  ft_tsec  : 5;
  213.     unsigned  ft_min   : 6;
  214.     unsigned  ft_hour  : 5;
  215.     unsigned  ft_day   : 5;
  216.     unsigned  ft_month : 4;
  217.     unsigned  ft_year  : 7;
  218. };
  219. #define setftime(a,b)
  220. #endif
  221.  /*
  222.   * this include file defines
  223.   *             struct ftime ...        (* file time/date stamp info *)
  224.   *             int setftime (int handle, struct ftime *ftimep);
  225.   *             #define SEEK_CUR  1     (* lseek() modes *)
  226.   *             #define SEEK_END  2
  227.   *             #define SEEK_SET  0
  228.   */
  229.  
  230. #include <fcntl.h>
  231. #ifdef AMIGA
  232. #define O_BINARY 0x0000
  233. #endif
  234.  /*
  235.   * this include file defines
  236.   *             #define O_BINARY 0x8000  (* no cr-lf translation *)
  237.   * as used in the open() standard function
  238.   */
  239.  
  240.  
  241. #ifndef AMIGA
  242. #include <sys/stat.h>
  243. #endif
  244.  /*
  245.   * this include file defines
  246.   *             #define S_IREAD 0x0100  (* owner may read *)
  247.   *             #define S_IWRITE 0x0080 (* owner may write *)
  248.   * as used in the creat() standard function
  249.   */
  250.  
  251. #ifdef AMIGA
  252. #define HIGH_LOW
  253. #else
  254. #undef HIGH_LOW
  255. #endif
  256.  /*
  257.   * change 'undef' to 'define' if your machine stores high order bytes in
  258.   * lower addresses.
  259.   */
  260.  
  261. void set_file_time(void)
  262.  /*
  263.   * set the output file date/time stamp according to information from the
  264.   * zipfile directory record for this file 
  265.   */
  266. {
  267.     union {
  268.                 struct ftime ft;        /* system file time record */
  269.         struct {
  270.                         word ztime;     /* date and time words */
  271.                         word zdate;     /* .. same format as in .ZIP file */
  272.         } zt;
  273.     } td;
  274.  
  275.     /*
  276.      * set output file date and time - this is optional and can be
  277.      * deleted if your compiler does not easily support setftime() 
  278.      */
  279.  
  280.     td.zt.ztime = lrec.last_mod_file_time;
  281.     td.zt.zdate = lrec.last_mod_file_date;
  282.  
  283.     setftime(outfd, &td.ft);
  284. }
  285.  
  286.  
  287. int create_output_file(void)
  288.  /* return non-0 if creat failed */
  289. {
  290.     /* create the output file with READ and WRITE permissions */
  291.     outfd = creat(filename, S_IWRITE | S_IREAD);
  292.     if (outfd < 1) {
  293.         printf("Can't create output: %s\n", filename);
  294.         return 1;
  295.     }
  296.  
  297.     /*
  298.      * close the newly created file and reopen it in BINARY mode to
  299.      * disable all CR/LF translations 
  300.      */
  301.     close(outfd);
  302.     outfd = open(filename, O_RDWR | O_BINARY);
  303.  
  304.     /* write a single byte at EOF to pre-allocate the file */
  305.         lseek(outfd, lrec.uncompressed_size - 1L, SEEK_SET);
  306.     write(outfd, "?", 1);
  307.     lseek(outfd, 0L, SEEK_SET);
  308.     return 0;
  309. }
  310.  
  311.  
  312. int open_input_file(void)
  313.  /* return non-0 if creat failed */
  314. {
  315.     /*
  316.      * open the zipfile for reading and in BINARY mode to prevent cr/lf
  317.      * translation, which would corrupt the bitstreams 
  318.      */
  319.  
  320.     zipfd = open(zipfn, O_RDONLY | O_BINARY);
  321.     if (zipfd < 1) {
  322.         printf("Can't open input file: %s\n", zipfn);
  323.         return (1);
  324.     }
  325.     return 0;
  326. }
  327.  
  328.  
  329. #ifdef HIGH_LOW
  330.  
  331. void swap_bytes(word *wordp)
  332.  /* convert intel style 'short int' variable to host format */
  333. {
  334.     char *charp = (char *) wordp;
  335.     char temp;
  336.  
  337.     temp = charp[0];
  338.     charp[0] = charp[1];
  339.     charp[1] = temp;
  340. }
  341.  
  342. void swap_lbytes(longint *longp)
  343.  /* convert intel style 'long' variable to host format */
  344. {
  345.     char *charp = (char *) longp;
  346.     char temp[4];
  347.  
  348.     temp[3] = charp[0];
  349.     temp[2] = charp[1];
  350.     temp[1] = charp[2];
  351.     temp[0] = charp[3];
  352.  
  353.     charp[0] = temp[0];
  354.     charp[1] = temp[1];
  355.     charp[2] = temp[2];
  356.     charp[3] = temp[3];
  357. }
  358.  
  359. #endif
  360.  
  361.  
  362.  
  363. /* ============================================================= */
  364.  
  365. int FillBuffer(void)
  366.  /* fill input buffer if possible */
  367. {
  368.     int readsize;
  369.  
  370.         if (lrec.compressed_size <= 0)
  371.         return incnt = 0;
  372.  
  373.         if (lrec.compressed_size > INBUFSIZ)
  374.         readsize = INBUFSIZ;
  375.     else
  376.                 readsize = (int) lrec.compressed_size;
  377.     incnt = read(zipfd, inbuf, readsize);
  378.  
  379.         lrec.compressed_size -= incnt;
  380.     inptr = inbuf;
  381.     return incnt--;
  382. }
  383.  
  384. int ReadByte(unsigned *x)
  385.  /* read a byte; return 8 if byte available, 0 if not */
  386. {
  387.     if (incnt-- == 0)
  388.         if (FillBuffer() == 0)
  389.             return 0;
  390.  
  391.     *x = *inptr++;
  392.     return 8;
  393. }
  394.  
  395.  
  396. /* ------------------------------------------------------------- */
  397. static unsigned mask_bits[] =
  398.         {0,     0x0001, 0x0003, 0x0007, 0x000f,
  399.                 0x001f, 0x003f, 0x007f, 0x00ff,
  400.                 0x01ff, 0x03ff, 0x07ff, 0x0fff,
  401.                 0x1fff, 0x3fff, 0x7fff, 0xffff
  402.         };
  403.  
  404.  
  405. int FillBitBuffer(register int bits)
  406. {
  407.     /* get the bits that are left and read the next word */
  408.     unsigned temp;
  409.         register int result = bitbuf;
  410.     int sbits = bits_left;
  411.     bits -= bits_left;
  412.  
  413.     /* read next word of input */
  414.     bits_left = ReadByte(&bitbuf);
  415.     bits_left += ReadByte(&temp);
  416.     bitbuf |= (temp << 8);
  417.     if (bits_left == 0)
  418.         zipeof = 1;
  419.  
  420.     /* get the remaining bits */
  421.         result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
  422.         bitbuf >>= bits;
  423.         bits_left -= bits;
  424.         return result;
  425. }
  426.  
  427. #define READBIT(nbits,zdest) { if (nbits <= bits_left) { zdest = (int)(bitbuf & mask_bits[nbits]); bitbuf >>= nbits; bits_left -= nbits; } else zdest = FillBitBuffer(nbits);}
  428.  
  429. /*
  430.  * macro READBIT(nbits,zdest)
  431.  *  {
  432.  *      if (nbits <= bits_left) {
  433.  *          zdest = (int)(bitbuf & mask_bits[nbits]);
  434.  *          bitbuf >>= nbits;
  435.  *          bits_left -= nbits;
  436.  *      } else
  437.  *          zdest = FillBitBuffer(nbits);
  438.  *  }
  439.  *
  440.  */
  441.  
  442.  
  443. /* ------------------------------------------------------------- */
  444.  
  445. #include "crc32.h"
  446.  
  447.  
  448. /* ------------------------------------------------------------- */
  449.  
  450. void FlushOutput(void)
  451.  /* flush contents of output buffer */
  452. {
  453.     UpdateCRC(outbuf, outcnt);
  454.     write(outfd, outbuf, outcnt);
  455.     outpos += outcnt;
  456.     outcnt = 0;
  457.     outptr = outbuf;
  458. }
  459.  
  460. #define OUTB(intc) { *outptr++=intc; if (++outcnt==OUTBUFSIZ) FlushOutput(); }
  461.  
  462. /*
  463.  *  macro OUTB(intc)
  464.  *  {
  465.  *      *outptr++=intc;
  466.  *      if (++outcnt==OUTBUFSIZ)
  467.  *          FlushOutput();
  468.  *  }
  469.  *
  470.  */
  471.  
  472.  
  473. /* ----------------------------------------------------------- */
  474.  
  475. void LoadFollowers(void)
  476. {
  477.         register int x;
  478.         register int i;
  479.  
  480.     for (x = 255; x >= 0; x--) {
  481.                 READBIT(6,Slen[x]);
  482.         for (i = 0; i < Slen[x]; i++) {
  483.                         READBIT(8,followers[x][i]);
  484.         }
  485.     }
  486. }
  487.  
  488.  
  489. /* ----------------------------------------------------------- */
  490. /*
  491.  * The Reducing algorithm is actually a combination of two
  492.  * distinct algorithms.  The first algorithm compresses repeated
  493.  * byte sequences, and the second algorithm takes the compressed
  494.  * stream from the first algorithm and applies a probabilistic
  495.  * compression method.
  496.  */
  497.  
  498. int L_table[] = {0, 0x7f, 0x3f, 0x1f, 0x0f};
  499.  
  500. int D_shift[] = {0, 0x07, 0x06, 0x05, 0x04};
  501. int D_mask[]  = {0, 0x01, 0x03, 0x07, 0x0f};
  502.  
  503. int B_table[] = {8, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5,
  504.          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
  505.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  506.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
  507.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  508.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  509.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  510.          7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  511.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  512.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  513.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  514.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  515.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  516.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  517.          8, 8, 8, 8};
  518.  
  519. /* ----------------------------------------------------------- */
  520.  
  521. void unReduce(void)
  522.  /* expand probablisticly reduced data */
  523. {
  524.         register int lchar;
  525.         int nchar;
  526.         int ExState;
  527.         int V;
  528.         int Len;
  529.  
  530.         factor = lrec.compression_method - 1;
  531.     ExState = 0;
  532.     lchar = 0;
  533.     LoadFollowers();
  534.  
  535.         while (((outpos + outcnt) < lrec.uncompressed_size) && (!zipeof)) {
  536.         if (Slen[lchar] == 0)
  537.                         READBIT(8,nchar)      /* ; */
  538.                 else
  539.         {
  540.                         READBIT(1,nchar);
  541.                         if (nchar != 0)
  542.                                 READBIT(8,nchar)      /* ; */
  543.                         else
  544.             {
  545.                                 int follower;
  546.                                 int bitsneeded = B_table[Slen[lchar]];
  547.                                 READBIT(bitsneeded,follower);
  548.                                 nchar = followers[lchar][follower];
  549.             }
  550.         }
  551.  
  552.         /* expand the resulting byte */
  553.         switch (ExState) {
  554.  
  555.         case 0:
  556.                         if (nchar != DLE)
  557.                                 OUTB(nchar) /*;*/
  558.             else
  559.                 ExState = 1;
  560.             break;
  561.  
  562.         case 1:
  563.                         if (nchar != 0) {
  564.                                 V = nchar;
  565.                 Len = V & L_table[factor];
  566.                 if (Len == L_table[factor])
  567.                     ExState = 2;
  568.                 else
  569.                     ExState = 3;
  570.             }
  571.             else {
  572.                                 OUTB(DLE);
  573.                 ExState = 0;
  574.             }
  575.             break;
  576.  
  577.                 case 2: {
  578.                                 Len += nchar;
  579.                 ExState = 3;
  580.             }
  581.             break;
  582.  
  583.                 case 3: {
  584.                 register int i = Len + 3;
  585.                 int offset = (((V >> D_shift[factor]) &
  586.                                           D_mask[factor]) << 8) + nchar + 1;
  587.                 longint op = outpos + outcnt - offset;
  588.  
  589.                 /* special case- before start of file */
  590.                 while ((op < 0L) && (i > 0)) {
  591.                     OUTB(0);
  592.                     op++;
  593.                     i--;
  594.                 }
  595.  
  596.                 /* normal copy of data from output buffer */
  597.                 {
  598.                     register int ix = (int) (op % OUTBUFSIZ);
  599.  
  600.                                         /* do a block memory copy if possible */
  601.                                         if ( ((ix    +i) < OUTBUFSIZ) &&
  602.                                              ((outcnt+i) < OUTBUFSIZ) ) {
  603.                                                 memcpy(outptr,&outbuf[ix],i);
  604.                                                 outptr += i;
  605.                                                 outcnt += i;
  606.                                         }
  607.  
  608.                                         /* otherwise copy byte by byte */
  609.                                         else while (i--) {
  610.                                                 OUTB(outbuf[ix]);
  611.                                                 if (++ix >= OUTBUFSIZ)
  612.                                                         ix = 0;
  613.                                         }
  614.                                 }
  615.  
  616.                 ExState = 0;
  617.             }
  618.             break;
  619.         }
  620.  
  621.                 /* store character for next iteration */
  622.                 lchar = nchar;
  623.         }
  624. }
  625.  
  626.  
  627. /* ------------------------------------------------------------- */
  628. /*
  629.  * Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
  630.  * with partial clearing.
  631.  *
  632.  */
  633.  
  634. void partial_clear(void)
  635. {
  636.         register int pr;
  637.         register int cd;
  638.  
  639.     /* mark all nodes as potentially unused */
  640.     for (cd = first_ent; cd < free_ent; cd++)
  641.         prefix_of[cd] |= 0x8000;
  642.  
  643.     /* unmark those that are used by other nodes */
  644.     for (cd = first_ent; cd < free_ent; cd++) {
  645.         pr = prefix_of[cd] & 0x7fff;    /* reference to another node? */
  646.                 if (pr >= first_ent)            /* flag node as referenced */
  647.             prefix_of[pr] &= 0x7fff;
  648.     }
  649.  
  650.     /* clear the ones that are still marked */
  651.     for (cd = first_ent; cd < free_ent; cd++)
  652.         if ((prefix_of[cd] & 0x8000) != 0)
  653.             prefix_of[cd] = -1;
  654.  
  655.     /* find first cleared node as next free_ent */
  656.         cd = first_ent;
  657.         while ((cd < maxcodemax) && (prefix_of[cd] != -1))
  658.                 cd++;
  659.         free_ent = cd;
  660. }
  661.  
  662.  
  663. /* ------------------------------------------------------------- */
  664.  
  665. void unShrink(void)
  666. {
  667.         #define  GetCode(dest) READBIT(codesize,dest)
  668.  
  669.     register int code;
  670.     register int stackp;
  671.     int finchar;
  672.     int oldcode;
  673.     int incode;
  674.  
  675.  
  676.     /* decompress the file */
  677.     maxcodemax = 1 << max_bits;
  678.     codesize = init_bits;
  679.     maxcode = (1 << codesize) - 1;
  680.     free_ent = first_ent;
  681.     offset = 0;
  682.     sizex = 0;
  683.  
  684.     for (code = maxcodemax; code > 255; code--)
  685.         prefix_of[code] = -1;
  686.  
  687.     for (code = 255; code >= 0; code--) {
  688.         prefix_of[code] = 0;
  689.         suffix_of[code] = code;
  690.     }
  691.  
  692.     GetCode(oldcode);
  693.     if (zipeof)
  694.         return;
  695.     finchar = oldcode;
  696.  
  697.         OUTB(finchar);
  698.  
  699.         stackp = hsize;
  700.  
  701.     while (!zipeof) {
  702.         GetCode(code);
  703.         if (zipeof)
  704.             return;
  705.  
  706.         while (code == clear) {
  707.             GetCode(code);
  708.             switch (code) {
  709.  
  710.             case 1:{
  711.                     codesize++;
  712.                     if (codesize == max_bits)
  713.                         maxcode = maxcodemax;
  714.                     else
  715.                         maxcode = (1 << codesize) - 1;
  716.                 }
  717.                 break;
  718.  
  719.             case 2:
  720.                 partial_clear();
  721.                 break;
  722.             }
  723.  
  724.             GetCode(code);
  725.             if (zipeof)
  726.                 return;
  727.         }
  728.  
  729.  
  730.         /* special case for KwKwK string */
  731.         incode = code;
  732.         if (prefix_of[code] == -1) {
  733.                         stack[--stackp] = finchar;
  734.             code = oldcode;
  735.         }
  736.  
  737.  
  738.         /* generate output characters in reverse order */
  739.         while (code >= first_ent) {
  740.                         stack[--stackp] = suffix_of[code];
  741.             code = prefix_of[code];
  742.         }
  743.  
  744.         finchar = suffix_of[code];
  745.                 stack[--stackp] = finchar;
  746.  
  747.  
  748.                 /* and put them out in forward order, block copy */
  749.                 if ((hsize-stackp+outcnt) < OUTBUFSIZ) {
  750.                         memcpy(outptr,&stack[stackp],hsize-stackp);
  751.                         outptr += hsize-stackp;
  752.                         outcnt += hsize-stackp;
  753.                         stackp = hsize;
  754.                 }
  755.  
  756.                 /* output byte by byte if we can't go by blocks */
  757.                 else while (stackp < hsize)
  758.                         OUTB(stack[stackp++]);
  759.  
  760.  
  761.         /* generate new entry */
  762.         code = free_ent;
  763.         if (code < maxcodemax) {
  764.             prefix_of[code] = oldcode;
  765.             suffix_of[code] = finchar;
  766.  
  767.             do
  768.                 code++;
  769.             while ((code < maxcodemax) && (prefix_of[code] != -1));
  770.  
  771.             free_ent = code;
  772.         }
  773.  
  774.         /* remember previous code */
  775.         oldcode = incode;
  776.     }
  777.  
  778. }
  779.  
  780.  
  781. /* ---------------------------------------------------------- */
  782.  
  783. void extract_member(void)
  784. {
  785.     unsigned b;
  786.  
  787.     bits_left = 0;
  788.     bitbuf = 0;
  789.     incnt = 0;
  790.     outpos = 0L;
  791.     outcnt = 0;
  792.     outptr = outbuf;
  793.     zipeof = 0;
  794.     crc32val = 0xFFFFFFFFL;
  795.  
  796.  
  797.     /* create the output file with READ and WRITE permissions */
  798.     if (create_output_file())
  799.         exit(1);
  800.  
  801.         switch (lrec.compression_method) {
  802.  
  803.     case 0:        /* stored */
  804.         {
  805.             printf(" Extracting: %-12s ", filename);
  806.             while (ReadByte(&b))
  807.                 OUTB(b);
  808.         }
  809.         break;
  810.  
  811.         case 1: {
  812.             printf("UnShrinking: %-12s ", filename);
  813.             unShrink();
  814.         }
  815.         break;
  816.  
  817.     case 2:
  818.     case 3:
  819.     case 4:
  820.         case 5: {
  821.             printf("  Expanding: %-12s ", filename);
  822.             unReduce();
  823.         }
  824.         break;
  825.  
  826.     default:
  827.         printf("Unknown compression method.");
  828.     }
  829.  
  830.  
  831.     /* write the last partial buffer, if any */
  832.     if (outcnt > 0) {
  833.         UpdateCRC(outbuf, outcnt);
  834.         write(outfd, outbuf, outcnt);
  835.     }
  836.  
  837.     /* set output file date and time */
  838.     set_file_time();
  839.  
  840.     close(outfd);
  841.  
  842.     crc32val = -1 - crc32val;
  843.         if (crc32val != lrec.crc32)
  844.                 printf(" Bad CRC %08lx  (should be %08lx)", lrec.crc32, crc32val);
  845.  
  846.     printf("\n");
  847. }
  848.  
  849.  
  850. /* ---------------------------------------------------------- */
  851.  
  852. void get_string(int len,
  853.                 char *s)
  854. {
  855.     read(zipfd, s, len);
  856.     s[len] = 0;
  857. }
  858.  
  859.  
  860. /* ---------------------------------------------------------- */
  861.  
  862. void process_local_file_header(void)
  863. {
  864.     read(zipfd, (char *)&lrec, sizeof(lrec));
  865.  
  866. #ifdef HIGH_LOW
  867.     swap_bytes(&lrec.version_needed_to_extract);
  868.     swap_bytes(&lrec.general_purpose_bit_flag);
  869.     swap_bytes(&lrec.compression_method);
  870.     swap_bytes(&lrec.last_mod_file_time);
  871.     swap_bytes(&lrec.last_mod_file_date);
  872.     swap_lbytes(&lrec.crc32);
  873.     swap_lbytes(&lrec.compressed_size);
  874.     swap_lbytes(&lrec.uncompressed_size);
  875.     swap_bytes(&lrec.filename_length);
  876.     swap_bytes(&lrec.extra_field_length);
  877. #endif
  878.  
  879.     get_string(lrec.filename_length, filename);
  880.     get_string(lrec.extra_field_length, extra);
  881.     extract_member();
  882. }
  883.  
  884.  
  885. /* ---------------------------------------------------------- */
  886.  
  887. void process_central_file_header(void)
  888. {
  889.     central_directory_file_header rec;
  890.     char filename[STRSIZ];
  891.     char extra[STRSIZ];
  892.     char comment[STRSIZ];
  893.  
  894.     read(zipfd, (char *)&rec, sizeof(rec));
  895.  
  896. #ifdef HIGH_LOW
  897.     swap_bytes(&rec.version_made_by);
  898.     swap_bytes(&rec.version_needed_to_extract);
  899.     swap_bytes(&rec.general_purpose_bit_flag);
  900.     swap_bytes(&rec.compression_method);
  901.     swap_bytes(&rec.last_mod_file_time);
  902.     swap_bytes(&rec.last_mod_file_date);
  903.     swap_lbytes(&rec.crc32);
  904.     swap_lbytes(&rec.compressed_size);
  905.     swap_lbytes(&rec.uncompressed_size);
  906.     swap_bytes(&rec.filename_length);
  907.     swap_bytes(&rec.extra_field_length);
  908.     swap_bytes(&rec.file_comment_length);
  909.     swap_bytes(&rec.disk_number_start);
  910.     swap_bytes(&rec.internal_file_attributes);
  911.     swap_lbytes(&rec.external_file_attributes);
  912.     swap_lbytes(&rec.relative_offset_local_header);
  913. #endif
  914.  
  915.         get_string(rec.filename_length, filename);
  916.     get_string(rec.extra_field_length, extra);
  917.     get_string(rec.file_comment_length, comment);
  918. }
  919.  
  920.  
  921. /* ---------------------------------------------------------- */
  922.  
  923. void process_end_central_dir(void)
  924. {
  925.     end_central_dir_record rec;
  926.     char comment[STRSIZ];
  927.  
  928.     read(zipfd, (char *)&rec, sizeof(rec));
  929.  
  930. #ifdef HIGH_LOW
  931.     swap_bytes(&rec.number_this_disk);
  932.     swap_bytes(&rec.number_disk_with_start_central_directory);
  933.     swap_bytes(&rec.total_entries_central_dir_on_this_disk);
  934.     swap_bytes(&rec.total_entries_central_dir);
  935.     swap_lbytes(&rec.size_central_directory);
  936.     swap_lbytes(&rec.offset_start_central_directory);
  937.     swap_bytes(&rec.zipfile_comment_length);
  938.  
  939. #endif
  940.  
  941.     get_string(rec.zipfile_comment_length, comment);
  942. }
  943.  
  944.  
  945. /* ---------------------------------------------------------- */
  946.  
  947. void process_headers(void)
  948. {
  949.     longint sig;
  950.  
  951.     while (1) {
  952.         if (read(zipfd, (char *)&sig, sizeof(sig)) != sizeof(sig))
  953.             return;
  954.  
  955. #ifdef HIGH_LOW
  956.         swap_lbytes(&sig);
  957. #endif
  958.  
  959.                 if (sig == LOCAL_FILE_HEADER_SIGNATURE)
  960.             process_local_file_header();
  961.                 else if (sig == CENTRAL_FILE_HEADER_SIGNATURE)
  962.             process_central_file_header();
  963.                 else if (sig == END_CENTRAL_DIR_SIGNATURE) {
  964.             process_end_central_dir();
  965.             return;
  966.         }
  967.                 else {
  968.             printf("Invalid Zipfile Header\n");
  969.             return;
  970.         }
  971.     }
  972.  
  973. }
  974.  
  975.  
  976. /* ---------------------------------------------------------- */
  977.  
  978. void extract_zipfile(void)
  979. {
  980.     /*
  981.      * open the zipfile for reading and in BINARY mode to prevent cr/lf
  982.      * translation, which would corrupt the bitstreams 
  983.      */
  984.  
  985.     if (open_input_file())
  986.         exit(1);
  987.  
  988.     process_headers();
  989.  
  990.     close(zipfd);
  991. }
  992.  
  993.  
  994. /* ---------------------------------------------------------- */
  995. /*
  996.  * main program
  997.  *
  998.  */
  999.  
  1000. void main(int argc, char **argv)
  1001. {
  1002.     if (argc != 2) {
  1003. /* NOTE: ANSI C is supposed to concatinate adjacent string literals.    */
  1004. /* See "The C Programming Language (Second Edition)" section A2.6 pg194    */
  1005. /* by Brian W. Kernighan, Dennis M. Ritchie                */
  1006. /* Prentice Hall Software Series                    */
  1007. /* ISBN 0-13-110362-8, 0-13-110370-9                    */
  1008.                 printf(    
  1009. "\n%s\nCourtesy of:  S.H.Smith  and  The Tool Shop BBS,  (602) 279-2673.\n\n"
  1010. "You may copy and distribute this program freely, provided that:\n"
  1011. "    1)   No fee is charged for such copying and distribution, and\n"
  1012. "    2)   It is distributed ONLY in its original, unmodified state.\n\n"
  1013. "If you wish to distribute a modified version of this program, you MUST\n"
  1014. "include the source code.\n\n"
  1015. "If you modify this program, I would appreciate a copy of the  new source\n"
  1016. "code.   I am holding the copyright on the source code, so please don't\n"
  1017. "delete my name from the program files or from the documentation.\n\n"
  1018. "IN NO EVENT WILL I BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY LOST\n"
  1019. "PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES\n"
  1020. "ARISING OUT OF YOUR USE OR INABILITY TO USE THE PROGRAM, OR FOR ANY\n"
  1021. "CLAIM BY ANY OTHER PARTY.\n\n"
  1022. "Amiga Tweeks by Gregg Tavares\n\n"
  1023. "Usage:  UnZip FILE[.zip]\n",
  1024.             VERSION);
  1025.                 exit(1);
  1026.     }
  1027.  
  1028.     /* .ZIP default if none provided by user */
  1029.     strcpy(zipfn, argv[1]);
  1030.     if (strchr(zipfn, '.') == NULL)
  1031.         strcat(zipfn, ".ZIP");
  1032.  
  1033.         /* allocate i/o buffers */
  1034.     inbuf = (byte *) (malloc(INBUFSIZ));
  1035.     outbuf = (byte *) (malloc(OUTBUFSIZ));
  1036.     if ((inbuf == NULL) || (outbuf == NULL)) {
  1037.         printf("Can't allocate buffers!\n");
  1038.         exit(1);
  1039.     }
  1040.  
  1041.         /* do the job... */
  1042.         extract_zipfile();
  1043.     exit(0);
  1044. }
  1045.  
  1046.