unzip applet by Laurence Anderson
authorGlenn L McGrath <bug1@ihug.co.nz>
Wed, 2 Jan 2002 13:52:26 +0000 (13:52 -0000)
committerGlenn L McGrath <bug1@ihug.co.nz>
Wed, 2 Jan 2002 13:52:26 +0000 (13:52 -0000)
----------------------------------------------------------------------

13 files changed:
archival/Makefile
archival/config.in
archival/libunarchive/Makefile
archival/libunarchive/decompress_unzip.c
archival/libunarchive/get_header_zip.c [new file with mode: 0644]
archival/libunarchive/unarchive.c
archival/libunarchive/unzip.c
archival/unzip.c [new file with mode: 0644]
include/applets.h
include/libbb.h
include/unarchive.h
include/usage.h
libbb/unzip.c

index 8787589ffb3c54681c5e9d047fcd0a1d44648fbe..35ba02f3bd0c3c06ef21eff4f508df01c5784502 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_GUNZIP)          += gunzip.o
 obj-$(CONFIG_GZIP)             += gzip.o
 obj-$(CONFIG_RPM2CPIO)         += rpm2cpio.o
 obj-$(CONFIG_TAR)              += tar.o
+obj-$(CONFIG_UNZIP)            += unzip.o
 
 
 # Hand off to toplevel Rules.mak
index 76a192e137ff10617fa305fa9a215bf58986ae44..7b5644f0125ed373260f0c44745a81959f85ebfe 100644 (file)
@@ -20,4 +20,5 @@ if [ "$CONFIG_TAR" = "y" ] ; then
     bool '  Enable -X and --exclude options (exclude files)'   CONFIG_FEATURE_TAR_EXCLUDE
     bool '  Enable -z option (currently only for extracting)'  CONFIG_FEATURE_TAR_GZIP
 fi
+bool 'unzip'       CONFIG_UNZIP
 endmenu
index 0c7219dcd7b679a22b0307df9e3dc70d328fa42a..a8409a432c3a514c557237644dca318c44dbecf7 100644 (file)
@@ -20,7 +20,7 @@
 TOPDIR   :=../..
 L_TARGET := libunarchive.a
 
-obj-y           := unarchive.o seek_sub_file.o 
+obj-y           := unarchive.o seek_sub_file.o
 obj-n           :=
 obj-            :=
 
@@ -41,13 +41,17 @@ ifeq ($(CONFIG_CPIO),y)
 endif
 
 ifeq ($(CONFIG_RPM2CPIO),y)
-       obj-y += get_header_cpio.o 
+       obj-y += get_header_cpio.o
 endif
 
 ifeq ($(CONFIG_TAR),y)
        obj-y += get_header_tar.o
 endif
 
+ifeq ($(CONFIG_UNZIP),y)
+       obj-y += get_header_zip.o
+endif
+
 
 # Hand off to toplevel Rules.mak
 include $(TOPDIR)/Rules.mak
index 6c28d181d05394cd49934d63cb8f31c7ac7dd421..8075fd7175d9a62f84a4af0a991b7d42ab965a99 100644 (file)
@@ -80,7 +80,7 @@ static const int ERROR = 1;
 
 /*
  * window size--must be a power of two, and
- *  at least 32K for zip's deflate method 
+ *  at least 32K for zip's deflate method
  */
 static const int WSIZE = 0x8000;
 
@@ -846,7 +846,7 @@ static int inflate_block(int *e)
  *
  * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
  */
