diff -urpN john-1.7.8-jumbo-6a/src/misc.c john-1.7.8-jumbo-6b/src/misc.c
--- john-1.7.8-jumbo-6a/src/misc.c	2011-08-30 14:57:27.296875000 +0000
+++ john-1.7.8-jumbo-6b/src/misc.c	2011-09-06 18:35:09.000000000 +0000
@@ -157,4 +157,16 @@ char *strlwr(char *s)
 
 	return s;
 }
+char *strupr(char *s)
+{
+	unsigned char *ptr = (unsigned char *)s;
+
+	while (*ptr)
+	if (*ptr >= 'a' && *ptr <= 'z')
+		*ptr++ ^= 0x20;
+	else
+		ptr++;
+
+	return s;
+}
 #endif
diff -urpN john-1.7.8-jumbo-6a/src/misc.h john-1.7.8-jumbo-6b/src/misc.h
--- john-1.7.8-jumbo-6a/src/misc.h	2011-08-30 14:57:27.312500000 +0000
+++ john-1.7.8-jumbo-6b/src/misc.h	2011-09-06 12:56:33.000000000 +0000
@@ -65,8 +65,10 @@ extern char *strnzcat(char *dst, const c
  */
 #ifndef _MSC_VER
 extern char *strlwr(char *s);
+extern char *strupr(char *s);
 #else
 #define strlwr _strlwr
+#define strupr _strupr
 #define strdup _strdup
 #endif
 
diff -urpN john-1.7.8-jumbo-6a/src/pkzip.h john-1.7.8-jumbo-6b/src/pkzip.h
--- john-1.7.8-jumbo-6a/src/pkzip.h	2011-08-30 14:57:27.500000000 +0000
+++ john-1.7.8-jumbo-6b/src/pkzip.h	2011-09-09 20:02:52.000000000 +0000
@@ -46,30 +46,42 @@ static const u32 pkz_crc_32_tab[] =
 
 #define pkzip_crc32(crc,byte) (pkz_crc_32_tab[(u8)((crc)^(byte))] ^ ((crc) >> 8))
 
-#define UBUF_SIZE (32*1024)
-#define MAX_PKZ_FILES 8
+#define MAX_PKZ_FILES 3
+
+#if USE_PKZIP_MAGIC
+typedef struct zip_magic_signatures_t {
+	u8 *magic_signature[8];
+	u8  magic_sig_len[8];
+	u8  magic_count;
+	u8  max_len;
+} ZIP_SIGS;
+#endif
+typedef struct zip_hash_type_t {
+	u8 *h;
+	u16 c;
+	u32 datlen;
+	u8 magic;					// This is used as 'magic' signature type. Also, 255 is 'generic text'
+	u8 full_zip;
+	u32 compType;				// the type of compression  0 or 8
+#if USE_PKZIP_MAGIC
+	ZIP_SIGS *pSig;
+#endif
+} ZIP_HASH;
+
 typedef struct zip_salt_t {
 	u32 cnt;					// number of hashes
 	u32 chk_bytes;				// number of bytes valid in checksum (1 or 2)
-	u32 flags;					// bit mask, that tells us what data is provided in the hash line, and also can tell us what steps to take or not take.
-	u8 h[MAX_PKZ_FILES][12];	// hash data (up to 8)
-	u16 c[MAX_PKZ_FILES];		// the 1 or 2 byte checksums (that match the 1 to 8 hashes)
-	u32 asciilen;				// the length of the asciidat field. This does not tell us how long it decomresses to, but tells us its compressed length.
-	u32 asciiCompType;			// a 0 or 8  (stored or imploded, the only types we handle.).
-	u8 *asciidat;
-	u8 *ascii_decr;
-	u8 *ascii_ucmp;
-	u32 ascii_ucmp_len;
-	u8 *encrDat;				// Encrypted data from the zip file. May be partial, or may be 'full'.  If an ASCII file, then partial will work.
+	ZIP_HASH H[MAX_PKZ_FILES];
 	u32 crc32;					// if a 'full' file of encr data, then this is the CRC
 	u32 compLen;				// length of compressed data (whether part or full)
 	u32 deCompLen;				// length of decompressed data (if full).
 	u32 compType;				// the type of compression  0 or 8
-	long     offset;
-	char *filename;
-	char *ifilename;
-	u8 *full_encr_dat;
-	u8 *full_decr_dat;
+	u32 full_zip_idx;			// the index (0, 1, 2) which contains the 'full zip' data.
+	char *fname;				// if the zip is too large, we open the file in cmp_exact read the
+								// data a small buffer at a time.  If the zip blob is small enough
+								// (under 16k), then it simply read into H[x].h at init() time.
+								// and cmp_exact does not need fname to be used.
+	u32 offset;					// this is the offset to zip data (if we have to read from the file).
 } PKZ_SALT;
 
 typedef union MY_WORD {
diff -urpN john-1.7.8-jumbo-6a/src/pkzip_fmt_plug.c john-1.7.8-jumbo-6b/src/pkzip_fmt_plug.c
--- john-1.7.8-jumbo-6a/src/pkzip_fmt_plug.c	2011-09-01 15:26:20.968750000 +0000
+++ john-1.7.8-jumbo-6b/src/pkzip_fmt_plug.c	2011-09-09 20:44:27.000000000 +0000
@@ -20,9 +20,11 @@
 #include "arch.h"
 #include "misc.h"
 #include "formats.h"
+//#define USE_PKZIP_MAGIC 1
 #include "pkzip.h"
 
 #include "zlib.h"
+#include "pkzip_inffixed.h"  // This file is a data file, taken from zlib
 
 #ifdef _OPENMP
 #include <omp.h>
@@ -33,7 +35,7 @@
 #define ALGORITHM_NAME			"N/A"
 
 #define BENCHMARK_COMMENT		""
-#define BENCHMARK_LENGTH		0
+#define BENCHMARK_LENGTH		-1001
 
 #define PLAINTEXT_LENGTH		31
 
@@ -49,7 +51,8 @@
 #define MAX_KEYS_PER_CRYPT		64
 #endif
 
-//#define ZIP_DEBUG
+//#define ZIP_DEBUG 1
+//#define ZIP_DEBUG 2
 
 /*
  * It is likely that this should be put into the arch.h files for the different systems,
@@ -59,79 +62,70 @@
  */
 #define PKZIP_USE_MULT_TABLE
 
+#if ARCH_LITTLE_ENDIAN
+#define KB1 0
+#define KB2 3
+#else
+#define KB1 3
+#define KB2 0
+#endif
+
 /*
- *  format:
- *    $pkzip1$					version 1 of pkzip hashes.
- *    Number of test records*
- *    bytes_of_checksum_valid*	Either 1 or 2 byte validation.  PKZIP > 2 will only use 1.
- *                               Older stuff (and many unixes), validate against both bytes.
- *                               These both byte validations cuts down a lot on items needing
- *                               to be validated.
+ *  format:  filename:$pkzip$C*B*[DT*MT{CL*UL*CR*OF*OX}*CT*DL*DA]*$/pkzip$
  *
- *    Flags (which fields are present, after the checksum hashes).
- *      1 chksum_tst_only  (only does a checksum test, not the decompress test)
- *      2 ASCII.     Field ascii length, and ascii 'hash' will be filled in.
- *      4 CRC_LEN    Fields CRC32, comp_len and decomp_len filled in.
- *      8 FileName   Fields Offset and FileName are filled in
- *      16 FileData  The .zip compressed/encrypted data will be provided.
+ * All numeric and 'binary data' fields are stored in hex.
+ *
+ * C   is the count of hashes present (the array of items, inside the []  C can be 1 to 3.).
+ * B   is number of valid bytes in the checksum (1 or 2).  Unix zip is 2 bytes, all others are 1
+ * ARRAY of data starts here (there will be C array elements)
+ *   DT  is a "Data Type enum".  This will be 1 2 or 3.  1 is 'partial'. 2 and 3 are full file data (2 is inline, 3 is load from file).
+ *   MT  Magic Type enum.  0 is no 'type'.  255 is 'text'. Other types (like MS Doc, GIF, etc), see source.
+ *     NOTE, CL, DL, CRC, OFF are only present if DT != 1
+ *     CL  Compressed length of file blob data (includes 12 byte IV).
+ *     UL  Uncompressed length of the file.
+ *     CR  CRC32 of the 'final' file.
+ *     OF  Offset to the PK\x3\x4 record for this file data. If DT==2, then this will be a 0, as it is not needed, all of the data is already included in the line.
+ *     OX  Additional offset (past OF), to get to the zip data within the file.
+ *     END OF 'optional' fields.
+ *   CT  Compression type  (0 or 8)  0 is stored, 8 is imploded.
+ *   DL  Length of the DA data.
+ *   DA  This is the 'data'.  It will be hex data if DT==1 or 2. If DT==3, then it is a filename (name of the .zip file).
+ * END of array items.
+ * The format string will end with $/pkzip$
+ *
+ * NOTE, after some code testing, it has come to show, that the 'magic' may not be needed, or very useful. The problem with it, is IF the file
+ * ends up NOT starting with any of the magic values, then we will have a false negative, and NEVER be able to crack the zip's password. For now
+ * we have a #define (right before the #include "pkzip.h").  If that define is uncommented, then pkzip format will be built with magic logic. 
+ * However, right now it is not being built that way.
  *
- *     12_byte_hash_plus_2_byte_chksum_inhex*    This is the 12 byte hash of the file,
- *                                               and the 2 bytes of crc.
- *     [12_byte_hash2*[hash3*[hash4*[hash5*]]]]  (up to 5 files from a zip file can be here.
- *                                               More files means a 'correct' checksum is
- *                                               likely to be the right one.
- *     ASCII hash len*   if flags&2
- *     asciiCompType*    if flags&2
- *     ASCII hash data*  if flags&2
- *     CRC32*            if flags&4
- *     Compr_len*        if flags&4
- *     deCompr_len*      if flags&4
- *     compType*         if flags&4       The compression type of the 'whole' blob. 0 or 8
- *     Offset*           Only if flags&8  this is the offset from start of file to the
- *                                        compressed/encrypted deflated 'blob' of data.
- *     FileName*         if flags&8       the name of the .zip file.  NOTE, that file WILL be
- *                                        required.  Filename cant contain a '*' charcter.
- *     InternalFName*    if flags*8       This is the name of the file.  Used if we implement
- *                                        a spawn to unzip -P to test passwords.
- *     FileData*         if flags&16      This IS the .zip data (the compressed/encrypted blob.
- *                                        If the file is small (or a small one 'exists' in the
- *                                        .zip, then the data can be put here inline.
  */
 static struct fmt_tests tests[] = {
-	/* a few 'simple' checksum only hashes */
-	{"$pkzip1$1*2*1*c97839b8fe9e0373ba3c7b29ac6f************", "love"},
-	{"$pkzip1$1*1*1*4f83334e87f67a42fce2a53ef967************", "john"},
-	{"$pkzip1$1*1*1*fcf7385e0c4466cd621743a7f967************", "john"},
-	/* 4 hashes in the next one. */
-	{"$pkzip1$4*2*1*dce4fb16f19b70cf9c368a5c139b*e27bc3e3adb1cc0f227758f38b8d*20f4ad0590ec2b44ff8510266aec*f63277b2a5ea02bcaed067ee71a6************", "john"},
-	/* 8 hashes (max) made with info-zip (2 byte checksums, NOTE they are all the same, since the files were created close to each other) */
-	{"$pkzip1$8*2*1*a4a8ac4a5dc8e54105390fb0742d*828c2ccc5be1dbd632aefa1c742d*7a89efd471da46d59570a465742d*47a2799835a2adffd7dbb4ef742d*f71e5644a2efb450173602d6742d*\
-b09fa98d83f0bb3a06a8bed0742d*1a042b99ad076f9a41e250f8742d*26222d5d8d26f6506c8c9fec742d************", "P^$sW0R9"},
-	/* 8 hashes (max) made by pkzip, so only 1 byte 'valid' */
-	{"$pkzip1$8*1*1*c18675da635e8c05bd4a1b76e162*4be88995ea780d02014c37cdf651*40a798f2dd1482860aea6e70e539*b146f66e800914fcfdd9f17e635c*05570fc392bf9e40080425c9901f*\
-234302627ca721b2acf8d97bcde1*057b6feb54ad24fa8e028e821233*89fc3126769848e44102d741a8c1************", "P^$sW0R9"},
-	{"$pkzip1$1*2*1*20f4ad0590ec2b44ff8510266aec************", "john"},
-	/* 1 hash, an ASCII check (step 2), and a 'full' inline test blob (test 3) */
-	{"$pkzip1$1*2*16*20f4ad0590ec2b44ff8510266aec*38*8*20f4ad0590ec2b44ff85102650314ec911cc2227bdb0e5ced23ea8517ce4bdc5ec77136e450641fcfe317fd36e069de280f6623e34085186*f967d462*\
-54*49*8****20F4AD0590EC2B44FF85102650314EC911CC2227BDB0E5CED23EA8517CE4BDC5EC77136E450641FCFE317FD36E069DE280F6623E34085186F3A4FEE45EB6D4C6AABF9B7A5A142D456CF542C1EB35BCAAE120330D*", "john"},
-    /* 1 hash, and an ASCII check (step 2) */
-	{"$pkzip1$1*2*2*20f4ad0590ec2b44ff8510266aec*38*8*20f4ad0590ec2b44ff85102650314ec911cc2227bdb0e5ced23ea8517ce4bdc5ec77136e450641fcfe317fd36e069de280f6623e34085186*********", "john"},
-	/* 1 hash, and a 'full' inline test blob (test 3) */
-	{"$pkzip1$5*1*14*556f978a58fa4d1bbd18c6ad7cf3*15d082fd66f783745e02a9a4e138*515d1afdf3036ceddd74f6c2e6a0*117e84fce498fc1aa4ba251efed7*55f7bd45d53f0345aac7a408ac0f*\
-***fed7246b*4c6*e00*8****117e84fce498fc1aa4ba251e5eae6d70747ce420626b1306568499b7600bc9758b0cb03b3eec5343b745b24a41f26b95794af638ff195878692a7bb012d6457bc36b6b48a4f01e99b5c7febaeee\
-a045abd0286f8fe676bbf28c6232555b71f242794cb3bf9df89eab681e8436c7fdc561c951d2ffbf6e3ac5302cbad5706c5f59f8f1806e76b465f1f4280e829db18c0ddc3b181b6fa992076b6f1641539b5f45142004db41d5ed\
-158338f663822612bd8ad18676dc7d40148bb006e4d4033f9dfe80526862286afb908d2f46b895cdc11e15fd2712932ba491a82aeadc231612c6cbc304858d80a46378f72dcda91ea70adfeda96c0fbdd17a954dd4f88fb6c44b\
-d362e0302fe209ac1b9a06a1b7f35dc6208b58d5315058322c85117184e279f4aaec3870a8f05dc2aff0e8bc8613adbc30a95f77f9594132027f44217164c193ab2568a7c175bc41bb6ba96e847746e40d179cc41da890049d35\
-7488645ff4ec952254f47c5d48edb59e1f46a406ae7c2002c88706168dcd24dd4829e9ea454e67ebe2633d162f0d50c41a3a78e6582ce132cf580dc507be23b4e58c9ef2f45d61b909ba68dc1b765e97699207d76e4f488b45be\
-a674feaa56f05bfbb9e103aef0790df9d57097803842aa9c975d4ddaaf68c770a54f815e64b518972feba8381f7d4ab36a3fef1098d75bad8d8bb87f2316e8f20e18e26955120b5c563b6017dd3d7e9ad00e38f60a00f516455f\
-70b9ce84cb46104de15130ecdb28d836197b35b0c2ac87f60ee5eda4dd1a0873ca9932027b1cccada6a00f2d3de6f682f0b74e8baccd40ffc3fc9765a6dd3f4f06e3ad33bb4f82f200d65040fa13ed4abc0204e97fc84bc819bb\
-95e20c8d58bff5b269c26a99094fa3333f857b36bfa1de58d99fcaee4f0261272d780d7416eae9606984599c65b29e5e83cfedbf5b6a3fc6047294770fded9f64dfbe05a933840a2a27aa7c5b13b6a5de598de67f7c8d531ccbd\
-9089c2aa081d95166f88650acf3804097ef5b65d3883397cdea39b33f5e490ed4677884c15270dce76970be24d8efcbdd7880dd9ef849aabfb5359cdcdbcd68dbe985b53caed3442ef0e2fe584bab26c84f5f3e26a6d15d6ceba\
-e5610c81da50ced1bd4d24e4761a9a33a48dd818af569ed9370d1a68436a1e285c454830af0a34402d810cf95044c24cc0b6f8602afc97229662a2ecc7791d4b9adbe763f4e873d98a8c71f7d378aa07e55d922500857c633885\
-501ef3444c1a169d07f16c72896f299472d21d09258ee8a82b2b8bb224557ca8f2fc0dcb5dd2a7548cc65937d8c160dc6e26dd0cbbc011c6bf85f60d944364052e1e7369eaa2c32f7203e8efc4b4bb4744d6d8f5272335377222\
-9f51dba75b8f695f824f0d23c69e257200d61091a55213b23dc3902960f27b66995a06c7796f87d9abe4aa1a94f7907d97d20f2591d8f370940d7419d732fdb13a93989467e5773c9ae3320c8ae9cfe0ce3b482bffd35be7df11\
-e3a33789cd383c4b56fa26aab823228e163c0981e73426dd3f5d0e2c887de924e7abdfe5818f98fde9afb359fe13925161cb017c0ac5be55a7294958e8792a0172bcdeb2605402ccf1299011e86861e85204b8c46afceea53502\
-d0cf4f6b2c23618eb41064842441345b3792abd1a258da71e54b3bddc542b566137e718d59ed219c6331d2846ed6fdeafe1d6f572fd87f28c1cd45f3d7122e0ae*", "password"},
+
+	/* compression of a perl file. We have the same password, same file used twice in a row (pkzip, 1 byte checksum).  NOTE, pkzip uses random IV, so both encrypted blobs are different */
+	{"\
+$pkzip$1*1*2*0*e4*1c5*eda7a8de*0*4c*8*e4*eda7*194883130e4c7419bd735c53dec36f0c4b6de6daefea0f507d67ff7256a49b5ea93ccfd9b12f2ee99053ee0b1c9e1c2b88aeaeb6bd4e60094a1ea118785d4ded6dae94\
+cade41199330f4f11b37cba7cda5d69529bdfa43e2700ba517bd2f7ff4a0d4b3d7f2559690ec044deb818c44844d6dd50adbebf02cec663ae8ebb0dde05d2abc31eaf6de36a2fc19fda65dd6a7e449f669d1f8c75e9daa0a3f7b\
+e8feaa43bf84762d6dbcc9424285a93cedfa3a75dadc11e969065f94fe3991bc23c9b09eaa5318aa29fa02e83b6bee26cafec0a5e189242ac9e562c7a5ed673f599cefcd398617*$/pkzip$", "password" },
+	{"\
+$pkzip$1*1*2*0*e4*1c5*eda7a8de*0*4c*8*e4*eda7*581f798527109cbadfca0b3318435a000be84366caf9723f841a2b13e27c2ed8cdb5628705a98c3fbbfb34552ed498c51a172641bf231f9948bca304a6be2138ab718f\
+6a5b1c513a2fb80c49030ff1a404f7bd04dd47c684317adea4107e5d70ce13edc356c60bebd532418e0855428f9dd582265956e39a0b446a10fd8b7ffb2b4af559351bbd549407381c0d2acc270f3bcaffb275cbe2f628cb09e2\
+978e87cd023d4ccb50caaa92b6c952ba779980d65f59f664dde2451cc456d435188be59301a5df1b1b4fed6b7509196334556c44208a9d7e2d9e237f591d6c9fc467b408bf0aaa*$/pkzip$", "password" },
+	/* Now the same file, compressed twice, using unix zip (info-zip), with 2 byte checksums */
+	{"\
+$pkzip$1*2*2*0*e4*1c5*eda7a8de*0*47*8*e4*4bb6*436c9ffa4328870f6272349b591095e1b1126420c3041744650282bc4f575d0d4a5fc5fb34724e6a1cde742192387b9ed749ab5c72cd6bb0206f102e9216538f095fb7\
+73661cfde82c2e2a619332998124648bf4cd0da56279f0c297567d9b5d684125ee92920dd513fd18c27afba2a9633614f75d8f8b9a14095e3fafe8165330871287222e6681dd9c0f830cf5d464457b257d0900eed29107fad8af\
+3ac4f87cf5af5183ff0516ccd9aeac1186006c8d11b18742dfb526aadbf2906772fbfe8fb18798967fd397a724d59f6fcd4c32736550986d227a6b447ef70585c049a1a4d7bf25*$/pkzip$", "password" },
+	{"\
+$pkzip$1*2*2*0*e4*1c5*eda7a8de*0*47*8*e4*4bb6*436c9ffa4328870f6272349b591095e1b1126420c3041744650282bc4f575d0d4a5fc5fb34724e6a1cde742192387b9ed749ab5c72cd6bb0206f102e9216538f095fb7\
+73661cfde82c2e2a619332998124648bf4cd0da56279f0c297567d9b5d684125ee92920dd513fd18c27afba2a9633614f75d8f8b9a14095e3fafe8165330871287222e6681dd9c0f830cf5d464457b257d0900eed29107fad8af\
+3ac4f87cf5af5183ff0516ccd9aeac1186006c8d11b18742dfb526aadbf2906772fbfe8fb18798967fd397a724d59f6fcd4c32736550986d227a6b447ef70585c049a1a4d7bf25*$/pkzip$", "password"},
+	/* now a pkzip archive, with 3 files, 1 byte checksum */
+	{"\
+$pkzip$3*1*1*0*8*24*4001*8986ec4d693e86c1a42c1bd2e6a994cb0b98507a6ec937fe0a41681c02fe52c61e3cc046*1*0*8*24*4003*a087adcda58de2e14e73db0043a4ff0ed3acc6a9aee3985d7cb81d5ddb32b840ea20\
+57d9*2*0*e4*1c5*eda7a8de*0*4c*8*e4*eda7*89a792af804bf38e31fdccc8919a75ab6eb75d1fd6e7ecefa3c5b9c78c3d50d656f42e582af95882a38168a8493b2de5031bb8b39797463cb4769a955a2ba72abe48ee75b103\
+f93ef9984ae740559b9bd84cf848d693d86acabd84749853675fb1a79edd747867ef52f4ee82435af332d43f0d0bb056c49384d740523fa75b86a6d29a138da90a8de31dbfa89f2f6b0550c2b47c43d907395904453ddf42a665\
+b5f7662de170986f89d46d944b519e1db9d13d4254a6b0a5ac02b3cfdd468d7a4965e4af05699a920e6f3ddcedb57d956a6b2754835b14e174070ba6aec4882d581c9f30*$/pkzip$", "3!files"},
+
 	{NULL}
 };
 
@@ -144,16 +138,18 @@ static u32  K12[MAX_KEYS_PER_CRYPT*3];
 static PKZ_SALT *salt;
 static u8 chk[MAX_KEYS_PER_CRYPT];
 static int dirty=1;
+#if USE_PKZIP_MAGIC
+static ZIP_SIGS SIGS[256];
+#endif
 #ifdef PKZIP_USE_MULT_TABLE
 static u8 mult_tab[16384];
+#define PKZ_MULT(b,w) b^mult_tab[(u16)(w.u)>>2]
+#else
+inline u8 PKZ_MULT(u8 b, MY_WORD w) {u16 t = w.u|2; return b ^ (u8)(((u16)(t*(t^1))>>8)); }
 #endif
 
-/* This field is used in cmp_exact loop.  It is a buffer where we decompress     */
-/* a block at a time, while also performing CRC checking                         */
-static u8 ucpr_buf[UBUF_SIZE];
-
 extern struct fmt_main fmt_pkzip;
-static const char *ValidateZipContents(FILE *in, long offset, int len, u32 crc, const char *sIntName);
+static const char *ValidateZipContents(FILE *in, long offset, u32 offex, int len, u32 crc);
 
 /* Similar to strtok, but written specifically for the format. */
 static u8 *GetFld(u8 *p, u8 **pRet) {
@@ -186,6 +182,16 @@ static int is_hex_str(const u8 *cp) {
 	return 1;
 }
 
+unsigned get_hex_num(const u8 *cp) {
+	char b[3];
+	unsigned u;
+	b[0] = (c8)cp[0];
+	b[1] = (c8)cp[1];
+	b[2] = 0;
+	sscanf(b, "%x", &u);
+	return u;
+}
+
 /* Since the pkzip format textual representation is pretty complex, with multiple   */
 /* 'optional' sections, we have a VERY complete valid.  Valid will make SURE that   */
 /* the format is completely valid. Thus, there is little or no error checking later */
@@ -199,19 +205,20 @@ static int is_hex_str(const u8 *cp) {
 static int valid(char *ciphertext, struct fmt_main *pFmt)
 {
 	u8 *p, *cp;
-	int cnt, len;
-	u32 flags, crc;
+	int cnt, len, data_len;
+	u32 crc;
 	FILE *in;
 	const char *sFailStr;
-	char *sName, *sIntName;
 	long offset;
+	u32 offex;
+	int type;
 
-	if (strncmp(ciphertext, "$pkzip1$", 7))
+	if (strncmp(ciphertext, "$pkzip$", 6))
 		return 0;
 
 	cp = (u8*)str_alloc_copy(ciphertext);
 
-	p = &cp[8];
+	p = &cp[7];
 	p = GetFld(p, &cp);
 	if (!p || *p==0) {
 		sFailStr = "Out of data, reading count of hashes field"; goto Bail; }
@@ -221,85 +228,70 @@ static int valid(char *ciphertext, struc
 	p = GetFld(p, &cp);
 	if (!p || *p==0 || *cp < '1' || *cp > '2') {
 		sFailStr = "Number of valid hash bytes empty or out of range"; goto Bail; }
-	p = GetFld(p, &cp);
-	if (!p || *p==0 || cp[0] == 0 || !is_hex_str(cp)) {
-		sFailStr = "Flags field empty, or not a hex string"; goto Bail; }
-	sscanf((c8*)cp, "%x", &flags);
 
 	while (cnt--) {
 		p = GetFld(p, &cp);
-		if ( !p || *p==0 || strlen((c8*)cp) != 28 || !is_hex_str(cp)) {
-			sFailStr = "Invalid hash found (missing or not 28 bytes of hex)"; goto Bail; }
-	}
-
-	/* Handle flags&2 */
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&2) && (!strlen((c8*)cp) || !is_hex_str(cp)))) {
-			sFailStr = "Length of ASCII blob missing (with flags&2 set)"; goto Bail; }
-	sscanf((c8*)cp, "%x", &len);
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&2) && !(*cp=='0'||*cp=='8'))) {
-			sFailStr = "Invalid compression type for ASCII blob (with flags&2 set)"; goto Bail; }
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&2) && (strlen((c8*)cp) != (len<<1) || !is_hex_str(cp)))) {
-			sFailStr = "ASCII blob missing, wrong legth or not hex (with flags&2 set)"; goto Bail; }
-
-	/* Handle flags&4 */
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&4) && (!strlen((c8*)cp) || !is_hex_str(cp)))) {
-			sFailStr = "Crc data missing or not hex, (with flags&4 set)"; goto Bail; }
-	sscanf((c8*)cp, "%x", &crc);
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&4) && (!strlen((c8*)cp) || !is_hex_str(cp)))) {
-			sFailStr = "Compressed Length data missing or not hex, (with flags&4 set)"; goto Bail; }
-	sscanf((c8*)cp, "%x", &len);
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&4) && (!strlen((c8*)cp) || !is_hex_str(cp)))) {
-			sFailStr = "deCompressed Length data missing or not hex, (with flags&4 set)"; goto Bail; }
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&4) && !(*cp=='0'||*cp=='8'))) {
-			sFailStr = "Invalid compression type for main FULL blob (with flags&4 set)"; goto Bail; }
-
-	/* Handle flags&8 */
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&8) && (!strlen((c8*)cp) || !is_hex_str(cp)))) {
-			sFailStr = "File Offset data missing or not hex, (with flags&8 set)"; goto Bail; }
-	sscanf((c8*)cp, "%lx", &offset);
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&8) && !strlen((c8*)cp))) {
-			sFailStr = "Zip-FileName data missing or not hex, (with flags&8 set)"; goto Bail; }
-	sName = (c8*)cp;
-	p = GetFld(p, &cp);
-	if ( !p || *p==0 || ((flags&8) && !strlen((c8*)cp))) {
-			sFailStr = "Internal FileName data missing or not hex, (with flags&8 set)"; goto Bail; }
-	sIntName = (c8*)cp;
-
-	if (flags&8) {
-		in = fopen(sName, "rb"); /* have to open in bin mode for OS's where this matters, DOS/Win32 */
-		if (!in) {
-			/* this error is listed, even if not in pkzip debugging mode. */
-			fprintf(stderr, "Error loading a pkzip hash line. The ZIP file '%s' could NOT be found\n", cp);
-			return 0;
+		if ( !p || *cp<'1' || *cp>'3') {
+			sFailStr = "Invalid data enumeration type"; goto Bail; }
+		type = *cp - '0';
+		p = GetFld(p, &cp);
+		if ( !p || !is_hex_str(cp)) {
+			sFailStr = "Invalid type enumeration"; goto Bail; }
+		if (type > 1) {
+			p = GetFld(p, &cp);
+			if ( !p || !cp[0] || !is_hex_str(cp)) {
+				sFailStr = "Invalid compressed length"; goto Bail; }
+			sscanf((c8*)cp, "%x", &len);
+			p = GetFld(p, &cp);
+			if ( !p || !cp[0] || !is_hex_str(cp)) {
+				sFailStr = "Invalid data length value"; goto Bail; }
+			p = GetFld(p, &cp);
+			if ( !p || !cp[0] || !is_hex_str(cp)) {
+				sFailStr = "Invalid CRC value"; goto Bail; }
+			sscanf((c8*)cp, "%x", &crc);
+			p = GetFld(p, &cp);
+			if ( !p || !cp[0] || !is_hex_str(cp)) {
+				sFailStr = "Invalid offset length"; goto Bail; }
+			sscanf((c8*)cp, "%lx", &offset);
+			p = GetFld(p, &cp);
+			if ( !p || !cp[0] || !is_hex_str(cp)) {
+				sFailStr = "Invalid offset length"; goto Bail; }
+			sscanf((c8*)cp, "%x", &offex);
 		}
-		sFailStr = ValidateZipContents(in, offset, len, crc, sIntName);
-		fclose(in);
-		if (*sFailStr) {
-			/* this error is listed, even if not in pkzip debugging mode. */
-			fprintf(stderr, "pkzip validation failed [%s] Hash is %s\n", sFailStr, ciphertext);
-			return 0;
+		p = GetFld(p, &cp);
+		if ( !p || (*cp != '0' && *cp != '8')) {
+			sFailStr = "Compression type enumeration"; goto Bail; }
+		p = GetFld(p, &cp);
+		if ( !p || !is_hex_str(cp)) {
+			sFailStr = "data length value"; goto Bail; }
+		sscanf((c8*)cp, "%x", &data_len);
+		p = GetFld(p, &cp);
+		if ( !p || !is_hex_str(cp) || strlen((c8*)cp) != 4) {
+			sFailStr = "invalid checksum value"; goto Bail; }
+		p = GetFld(p, &cp);
+		if (type == 3) {
+			if ( !p || strlen((c8*)cp) != data_len) {
+				sFailStr = "invalid checksum value"; goto Bail; }
+			in = fopen((c8*)cp, "rb"); /* have to open in bin mode for OS's where this matters, DOS/Win32 */
+			if (!in) {
+				/* this error is listed, even if not in pkzip debugging mode. */
+				fprintf(stderr, "Error loading a pkzip hash line. The ZIP file '%s' could NOT be found\n", cp);
+				return 0;
+			}
+			sFailStr = ValidateZipContents(in, offset, offex, len, crc);
+			fclose(in);
+			if (*sFailStr) {
+				/* this error is listed, even if not in pkzip debugging mode. */
+				fprintf(stderr, "pkzip validation failed [%s] Hash is %s\n", sFailStr, ciphertext);
+				return 0;
+			}
+		} else {
+			if ( !p || !is_hex_str(cp) || strlen((c8*)cp) != data_len<<1) {
+				sFailStr = "invalid checksum value"; goto Bail; }
 		}
 	}
-
-	/* Handle flags&16 */
 	p = GetFld(p, &cp);
-	if ( !p || *p || ((flags&16) && (strlen((c8*)cp) != (len<<1) || !is_hex_str(cp)))) {
-			sFailStr = "Compressed/Encrypted ZIP data is missing or not right size, or not hex, (with flags&16 set)"; goto Bail; }
-
-	// if we have the 'full' file (or file name), and not the CRC and complen, then bail.
-	if ( (flags & (8|16)) && !(flags&4)) {
-			sFailStr = "Flags are set wrong.  If either flags&8 or flags&16, then flags&4 must be set."; goto Bail; }
-
-	return 1;
+	return !strcmp((c8*)cp, "$/pkzip$");
 
 Bail:;
 #ifdef ZIP_DEBUG
@@ -326,57 +318,42 @@ static u16 fget16(FILE * fp)
 	return v;
 }
 
-static const char *ValidateZipContents(FILE *fp, long offset, int _len, u32 _crc, const char *_sIntName) {
-	long curoff, offmin;
+static const char *ValidateZipContents(FILE *fp, long offset, u32 offex, int _len, u32 _crc) {
 	u32 id;
+	u16 version, flags, method, modtm, moddt, namelen, exlen;
+	u32 crc, complen, uncomplen;
 
-	/* 31 is the MINIMUM offset from start of file, to start of a compressed block. (old pkzip, 1 byte filename length) */
-	if (offset < 31)
-		return "Compressed zip file offset is too small (or negative). (with flags&8 set)";
-
-	offmin = offset-4096;
-	if (offmin < 0) offmin = 0;
-	for (curoff = offset-1; curoff >= offmin; --curoff) {
-		fseek(fp, curoff, SEEK_SET);
-		id = fget32(fp);
-		if (id == 0x04034b50UL) {	/* Found the local header */
-			/* Ok, see if this IS the correct file blob. */
-			u16 version = fget16(fp);
-			u16 flags = fget16(fp);
-			u16 method = fget16(fp);
-			u16 modtm = fget16(fp);
-			u16 moddt = fget16(fp);
-			u32 crc = fget32(fp);
-			u32 complen = fget32(fp);
-			u32 uncomplen = fget32(fp);
-			u16 namelen = fget16(fp);
-			u16 exlen = fget16(fp);
-
-			/* unused vars. */
-			(void)uncomplen;
-			(void)modtm;
-			(void)moddt;
-
-			/* Even if we 'miss', we keep walking back. We 'can' miss if the CRC of file, or some other       */
-			/* binary data happens to have the 0x04034b50 signature, thus giving us a false local header hit. */
-			if (_crc == crc && _len == complen && 0x14 == version && (flags & 1) && (method == 8 || method == 0)) {
-				/* skip file name, an any 'extra' data. */
-				(void)_sIntName;
-				fseek(fp, namelen, SEEK_CUR);
-				if (exlen)
-					fseek(fp, exlen, SEEK_CUR);
-				if (ftell(fp) == offset)
-					/* This is actually the SUCCESS :) */
-					return "";
+	if (fseek(fp, offset, SEEK_SET) != 0)
+		return "Not able to seek to specified offset in the .zip file, to read the zip blob data.";
 
-				return "The offset to the internal ZIP data for this file is NOT valid";
-			}
-		}
-	}
+	id = fget32(fp);
+	if (id != 0x04034b50U)
+		return "Compressed zip file offset does not point to start of zip blob";
+
+	/* Ok, see if this IS the correct file blob. */
+	version = fget16(fp);
+	flags = fget16(fp);
+	method = fget16(fp);
+	modtm = fget16(fp);
+	moddt = fget16(fp);
+	crc = fget32(fp);
+	complen = fget32(fp);
+	uncomplen = fget32(fp);
+	namelen = fget16(fp);
+	exlen = fget16(fp);
+
+	/* unused vars. */
+	(void)uncomplen;
+	(void)modtm;
+	(void)moddt;
+
+	/* Even if we 'miss', we keep walking back. We 'can' miss if the CRC of file, or some other       */
+	/* binary data happens to have the 0x04034b50 signature, thus giving us a false local header hit. */
+	if (_crc == crc && _len == complen && 0x14 == version && (flags & 1) && (method == 8 || method == 0) && offex==30+namelen+exlen)
+		return "";
 	return "We could NOT find the internal zip data in this ZIP file";
 }
 
-
 static void init(struct fmt_main *pFmt)
 {
 	unsigned short n=0;
@@ -397,32 +374,113 @@ static void init(struct fmt_main *pFmt)
 #endif
 
 #ifdef _OPENMP
-	// This can be tuned but it's tedious.
+	/* This can be tuned but it's tedious. */
 	n = omp_get_max_threads();
 	if (n*256 < MAX_KEYS_PER_CRYPT)
 		fmt_pkzip.params.max_keys_per_crypt = n*256;
 #endif
-	// if not openmp and not use mult_tab, make sure we quiet the unused warning.
+	/* if not openmp and not use mult_tab, make sure we quiet the unused warning. */
 	(void)n;
+
+#if USE_PKZIP_MAGIC
+
+	//static char *MagicTypes[]= { "", "DOC", "XLS", "DOT", "XLT", "EXE", "DLL", "ZIP", "BMP", "DIB", "GIF", "PDF", "GZ", "TGZ", "BZ2", "TZ2", "FLV", "SWF", "MP3", NULL };
+	//static int  MagicToEnum[] = {0,  1,    1,     1,     1,     2,     2,     3,     4,     4,     5,     6,     7,    7,     8,     8,     9,     10,    11,  0};
+	// decent sources of these:
+	// http://www.garykessler.net/library/file_sigs.html
+	// http://en.wikipedia.org/wiki/List_of_file_signatures 
+	// http://toorcon.techpathways.com/uploads/headersig.txt
+	// there are many more.
+
+//case 1: // DOC/XLS
+	SIGS[1].magic_signature[0] = (u8*)str_alloc_copy("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1");
+	SIGS[1].magic_sig_len[0] = 8;
+	SIGS[1].magic_signature[1] = buf_copy("\x50\x4B\x03\x04\x14\x00\x06\x00\x08", 10);  // a .zip file 'sort of'
+	SIGS[1].magic_sig_len[1] = 9;
+	SIGS[1].magic_signature[2] = buf_copy("\x09\x04\x06\x00\x00\x00\x10\x00\xF6\x05\x5C\x00", 13); // older XLS format (office 95)
+	SIGS[1].magic_sig_len[2] = 12;
+	SIGS[1].magic_signature[3] = buf_copy("\x09\x02\x06\x00\x00\x00\x10\x00\xB9\x04\x5C\x00", 13); // older XLS v2
+	SIGS[1].magic_sig_len[3] = 12;
+	SIGS[1].magic_signature[4] = buf_copy("\x50\x4B\x03\x04\x14\x00\x00\x00\x00\x00", 11); //DOC Star Writer 6.0 
+	SIGS[1].magic_sig_len[4] = 10;
+	SIGS[1].magic_signature[5] = buf_copy("\x31\xBE\x00\x00\x00\xAB\x00\x00", 9); //DOC MS Word for DOS v6 File 
+	SIGS[1].magic_sig_len[5] = 8;
+	SIGS[1].magic_signature[6] = (u8*)str_alloc_copy("\x12\x34\x56\x78\x90\xFF"); //DOC MS Word 6.0 File 
+	SIGS[1].magic_sig_len[6] = 6;
+	SIGS[1].magic_signature[7] = (u8*)str_alloc_copy("\x7F\xFE\x34\x0A");  //MS Word File
+	SIGS[1].magic_sig_len[7] = 4;
+	SIGS[1].magic_count = 8;
+	SIGS[1].max_len = 12;
+//case 2: // Win32/DOS exe file MZ
+	SIGS[2].magic_signature[0] = (u8*)str_alloc_copy("MZ");
+	SIGS[2].magic_sig_len[0] = 2;
+	SIGS[2].magic_count = 1;
+	SIGS[2].max_len = 2;
+//case 3: // PKZIP
+	SIGS[3].magic_signature[0] = (u8*)str_alloc_copy("\x50\x4B\x03\x04");
+	SIGS[3].magic_sig_len[0] = 4;
+	SIGS[3].magic_count = 1;
+	SIGS[3].max_len = 4;
+//case 4: // BMP
+	SIGS[4].magic_signature[0] = (u8*)str_alloc_copy("BM");
+	SIGS[4].magic_sig_len[0] = 2;
+	SIGS[4].magic_count = 1;
+	SIGS[4].max_len = 2;
+//case 5: // GIF
+	SIGS[5].magic_signature[0] = (u8*)str_alloc_copy("GIF87a");
+	SIGS[5].magic_sig_len[0] = 6;
+	SIGS[5].magic_signature[1] = (u8*)str_alloc_copy("GIF89a");
+	SIGS[5].magic_sig_len[1] = 6;
+	SIGS[5].magic_count = 2;
+	SIGS[5].max_len = 6;
+//case 6: // PDF
+	SIGS[6].magic_signature[0] = (u8*)str_alloc_copy("%PDF");
+	SIGS[6].magic_sig_len[0] = 4;
+	SIGS[6].magic_count = 1;
+	SIGS[6].max_len = 4;
+//case 7: // GZ
+	SIGS[7].magic_signature[0] = (u8*)str_alloc_copy("\x1F\x8B\x08");
+	SIGS[7].magic_sig_len[0] = 3;
+	SIGS[7].magic_count = 1;
+	SIGS[7].max_len = 3;
+//case 8: // BZ2  (there is a 'magic' pi, but byte 4 is 1 to 9, so skip the 'pi')
+	SIGS[8].magic_signature[0] = (u8*)str_alloc_copy("BZh");
+	SIGS[8].magic_sig_len[0] = 3;
+	SIGS[8].magic_signature[1] = (u8*)str_alloc_copy("BZ0");
+	SIGS[8].magic_sig_len[1] = 3;
+	SIGS[8].magic_count = 2;
+	SIGS[8].max_len = 3;
+//case 9: // FLV
+	SIGS[9].magic_signature[0] = (u8*)str_alloc_copy("FLV\x01");
+	SIGS[9].magic_sig_len[0] = 4;
+	SIGS[9].magic_count = 1;
+	SIGS[9].max_len = 4;
+//case 10: // SWF
+	SIGS[10].magic_signature[0] = (u8*)str_alloc_copy("FWS");
+	SIGS[10].magic_sig_len[0] = 5;
+	SIGS[10].magic_count = 1;
+	SIGS[10].max_len = 5;
+//case 11: // MP3
+	SIGS[11].magic_signature[0] = (u8*)str_alloc_copy("ID3");
+	SIGS[11].magic_sig_len[0] = 3;
+	SIGS[11].magic_count = 1;
+	SIGS[11].max_len = 3;
+
+	SIGS[255].max_len = 64;
+#endif
 }
 
 static void set_salt(void *_salt) {
 	salt = *((PKZ_SALT**)_salt);
 }
 
-static void load_bin_data(u8 *inp, u8 **out) {
-	int i, len = strlen((c8*)inp);
-	/* Needs word align on REQ_ALIGN systems */
-	*out = mem_alloc_tiny(len>>1, MEM_ALIGN_WORD);
-	for (i = 0; i < len>>1; ++i)
-		(*out)[i] = (atoi16[ARCH_INDEX(inp[i<<1])]<<4) + atoi16[ARCH_INDEX(inp[(i<<1)+1])];
-}
-
 static void *get_salt(char *ciphertext)
 {
 	/* NOTE, almost NO error checking at all in this function.  Proper error checking done in valid() */
 	static unsigned char salt_p[8];
 	PKZ_SALT *salt;
+	long offset=0;
+	u32 offex;
 	int i, j;
 	u8 *p, *cp, *cpalloc = (unsigned char*)mem_alloc(strlen(ciphertext)+1);
 
@@ -433,67 +491,106 @@ static void *get_salt(char *ciphertext)
 
 	cp = cpalloc;
 	strcpy((c8*)cp, ciphertext);
-	p = &cp[8];
+	p = &cp[7];
 	p = GetFld(p, &cp);
 	sscanf((c8*)cp, "%x", &(salt->cnt));
 	p = GetFld(p, &cp);
 	sscanf((c8*)cp, "%x", &(salt->chk_bytes));
-	p = GetFld(p, &cp);
-	sscanf((c8*)cp, "%x", &(salt->flags));
 	for(i = 0; i < salt->cnt; ++i) {
+		int data_enum;
 		p = GetFld(p, &cp);
-		salt->c[i] = atoi16[ARCH_INDEX(cp[24])];
-		salt->c[i] <<= 4;
-		salt->c[i] |= atoi16[ARCH_INDEX(cp[25])];
-		salt->c[i] <<= 4;
-		salt->c[i] |= atoi16[ARCH_INDEX(cp[26])];
-		salt->c[i] <<= 4;
-		salt->c[i] |= atoi16[ARCH_INDEX(cp[27])];
-		for (j = 0; j < 12; ++j)
-			salt->h[i][j] = (atoi16[ARCH_INDEX(cp[j*2])]<<4) + atoi16[ARCH_INDEX(cp[j*2+1])];
-	}
+		data_enum = *cp - '0';
+		p = GetFld(p, &cp);
+#if USE_PKZIP_MAGIC
+		sscanf((c8*)cp, "%hhx", &(salt->H[i].magic));
+		salt->H[i].pSig = &SIGS[salt->H[i].magic];
+#endif
 
-	/* Handle flags&2 */
-	p = GetFld(p, &cp);
-	if (salt->flags&2)
-		sscanf((c8*)cp, "%x", &(salt->asciilen));
-	p = GetFld(p, &cp);
-	if (salt->flags&2)
-		sscanf((c8*)cp, "%x", &(salt->asciiCompType));
-	p = GetFld(p, &cp);
-	if (salt->flags&2)
-		load_bin_data(cp, &(salt->asciidat));
+		if (data_enum > 1) {
+			p = GetFld(p, &cp);
+			sscanf((c8*)cp, "%x", &(salt->compLen));
+			p = GetFld(p, &cp);
+			sscanf((c8*)cp, "%x", &(salt->deCompLen));
+			p = GetFld(p, &cp);
+			sscanf((c8*)cp, "%x", &(salt->crc32));
+			p = GetFld(p, &cp);
+			sscanf((c8*)cp, "%lx", &offset);
+			p = GetFld(p, &cp);
+			sscanf((c8*)cp, "%x", &offex);
+		}
+		p = GetFld(p, &cp);
+		sscanf((c8*)cp, "%x", &(salt->H[i].compType));
+		p = GetFld(p, &cp);
+		sscanf((c8*)cp, "%x", &(salt->H[i].datlen));
+		p = GetFld(p, &cp);
 
-	/* Handle flags&4 */
-	p = GetFld(p, &cp);
-	if (salt->flags&4)
-		sscanf((c8*)cp, "%x", &(salt->crc32));
-	p = GetFld(p, &cp);
-	if (salt->flags&4)
-		sscanf((c8*)cp, "%x", &(salt->compLen));
-	p = GetFld(p, &cp);
-	if (salt->flags&4)
-		sscanf((c8*)cp, "%x", &(salt->deCompLen));
-	p = GetFld(p, &cp);
-	if (salt->flags&4)
-		sscanf((c8*)cp, "%x", &(salt->compType));
+		for (j = 0; j < 4; ++j) {
+			salt->H[i].c <<= 4;
+			salt->H[i].c |= atoi16[ARCH_INDEX(cp[j])];
+		}
+		p = GetFld(p, &cp);
+		if (data_enum > 1) {
+			/* if 2 or 3, we have the FULL zip blob for decrypting. */
+			if (data_enum == 3) {
+				/* read from file. */
+				FILE *fp;
+				fp = fopen((c8*)cp, "rb");
+				if (!fp) {
+					fprintf (stderr, "Error opening file for pkzip data:  %s\n", cp);
+					MEM_FREE(cpalloc);
+					return 0;
+				}
+				fseek(fp, offset+offex, SEEK_SET);
+				if (salt->compLen < 16*1024) {
+					/* simply load the whole blob */
+					salt->H[i].h = mem_alloc_tiny(salt->compLen, MEM_ALIGN_WORD);
+					if (fread(salt->H[i].h, 1, salt->compLen, fp) != salt->compLen) {
+						fprintf (stderr, "Error reading zip file for pkzip data:  %s\n", cp);
+						fclose(fp);
+						MEM_FREE(cpalloc);
+						return 0;
+					}
+					fclose(fp);
+					salt->H[i].datlen = salt->compLen;
+				}
+				else {
+					/* Only load a small part (to be used in crypt_all), and set the filename in */
+					/* the salt->fname string, so that cmp_all can open the file, and buffered   */
+					/* read the zip data only when it 'needs' it.                                */
+					salt->fname = str_alloc_copy((c8*)cp);
+					salt->offset = offset+offex;
+					salt->H[i].h = mem_alloc_tiny(384, MEM_ALIGN_WORD);
+					if (fread(salt->H[i].h, 1, 384, fp) != 384) {
+						fprintf (stderr, "Error reading zip file for pkzip data:  %s\n", cp);
+						fclose(fp);
+						MEM_FREE(cpalloc);
+						return 0;
+					}
+					fclose(fp);
+					salt->H[i].datlen = 384;
+				}
+			} else {
+				/* 'inline' data. */
+				if (salt->compLen != salt->H[i].datlen) {
+					fprintf(stderr, "Error, length of full data does not match the salt len. %s\n", ciphertext);
+					return 0;
+				}
+				salt->H[i].h = mem_alloc_tiny(salt->compLen, MEM_ALIGN_WORD);
+				for (j = 0; j < salt->H[i].datlen; ++j)
+					salt->H[i].h[j] = (atoi16[ARCH_INDEX(cp[j*2])]<<4) + atoi16[ARCH_INDEX(cp[j*2+1])];
+			}
 
-	/* Handle flags&8 */
-	p = GetFld(p, &cp);
-	if (salt->flags&8)
-		sscanf((c8*)cp, "%lx", &(salt->offset));
-	p = GetFld(p, &cp);
-	if (salt->flags&8)
-		salt->filename = str_alloc_copy((c8*)cp);
-	p = GetFld(p, &cp);
-	if (salt->flags&8)
-		salt->ifilename = str_alloc_copy((c8*)cp);
+			/* we also load this into the 'building' salt */
+			salt->compType = salt->H[i].compType;
 
-	/* Handle flags&16 */
-	p = GetFld(p, &cp);
-	if (salt->flags&16) {
-		load_bin_data(cp, &(salt->full_encr_dat));
-		salt->full_decr_dat = mem_alloc_tiny(salt->compLen-12, MEM_ALIGN_NONE);
+			/* Now, set the 'is full zip' flag, so we later process as a zip file. */
+			salt->H[i].full_zip = 1;
+			salt->full_zip_idx = i;
+		} else {
+			salt->H[i].h = mem_alloc_tiny(salt->H[i].datlen, MEM_ALIGN_WORD);
+			for (j = 0; j < salt->H[i].datlen; ++j)
+				salt->H[i].h[j] = (atoi16[ARCH_INDEX(cp[j*2])]<<4) + atoi16[ARCH_INDEX(cp[j*2+1])];
+		}
 	}
 
 	MEM_FREE(cpalloc);
@@ -511,133 +608,11 @@ static void set_key(char *key, int index
 	dirty = 1;
 }
 
-
 static char *get_key(int index)
 {
 	return saved_key[index];
 }
 
-/*
- * Crypt_all simply performs the checksum .zip validatation of the data. It performs
- * this for ALL hashes provided. If any of them fail to match, then crypt all puts the
- * complement of the 'proper' checksum of the first hash into the output. These 2 bytes
- * are checked against the binary for this salt/password combination.  Thus, if any
- * checksum fails, it will never match binary.  However, if ALL of the checksums match
- * we then put the checksum bytes from the first hash, into our output data. Then, when
- * the binary check (cmp_all, cmp_one) is performed, it WILL match.  NOTE, this does
- * not mean we have found the password.  Just that all hashes quick check checksums
- * for this password 'work'.
- */
-static void crypt_all(int _count)
-{
-	int idx;
-
-	// pkzip kinda sucks a little for multi-threading, since there is different amount of work to be
-	// done, depenging upon the password.  Thus, we pack in OMP_MOD passwords into each thread, and
-	// hopefully some of the differnces will even themselves out in the end.  If we have 2 threads
-	// then thread 1 gets 0 to 127 password, and thread 2 gets 128-256.  Once they 'get' their data,
-	// there should be no mutexing of the runtime data, thus the threads should run fast.
-	// Also, since we have 'multiple' files in a .zip file (and multiple checksums), we bail as at the
-	// first time we fail to match checksum.  So, there may be some threads which check more checksums.
-	// Again, hopefully globbing many tests into a threads working set will flatten out these differences.
-#ifdef _OPENMP
-#pragma omp parallel for private(idx)
-#endif
-	for (idx = 0; idx < _count; ++idx) {
-		int cur_hash_count = salt->cnt;
-		int cur_hash_idx = -1;
-		MY_WORD key0, key1, key2;
-		/* use the pwkey for each hash.  We mangle on the 12 bytes of IV to what  was computed in the pwkey load. */
-
-		if (dirty) {
-			u8 *p = (u8*)saved_key[idx];
-
-			/* load the 'pwkey' one time, put it into the K12 array */
-			key0.u = 0x12345678UL; key1.u = 0x23456789UL; key2.u = 0x34567890UL;
-			do {
-				key0.u = pkzip_crc32 (key0.u, *p++);
-#if ARCH_LITTLE_ENDIAN
-				key1.u = (key1.u + key0.c[0]) * 134775813 + 1;
-				key2.u = pkzip_crc32 (key2.u, key1.c[3]);
-#else
-				key1.u = (key1.u + key0.c[3]) * 134775813 + 1;
-				key2.u = pkzip_crc32 (key2.u, key1.c[0]);
-#endif
-			} while (*p);
-			K12[idx*3] = key0.u, K12[idx*3+1] = key1.u, K12[idx*3+2] = key2.u;
-			goto SkipKeyLoadInit;
-		}
-
-		do
-		{
-			u8 checkSum1, checkSum2;
-			const u8 *b;
-			int k;
-			u16 e;
-
-			// 2nd, and later times through the loop, AND if keys are not dirty (i.e. multiple salts
-			// for the same key load), we do NOT perform the key compute, but instead load the pre-computed
-			// key data from the array.
-			key0.u = K12[idx*3], key1.u = K12[idx*3+1], key2.u = K12[idx*3+2];
-
-SkipKeyLoadInit:;
-			b = salt->h[++cur_hash_idx];
-			k=11;
-			e = salt->c[cur_hash_idx];
-
-			do
-			{
-#ifdef PKZIP_USE_MULT_TABLE
-				checkSum2 = *b++ ^ mult_tab [(u16)(key2.u) >> 2];	/* 6850K/GCC  7230K/VC  Midrange Core 32 bit, Win32 */
-#else
-				u16 t = key2.u | 2;
-				checkSum2 = *b++ ^ (u8)(((u16) (t * (t^1)) >> 8));	/* 5926K/GCC  6429K/VC  Midrange Core 32 bit, Win32 */
-#endif
-				key0.u = pkzip_crc32 (key0.u, checkSum2);
-#if ARCH_LITTLE_ENDIAN
-				key1.u = (key1.u + key0.c[0]) * 134775813 + 1;
-				key2.u = pkzip_crc32 (key2.u, key1.c[3]);
-#else
-				key1.u = (key1.u + key0.c[3]) * 134775813 + 1;
-				key2.u = pkzip_crc32 (key2.u, key1.c[0]);
-#endif
-			}
-			while(--k);
-
-			/* if the hash is a 2 byte checksum type, then check that value first */
-			/* There is no reason to continue if this byte does not check out.  */
-			if (salt->chk_bytes == 2 && checkSum2 != (e&0xFF))
-				goto Failed_Bailout;
-
-#ifdef PKZIP_USE_MULT_TABLE
-			checkSum1 = *b++ ^ mult_tab [(u16)(key2.u) >> 2];
-#else
-			{
-				u16 t = key2.u | 2;
-				checkSum1 = *b++ ^ (u8)(((u16) (t * (t^1)) >> 8));
-			}
-#endif
-			if (checkSum1 != (e>>8))
-				goto Failed_Bailout;
-		}
-		while(--cur_hash_count);
-
-		/* We got a checksum HIT!!!! All hash checksums matched. */
-		/* We load the proper checksum value for the gethash */
-		chk[idx] = 1;
-
-		continue;
-		
-Failed_Bailout: ;
-		/* We load the wrong checksum value for the gethash */
-		chk[idx] = 0;
-	}
-
-	/* clear the 'dirty' flag.  Then on multiple different salt calls, we will not have to */
-	/* encrypt the passwords again. They will have already been loaded in the K12[] array. */
-	dirty = 0;
-}
-
 static int cmp_one(void *binary, int idx)
 {
 	return chk[idx] == 1;
@@ -645,138 +620,243 @@ static int cmp_one(void *binary, int idx
 
 static int cmp_all(void *binary, int count)
 {
-	return memchr(chk, 1, count) != NULL;
+	int i,j;
+	for (i=j=0; i<count; ++i)
+		j+=chk[i]; /* hopefully addition like this is faster then 'count' conditional if statments */
+	return j;
 }
 
-static void decrypt (int idx, u8 *inp, u8 *out, int inplen) {
-	MY_WORD key0, key1, key2;
+/* this function is used by cmp_exact_loadfile.  It will load the next 
+ * part of the file then decrypt the data, and return just how many
+ * bytes were loaded.
+ *
+ * This function is 'similar' to an fread().  However, it also decrypts data 
+ */
+static int get_next_decrypted_block(u8 *in, int sizeof_n, FILE *fp, u32 *inp_used, MY_WORD *pkey0, MY_WORD *pkey1, MY_WORD *pkey2) {
+	u32 new_bytes = sizeof_n, k;
 	u8 C;
-	int k=12;
-	const u8 *b = inp;
-
-	/* load pre-computed key data */
-	key0.u = K12[idx*3], key1.u = K12[idx*3+1], key2.u = K12[idx*3+2];
 
-	/* Load the IV into the keys. */
-	do {
-#ifdef PKZIP_USE_MULT_TABLE
-		C = *b++ ^ mult_tab [(u16)(key2.u) >> 2];
-#else
-		u16 t = key2.u | 2;
-		C = *b++ ^ (u8)(((u16) (t * (t^1)) >> 8));
-#endif
-		key0.u = pkzip_crc32 (key0.u, C);
-#if ARCH_LITTLE_ENDIAN
-		key1.u = (key1.u + key0.c[0]) * 134775813 + 1;
-		key2.u = pkzip_crc32 (key2.u, key1.c[3]);
-#else
-		key1.u = (key1.u + key0.c[3]) * 134775813 + 1;
-		key2.u = pkzip_crc32 (key2.u, key1.c[0]);
-#endif
-	} while (--k);
+	/* we have read all the bytes, we're done */
+	if (*inp_used >= salt->compLen)
+		return 0;
+	if (*inp_used + new_bytes > salt->compLen)
+		/* this is the last block.  Only load the bytes that are left */
+		new_bytes = salt->compLen - *inp_used;
+	/* return the correct 'offset', so we can track when the file buffer has been fully read */
+	*inp_used += new_bytes;
+	/* read the data */
+	if (fread(in, 1, new_bytes, fp) != new_bytes)
+		return 0;
 
-	/* now decrypt the rest of the data. */
-	k = inplen-12;
-	do {
-#ifdef PKZIP_USE_MULT_TABLE
-		C = *b++ ^ mult_tab [(u16)(key2.u) >> 2];
-#else
-		u16 t = key2.u | 2;
-		C = *b++ ^ (u8)(((u16) (t * (t^1)) >> 8));
-#endif
-		/* write out this decrypted byte. */
-		*out++ = C;
-		key0.u = pkzip_crc32 (key0.u, C);
-#if ARCH_LITTLE_ENDIAN
-		key1.u = (key1.u + key0.c[0]) * 134775813 + 1;
-		key2.u = pkzip_crc32 (key2.u, key1.c[3]);
-#else
-		key1.u = (key1.u + key0.c[3]) * 134775813 + 1;
-		key2.u = pkzip_crc32 (key2.u, key1.c[0]);
-#endif
-	} while (--k);
+	/* decrypt the data bytes (in place, in same buffer). Easy to do, only requires 1 temp character variable.  */
+	for (k = 0; k < new_bytes; ++k) {
+		C = PKZ_MULT(in[k],(*pkey2));
+		pkey0->u = pkzip_crc32 (pkey0->u, C);
+		pkey1->u = (pkey1->u + pkey0->c[KB1]) * 134775813 + 1;
+		pkey2->u = pkzip_crc32 (pkey2->u, pkey1->c[KB2]);
+		in[k] = C;
+	}
+	/* return the number of bytes we read from the file on this read */
+	return new_bytes;
 }
 
-/*
- * This is the 'third' step in cracking the key. We do a full decrypt, then
- * full inflate, and then make sure the size and CRC matches.
+/* Ok, this is the more complex example.  Here we have to load the file (which may be HUGE)
+ * decrypt the bytes from this file, and then inflate that data, and crc the bytes which we
+ * have inflated from that stream. Then in the end, when we use all input bytes, if we have
+ * inflated the right amount of data, ended up with a Z_STREAM_END, and the proper sized
+ * decompression buffer, and the CRC matches, then we know we have the correct password 
+ *
+ * This function is called from cmp_exact(), when cmp_exact finds out we have to decrypt from
+ * the stored .zip file.
+ *
+ * this code is modifications made to the zpipe.c 'example' code from the zlib web site.
  */
-static int decomp_validate(u8 *inp, int inplen, int outlen, u32 crcExpect) {
-	z_stream strm;
-	int ret, i;
-	u32 crc = 0xFFFFFFFF; /* Later we will have to check ~crc to see if the crc matches */
-	int last_out, bytes_this_time;
-
-	if (salt->compType == 0) {
-		/* file is stored, so simply CRC the data) */
-		if (inplen != outlen)
-			return 0;
-		for (i = 0; i < inplen; ++i)
-			crc = pkzip_crc32(crc,inp[i]);
-		return ~crc == crcExpect;
-	}
-
-	strm.zalloc = Z_NULL;
-	strm.zfree = Z_NULL;
-	strm.opaque = Z_NULL;
-	strm.avail_in = 0;
-	strm.next_in = Z_NULL;
-
-	ret = inflateInit2(&strm, -15); /* 'raw', since we do not have gzip header, or gzip crc. .ZIP files are 'raw' implode data. */
-	if (ret != Z_OK)
-	   perror("Error, initializing the libz inflateInit2() system\n");
+#define CHUNK (64*1024)
+static int cmp_exact_loadfile(int index) {
 
-	strm.avail_in = inplen;
-	strm.next_in = inp;
+    int ret;
+    u32 have, k;
+    z_stream strm;
+    unsigned char in[CHUNK];
+    unsigned char out[CHUNK];
+	FILE *fp;
+	MY_WORD key0, key1, key2;
+	u8 *b, C;
+	u32 inp_used, decomp_len=0;
+	u32 crc = 0xFFFFFFFF;
+
+	/* Open the zip file, and 'seek' to the proper offset of the binary zip blob */
+	fp = fopen(salt->fname, "rb");
+	if (!fp) {
+		fprintf (stderr, "\nERROR, the zip file: %s has been removed.\nWe are a possible password has been found, but FULL validation can not be done!\n", salt->fname);
+		return 1;
+	}
+	if (fseek(fp, salt->offset, SEEK_SET)) {
+		fprintf (stderr, "\nERROR, the zip file: %s fseek() failed.\nWe are a possible password has been found, but FULL validation can not be done!\n", salt->fname);
+		fclose(fp);
+		return 1;
+	}
+
+    /* allocate inflate state */
+    strm.zalloc = Z_NULL;
+    strm.zfree = Z_NULL;
+    strm.opaque = Z_NULL;
+    strm.avail_in = 0;
+    strm.next_in = Z_NULL;
+    ret = inflateInit2(&strm, -15);
+	if (ret != Z_OK) /* if zlib is hosed, then likely there is no reason at all to continue.  Better to exit, and let the user 'fix' the system */
+		perror("Error, initializing the libz inflateInit2() system\n");
+
+	/* 'seed' the decryption with the IV. We do NOT use these bytes, they simply seed us. */
+	key0.u = K12[index*3], key1.u = K12[index*3+1], key2.u = K12[index*3+2];
+	k=12;
+	if (fread(in, 1, 12, fp) != 12) {
+		fprintf (stderr, "\nERROR, the zip file: %s fread() failed.\nWe are a possible password has been found, but FULL validation can not be done!\n", salt->fname);
+		fclose(fp);
+		return 1;
+	}
 
+	b = salt->H[salt->full_zip_idx].h;
 	do {
-		strm.avail_out = UBUF_SIZE;
-		strm.next_out = ucpr_buf;
-		last_out = strm.total_out;
+		C = PKZ_MULT(*b++,key2);
+		key0.u = pkzip_crc32 (key0.u, C);
+		key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+		key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+	}
+	while(--k);
 
-		ret = inflate(&strm, Z_SYNC_FLUSH);
-		if (ret != Z_OK) {
-			inflateEnd(&strm);
-			if (ret == Z_STREAM_END) {
-				/* This is the MOST LIKELY successful spot. */
-				if (strm.total_out != outlen)
+	/* this is 'sort of' our file pointer.  It is the 'index' into the file's encrypted, compressed data buffer. */
+	/* we have read the 12 bytes of IV data, and updated our keys. Now we start processing the rest of the bytes */
+	/* to get the data to inflate, and crc check                                                                 */
+	inp_used = 12;
+
+    /* decompress until deflate stream ends or end of file */
+    do {
+        strm.avail_in = get_next_decrypted_block(in, CHUNK, fp, &inp_used, &key0, &key1, &key2);
+        if (ferror(fp)) {
+            inflateEnd(&strm);
+			fclose(fp);
+			fprintf (stderr, "\nERROR, the zip file: %s fread() failed.\nWe are a possible password has been found, but FULL validation can not be done!\n", salt->fname);
+            return 1;
+        }
+        if (strm.avail_in == 0)
+            break;
+        strm.next_in = in;
+
+        /* run inflate() on input until output buffer not full */
+        do {
+            strm.avail_out = CHUNK;
+            strm.next_out = out;
+            ret = inflate(&strm, Z_NO_FLUSH);
+            switch (ret) {
+	            case Z_NEED_DICT:
+			    case Z_DATA_ERROR:
+				case Z_MEM_ERROR:
+					inflateEnd(&strm);
+					fclose(fp);
 					return 0;
-				bytes_this_time = strm.total_out - last_out;
-				for (i = 0; i < bytes_this_time; ++i)
-					crc = pkzip_crc32(crc,ucpr_buf[i]);
-				if (~crc == crcExpect) {
-					/* yea!  we found it.                     */
-					/* This time we KNOW we have the password */
+            }
+            have = CHUNK - strm.avail_out;
+			/* now update our crc value */
+			for (k = 0; k < have; ++k)
+				crc = pkzip_crc32(crc,out[k]);
+			decomp_len += have;
+        } while (strm.avail_out == 0);
+
+        /* done when inflate() says it's done */
+    } while (ret != Z_STREAM_END);
+
+    /* clean up and return */
+    inflateEnd(&strm);
+	fclose(fp);
+	return ret == Z_STREAM_END && inp_used == salt->compLen && decomp_len == salt->deCompLen && salt->crc32 == ~crc;
+}
+
+
+static int cmp_exact(char *source, int index)
+{
+	const u8 *b;
+	u8 C, *decompBuf, *decrBuf, *B;
+	u32 k, crc;
+	MY_WORD key0, key1, key2;
+	z_stream strm;
+	int ret;
+	
+	if (salt->H[salt->full_zip_idx].full_zip == 0)
+		/* we do not have a zip file, this is 'checksum' only
+		 * POSSIBLY, we should log and output to screen that 
+		 * we are not 100% 'sure' we have the right password!! */
+		return 1;
+
 #ifdef ZIP_DEBUG
-					fprintf(stderr, "YEA, Found it!! (full zip validation)  Crc=%x Expected=%x\n", ~crc, crcExpect);
+	fprintf(stderr, "FULL zip test being done. (pass=%s)\n", saved_key[index]);
 #endif
-					return 1;
-				}
-			}
-			return 0;
+
+	if (salt->fname == NULL) {
+		/* we have the whole zip blob in memory, simply allocate a decrypt buffer, decrypt
+		 * in one step, crc and be done with it. This is the 'trivial' type. */
+		decompBuf = mem_alloc(salt->deCompLen);
+		decrBuf = mem_alloc(salt->compLen-12);
+
+		key0.u = K12[index*3], key1.u = K12[index*3+1], key2.u = K12[index*3+2];
+
+		b = salt->H[salt->full_zip_idx].h;
+		k=12;
+		do {
+			C = PKZ_MULT(*b++,key2);
+			key0.u = pkzip_crc32 (key0.u, C);
+			key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+			key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
 		}
-		bytes_this_time = strm.total_out - last_out;
-		for (i = 0; i < bytes_this_time; ++i)
-			crc = pkzip_crc32(crc,ucpr_buf[i]);
-		if (strm.total_out > outlen) {
-			inflateEnd(&strm);
+		while(--k);
+		B = decrBuf;
+		k = salt->compLen-12;
+		do {
+			C = PKZ_MULT(*b++,key2);
+			key0.u = pkzip_crc32 (key0.u, C);
+			*B++ = C;
+			key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+			key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+		} while (--k);
+
+		strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.next_in = Z_NULL; strm.avail_in = 0;
+
+		ret = inflateInit2(&strm, -15); /* 'raw', since we do not have gzip header, or gzip crc. .ZIP files are 'raw' implode data. */
+		if (ret != Z_OK)
+		   perror("Error, initializing the libz inflateInit2() system\n");
+
+		strm.next_in = decrBuf;
+		strm.avail_in = salt->compLen-12;
+		strm.avail_out = salt->deCompLen;
+		strm.next_out = decompBuf;
+
+
+		ret = inflate(&strm, Z_SYNC_FLUSH);
+		inflateEnd(&strm);
+		if (ret != Z_STREAM_END || strm.total_out != salt->deCompLen) {
+			MEM_FREE(decompBuf);
+			MEM_FREE(decrBuf);
 			return 0;
 		}
-	} while (bytes_this_time == UBUF_SIZE);
 
-	/* this will likely only happen, if the output len mod UBUF_SIZE == 0, but it 'can' happen. */
-	inflateEnd(&strm);
-	if (~crc != crcExpect || strm.total_out != outlen)
-		return 0;
-	/* yea!  we found it. */
-	return 1;
+		crc = 0xFFFFFFFF;
+		for (k = 0; k < strm.total_out; ++k)
+			crc = pkzip_crc32(crc,decompBuf[k]);
+		MEM_FREE(decompBuf);
+		MEM_FREE(decrBuf);
+		return ~crc == salt->crc32;
+	}
+	/* we have a stand alone function to handle this more complex method of
+	 * loading from file, decrypting, decompressing, and crc'ing the data
+	 * It is complex enough of a task, to have it's own function. */
+	return cmp_exact_loadfile(index);
 }
 
+#if USE_PKZIP_MAGIC
 const char exBytesUTF8[64] = {
 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 	2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
 };
-
 static int isLegalUTF8_char(const u8 *source, int length) {
     u8 a;
 	int len;
@@ -810,118 +890,612 @@ static int isLegalUTF8_char(const u8 *so
     if (*source > 0xF4) return -1;
     return len+1;
 }
+static u8 *buf_copy (char *p, int len) {
+	u8 *op = mem_alloc_tiny(len, MEM_ALIGN_NONE);
+	memcpy(op, p, len);
+	return op;
+}
+static int validate_ascii(const u8 *out, int inplen) {
+	int i;
+	int unicode=0, utf8=0;
 
-
-static int decomp_validate_ascii(u8 *inp, u8 *out, int inplen, int outlen) {
-
-	z_stream strm;
-	int ret, i;
-
-	if (salt->asciiCompType == 0) {
-		/* file is stored, so simply check the bytes no need to decompress */
-		for (i = 0; i < inplen-1; ++i) {
-			if (inp[i] > 0x7E)
-				return 0;
-			if (inp[i] < 0x20) {
-				/* we do not need to deal with DOS EOF char 0x1a, since we will never have the 'end' of the file */
-				if (inp[i]!='\n' && inp[i]!='\r' && inp[i]!='\t')
-					return 0;
-			}
-		}
-		return 1;
-	}
-
-	strm.zalloc = Z_NULL;
-	strm.zfree = Z_NULL;
-	strm.opaque = Z_NULL;
-	strm.avail_in = 0;
-	strm.next_in = Z_NULL;
-	
-	ret = inflateInit2(&strm, -15); /* 'raw', since we do not have gzip header, or gzip crc. .ZIP files are 'raw' implode data. */
-	if (ret != Z_OK)
-	   perror("Error, initializing the libz inflateInit2() system\n");
-
-	strm.avail_in = inplen;
-	strm.next_in = inp;
-	strm.avail_out = outlen;
-	strm.next_out = out;
-
-	ret = inflate(&strm, Z_SYNC_FLUSH);
-
-	inflateEnd(&strm);
-
-	if (ret != Z_OK || strm.total_out < 30)
-		return 0;
-
-	for (i = 0; i < strm.total_out-1; ++i) {
+	for (i = 0; i < inplen-1; ++i) {
 		if (out[i] > 0x7E) {
 			// first check to 'see' if this is a valid utf8 character.  If so, let it 'pass'.
+			if (unicode)
+				return 0; // in unicode mode, we ONLY handle 'ascii' bytes in the low byte.
+
 			if (out[i] > 0xC0) {
 				int len;
-				if(i > strm.total_out-4)
+				if(i > inplen-4)
 					return 1;
 				len = isLegalUTF8_char(&out[i], 5);
 				if (len < 0) return 0;
 				i += (len-1);
 			}
-			else if (out[i] != 0xA9)
-				return 0;
+			else {
+				if (i) {
+					// check for utf8 BOM  \xEF \xBB \xBF
+					if (out[0] == 0xEF && out[1] == 0xBB && out[2] == 0xBF) {
+						i = 2;
+						utf8 = 1;
+						continue;
+					}
+					/* check for Unicode BOM  (FF FE for utf16le, FE FF for utf16be, FF FE 00 00 for utf32le, not sure if 00 00 FE FF is utf32be, but likely is) */
+					if (out[0] == 0xFF && out[1] == 0xFE) {
+						unicode = 1;
+						i++;
+						continue;
+					}
+					/* unicode BE bom */
+					if (out[0] == 0xFE && out[1] == 0xFF) {
+						unicode = 1;
+						i += 2;
+						continue;
+					}
+					/* utf32 LE */
+					if (out[0] == 0xFF && out[1] == 0xFE && out[2] == 0 && out[3] == 0) {
+						unicode = 3;
+						i += 3;
+						continue;
+					}
+					/* utf32 BE bom */
+					if (out[0] == 0 && out[1] == 0 && out[2] == 0xFE && out[3] == 0xFF) {
+						unicode = 3;
+						i += 6;
+						continue;
+					}
+
+					// allow a 'single' byte > 0x7E as long as bytes following are ascii.
+					if (out[1] <= 0x7E && out[1] >= 0x20) {
+						++i;
+						continue;
+					}
+					return 0;
+				}
+			}
 		} else if (out[i] < 0x20) {
 			/* we do not need to deal with DOS EOF char 0x1a, since we will never have the 'end' of the file */
-			if (out[i]!='\n' && out[i]!='\r' && out[i]!='\t')
+			/* we do allow the ESC character for ANSI files, however, they are frequently also binary, so will fail in other places */
+			if (out[i]!='\n' && out[i]!='\r' && out[i]!='\t' && out[i]!=0x1B) 
 				return 0;
 		}
+		i += unicode; // skip the null bytes
 	}
+	return 1;
+}
+static int CheckSigs(const u8 *p, int len, ZIP_SIGS *pSig) {
+	int i, j;
 
-//printf ("strm.total_out=%03d  ", strm.total_out);
-#ifdef ZIP_DEBUG
-	salt->ascii_ucmp[strm.total_out-1] = 0;
-	printf ("ASCII find:  decoded to: len=%ld [%s]\n", strm.total_out, salt->ascii_ucmp);
+	for (i = 0; i < pSig->magic_count; ++i) {
+		int fnd = 1;
+		u8 *pS = pSig->magic_signature[i];
+		for (j = 0; j < pSig->magic_sig_len[i]; ++j) {
+			if (p[j] != pS[j]) {
+				fnd = 0;
+				break;
+			}
+		}
+		if (fnd)
+			return 1;
+	}
+	return 0;
+}
 #endif
-	return 1;
+
+#ifdef __GNUC__
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+__attribute__((always_inline))
+#else
+__inline__
+#endif
+#endif
+/* note, Buf is the 'full' decrypted zip buffer (len bytes long). It DOES contain the first 3 bits, which have already 
+ * been decoded, and have told us we had a code 2 (var table block) 
+ * all done without BITS(), PULLBYTE(), BITSNEEDED() macros.  We 'know' the data we need, and we know that we have
+ * 'enough', so we do not worry about all of the overhead, and validation logic.
+ *
+ * In testing, this function catches ALL bad decryptions, except about 1/300 to 1/350. So, it is not too bad.
+ */
+static int check_inflate_CODE2(u8 *next) {
+	u32 bits, hold, thisget, have, i;
+	int left;
+	u32 ncode;
+	u32 ncount[2];	// ends up being an array of 8 u8 count values.  But we can clear it, and later 'check' it with 2 u32 instructions.
+	u8 *count;		// this will point to ncount array. NOTE, this is alignment required 'safe' for Sparc systems or others requiring alignment.
+#if (ARCH_LITTLE_ENDIAN==1) && (ARCH_ALLOWS_UNALIGNED==1)
+	// 'speedup' for x86 type systems.  pkzip/inflate was designed here, so why not use it.
+	hold = *((u32*)next);
+#else
+	hold = *next + (((u32*)next[1])<<8) + (((u32*)next[2])<<16) + (((u32*)next[3])<<24);
+#endif
+	next += 3;	// we pre-increment when pulling it in the loop, thus we need to be 1 byte back.
+	hold >>= 3;	// we already processed 3 bits
+	count = (u8*)ncount;
+
+	if (257+(hold&0x1F) > 286) return 0;	// nlen, but we do not use it.
+	hold >>= 5;
+	if(1+(hold&0x1F) > 30) return 0;		// ndist, but we do not use it.
+	hold >>= 5;
+    ncode = 4+(hold&0xF);
+	hold >>= 4;
+
+	// we have 15 bits left.
+	hold += ((u32)(*++next)) << 15;
+	hold += ((u32)(*++next)) << 23;
+	// we now have 31 bits.  We need to know this for the loop below.  
+	bits = 31;
+
+	// We have 31 bits now, in accum.  If we are processing 19 codes, we do 7, then have 10 bits.  
+	// Add 16 more and have 26, then use 21, have 5.  Then load 16 more, then eat 15 of them.
+	have = 0;
+
+	ncount[0] = ncount[1] = 0;
+	for (;;) {
+		if (have+7>ncode)
+			thisget = ncode-have;
+		else 
+			thisget = 7;
+		have += thisget;
+		bits -= thisget*3;
+		while (thisget--) {
+			++count[hold&7];
+			hold>>=3;
+		}
+		if (have == ncode)
+			break;
+		hold += ((u32)(*++next)) << bits;
+		bits += 8;
+		hold += ((u32)(*++next)) << bits;
+		bits += 8;
+	}
+	count[0] = 0;
+	if (!ncount[0] && !ncount[1]) return 0; /* if no codes at all, then simply bail, that is invalid */
+
+    /* check for an over-subscribed or incomplete set of lengths */
+	/* this will catch about 319 out of 320 'bad' passwords that */
+	/* have made it into this function. Note, only 1/4 of the    */
+	/* passwords which pass the checksum, can make it here.  Of  */
+	/* those, we drop 319/320 or about that many (a good check!) */
+    left = 1;
+    for (i = 1; i <= 7; ++i) {
+        left <<= 1;
+        left -= count[i];
+        if (left < 0)
+			return 0;	/* over-subscribed */
+    }
+    if (left > 0)
+        return 0;		/* incomplete set */
+
+	return 1;			/* Passed this check! */
 }
 
-static int cmp_exact(char *source, int index)
-{
-	if (salt->flags&1) /* checksum only */
-		return 1;
+//static code const * const lcode = lenfix;
+//static code const * const dcode = distfix;
 
-	/* Do we have ASCII data? */
-	if (salt->flags&2) {
-		if (!salt->ascii_ucmp) {
-			salt->ascii_ucmp_len = salt->asciilen*5;
-			salt->ascii_ucmp = mem_alloc_tiny(salt->ascii_ucmp_len, MEM_ALIGN_NONE);
-			salt->ascii_decr = mem_alloc_tiny(salt->asciilen-12, MEM_ALIGN_NONE);
+#ifdef __GNUC__
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+__attribute__((always_inline))
+#else
+__inline__
+#endif
+#endif
+/* This function handles inflate CODE type 1. This is a 'fixed' table code.  We set the fixed table, */
+/* and then inflate some data (without writing anything.  If we find any BAD lookback data, we can   */
+/* return a failure.  We have 24 bytes of inflate data, and this almost always is more than enough   */
+/* to turn up an error.  If we find we need more, we will do more than 24                            */
+static int check_inflate_CODE1(u8 *next, int left) {
+	u32 whave, op, bits, hold,len;
+	code here;
+
+#if (ARCH_LITTLE_ENDIAN==1) && (ARCH_ALLOWS_UNALIGNED==1)
+	// 'speedup' for x86 type systems.  pkzip/inflate was designed here, so why not use it.
+	hold = *((u32*)next);
+#else
+	hold = *next + (((u32*)next[1])<<8) + (((u32*)next[2])<<16) + (((u32*)next[3])<<24);
+#endif
+	next += 3; // we pre-increment when pulling it in the loop, thus we need to be 1 byte back.
+	left -= 4;
+	hold >>= 3;  // we already processed 3 bits
+	bits = 32-3;
+	for (;;) {
+		if (bits < 15) {
+			if (left < 2)
+				return 1;	// we are out of bytes.  Return we had no error.
+			left -= 2;
+            hold += (u32)(*++next) << bits;
+            bits += 8;
+            hold += (u32)(*++next) << bits;
+            bits += 8;
 		}
-		decrypt(index, salt->asciidat, salt->ascii_decr, salt->asciilen);
-		if (!decomp_validate_ascii(salt->ascii_decr, salt->ascii_ucmp, salt->asciilen-12, salt->ascii_ucmp_len))
+		here=lenfix[hold & 0x1FF];
+        op = (unsigned)(here.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(here.op);
+        if (op == 0)							/* literal */
+			++whave;
+        else if (op & 16) {						/* length base */
+            len = (unsigned)(here.val);
+            op &= 15;							/* number of extra bits */
+            if (op) {
+                if (bits < op) {
+					if (!left)
+						return 1;	/*we are out of bytes.  Return we had no error.*/
+					--left;
+                    hold += (u32)(*++next) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            if (bits < 15) {
+				if (left < 2)
+					return 1;	/*we are out of bytes.  Return we had no error.*/
+				left -= 2;
+                hold += (u32)(*++next) << bits;
+                bits += 8;
+                hold += (u32)(*++next) << bits;
+                bits += 8;
+            }
+            here = distfix[hold & 0x1F];
+          dodist:
+            op = (unsigned)(here.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(here.op);
+            if (op & 16) {                      /* distance base */
+                u32 dist = (unsigned)(here.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+					if (!left)
+						return 1;	/*we are out of bytes.  Return we had no error.*/
+					--left;
+                    hold += (u32)(*++next) << bits;
+                    bits += 8;
+                    if (bits < op) {
+						if (!left)
+							return 1;	/*we are out of bytes.  Return we had no error.*/
+						--left;
+                        hold += (u32)(*++next) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+                if (dist > whave)
+					return 0;  /*invalid distance too far back*/
+                hold >>= op;
+                bits -= op;
+				whave += dist;
+            }
+            else if ((op & 64) == 0) {	/* 2nd level distance code */
+                here = distfix[here.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else
+				return 0;		/*invalid distance code*/
+        }
+		else if (op & 64) {
+			// 2nd level length code.
+            //here = lcode[here.val + (hold & ((1U << op) - 1))];
+            //goto dolen;
+
+			// this causes an infinite loop. Also, I VERY seriously doubt, this will EVER happen in the first
+			// 24 bytes of code.  NOTE, there may be problems, in the fact this causes a inf loop!, but for now,
+			// simply return 0, then debug later.
 			return 0;
+		}
+		else if (op & 32) {
+			// end of block  NOTE, we need to find out if we EVER hit the end of a block, at only 24 bytes??? 
+			// It is VERY likely we do SHOULD NOT EVER hit this. If that is the case, return that this block is bogus.
+			// check next OP (if we have enough bits left), if CODE=3, fail.  If code==0, check
+			return 0;
+		}
+		else {
+			return 0; // invalid literal/length code.
+		}
 	}
-	if (salt->flags&4) {
-		if (!salt->full_encr_dat && salt->filename) {
-			FILE *in = fopen(salt->filename, "rb");
-			salt->full_encr_dat = mem_alloc_tiny(salt->compLen, MEM_ALIGN_NONE);
-			fseek(in, salt->offset, SEEK_SET);
-			if(fread(salt->full_encr_dat, 1, salt->compLen, in) != salt->compLen) {
-				fprintf(stderr, "\nError, can not read the Compressed file from the zipfile.  No additional checking will be performed.\n");
-				return 1;
-			}
-			fclose(in);
+}
+
+/*
+ * Crypt_all simply performs the checksum .zip validatation of the data. It performs
+ * this for ALL hashes provided. If any of them fail to match, then crypt all puts the
+ * complement of the 'proper' checksum of the first hash into the output. These 2 bytes
+ * are checked against the binary for this salt/password combination.  Thus, if any
+ * checksum fails, it will never match binary.  However, if ALL of the checksums match
+ * we then put the checksum bytes from the first hash, into our output data. Then, when
+ * the binary check (cmp_all, cmp_one) is performed, it WILL match.  NOTE, this does
+ * not mean we have found the password.  Just that all hashes quick check checksums
+ * for this password 'work'.
+ */
+static void crypt_all(int _count)
+{
+	int idx;
+#if (ZIP_DEBUG==2)
+	static int CNT, FAILED, FAILED2;
+	++CNT;
+#endif
+
+	// pkzip kinda sucks a little for multi-threading, since there is different amount of work to be
+	// done, depenging upon the password.  Thus, we pack in OMP_MOD passwords into each thread, and
+	// hopefully some of the differnces will even themselves out in the end.  If we have 2 threads
+	// then thread 1 gets 0 to 127 password, and thread 2 gets 128-256.  Once they 'get' their data,
+	// there should be no mutexing of the runtime data, thus the threads should run fast.
+	// Also, since we have 'multiple' files in a .zip file (and multiple checksums), we bail as at the
+	// first time we fail to match checksum.  So, there may be some threads which check more checksums.
+	// Again, hopefully globbing many tests into a threads working set will flatten out these differences.
+#ifdef _OPENMP
+#pragma omp parallel for private(idx)
+#endif
+	for (idx = 0; idx < _count; ++idx) {
+		int cur_hash_count = salt->cnt;
+		int cur_hash_idx = -1;
+		MY_WORD key0, key1, key2;
+		u8 C;
+		const u8 *b;
+		u8 curDecryBuf[256];
+#if USE_PKZIP_MAGIC
+		u8 curInfBuf[128];
+#endif
+		int k, SigChecked;
+		u16 e, v1, v2;
+		z_stream strm;
+		int ret;
+
+		/* use the pwkey for each hash.  We mangle on the 12 bytes of IV to what  was computed in the pwkey load. */
+
+		if (dirty) {
+			u8 *p = (u8*)saved_key[idx];
+
+			/* load the 'pwkey' one time, put it into the K12 array */
+			key0.u = 0x12345678UL; key1.u = 0x23456789UL; key2.u = 0x34567890UL;
+			do {
+				key0.u = pkzip_crc32 (key0.u, *p++);
+				key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+				key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+			} while (*p);
+			K12[idx*3] = key0.u, K12[idx*3+1] = key1.u, K12[idx*3+2] = key2.u;
+			goto SkipKeyLoadInit;
 		}
-		if (!salt->full_decr_dat)
-			salt->full_decr_dat = mem_alloc_tiny(salt->compLen-12, MEM_ALIGN_NONE);
-		decrypt(index, salt->full_encr_dat, salt->full_decr_dat, salt->compLen);
-		if (!decomp_validate(salt->full_decr_dat, salt->compLen-12, salt->deCompLen, salt->crc32)) {
-#ifdef ZIP_DEBUG
-			fprintf(stderr, "False positive:  PW found is:  %s\n", saved_key[index]);
+
+		do
+		{
+			// 2nd, and later times through the loop, AND if keys are not dirty (i.e. multiple salts
+			// for the same key load), we do NOT perform the key compute, but instead load the pre-computed
+			// key data from the array.
+			key0.u = K12[idx*3], key1.u = K12[idx*3+1], key2.u = K12[idx*3+2];
+
+SkipKeyLoadInit:;
+			b = salt->H[++cur_hash_idx].h;
+			k=11;
+			e = salt->H[cur_hash_idx].c;
+
+			do
+			{
+				C = PKZ_MULT(*b++,key2);
+				key0.u = pkzip_crc32 (key0.u, C);
+				key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+				key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+			}
+			while(--k);
+
+			/* if the hash is a 2 byte checksum type, then check that value first */
+			/* There is no reason to continue if this byte does not check out.  */
+			if (salt->chk_bytes == 2 && C != (e&0xFF))
+				goto Failed_Bailout;
+
+			C = PKZ_MULT(*b++,key2);
+			if (C != (e>>8))
+				goto Failed_Bailout;
+
+			// Now, update the key data (with that last byte.
+			key0.u = pkzip_crc32 (key0.u, C);
+			key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+			key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+
+			// Ok, we now have validated this checksum.  We need to 'do some' extra pkzip validation work.
+			// What we do here, is to decrypt a little data (possibly only 1 byte), and perform a single
+			// 'inflate' check (if type is 8).  If type is 0 (stored), and we have a signature check, then
+			// we do that here.  Also, if the inflate code is a 0 (stored block), and we do sig check, then
+			// we can do that WITHOUT having to call inflate.  however, if there IS a sig check, we will have
+			// to call inflate on 'some' data, to get a few bytes (or error code). Also, if this is a type
+			// 2 or 3, then we do the FULL inflate, CRC check here.
+			e = 0;
+
+			// First, we want to get the inflate CODE byte (the first one).
+
+			C = PKZ_MULT(*b++,key2);
+			// Ok, if this is a code 3, we are done.
+			if ( (C & 6) == 6)
+				goto Failed_Bailout;
+			SigChecked = 0;
+			if ( (C & 6) == 0) {
+				// Check that checksum2 is 0 or 1.  If not, I 'think' we can be done
+				if (C > 1)
+					goto Failed_Bailout;
+				// now get 4 bytes.  This is the length.  It is made up of 2 16 bit values.
+				// these 2 values are checksumed, so it is easy to tell if the data is WRONG.
+				// correct data is u16_1 == (u16_2^0xFFFF)
+				curDecryBuf[0] = C;
+				for (e = 0; e <= 4; ) {
+					key0.u = pkzip_crc32 (key0.u, curDecryBuf[e]);
+					key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+					key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+					curDecryBuf[++e] = PKZ_MULT(*b++,key2);
+				}
+				v1 = curDecryBuf[1] | (((u16)curDecryBuf[2])<<8);
+				v2 = curDecryBuf[3] | (((u16)curDecryBuf[4])<<8);
+				if (v1 != (v2^0xFFFF))
+					goto Failed_Bailout;
+#if USE_PKZIP_MAGIC
+				// Ok, if we have a signature, check it here, WITHOUT having to call zLib's inflate.
+				if (salt->H[cur_hash_idx].pSig->max_len) {
+					int len = salt->H[cur_hash_idx].pSig->max_len + 5;
+					if (len > salt->H[cur_hash_idx].datlen-12)
+						len = salt->H[cur_hash_idx].datlen-12;
+					SigChecked = 1;
+					for (; e < len;) {
+						key0.u = pkzip_crc32 (key0.u, curDecryBuf[e]);
+						key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+						key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+						curDecryBuf[++e] = PKZ_MULT(*b++,key2);
+					}
+
+					if (salt->H[cur_hash_idx].magic == 255) {
+						if (!validate_ascii(&curDecryBuf[5], len-5))
+							goto Failed_Bailout;
+					} else {
+						if (!CheckSigs(&curDecryBuf[5], len-5, salt->H[cur_hash_idx].pSig))
+							goto Failed_Bailout;
+					}
+				}
 #endif
-			return 0;
+			}
+			else {
+				// Ok, now we have handled inflate code type 3 and inflate code 0 (50% of 'random' data)
+				// We now have the 2 'hard' ones left (fixed table, and variable table)
+
+				curDecryBuf[0] = C;
+
+				if ((C&6) == 4) { // inflate 'code' 2  (variable table)
+#if (ZIP_DEBUG==2)
+					static unsigned count, found;
+					++count;
+#endif
+					// we need 4 bytes, + 2, + 4 at most.
+					for (; e < 10;) {
+						key0.u = pkzip_crc32 (key0.u, curDecryBuf[e]);
+						key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+						key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+						curDecryBuf[++e] = PKZ_MULT(*b++,key2);
+					}
+					if (!check_inflate_CODE2(curDecryBuf))
+						goto Failed_Bailout;
+#if (ZIP_DEBUG==2)
+					fprintf (stderr, "CODE2 Pass=%s  count = %u, found = %u\n", saved_key[idx], count, ++found);
+#endif
+				}
+				else {
+					int til;
+#if (ZIP_DEBUG==2)
+					static unsigned count, found;
+					++count;
+#endif
+					til = 36;
+					if (salt->H[cur_hash_idx].datlen-12 < til)
+						til = salt->H[cur_hash_idx].datlen-12;
+					for (; e < til;) {
+						key0.u = pkzip_crc32 (key0.u, curDecryBuf[e]);
+						key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+						key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+						curDecryBuf[++e] = PKZ_MULT(*b++,key2);
+					}
+					if (!check_inflate_CODE1(curDecryBuf, til))
+						goto Failed_Bailout;
+#if (ZIP_DEBUG==2)
+					fprintf (stderr, "CODE1 Pass=%s  count = %u, found = %u\n", saved_key[idx], count, ++found);
+#endif
+				}
+			}
+#if USE_PKZIP_MAGIC
+			// Ok, now see if we need to check sigs, or do a FULL inflate/crc check.
+			if (!SigChecked && salt->H[cur_hash_idx].pSig->max_len) {
+				int til = 180;
+				if (salt->H[cur_hash_idx].datlen-12 < til)
+					til = salt->H[cur_hash_idx].datlen-12;
+				for (; e < til;) {
+					key0.u = pkzip_crc32 (key0.u, curDecryBuf[e]);
+					key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+					key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+					curDecryBuf[++e] = PKZ_MULT(*b++,key2);
+				}
+				strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.next_in = Z_NULL;
+				strm.avail_in = til;
+		
+				ret = inflateInit2(&strm, -15); /* 'raw', since we do not have gzip header, or gzip crc. .ZIP files are 'raw' implode data. */
+				if (ret != Z_OK)
+				   perror("Error, initializing the libz inflateInit2() system\n");
+
+				strm.next_in = curDecryBuf;
+				strm.avail_out = sizeof(curInfBuf);
+				strm.next_out = curInfBuf;
+
+				ret = inflate(&strm, Z_SYNC_FLUSH);
+
+				inflateEnd(&strm);
+				if (ret != Z_OK)
+					goto Failed_Bailout;
+				if (!strm.total_out)
+					goto Failed_Bailout;
+
+				ret = salt->H[cur_hash_idx].pSig->max_len;
+				if (salt->H[cur_hash_idx].magic == 255) {
+					if (!validate_ascii(curInfBuf, strm.total_out))
+						goto Failed_Bailout;
+				} else {
+					if (strm.total_out < ret)
+						goto Failed_Bailout;
+					if (!CheckSigs(curInfBuf, strm.total_out, salt->H[cur_hash_idx].pSig))
+						goto Failed_Bailout;
+				}
+			}
+#endif
+
+			if (salt->H[cur_hash_idx].full_zip) {
+				u8 inflateBufTmp[1024];
+				if (salt->compLen > 240 && salt->H[cur_hash_idx].datlen >= 200) {
+					for (;e < 200;) {
+						key0.u = pkzip_crc32 (key0.u, curDecryBuf[e]);
+						key1.u = (key1.u + key0.c[KB1]) * 134775813 + 1;
+						key2.u = pkzip_crc32 (key2.u, key1.c[KB2]);
+						curDecryBuf[++e] = PKZ_MULT(*b++,key2);
+					}
+					strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.next_in = Z_NULL;
+					strm.avail_in = e;
+			
+					ret = inflateInit2(&strm, -15); /* 'raw', since we do not have gzip header, or gzip crc. .ZIP files are 'raw' implode data. */
+					if (ret != Z_OK)
+					   perror("Error, initializing the libz inflateInit2() system\n");
+
+					strm.next_in = curDecryBuf;
+					strm.avail_out = sizeof(inflateBufTmp);
+					strm.next_out = inflateBufTmp;
+
+					ret = inflate(&strm, Z_SYNC_FLUSH);
+					inflateEnd(&strm);
+
+					if (ret != Z_OK) {
+#if (ZIP_DEBUG==2)
+#ifdef _MSC_VER
+						fprintf(stderr, "fail=%d fail2=%d tot=%lld\n", ++FAILED, FAILED2, ((long long)CNT)*_count);
+#else
+						fprintf(stderr, "fail=%d fail2=%d tot=%lld\n", ++FAILED, FAILED2, ((long long)CNT)*_count);
+#endif
+#endif
+						goto Failed_Bailout;
+					}
+				}
+				goto KnownSuccess;
+			}
 		}
-		/* we found the biatch */
-		return 1;
+		while(--cur_hash_count);
+
+		/* We got a checksum HIT!!!! All hash checksums matched. */
+		/* We load the proper checksum value for the gethash */
+KnownSuccess: ;
+		chk[idx] = 1;
+
+		continue;
+		
+Failed_Bailout: ;
+		/* We load the wrong checksum value for the gethash */
+		chk[idx] = 0;
 	}
 
-	return 1;
+	/* clear the 'dirty' flag.  Then on multiple different salt calls, we will not have to */
+	/* encrypt the passwords again. They will have already been loaded in the K12[] array. */
+	dirty = 0;
 }
 
 struct fmt_main fmt_pkzip = {
diff -urpN john-1.7.8-jumbo-6a/src/pkzip_inffixed.h john-1.7.8-jumbo-6b/src/pkzip_inffixed.h
--- john-1.7.8-jumbo-6a/src/pkzip_inffixed.h	1970-01-01 00:00:00.000000000 +0000
+++ john-1.7.8-jumbo-6b/src/pkzip_inffixed.h	2011-09-08 15:13:23.000000000 +0000
@@ -0,0 +1,143 @@
+#if !defined (_PKZIP_INFFIXED_H_)
+#define _PKZIP_INFFIXED_H_
+
+/**********************************************************************/
+/* NOTE, this data file was taken from the zLib library directory.    */
+/* This is the pre-made fixed length inflate tree data                */
+/* This code used in pkzip, to handle inflate CODE==1, quick checking */
+/*                                                                    */
+/* HERE is the copyright notice copied from zlib.h                    */
+/**********************************************************************/
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.5, April 19th, 2010
+
+  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+	/* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications. It
+       is part of the implementation of the compression library and
+       is subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
+
+#endif //#define _PKZIP_INFFIXED_H_
diff -urpN john-1.7.8-jumbo-6a/src/zip2john.c john-1.7.8-jumbo-6b/src/zip2john.c
--- john-1.7.8-jumbo-6a/src/zip2john.c	2011-09-01 15:26:21.031250000 +0000
+++ john-1.7.8-jumbo-6b/src/zip2john.c	2011-09-09 20:44:27.000000000 +0000
@@ -5,12 +5,9 @@
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted.
  *
- * Updated in Aug 2011 by Jim Fougeron.  Added PKZIP 'old' encryption.  The signature
- * on the pkzip will be $pkzip1$ and does not look like the AES version written by Dhiru
+ * Updated in Aug 2011 by JimF.  Added PKZIP 'old' encryption.  The signature on the
+ * pkzip will be $pkzip$ and does not look like the AES version written by Dhiru
  * Also fixed some porting issues, such as variables needing declared at top of blocks.
- * Added a -a= switch for 'old' format.  That allows a user to give a hint that a specific
- * file 'is' known to be ASCII.  This allows john to have a significant performance
- * improvement when there are no small files.
  *
  * References:
  *
@@ -36,58 +33,28 @@
  * For type = 0, for ZIP files encrypted using AES
  * filename:$zip$*type*hex(CRC)*encryption_strength*hex(salt)*hex(password_verfication_value):hex(authentication_code)
  *
- * For pkzip type:  (JimF, with longer explaination of fields)
- * filename:$pkzip1$C*B*F*H*[H*[H*...]]*AL*AT*AD*crc*cmplen*decomplen*compType*offset*filename*intfilename*filedata*
+ * For original pkzip encryption:  (JimF, with longer explaination of fields)
+ * filename:$pkzip$C*B*[DT*MT{CL*UL*CR*OF*OX}*CT*DL*DA]*$/pkzip$
  *
  * All numeric and 'binary data' fields are stored in hex.
  *
- * C  is the count of hashes present (the H's.).
- * B  is number of valid bytes in the checksum (1 or 2).  Unix zip is 2 bytes, all others are 1
- * F  is a set of flags. The bits of the flag list which fields following the array of H's should have data.
- * H  is a 'hash'. This is the first 12 bytes of the encrypted imploded data blob (the IV), and also the 2 bytes of checksum,
- *    either from the CRC32 of the file, or the Dos timestamp. There can be up to 8 of these (if there are 8 encrypted files
- *    in the .zip file, and this 'assumes' that all files have the same password.
- * AL is the 'length' of the ASCII compressed file blob.  This assumes that there is a 'known to be' total ASCII text file
- *    encrypted in the zip.  Only a tiny part of the start of the file is decrypted and decompressed. Then if that decompressed
- *    data is 'all' ASCII items, then that is a better validation than a checksum match.
- * AT is the 'type' of compression. Only 0 or 8 are handled (store or inflate)
- * AD This is the compressed ASCII data.  It is the first 12 bytes (the IV), of the imploded data of the ASCII file, and some
- *    more.  80-90 bytes is more than adequate.  This number may be reduced, if it speeds things up in the end.
- * CRC32       This is the crc of the 'whole' file we have to test
- * Compr_len   This is the length of compressed data (the test-3 full test data).
- * deComp_len  The length of the decompressed data (full file test data).
- * compType    is the 'type' of compression. Only 0 or 8 are handled (store or inflate)
- * Offset      This is the offset of this data within the .zip file. If the file is too large, then it can not be placed into
- *             the john input line.  If that is the case, the .zip file must be present (name listed next), and when john
- *             runs, it will load the zip data.
- * FileName    The name of the .zip file (can contain path's).
- * IntFileName This is the name of the compressed/encrypted file within the .zip.  This is needed if we spawn out to unzip -P
- *             to perform the test (this field may go away.
- * FileData    We can provide the file data, if it is small enough.  NOTE the file should be a couple hundred bytes long at
- *             least, to make it MUCH more unlikely that we could decrypt/explode/crc and have proper size and crc.  If the
- *             file data is provided, then the Offset/FileName/IntFileName are not needed.
- *
- * NOTE the flags field lists which of the above fields are present in the hash.  NOTE, it is valid to have only the hashes
- * (the 'H' data) present.  John will be able to crack based only upon that.  Within the format, many of the test vectors
- * are Hash only.
-
- * There are 3 'test' items in a file.  The more of these that are present, the less likely it is to have false positive
- *   passwords.
- * The first is the checksum hash. There can be up to 8 of these hashes.  The hashes may have 1 or 2 bytes that 'match'
- *   in the checksum.  The 2 byte checksums provide much stronger 'pre' validation.  If there are enough of these
- *   checksums, then this may be all the data needed.  This is the array of 'H' data.  Unix (info-zip) makes zips
- *   which have 2 bytes valid in the checksum (and the checksum checks against the dos-timestamp). Winzip and pkzip 2.00+
- *   both only have 1 byte of valid checksum data, and it is the LSB of the CRC field.
- * The second (optional), is the first part of a 'text' file. If there is a file that is KNOWN to be pure ASCII
- *   text, then we can grab the first small part of the encrypted/compressed data, decrypt it, decompress it, and
- *   see if all the data is ASCII (ignoring the last couple of bytes).  This is not perfect, but may be very fast,
- *   compared to step 3 if all files are LARGE, and it eliminates almost ALL false positives that passed the
- *   checksum checks.   This is the AL and AD data, and is optional.
- * The 3rd part, is an entire compressed data blob, it's length it's CRC32.  This is the real 'test'.  The file should
- *   have a certain minimum size, say 100 bytes, decompressed.  john will either spawn unzip -P to test the .zip file
- *   or will perform the full decryption of the data blob, the full explosion of the data blob, and if the length matches
- *   what it is supposed to, and the CRC of the decompressed data blob matches, THEN we know we have the password found.
- *
+ * C   is the count of hashes present (the array of items, inside the []  C can be 1 to 3.).
+ * B   is number of valid bytes in the checksum (1 or 2).  Unix zip is 2 bytes, all others are 1
+ * ARRAY of data starts here
+ *   DT  is a "Data Type enum".  This will be 1 2 or 3.  1 is 'partial'. 2 and 3 are full file data (2 is inline, 3 is load from file).
+ *   MT  Magic Type enum.  0 is no 'type'.  255 is 'text'. Other types (like MS Doc, GIF, etc), see source.
+ *     NOTE, CL, DL, CRC, OFF are only present if DT != 1
+ *     CL  Compressed length of file blob data (includes 12 byte IV).
+ *     UL  Uncompressed length of the file.
+ *     CR  CRC32 of the 'final' file.
+ *     OF  Offset to the PK\x3\x4 record for this file data. If DT==2, then this will be a 0, as it is not needed, all of the data is already included in the line.
+ *     OX  Additional offset (past OF), to get to the zip data within the file.
+ *     END OF 'optional' fields.
+ *   CT  Compression type  (0 or 8)  0 is stored, 8 is imploded.
+ *   DL  Length of the DA data.
+ *   DA  This is the 'data'.  It will be hex data if DT==1 or 2. If DT==3, then it is a filename (name of the .zip file).
+ * END of array item.  There will be C (count) array items.
+ * The format string will end with $/pkzip$
  */
 
 #include <stdio.h>
@@ -98,11 +65,15 @@
 #include <string.h>
 #include <assert.h>
 #include "common.h"
+#include "misc.h"
+#include "formats.h"
 
-static int ascii_mode=0;
-static int checksum_only=0;
+static int ascii_mode=0, checksum_only=0;
 static char *ascii_fname;
 
+static char *MagicTypes[]= { "", "DOC", "XLS", "DOT", "XLT", "EXE", "DLL", "ZIP", "BMP", "DIB", "GIF", "PDF", "GZ", "TGZ", "BZ2", "TZ2", "FLV", "SWF", "MP3", NULL };
+static int  MagicToEnum[] = {0,  1,    1,     1,     1,     2,     2,     3,     4,     4,     5,     6,     7,    7,     8,     8,     9,     10,    11,  0};
+
 /* helper functions for byte order conversions, header values are stored
  * in little-endian byte order */
 static uint32_t fget32(FILE * fp)
@@ -161,7 +132,10 @@ static void process_file(const char *fna
 			(void) crc;
 			(void) uncompressed_size;
 
-			fread(filename, 1, filename_length, fp);
+			if (fread(filename, 1, filename_length, fp) != filename_length) {
+				fprintf(stderr, "Error, in fread of file data!\n");
+				goto cleanup;
+			}
 			filename[filename_length] = 0;
 
 			if (compression_method == 99) {	/* AES encryption */
@@ -192,15 +166,24 @@ static void process_file(const char *fna
 				switch (efh_aes_strength) {
 				case 1:
 					n = 8;
-					fread(salt, 1, n, fp);
+					if (fread(salt, 1, n, fp) != n) {
+						fprintf(stderr, "Error, in fread of file data!\n");
+						goto cleanup;
+					}
 					break;
 				case 2:
 					n = 12;
-					fread(salt, 1, n, fp);
+					if (fread(salt, 1, n, fp) != n) {
+						fprintf(stderr, "Error, in fread of file data!\n");
+						goto cleanup;
+					}
 					break;
 				case 3:
 					n = 16;
-					fread(salt, 1, n, fp);
+					if (fread(salt, 1, n, fp) != n) {
+						fprintf(stderr, "Error, in fread of file data!\n");
+						goto cleanup;
+					}
 					break;
 
 				}
@@ -242,31 +225,147 @@ cleanup:
 	fclose(fp);
 }
 
-static void process_old_zip(const char *fname) {
-	/* instead of using anything from the process_file, we simply detected a encrypted old style
-	   password, close the file, and call this function.  This function handles the older pkzip
-	   password, while the process_file handles ONLY the AES from WinZip */
+/* instead of using anything from the process_file, we simply detected a encrypted old style
+ * password, close the file, and call this function.  This function handles the older pkzip
+ * password, while the process_file handles ONLY the AES from WinZip 
+ */
+typedef struct _zip_ptr
+{
+	uint16_t      magic_type, cmptype;
+	uint32_t      offset, offex, crc, cmp_len, decomp_len;
+	char          chksum[5];
+	char         *hash_data;
+} zip_ptr;
+typedef struct _zip_file
+{
+	int unix_made;
+	int check_in_crc;
+	int two_byte_check;
+} zip_file;
+
+static int magic_type(const char *filename) {
+	char *Buf = str_alloc_copy((char*)filename), *cp;
+	int i;
 
+	strupr(Buf);
+	if (ascii_fname && !strcasecmp(Buf, ascii_fname)) 
+		return 255;
+
+	cp = strrchr(Buf, '.');
+	if (!cp) return 0;
+	++cp;
+	for (i = 1; MagicTypes[i]; ++i)
+		if (!strcmp(cp, MagicTypes[i]))
+			return MagicToEnum[i];
+	return 0;
+}
+static char *toHex(unsigned char *p, int len) {
+	static char Buf[4096];
+	char *cp = Buf;
+	int i;
+	for (i = 0; i < len; ++i)
+		cp += sprintf(cp, "%02x", p[i]);
+	return Buf;
+}
+static int LoadZipBlob(FILE *fp, zip_ptr *p, zip_file *zfp, const char *zip_fname)
+{
+	uint16_t version,flags,lastmod_time,lastmod_date,filename_length,extrafield_length;
 	unsigned char filename[1024];
-	unsigned char H[12];
-	char building_hash[29*8+1];  // store up to 8 hashes. They are 12 bytes + 2 bytes (in hex), which is 28 bytes, and the '*' char (and +1 for the null byte).
-	char *pbuilding_hash=building_hash;
-	int count_of_hashes = 0;
-	FILE *fp;
-	char *FileData = "";
-	int unix_made=0, check_in_crc = 1, two_byte_check = 0;
-	unsigned Flag_bits = 1;
-	// todo.
-	unsigned AL=0, AT=0;
-	char *AD = "";
-	char sAL[8] = {0}, sAT[8] = {0};
 
-	uint32_t best_size=0xFFFFFFFF, best_off=0, best_crc=0, best_cmp_size=0;
-	char best_filename[1024]={0}, best_str_off[20]={0}, best_fname[1024]={0}, best_type[8]={0};
+	memset(p, 0, sizeof(*p));
+
+	p->offset = ftell(fp)-4;
+	version = fget16(fp);
+	flags = fget16(fp);
+	p->cmptype = fget16(fp);
+	lastmod_time = fget16(fp);
+	lastmod_date = fget16(fp);
+	p->crc = fget32(fp);
+	p->cmp_len= fget32(fp);
+	p->decomp_len = fget32(fp);
+	filename_length = fget16(fp);
+	extrafield_length = fget16(fp);
+	/* unused variables */
+	(void) lastmod_date;
+
+	if (fread(filename, 1, filename_length, fp) != filename_length) {
+		fprintf(stderr, "Error, fread could not read the data from the file:  %s\n", zip_fname);
+		return 0;
+	}
+	filename[filename_length] = 0;
+	p->magic_type = magic_type((char*)filename);
+
+	p->offex = 30 + filename_length + extrafield_length;
+
+	// we only handle implode or store.
+	if ( (version == 0x14||version==0xA) && (flags & 1) && (p->cmptype == 8 || p->cmptype == 0)) {
+		uint16_t extra_len_used = 0;
+		if (flags & 8) {
+			while (extra_len_used < extrafield_length) {
+				uint16_t efh_id = fget16(fp);
+				uint16_t efh_datasize = fget16(fp);
+				extra_len_used += 4 + efh_datasize;
+				fseek(fp, efh_datasize, SEEK_CUR);
+				//http://svn.assembla.com/svn/os2utils/unzip60f/proginfo/extrafld.txt
+				//http://emerge.hg.sourceforge.net/hgweb/emerge/emerge/diff/c2f208617d32/Source/unzip/proginfo/extrafld.txt
+				if (efh_id == 0x07c8 ||  // Info-ZIP Macintosh (old, J. Lee)
+					efh_id == 0x334d ||  // Info-ZIP Macintosh (new, D. Haase's 'Mac3' field)
+					efh_id == 0x4d49 ||  // Info-ZIP OpenVMS (obsolete)
+					efh_id == 0x5855 ||  // Info-ZIP UNIX (original; also OS/2, NT, etc.)
+					efh_id == 0x6375 ||  // Info-ZIP UTF-8 comment field
+					efh_id == 0x7075 ||  // Info-ZIP UTF-8 name field
+					efh_id == 0x7855 ||  // Info-ZIP UNIX (16-bit UID/GID info)
+					efh_id == 0x7875)    // Info-ZIP UNIX 3rd generation (generic UID/GID, ...)
+
+					// 7zip ALSO is 2 byte checksum, but I have no way to find them.  NOTE, it is 2 bytes of CRC, not timestamp like InfoZip.
+					// OLD winzip (I think 8.01 or before), is also supposed to be 2 byte.
+					// old v1 pkzip (the DOS builds) are 2 byte checksums.
+				{
+					zfp->unix_made = 1;
+					zfp->two_byte_check = 1;
+					zfp->check_in_crc = 0;
+				}
+			}
+		}
+		else if (extrafield_length)
+			fseek(fp, extrafield_length, SEEK_CUR);
+
+		fprintf(stderr,
+			"%s->%s PKZIP Encr:%s%s cmplen=%d, decmplen=%d, crc=%X\n",
+			zip_fname, filename, zfp->two_byte_check?" 2b chk,":"", zfp->check_in_crc?"":" TS_chk,", p->cmp_len, p->decomp_len, p->crc);
+
+		p->hash_data = mem_alloc_tiny(p->cmp_len+1, MEM_ALIGN_WORD);
+		if (fread(p->hash_data, 1, p->cmp_len, fp) != p->cmp_len) {
+			fprintf(stderr, "Error, fread could not read the data from the file:  %s\n", zip_fname);
+			return 0;
+		}
+
+		// Ok, now set checksum bytes.  This will depend upon if from crc, or from timestamp
+		if (zfp->check_in_crc)
+			sprintf (p->chksum, "%02x%02x", (p->crc>>24)&0xFF, (p->crc>>16)&0xFF);
+		else
+			sprintf(p->chksum, "%02x%02x", lastmod_time>>8, lastmod_time&0xFF);
+
+		return 1;
+
+	}
+	fprintf(stderr, "%s->%s is not encrypted, or stored with non-handled compression type\n", zip_fname, filename);
+	fseek(fp, extrafield_length, SEEK_CUR);
+	fseek(fp, p->cmp_len, SEEK_CUR);
+
+	return 0;
+}
+
+static void process_old_zip(const char *fname)
+{
+	FILE *fp;
 
-	strcpy(best_fname, fname);
+	int count_of_hashes = 0;
+	zip_ptr hashes[3], curzip;
+	zip_file zfp;
 
-	memset(building_hash, 0, sizeof(building_hash));
+	zfp.check_in_crc = 1;
+	zfp.two_byte_check = zfp.unix_made = 0;
 
 	if (!(fp = fopen(fname, "rb"))) {
 		fprintf(stderr, "! %s : %s\n", fname, strerror(errno));
@@ -277,100 +376,76 @@ static void process_old_zip(const char *
 		uint32_t id = fget32(fp);
 
 		if (id == 0x04034b50UL) {	/* local header */
-			uint16_t version = fget16(fp);
-			uint16_t flags = fget16(fp);
-			uint16_t compression_method = fget16(fp);
-			uint16_t lastmod_time = fget16(fp);
-			uint16_t lastmod_date = fget16(fp);
-			uint32_t crc = fget32(fp);
-			uint32_t compressed_size = fget32(fp);
-			uint32_t uncompressed_size = fget32(fp);
-			uint16_t filename_length = fget16(fp);
-			uint16_t extrafield_length = fget16(fp);
-			/* unused variables */
-			(void) lastmod_date;
-
-			fread(filename, 1, filename_length, fp);
-			filename[filename_length] = 0;
-
-			// we only handle implode or store.
-			if ( (version == 0x14||version==0xA) && (flags & 1) && (compression_method == 8 || compression_method == 0)) {
-				uint16_t extra_len_used = 0;
-				if (flags & 8) {
-					while (extra_len_used < extrafield_length) {
-						uint16_t efh_id = fget16(fp);
-						uint16_t efh_datasize = fget16(fp);
-						extra_len_used += 4 + efh_datasize;
-						fseek(fp, efh_datasize, SEEK_CUR);
-						//http://svn.assembla.com/svn/os2utils/unzip60f/proginfo/extrafld.txt
-						//http://emerge.hg.sourceforge.net/hgweb/emerge/emerge/diff/c2f208617d32/Source/unzip/proginfo/extrafld.txt
-						if (efh_id == 0x07c8 ||  // Info-ZIP Macintosh (old, J. Lee)
-							efh_id == 0x334d ||  // Info-ZIP Macintosh (new, D. Haase's 'Mac3' field)
-							efh_id == 0x4d49 ||  // Info-ZIP OpenVMS (obsolete)
-							efh_id == 0x5855 ||  // Info-ZIP UNIX (original; also OS/2, NT, etc.)
-							efh_id == 0x6375 ||  // Info-ZIP UTF-8 comment field
-							efh_id == 0x7075 ||  // Info-ZIP UTF-8 name field
-							efh_id == 0x7855 ||  // Info-ZIP UNIX (16-bit UID/GID info)
-							efh_id == 0x7875)    //  Info-ZIP UNIX 3rd generation (generic UID/GID, ...)
-						{
-							unix_made = 1;
-							two_byte_check = 1;
-							check_in_crc = 0;
+			if (LoadZipBlob(fp, &curzip, &zfp, fname) && curzip.decomp_len > 12) {
+				if (!count_of_hashes)
+					memcpy(&(hashes[count_of_hashes++]), &curzip, sizeof(curzip));
+				else {
+					if (count_of_hashes == 1) {
+						if (curzip.cmp_len < hashes[0].cmp_len) {
+							memcpy(&(hashes[count_of_hashes++]), &(hashes[0]), sizeof(curzip));
+							memcpy(&(hashes[0]), &curzip, sizeof(curzip));
+						} else
+							memcpy(&(hashes[count_of_hashes++]), &curzip, sizeof(curzip));
+					}
+					else if (count_of_hashes == 2) {
+						if (curzip.cmp_len < hashes[0].cmp_len) {
+							memcpy(&(hashes[count_of_hashes++]), &(hashes[1]), sizeof(curzip));
+							memcpy(&(hashes[1]), &(hashes[0]), sizeof(curzip));
+							memcpy(&(hashes[0]), &curzip, sizeof(curzip));
+						} else if (curzip.cmp_len < hashes[1].cmp_len) {
+							memcpy(&(hashes[count_of_hashes++]), &(hashes[1]), sizeof(curzip));
+							memcpy(&(hashes[1]), &curzip, sizeof(curzip));
+						} else
+							memcpy(&(hashes[count_of_hashes++]), &curzip, sizeof(curzip));
+					}
+					else {
+						int done=0;
+						if (curzip.magic_type && curzip.cmp_len > hashes[0].cmp_len) {
+							// if we have a magic type, we will replace any NON magic type, for the 2nd and 3rd largest, without caring about
+							// the size.
+							if (hashes[1].magic_type == 0) {
+								if (hashes[2].cmp_len < curzip.cmp_len) {
+									memcpy(&(hashes[1]), &(hashes[2]), sizeof(curzip));
+									memcpy(&(hashes[2]), &curzip, sizeof(curzip));
+									done=1;
+								} else {
+									memcpy(&(hashes[1]), &curzip, sizeof(curzip));
+									done=1;
+								}
+							} else if (hashes[2].magic_type == 0) {
+								if (hashes[1].cmp_len < curzip.cmp_len) {
+									memcpy(&(hashes[2]), &curzip, sizeof(curzip));
+									done=1;
+								} else {
+									memcpy(&(hashes[2]), &(hashes[1]), sizeof(curzip));
+									memcpy(&(hashes[1]), &curzip, sizeof(curzip));
+									done=1;
+								}
+							}
+						}
+						if (!done && curzip.cmp_len < hashes[0].cmp_len) {
+							// we 'only' replace the smallest zip, and always keep as many any other magic as possible.
+							if (hashes[0].magic_type == 0)
+								memcpy(&(hashes[0]), &curzip, sizeof(curzip));
+							else {
+								// Ok, the 1st is a magic, we WILL keep it.
+								if (hashes[1].magic_type) {  // Ok, we found our 2
+									memcpy(&(hashes[2]), &(hashes[1]), sizeof(curzip));
+									memcpy(&(hashes[1]), &(hashes[0]), sizeof(curzip));
+									memcpy(&(hashes[0]), &curzip, sizeof(curzip));
+								} else if (hashes[2].magic_type) {  // Ok, we found our 2
+									memcpy(&(hashes[1]), &(hashes[0]), sizeof(curzip));
+									memcpy(&(hashes[0]), &curzip, sizeof(curzip));
+								} else {
+									// found none.  So we will simply roll them down (liek when #1 was a magic also).
+									memcpy(&(hashes[2]), &(hashes[1]), sizeof(curzip));
+									memcpy(&(hashes[1]), &(hashes[0]), sizeof(curzip));
+									memcpy(&(hashes[0]), &curzip, sizeof(curzip));
+								}
+							}
 						}
 					}
 				}
-				else if (extrafield_length)
-					fseek(fp, extrafield_length, SEEK_CUR);
-
-				fprintf(stderr,
-					"%s->%s PKZIP Encr:%s%s cmplen=%d, decmplen=%d, crc=%X\n",
-					fname, filename, two_byte_check?" 2b chk,":"", check_in_crc?"":" TS_chk,", compressed_size, uncompressed_size, crc);
-
-				if (!checksum_only && uncompressed_size > 24 && uncompressed_size < best_size) {
-					best_size=uncompressed_size;
-					best_off=ftell(fp);
-					best_crc=crc;
-					best_cmp_size=compressed_size;
-					strcpy(best_filename, (char*)filename);
-					sprintf(best_type, "%x", compression_method);
-				}
-
-				if (!checksum_only && ascii_mode && !strcmp((char*)filename, ascii_fname)) {
-					long whence = ftell(fp);
-					unsigned char Buf[128+12+1];
-					AL = 128+12;
-					if (compressed_size < 128+12)
-						AL = compressed_size;
-					AT = compression_method;
-					fread(Buf, 1, AL, fp);
-					fseek(fp, whence, SEEK_SET);
-					AD = mem_alloc_tiny( (AL<<1)+1, MEM_ALIGN_NONE);
-					convert_to_hex(AD, Buf, AL);
-					sprintf(sAL, "%x", AL);
-					sprintf(sAT, "%x", AT);
-					Flag_bits |= 2;
-					Flag_bits &= (~1); // remove the 'checksum' only flag bit.
-				}
-				if (count_of_hashes < 8 && compressed_size > 14) {
-					fread(H, 1, 12, fp);
-					fseek(fp, compressed_size-12, SEEK_CUR);
-					if (pbuilding_hash != building_hash)
-						*pbuilding_hash++ = '*';
-					pbuilding_hash += convert_to_hex(pbuilding_hash, H, 12);
-					if (!check_in_crc)
-						sprintf (pbuilding_hash, "%02x%02x", lastmod_time>>8, lastmod_time&0xFF);
-					else
-						sprintf (pbuilding_hash, "%02x%02x", (crc>>24)&0xFF, (crc>>16)&0xFF);
-					pbuilding_hash += 4;
-					++count_of_hashes;
-				}
-				else
-					fseek(fp, compressed_size, SEEK_CUR);
-
-			} else {
-				fprintf(stderr, "%s->%s is not encrypted, or stored with non-handled compression type\n", fname, filename);
-				fseek(fp, extrafield_length, SEEK_CUR);
-				fseek(fp, compressed_size, SEEK_CUR);
 			}
 		} else if (id == 0x08074b50UL) {	/* data descriptor */
 			fseek(fp, 12, SEEK_CUR);
@@ -380,42 +455,31 @@ static void process_old_zip(const char *
 	}
 
 print_and_cleanup:;
-
-	sprintf (best_str_off, "%x", best_off);
-	if (!checksum_only && best_cmp_size != 0xFFFFFFFF) {
-		Flag_bits |= (4|8);
-		Flag_bits &= (~1); // remove the checksum only bit.
-	}
-	if (!checksum_only && best_cmp_size < 1400) {
-		// we can store the whole ZIP BLOB in the hash line.
-		unsigned char Buf[1400];
-		static char sBuf[2801];
-		// remove bit 3 and set bit 4
-		Flag_bits &= (~8);
-		Flag_bits |= 16;
-		fseek(fp, best_off, SEEK_SET);
-		fread(Buf, 1, best_cmp_size, fp);
-		convert_to_hex(sBuf, Buf, best_cmp_size);
-		FileData = sBuf;
-		best_off = 0;
-		// now, 'remove' the offset, the zip name and the internal file name, since we are storing the 'real' data.
-		*best_filename = 0;
-		*best_fname = 0;
-		*best_str_off = 0;
-
-		if (best_cmp_size < 128+12) // in this case, simply skip doing ANY ascii checking, and run right to the final checking.
-		{
-			Flag_bits &= (~2);
-			AD = "";
-			*sAL = 0;
-			*sAT = 0;
+	if (count_of_hashes) {
+		int i=1;
+		printf ("$pkzip$%x*%x*", count_of_hashes, zfp.two_byte_check?2:1);
+		if (checksum_only)
+			i = 0;
+		for (; i < count_of_hashes; ++i) {
+			int len = 12+24;
+			if (hashes[i].magic_type)
+				len = 12+180;
+			if (len > hashes[i].cmp_len)
+				len = hashes[i].cmp_len; // even though we 'could' output a '2', we do not.  We only need one full inflate CRC check file.
+			printf("1*%x*%x*%x*%s*%s*", hashes[i].magic_type, hashes[i].cmptype, len, hashes[i].chksum, toHex((unsigned char*)hashes[i].hash_data, len));
+		}
+		// Ok, now output the 'little' one (the first).
+		if (checksum_only)
+			printf ("\n");
+		else {
+			printf("%x*%x*%x*%x*%x*%x*%x*%x*", hashes[0].cmp_len<1500?2:3, hashes[0].magic_type, hashes[0].cmp_len, hashes[0].decomp_len, hashes[0].crc, hashes[0].offset, hashes[0].offex, hashes[0].cmptype);
+			if (hashes[0].cmp_len<1500)
+				printf("%x*%s*%s*", hashes[0].cmp_len, hashes[0].chksum, toHex((unsigned char*)hashes[0].hash_data, hashes[0].cmp_len));
+			else
+				printf("%x*%s*%s*", strlen(fname), hashes[0].chksum, fname);
 		}
+		printf("$/pkzip$\n");
 	}
-	printf ("%s:$pkzip1$%x*%x*%x*%s*", fname, count_of_hashes, two_byte_check+1, Flag_bits, building_hash);
-	if (checksum_only)
-		printf("***********\n");
-	else
-		printf("%s*%s*%s*%x*%x*%x*%s*%s*%s*%s*%s*\n", sAL, sAT, AD, best_crc, best_cmp_size, best_size, best_type, best_str_off, best_fname, best_filename, FileData );
 	fclose(fp);
 }
 
