unzip applet by Laurence Anderson
----------------------------------------------------------------------
diff --git a/archival/libunarchive/Makefile b/archival/libunarchive/Makefile
index 0c7219d..a8409a4 100644
--- a/archival/libunarchive/Makefile
+++ b/archival/libunarchive/Makefile
@@ -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 @@
 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
diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libunarchive/decompress_unzip.c
index 6c28d18..8075fd7 100644
--- a/archival/libunarchive/decompress_unzip.c
+++ b/archival/libunarchive/decompress_unzip.c
@@ -80,7 +80,7 @@
 
 /*
  * 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 @@
  *
  * 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 @@
 	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 @@
 
 	/* 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 @@
 	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 @@
 	}
 #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 @@
 	 * 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 @@
 		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
index 0000000..84f2a54
--- /dev/null
+++ b/archival/libunarchive/get_header_zip.c
@@ -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);
+}
diff --git a/archival/libunarchive/unarchive.c b/archival/libunarchive/unarchive.c
index ff9b587..41be963 100644
--- a/archival/libunarchive/unarchive.c
+++ b/archival/libunarchive/unarchive.c
@@ -120,7 +120,8 @@
 						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;
diff --git a/archival/libunarchive/unzip.c b/archival/libunarchive/unzip.c
index 6c28d18..8075fd7 100644
--- a/archival/libunarchive/unzip.c
+++ b/archival/libunarchive/unzip.c
@@ -80,7 +80,7 @@
 
 /*
  * 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 @@
  *
  * 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 @@
 	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 @@
 
 	/* 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 @@
 	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 @@
 	}
 #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 @@
 	 * 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 @@
 		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)
 {