-static int inflate(void)
+extern int inflate(FILE *in, FILE *out)
 {
        int e;                          /* last block flag */
        int r;                          /* result code */
@@ -857,6 +857,13 @@ static int inflate(void)
        bk = 0;
        bb = 0;
 
+       in_file = in;
+       out_file = out;
+
+       /* Allocate all global buffers (for DYN_ALLOC option) */
+       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
+       bytes_out = 0L;
+
        /* Create the crc table */
        make_crc_table();
 
@@ -881,13 +888,15 @@ static int inflate(void)
 
        /* flush out window */
        flush_window();
+       free(window);
+       free(crc_table);
 
        /* return success */
        return 0;
 }
 
 /* ===========================================================================
- * Unzip in to out.  This routine works on both gzip and pkzip files.
+ * Unzip in to out.  This routine works on gzip files only.
  *
  * IN assertions: the buffer inbuf contains already the beginning of
  *   the compressed data, from offsets inptr to insize-1 included.
@@ -901,9 +910,6 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
        typedef void (*sig_type) (int);
        unsigned short i;
 
-       in_file = l_in_file;
-       out_file = l_out_file;
-
        if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
                (void) signal(SIGINT, (sig_type) abort_gzip);
        }
@@ -918,53 +924,48 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
        }
 #endif
 
-       /* Allocate all global buffers (for DYN_ALLOC option) */
-       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
-       outcnt = 0;
-       bytes_out = 0L;
-
        /* Magic header for gzip files, 1F 8B = \037\213 */
-       if ((fgetc(in_file) != 0x1F) || (fgetc(in_file) != 0x8b)) { 
+       if ((fgetc(l_in_file) != 0x1F) || (fgetc(l_in_file) != 0x8b)) {
                error_msg("Invalid gzip magic");
                return EXIT_FAILURE;
        }
 
        /* Check the compression method */
-       if (fgetc(in_file) != 8) {
+       if (fgetc(l_in_file) != 8) {
                error_msg("Unknown compression method");
                return(-1);
        }
 
-       flags = (unsigned char) fgetc(in_file);
+       flags = (unsigned char) fgetc(l_in_file);
 
        /* Ignore time stamp(4), extra flags(1), OS type(1) */
        for (i = 0; i < 6; i++) {
-               fgetc(in_file);
+               fgetc(l_in_file);
        }
 
        if (flags & 0x04) {
                /* bit 2 set: extra field present */
-               const unsigned short extra = fgetc(in_file) + (fgetc(in_file) << 8);
+               const unsigned short extra = fgetc(l_in_file) + (fgetc(l_in_file) << 8);
 
                for (i = 0; i < extra; i++) {
-                       fgetc(in_file);
+                       fgetc(l_in_file);
                }
        }
 
        /* Discard original name if any */
        if (flags & 0x08) {
                /* bit 3 set: original file name present */
-               while (fgetc(in_file) != 0);    /* null */
+               while (fgetc(l_in_file) != 0);  /* null */
        }
 
        /* Discard file comment if any */
        if (flags & 0x10) {
                /* bit 4 set: file comment present */
-               while (fgetc(in_file) != 0);    /* null */
+               while (fgetc(l_in_file) != 0);  /* null */
        }
 
        /* Decompress */
-       if (inflate() != 0) {
+       if (inflate(l_in_file, l_out_file) != 0) {
                error_msg("invalid compressed data--format violated");
        }
 
@@ -972,7 +973,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
         * crc32  (see algorithm.doc)
         * uncompressed input size modulo 2^32
         */
-       fread(buf, 1, 8, in_file);
+       fread(buf, 1, 8, l_in_file);
 
        /* Validate decompression - crc */
        if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
@@ -983,14 +984,11 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
                error_msg("invalid compressed data--length error");
        }
 
-       free(window);
-       free(crc_table);
-
        return 0;
 }
 
 /*
- * This needs access to global variables wondow and crc_table, so its not in its own file.
+ * This needs access to global variables window and crc_table, so its not in its own file.
  */
 extern void gz_close(int gunzip_pid)
 {
diff --git a/archival/libunarchive/get_header_zip.c b/archival/libunarchive/get_header_zip.c
new file mode 100644 (file)
index 0000000..84f2a54
--- /dev/null
@@ -0,0 +1,110 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * get_header_zip for busybox
+ *
+ * Copyright (C) 2001 by Laurence Anderson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "unarchive.h"
+#include "libbb.h"
+
+#define ZIP_FILEHEADER_MAGIC 0x04034b50
+#define ZIP_CDS_MAGIC 0x02014b50
+#define ZIP_CDS_END_MAGIC 0x06054b50
+#define ZIP_DD_MAGIC 0x8074b50
+
+file_header_t *get_header_zip(FILE *zip_stream)
+{
+       struct {
+               short version __attribute__ ((packed));
+               short flags __attribute__ ((packed));
+               short method __attribute__ ((packed));
+               short modtime __attribute__ ((packed));
+               short moddate __attribute__ ((packed));
+               int crc32 __attribute__ ((packed));
+               int cmpsize __attribute__ ((packed));
+               int ucmpsize __attribute__ ((packed));
+               short filename_len __attribute__ ((packed));
+               short extra_len __attribute__ ((packed));
+       } zip_header;
+       file_header_t *zip_entry = NULL;
+       int magic;
+       static int dd_ahead = 0; // If this is true, the we didn't know how long the last extraced file was
+
+       fread (&magic, 4, 1, zip_stream);
+       archive_offset += 4;
+
+       if (feof(zip_stream)) return(NULL);
+checkmagic:
+       switch (magic) {
+               case ZIP_FILEHEADER_MAGIC:
+                       zip_entry = xcalloc(1, sizeof(file_header_t));
+                       fread (&zip_header, sizeof(zip_header), 1, zip_stream);
+                       archive_offset += sizeof(zip_header);
+                       if (!(zip_header.method == 8 || zip_header.method == 0)) { printf("Unsupported compression method %d\n", zip_header.method); return(NULL); }
+                       zip_entry->name = calloc(zip_header.filename_len + 1, sizeof(char));
+                       fread (zip_entry->name, sizeof(char), zip_header.filename_len, zip_stream);
+                       archive_offset += zip_header.filename_len;
+                       seek_sub_file(zip_stream, zip_header.extra_len);
+                       zip_entry->size = zip_header.cmpsize;
+                       if (zip_header.method == 8) zip_entry->extract_func = &inflate;
+                       zip_entry->mode = S_IFREG | 0777;
+                       // Time/Date?
+                       if (*(zip_entry->name + strlen(zip_entry->name) - 1) == '/') { // Files that end in a / are directories
+                               zip_entry->mode ^= S_IFREG;
+                               zip_entry->mode |= S_IFDIR;
+                               *(zip_entry->name + strlen(zip_entry->name) - 1) = '\0'; // Remove trailing / so unarchive doesn't get confused
+                       }
+                       //printf("cmpsize: %d, ucmpsize: %d, method: %d\n", zip_header.cmpsize, zip_header.ucmpsize, zip_header.method);
+                       if (zip_header.flags & 0x8) { // crc32, and sizes are in the data description _after_ the file
+                               if (zip_header.cmpsize == 0) dd_ahead = 1; // As we don't know how long this file it is difficult to skip! but it is compressed, so normally its ok
+                               if (zip_header.ucmpsize != 0) dd_ahead = 2; // Humm... we would otherwise skip this twice - not good!
+                       }
+                       break;
+               case ZIP_CDS_MAGIC: /* FALLTHRU */
+               case ZIP_CDS_END_MAGIC:
+                       return(NULL);
+                       break;
+               case ZIP_DD_MAGIC: {
+                       int cmpsize;
+                       seek_sub_file(zip_stream, 4); // Skip crc32
+                       fread(&cmpsize, 4, 1, zip_stream);
+                       archive_offset += 4;
+                       if (dd_ahead == 1) archive_offset += cmpsize;
+                       seek_sub_file(zip_stream, 4); // Skip uncompressed size
+                       dd_ahead = 0;
+                       return (get_header_zip(zip_stream));
+                       break; }
+               default:
+                       if (!dd_ahead) error_msg("Invalid magic (%#x): Trying to skip junk", magic);
+                       dd_ahead = 0;
+                       while (!feof(zip_stream)) {
+                               int tmpmagic;
+                               tmpmagic = fgetc(zip_stream);
+                               archive_offset++;
+                               magic = ((magic >> 8) & 0x00ffffff) | ((tmpmagic << 24) & 0xff000000);
+                               if (magic == ZIP_FILEHEADER_MAGIC || magic == ZIP_CDS_MAGIC || magic == ZIP_CDS_END_MAGIC) goto checkmagic;
+                       }
+                       error_msg("End of archive reached: Bad archive");
+                       return(NULL);
+       }
+       //if (archive_offset != ftell(zip_stream)) printf("Archive offset out of sync (%d,%d)\n", (int) archive_offset, (int) ftell(zip_stream));
+       return(zip_entry);
+}
index ff9b5876fd714de419dab7046ea2e185493c1ec3..41be963efa294d9fabb620a4a44c1fbd4139fcbd 100644 (file)
@@ -120,7 +120,8 @@ char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *f
                                                return NULL;
                                        }
                                        archive_offset += file_entry->size;
-                                       copy_file_chunk(src_stream, dst_stream, file_entry->size);                      
+                                       if (file_entry->extract_func) file_entry->extract_func(src_stream, dst_stream);
+                                       else copy_file_chunk(src_stream, dst_stream, file_entry->size);                 
                                        fclose(dst_stream);
                                }
                                break;
index 6c28d181d05394cd49934d63cb8f31c7ac7dd421..8075fd7175d9a62f84a4af0a991b7d42ab965a99 100644 (file)
@@ -80,7 +80,7 @@ static const int ERROR = 1;
 
 /*
  * window size--must be a power of two, and
- *  at least 32K for zip's deflate method 
+ *  at least 32K for zip's deflate method
  */
 static const int WSIZE = 0x8000;
 
@@ -846,7 +846,7 @@ static int inflate_block(int *e)
  *
  * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
  */
-static int inflate(void)
+extern int inflate(FILE *in, FILE *out)
 {
        int e;                          /* last block flag */
        int r;                          /* result code */
@@ -857,6 +857,13 @@ static int inflate(void)
        bk = 0;
        bb = 0;
 
+       in_file = in;
+       out_file = out;
+
+       /* Allocate all global buffers (for DYN_ALLOC option) */
+       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
+       bytes_out = 0L;
+
        /* Create the crc table */
        make_crc_table();
 
@@ -881,13 +888,15 @@ static int inflate(void)
 
        /* flush out window */
        flush_window();
+       free(window);
+       free(crc_table);
 
        /* return success */
        return 0;
 }
 
 /* ===========================================================================
- * Unzip in to out.  This routine works on both gzip and pkzip files.
+ * Unzip in to out.  This routine works on gzip files only.
  *
  * IN assertions: the buffer inbuf contains already the beginning of
  *   the compressed data, from offsets inptr to insize-1 included.
@@ -901,9 +910,6 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
        typedef void (*sig_type) (int);
        unsigned short i;
 
-       in_file = l_in_file;
-       out_file = l_out_file;
-
        if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
                (void) signal(SIGINT, (sig_type) abort_gzip);
        }
@@ -918,53 +924,48 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
        }
 #endif
 
-       /* Allocate all global buffers (for DYN_ALLOC option) */
-       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
-       outcnt = 0;
-       bytes_out = 0L;
-
        /* Magic header for gzip files, 1F 8B = \037\213 */
-       if ((fgetc(in_file) != 0x1F) || (fgetc(in_file) != 0x8b)) { 
+       if ((fgetc(l_in_file) != 0x1F) || (fgetc(l_in_file) != 0x8b)) {
                error_msg("Invalid gzip magic");
                return EXIT_FAILURE;
        }
 
        /* Check the compression method */
-       if (fgetc(in_file) != 8) {
+       if (fgetc(l_in_file) != 8) {
                error_msg("Unknown compression method");
                return(-1);
        }
 
-       flags = (unsigned char) fgetc(in_file);
+       flags = (unsigned char) fgetc(l_in_file);
 
        /* Ignore time stamp(4), extra flags(1), OS type(1) */
        for (i = 0; i < 6; i++) {
-               fgetc(in_file);
+               fgetc(l_in_file);
        }
 
        if (flags & 0x04) {
                /* bit 2 set: extra field present */
-               const unsigned short extra = fgetc(in_file) + (fgetc(in_file) << 8);
+               const unsigned short extra = fgetc(l_in_file) + (fgetc(l_in_file) << 8);
 
                for (i = 0; i < extra; i++) {
-                       fgetc(in_file);
+                       fgetc(l_in_file);
                }
        }
 
        /* Discard original name if any */
        if (flags & 0x08) {
                /* bit 3 set: original file name present */
-               while (fgetc(in_file) != 0);    /* null */
+               while (fgetc(l_in_file) != 0);  /* null */
        }
 
        /* Discard file comment if any */
        if (flags & 0x10) {
                /* bit 4 set: file comment present */
-               while (fgetc(in_file) != 0);    /* null */
+               while (fgetc(l_in_file) != 0);  /* null */
        }
 
        /* Decompress */
-       if (inflate() != 0) {
+       if (inflate(l_in_file, l_out_file) != 0) {
                error_msg("invalid compressed data--format violated");
        }
 
@@ -972,7 +973,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
         * crc32  (see algorithm.doc)
         * uncompressed input size modulo 2^32
         */
-       fread(buf, 1, 8, in_file);
+       fread(buf, 1, 8, l_in_file);
 
        /* Validate decompression - crc */
        if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
@@ -983,14 +984,11 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
                error_msg("invalid compressed data--length error");
        }
 
-       free(window);
-       free(crc_table);
-
        return 0;
 }
 
 /*
- * This needs access to global variables wondow and crc_table, so its not in its own file.
+ * This needs access to global variables window and crc_table, so its not in its own file.
  */
 extern void gz_close(int gunzip_pid)
 {
diff --git a/archival/unzip.c b/archival/unzip.c
new file mode 100644 (file)
index 0000000..ae0d7c1
--- /dev/null
@@ -0,0 +1,94 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini unzip implementation for busybox
+ *
+ * Copyright (C) 2001 by Laurence Anderson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "unarchive.h"
+#include "busybox.h"
+
+extern int unzip_main(int argc, char **argv)
+{
+       FILE *src_stream;
+       int extract_function = extract_all_to_fs | extract_create_leading_dirs;
+       char **extract_names = NULL;
+       char **exclude_names = NULL;
+       int opt = 0;
+       int num_of_entries = 0;
+       int exclude = 0;
+       char *outdir = "./";
+       FILE *msgout = stdout;
+
+       while ((opt = getopt(argc, argv, "lnopqxd:")) != -1) {
+               switch (opt) {
+                       case 'l':
+                               extract_function |= extract_verbose_list;
+                               extract_function ^= extract_all_to_fs;
+                               break;
+                       case 'n':
+                               break;
+                       case 'o':
+                               extract_function |= extract_unconditional;
+                               break;
+                       case 'p':
+                               extract_function |= extract_to_stdout;
+                               extract_function ^= extract_all_to_fs;
+                               /* FALLTHROUGH */
+                       case 'q':
+                               msgout = xfopen("/dev/null", "w");
+                               break;
+                       case 'd':
+                               outdir = xstrdup(optarg);
+                               strcat(outdir, "/");
+                               break;
+                       case 'x':
+                               exclude = 1;
+                               break;
+               }
+       }
+
+       if (optind == argc) {
+               show_usage();
+       }
+
+       if (*argv[optind] == '-') src_stream = stdin;
+       else src_stream = xfopen(argv[optind++], "r");
+
+       while (optind < argc) {
+               if (exclude) {
+                       exclude_names = xrealloc(exclude_names, sizeof(char *) * (num_of_entries + 2));
+                       exclude_names[num_of_entries] = xstrdup(argv[optind]);
+               } else {
+                       extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
+                       extract_names[num_of_entries] = xstrdup(argv[optind]);
+               }
+               num_of_entries++;
+               if (exclude) exclude_names[num_of_entries] = NULL;
+               else extract_names[num_of_entries] = NULL;
+               optind++;
+       }
+
+       unarchive(src_stream, msgout, &get_header_zip, extract_function, outdir, extract_names, exclude_names);
+       return EXIT_SUCCESS;
+}
index ba0a9aaa98dc6b10df72ca3254e75f3d04077bb0..0d310bdc329da63c4d12b58d07fdce23bfc34c09 100644 (file)
 #ifdef CONFIG_UNIX2DOS
        APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN)
 #endif
+#ifdef CONFIG_UNZIP
+       APPLET(unzip, unzip_main, _BB_DIR_USR_BIN)
+#endif
 #ifdef CONFIG_UPDATE
        APPLET(update, update_main, _BB_DIR_SBIN)
 #endif
index fccdf5fdff9845c5389e4d13514c20cbb0d9807c..8dadfd9584048e1a79d2ddaba15001c9fd76bbae 100644 (file)
@@ -215,6 +215,7 @@ extern long arith (const char *startbuf, int *errcode);
 int read_package_field(const char *package_buffer, char **field_name, char **field_value);
 char *fgets_str(FILE *file, const char *terminating_string);
 
+extern int inflate(FILE *in, FILE *out);
 extern int unzip(FILE *l_in_file, FILE *l_out_file);
 extern void gz_close(int gunzip_pid);
 extern FILE *gz_open(FILE *compressed_file, int *pid);
index be49f3d01955183c6e14ff711ab784d500de0e0b..eada1c3376052e073adef7f07625f8c8e65f5261 100644 (file)
@@ -26,11 +26,13 @@ typedef struct file_headers_s {
        mode_t mode;
        time_t mtime;
        dev_t device;
+       int (*extract_func)(FILE *, FILE *);
 } file_header_t;
 
 file_header_t *get_header_ar(FILE *in_file);
 file_header_t *get_header_cpio(FILE *src_stream);
 file_header_t *get_header_tar(FILE *tar_stream);
+file_header_t *get_header_zip(FILE *zip_stream);
 
 void seek_sub_file(FILE *src_stream, const int count);
 
index 20e2448fd3f181c6e233f00185eaa49419380104..cd3af9c550b675e201f66d815d01319c65046f18 100644 (file)
        "\t-u\toutput will be in UNIX format\n" \
        "\t-d\toutput will be in DOS format"
 
+#define unzip_trivial_usage \
+       "[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]"
+#define unzip_full_usage \
+       "Extracts files from ZIP archives\n" \
+       "Options:\n" \
+       "\t-l\tlist archive contents (short form)\n" \
+       "\t-n\tnever overwrite existing files (default)\n" \
+       "\t-o\toverwrite files without prompting\n" \
+       "\t-p\tsend output to stdout\n" \
+       "\t-q\tbe quiet\n" \
+       "\t-x\texclude these files\n" \
+       "\t-d\textract files into this directory"
+
 #define update_trivial_usage \
        "[options]"
 #define update_full_usage \
index 6c28d181d05394cd49934d63cb8f31c7ac7dd421..8075fd7175d9a62f84a4af0a991b7d42ab965a99 100644 (file)
@@ -80,7 +80,7 @@ static const int ERROR = 1;
 
 /*
  * window size--must be a power of two, and
- *  at least 32K for zip's deflate method 
+ *  at least 32K for zip's deflate method
  */
 static const int WSIZE = 0x8000;
 
@@ -846,7 +846,7 @@ static int inflate_block(int *e)
  *
  * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
  */
-static int inflate(void)
+extern int inflate(FILE *in, FILE *out)
 {
        int e;                          /* last block flag */
        int r;                          /* result code */
@@ -857,6 +857,13 @@ static int inflate(void)
        bk = 0;
        bb = 0;
 
+       in_file = in;
+       out_file = out;
+
+       /* Allocate all global buffers (for DYN_ALLOC option) */
+       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
+       bytes_out = 0L;
+
        /* Create the crc table */
        make_crc_table();
 
@@ -881,13 +888,15 @@ static int inflate(void)
 
        /* flush out window */
        flush_window();
+       free(window);
+       free(crc_table);
 
        /* return success */
        return 0;
 }
 
 /* ===========================================================================
- * Unzip in to out.  This routine works on both gzip and pkzip files.
+ * Unzip in to out.  This routine works on gzip files only.
  *
  * IN assertions: the buffer inbuf contains already the beginning of
  *   the compressed data, from offsets inptr to insize-1 included.
@@ -901,9 +910,6 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
        typedef void (*sig_type) (int);
        unsigned short i;
 
-       in_file = l_in_file;
-       out_file = l_out_file;
-
        if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
                (void) signal(SIGINT, (sig_type) abort_gzip);
        }
@@ -918,53 +924,48 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
        }
 #endif
 
-       /* Allocate all global buffers (for DYN_ALLOC option) */
-       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
-       outcnt = 0;
-       bytes_out = 0L;
-
        /* Magic header for gzip files, 1F 8B = \037\213 */
-       if ((fgetc(in_file) != 0x1F) || (fgetc(in_file) != 0x8b)) { 
+       if ((fgetc(l_in_file) != 0x1F) || (fgetc(l_in_file) != 0x8b)) {
                error_msg("Invalid gzip magic");
                return EXIT_FAILURE;
        }
 
        /* Check the compression method */
-       if (fgetc(in_file) != 8) {
+       if (fgetc(l_in_file) != 8) {
                error_msg("Unknown compression method");
                return(-1);
        }
 
-       flags = (unsigned char) fgetc(in_file);
+       flags = (unsigned char) fgetc(l_in_file);
 
        /* Ignore time stamp(4), extra flags(1), OS type(1) */
        for (i = 0; i < 6; i++) {
-               fgetc(in_file);
+               fgetc(l_in_file);
        }
 
        if (flags & 0x04) {
                /* bit 2 set: extra field present */
-               const unsigned short extra = fgetc(in_file) + (fgetc(in_file) << 8);
+               const unsigned short extra = fgetc(l_in_file) + (fgetc(l_in_file) << 8);
 
                for (i = 0; i < extra; i++) {
-                       fgetc(in_file);
+                       fgetc(l_in_file);
                }
        }
 
        /* Discard original name if any */
        if (flags & 0x08) {
                /* bit 3 set: original file name present */
-               while (fgetc(in_file) != 0);    /* null */
+               while (fgetc(l_in_file) != 0);  /* null */
        }
 
        /* Discard file comment if any */
        if (flags & 0x10) {
                /* bit 4 set: file comment present */
-               while (fgetc(in_file) != 0);    /* null */
+               while (fgetc(l_in_file) != 0);  /* null */
        }
 
        /* Decompress */
-       if (inflate() != 0) {
+       if (inflate(l_in_file, l_out_file) != 0) {
                error_msg("invalid compressed data--format violated");
        }
 
@@ -972,7 +973,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
         * crc32  (see algorithm.doc)
         * uncompressed input size modulo 2^32
         */
-       fread(buf, 1, 8, in_file);
+       fread(buf, 1, 8, l_in_file);
 
        /* Validate decompression - crc */
        if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
@@ -983,14 +984,11 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
                error_msg("invalid compressed data--length error");
        }
 
-       free(window);
-       free(crc_table);
-
        return 0;
 }
 
 /*
- * This needs access to global variables wondow and crc_table, so its not in its own file.
+ * This needs access to global variables window and crc_table, so its not in its own file.
  */
 extern void gz_close(int gunzip_pid)
 {