aboutsummaryrefslogtreecommitdiff
path: root/src/pklib
diff options
context:
space:
mode:
authorLadislav Zezula <ladislav.zezula@avg.com>2013-01-11 14:55:08 +0100
committerLadislav Zezula <ladislav.zezula@avg.com>2013-01-11 14:55:08 +0100
commit3a926f0228c68d7d91cf3946624d7859976440ec (patch)
treec4e7d36dc8157576929988cdfcf5bfd8262cd09c /src/pklib
parentdf4b0c085478389c9a21a09521d46735a0109c8a (diff)
Initial creation
Diffstat (limited to 'src/pklib')
-rw-r--r--src/pklib/crc32.c66
-rw-r--r--src/pklib/explode.c522
-rw-r--r--src/pklib/implode.c769
-rw-r--r--src/pklib/pklib.h148
4 files changed, 1505 insertions, 0 deletions
diff --git a/src/pklib/crc32.c b/src/pklib/crc32.c
new file mode 100644
index 0000000..cd47b1d
--- /dev/null
+++ b/src/pklib/crc32.c
@@ -0,0 +1,66 @@
+/*****************************************************************************/
+/* crc32.c Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Pkware Data Compression Library Version 1.11 */
+/* Dissassembled method crc32 - cdecl version */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 09.04.03 1.00 Lad The first version of crc32.c */
+/* 02.05.03 1.00 Lad Stress test done */
+/*****************************************************************************/
+
+#include "pklib.h"
+
+static unsigned long crc_table[] =
+{
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+
+unsigned long PKEXPORT crc32_pklib(char * buffer, unsigned int * psize, unsigned long * old_crc)
+{
+ unsigned int size = *psize;
+ unsigned long ch;
+ unsigned long crc_value = *old_crc;
+
+ while(size-- != 0)
+ {
+ ch = *buffer++ ^ (char)crc_value;
+ crc_value >>= 8;
+
+ crc_value = crc_table[ch & 0x0FF] ^ crc_value;
+ }
+ return crc_value;
+}
diff --git a/src/pklib/explode.c b/src/pklib/explode.c
new file mode 100644
index 0000000..73c5004
--- /dev/null
+++ b/src/pklib/explode.c
@@ -0,0 +1,522 @@
+/*****************************************************************************/
+/* explode.c Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Implode function of PKWARE Data Compression library */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */
+/* 08.04.03 1.01 Lad Renamed to explode.c to be compatible with pklib */
+/* 02.05.03 1.01 Lad Stress test done */
+/* 22.04.10 1.01 Lad Documented */
+/*****************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "pklib.h"
+
+#define PKDCL_OK 0
+#define PKDCL_STREAM_END 1 // All data from the input stream is read
+#define PKDCL_NEED_DICT 2 // Need more data (dictionary)
+#define PKDCL_CONTINUE 10 // Internal flag, not returned to user
+#define PKDCL_GET_INPUT 11 // Internal flag, not returned to user
+
+char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n"
+ "Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n"
+ "Patent No. 5,051,745\r\n"
+ "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n"
+ "Version 1.11\r\n";
+
+//-----------------------------------------------------------------------------
+// Tables
+
+static unsigned char DistBits[] =
+{
+ 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
+};
+
+static unsigned char DistCode[] =
+{
+ 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
+ 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
+ 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
+ 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
+};
+
+static unsigned char ExLenBits[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
+};
+
+static unsigned short LenBase[] =
+{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106
+};
+
+static unsigned char LenBits[] =
+{
+ 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
+};
+
+static unsigned char LenCode[] =
+{
+ 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
+};
+
+static unsigned char ChBitsAsc[] =
+{
+ 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
+ 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
+ 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
+ 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
+ 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
+ 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
+ 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
+};
+
+static unsigned short ChCodeAsc[] =
+{
+ 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
+ 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
+ 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
+ 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
+ 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
+ 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
+ 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
+ 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
+ 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
+ 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
+ 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
+ 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
+ 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
+ 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
+ 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
+ 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
+ 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
+ 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
+ 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
+ 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
+ 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
+ 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
+ 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
+ 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
+ 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
+ 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
+ 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
+ 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
+ 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
+ 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
+ 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
+ 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
+};
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static void GenDecodeTabs(
+ unsigned char * positions, // [out] Table of positions
+ unsigned char * start_indexes, // [in] Table of start indexes
+ unsigned char * length_bits, // [in] Table of lengths. Each length is stored as number of bits
+ size_t elements) // [in] Number of elements in start_indexes and length_bits
+{
+ unsigned int index;
+ unsigned int length;
+ size_t i;
+
+ for(i = 0; i < elements; i++)
+ {
+ length = 1 << length_bits[i]; // Get the length in bytes
+
+ for(index = start_indexes[i]; index < 0x100; index += length)
+ {
+ positions[index] = (unsigned char)i;
+ }
+ }
+}
+
+static void GenAscTabs(TDcmpStruct * pWork)
+{
+ unsigned short * pChCodeAsc = &ChCodeAsc[0xFF];
+ unsigned int acc, add;
+ unsigned short count;
+
+ for(count = 0x00FF; pChCodeAsc >= ChCodeAsc; pChCodeAsc--, count--)
+ {
+ unsigned char * pChBitsAsc = pWork->ChBitsAsc + count;
+ unsigned char bits_asc = *pChBitsAsc;
+
+ if(bits_asc <= 8)
+ {
+ add = (1 << bits_asc);
+ acc = *pChCodeAsc;
+
+ do
+ {
+ pWork->offs2C34[acc] = (unsigned char)count;
+ acc += add;
+ }
+ while(acc < 0x100);
+ }
+ else if((acc = (*pChCodeAsc & 0xFF)) != 0)
+ {
+ pWork->offs2C34[acc] = 0xFF;
+
+ if(*pChCodeAsc & 0x3F)
+ {
+ bits_asc -= 4;
+ *pChBitsAsc = bits_asc;
+
+ add = (1 << bits_asc);
+ acc = *pChCodeAsc >> 4;
+ do
+ {
+ pWork->offs2D34[acc] = (unsigned char)count;
+ acc += add;
+ }
+ while(acc < 0x100);
+ }
+ else
+ {
+ bits_asc -= 6;
+ *pChBitsAsc = bits_asc;
+
+ add = (1 << bits_asc);
+ acc = *pChCodeAsc >> 6;
+ do
+ {
+ pWork->offs2E34[acc] = (unsigned char)count;
+ acc += add;
+ }
+ while(acc < 0x80);
+ }
+ }
+ else
+ {
+ bits_asc -= 8;
+ *pChBitsAsc = bits_asc;
+
+ add = (1 << bits_asc);
+ acc = *pChCodeAsc >> 8;
+ do
+ {
+ pWork->offs2EB4[acc] = (unsigned char)count;
+ acc += add;
+ }
+ while(acc < 0x100);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Removes given number of bits in the bit buffer. New bits are reloaded from
+// the input buffer, if needed.
+// Returns: PKDCL_OK: Operation was successful
+// PKDCL_STREAM_END: There are no more bits in the input buffer
+
+static int WasteBits(TDcmpStruct * pWork, unsigned int nBits)
+{
+ // If number of bits required is less than number of (bits in the buffer) ?
+ if(nBits <= pWork->extra_bits)
+ {
+ pWork->extra_bits -= nBits;
+ pWork->bit_buff >>= nBits;
+ return PKDCL_OK;
+ }
+
+ // Load input buffer if necessary
+ pWork->bit_buff >>= pWork->extra_bits;
+ if(pWork->in_pos == pWork->in_bytes)
+ {
+ pWork->in_pos = sizeof(pWork->in_buff);
+ if((pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param)) == 0)
+ return PKDCL_STREAM_END;
+ pWork->in_pos = 0;
+ }
+
+ // Update bit buffer
+ pWork->bit_buff |= (pWork->in_buff[pWork->in_pos++] << 8);
+ pWork->bit_buff >>= (nBits - pWork->extra_bits);
+ pWork->extra_bits = (pWork->extra_bits - nBits) + 8;
+ return PKDCL_OK;
+}
+
+//-----------------------------------------------------------------------------
+// Decodes next literal from the input (compressed) data.
+// Returns : 0x000: One byte 0x00
+// 0x001: One byte 0x01
+// ...
+// 0x0FF: One byte 0xFF
+// 0x100: Repetition, length of 0x02 bytes
+// 0x101: Repetition, length of 0x03 bytes
+// ...
+// 0x304: Repetition, length of 0x206 bytes
+// 0x305: End of stream
+// 0x306: Error
+
+static unsigned int DecodeLit(TDcmpStruct * pWork)
+{
+ unsigned int extra_length_bits; // Number of bits of extra literal length
+ unsigned int length_code; // Length code
+ unsigned int value;
+
+ // Test the current bit in byte buffer. If is not set, simply return the next 8 bits.
+ if(pWork->bit_buff & 1)
+ {
+ // Remove one bit from the input data
+ if(WasteBits(pWork, 1))
+ return 0x306;
+
+ // The next 8 bits hold the index to the length code table
+ length_code = pWork->LengthCodes[pWork->bit_buff & 0xFF];
+
+ // Remove the apropriate number of bits
+ if(WasteBits(pWork, pWork->LenBits[length_code]))
+ return 0x306;
+
+ // Are there some extra bits for the obtained length code ?
+ if((extra_length_bits = pWork->ExLenBits[length_code]) != 0)
+ {
+ unsigned int extra_length = pWork->bit_buff & ((1 << extra_length_bits) - 1);
+
+ if(WasteBits(pWork, extra_length_bits))
+ {
+ if((length_code + extra_length) != 0x10E)
+ return 0x306;
+ }
+ length_code = pWork->LenBase[length_code] + extra_length;
+ }
+
+ // In order to distinguish uncompressed byte from repetition length,
+ // we have to add 0x100 to the length.
+ return length_code + 0x100;
+ }
+
+ // Remove one bit from the input data
+ if(WasteBits(pWork, 1))
+ return 0x306;
+
+ // If the binary compression type, read 8 bits and return them as one byte.
+ if(pWork->ctype == CMP_BINARY)
+ {
+ unsigned int uncompressed_byte = pWork->bit_buff & 0xFF;
+
+ if(WasteBits(pWork, 8))
+ return 0x306;
+ return uncompressed_byte;
+ }
+
+ // When ASCII compression ...
+ if(pWork->bit_buff & 0xFF)
+ {
+ value = pWork->offs2C34[pWork->bit_buff & 0xFF];
+
+ if(value == 0xFF)
+ {
+ if(pWork->bit_buff & 0x3F)
+ {
+ if(WasteBits(pWork, 4))
+ return 0x306;
+
+ value = pWork->offs2D34[pWork->bit_buff & 0xFF];
+ }
+ else
+ {
+ if(WasteBits(pWork, 6))
+ return 0x306;
+
+ value = pWork->offs2E34[pWork->bit_buff & 0x7F];
+ }
+ }
+ }
+ else
+ {
+ if(WasteBits(pWork, 8))
+ return 0x306;
+
+ value = pWork->offs2EB4[pWork->bit_buff & 0xFF];
+ }
+
+ return WasteBits(pWork, pWork->ChBitsAsc[value]) ? 0x306 : value;
+}
+
+//-----------------------------------------------------------------------------
+// Decodes the distance of the repetition, backwards relative to the
+// current output buffer position
+
+static unsigned int DecodeDist(TDcmpStruct * pWork, unsigned int rep_length)
+{
+ unsigned int dist_pos_code; // Distance position code
+ unsigned int dist_pos_bits; // Number of bits of distance position
+ unsigned int distance; // Distance position
+
+ // Next 2-8 bits in the input buffer is the distance position code
+ dist_pos_code = pWork->DistPosCodes[pWork->bit_buff & 0xFF];
+ dist_pos_bits = pWork->DistBits[dist_pos_code];
+ if(WasteBits(pWork, dist_pos_bits))
+ return 0;
+
+ if(rep_length == 2)
+ {
+ // If the repetition is only 2 bytes length,
+ // then take 2 bits from the stream in order to get the distance
+ distance = (dist_pos_code << 2) | (pWork->bit_buff & 0x03);
+ if(WasteBits(pWork, 2))
+ return 0;
+ }
+ else
+ {
+ // If the repetition is more than 2 bytes length,
+ // then take "dsize_bits" bits in order to get the distance
+ distance = (dist_pos_code << pWork->dsize_bits) | (pWork->bit_buff & pWork->dsize_mask);
+ if(WasteBits(pWork, pWork->dsize_bits))
+ return 0;
+ }
+ return distance + 1;
+}
+
+static unsigned int Expand(TDcmpStruct * pWork)
+{
+ unsigned int next_literal; // Literal decoded from the compressed data
+ unsigned int result; // Value to be returned
+ unsigned int copyBytes; // Number of bytes to copy to the output buffer
+
+ pWork->outputPos = 0x1000; // Initialize output buffer position
+
+ // Decode the next literal from the input data.
+ // The returned literal can either be an uncompressed byte (next_literal < 0x100)
+ // or an encoded length of the repeating byte sequence that
+ // is to be copied to the current buffer position
+ while((result = next_literal = DecodeLit(pWork)) < 0x305)
+ {
+ // If the literal is greater than 0x100, it holds length
+ // of repeating byte sequence
+ // literal of 0x100 means repeating sequence of 0x2 bytes
+ // literal of 0x101 means repeating sequence of 0x3 bytes
+ // ...
+ // literal of 0x305 means repeating sequence of 0x207 bytes
+ if(next_literal >= 0x100)
+ {
+ unsigned char * source;
+ unsigned char * target;
+ unsigned int rep_length; // Length of the repetition, in bytes
+ unsigned int minus_dist; // Backward distance to the repetition, relative to the current buffer position
+
+ // Get the length of the repeating sequence.
+ // Note that the repeating block may overlap the current output position,
+ // for example if there was a sequence of equal bytes
+ rep_length = next_literal - 0xFE;
+
+ // Get backward distance to the repetition
+ if((minus_dist = DecodeDist(pWork, rep_length)) == 0)
+ {
+ result = 0x306;
+ break;
+ }
+
+ // Target and source pointer
+ target = &pWork->out_buff[pWork->outputPos];
+ source = target - minus_dist;
+
+ // Update buffer output position
+ pWork->outputPos += rep_length;
+
+ // Copy the repeating sequence
+ while(rep_length-- > 0)
+ *target++ = *source++;
+ }
+ else
+ {
+ pWork->out_buff[pWork->outputPos++] = (unsigned char)next_literal;
+ }
+
+ // Flush the output buffer, if number of extracted bytes has reached the end
+ if(pWork->outputPos >= 0x2000)
+ {
+ // Copy decompressed data into user buffer
+ copyBytes = 0x1000;
+ pWork->write_buf((char *)&pWork->out_buff[0x1000], &copyBytes, pWork->param);
+
+ // Now copy the decompressed data to the first half of the buffer.
+ // This is needed because the decompression might reuse them as repetitions.
+ // Note that if the output buffer overflowed previously, the extra decompressed bytes
+ // are stored in "out_buff_overflow", and they will now be
+ // within decompressed part of the output buffer.
+ memcpy(pWork->out_buff, &pWork->out_buff[0x1000], pWork->outputPos - 0x1000);
+ pWork->outputPos -= 0x1000;
+ }
+ }
+
+ // Flush any remaining decompressed bytes
+ copyBytes = pWork->outputPos - 0x1000;
+ pWork->write_buf((char *)&pWork->out_buff[0x1000], &copyBytes, pWork->param);
+ return result;
+}
+
+
+//-----------------------------------------------------------------------------
+// Main exploding function.
+
+unsigned int explode(
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
+ void (*write_buf)(char *buf, unsigned int *size, void *param),
+ char *work_buf,
+ void *param)
+{
+ TDcmpStruct * pWork = (TDcmpStruct *)work_buf;
+
+ // Initialize work struct and load compressed data
+ // Note: The caller must zero the "work_buff" before passing it to explode
+ pWork->read_buf = read_buf;
+ pWork->write_buf = write_buf;
+ pWork->param = param;
+ pWork->in_pos = sizeof(pWork->in_buff);
+ pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param);
+ if(pWork->in_bytes <= 4)
+ return CMP_BAD_DATA;
+
+ pWork->ctype = pWork->in_buff[0]; // Get the compression type (CMP_BINARY or CMP_ASCII)
+ pWork->dsize_bits = pWork->in_buff[1]; // Get the dictionary size
+ pWork->bit_buff = pWork->in_buff[2]; // Initialize 16-bit bit buffer
+ pWork->extra_bits = 0; // Extra (over 8) bits
+ pWork->in_pos = 3; // Position in input buffer
+
+ // Test for the valid dictionary size
+ if(4 > pWork->dsize_bits || pWork->dsize_bits > 6)
+ return CMP_INVALID_DICTSIZE;
+
+ pWork->dsize_mask = 0xFFFF >> (0x10 - pWork->dsize_bits); // Shifted by 'sar' instruction
+
+ if(pWork->ctype != CMP_BINARY)
+ {
+ if(pWork->ctype != CMP_ASCII)
+ return CMP_INVALID_MODE;
+
+ memcpy(pWork->ChBitsAsc, ChBitsAsc, sizeof(pWork->ChBitsAsc));
+ GenAscTabs(pWork);
+ }
+
+ memcpy(pWork->LenBits, LenBits, sizeof(pWork->LenBits));
+ GenDecodeTabs(pWork->LengthCodes, LenCode, pWork->LenBits, sizeof(pWork->LenBits));
+ memcpy(pWork->ExLenBits, ExLenBits, sizeof(pWork->ExLenBits));
+ memcpy(pWork->LenBase, LenBase, sizeof(pWork->LenBase));
+ memcpy(pWork->DistBits, DistBits, sizeof(pWork->DistBits));
+ GenDecodeTabs(pWork->DistPosCodes, DistCode, pWork->DistBits, sizeof(pWork->DistBits));
+ if(Expand(pWork) != 0x306)
+ return CMP_NO_ERROR;
+
+ return CMP_ABORT;
+}
diff --git a/src/pklib/implode.c b/src/pklib/implode.c
new file mode 100644
index 0000000..1771b18
--- /dev/null
+++ b/src/pklib/implode.c
@@ -0,0 +1,769 @@
+/*****************************************************************************/
+/* implode.c Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Implode function of PKWARE Data Compression library */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 11.04.03 1.00 Lad First version of implode.c */
+/* 02.05.03 1.00 Lad Stress test done */
+/* 22.04.10 1.01 Lad Documented */
+/*****************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "pklib.h"
+
+#if ((1200 < _MSC_VER) && (_MSC_VER < 1400))
+#pragma optimize("", off) // Fucking Microsoft VS.NET 2003 compiler !!! (_MSC_VER=1310)
+#endif
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define MAX_REP_LENGTH 0x204 // The longest allowed repetition
+
+//-----------------------------------------------------------------------------
+// Tables
+
+static unsigned char DistBits[] =
+{
+ 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
+};
+
+static unsigned char DistCode[] =
+{
+ 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
+ 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
+ 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
+ 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
+};
+
+static unsigned char ExLenBits[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
+};
+
+static unsigned char LenBits[] =
+{
+ 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
+};
+
+static unsigned char LenCode[] =
+{
+ 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
+};
+
+static unsigned char ChBitsAsc[] =
+{
+ 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
+ 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
+ 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
+ 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
+ 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
+ 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
+ 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
+};
+
+static unsigned short ChCodeAsc[] =
+{
+ 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
+ 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
+ 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
+ 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
+ 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
+ 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
+ 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
+ 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
+ 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
+ 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
+ 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
+ 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
+ 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
+ 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
+ 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
+ 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
+ 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
+ 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
+ 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
+ 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
+ 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
+ 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
+ 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
+ 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
+ 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
+ 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
+ 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
+ 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
+ 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
+ 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
+ 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
+ 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
+};
+
+//-----------------------------------------------------------------------------
+// Macros
+
+// Macro for calculating hash of the current byte pair.
+// Note that most exact byte pair hash would be buffer[0] + buffer[1] << 0x08,
+// but even this way gives nice indication of equal byte pairs, with significantly
+// smaller size of the array that holds numbers of those hashes
+#define BYTE_PAIR_HASH(buffer) ((buffer[0] * 4) + (buffer[1] * 5))
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+// Builds the "hash_to_index" table and "pair_hash_offsets" table.
+// Every element of "hash_to_index" will contain lowest index to the
+// "pair_hash_offsets" table, effectively giving offset of the first
+// occurence of the given PAIR_HASH in the input data.
+static void SortBuffer(TCmpStruct * pWork, unsigned char * buffer_begin, unsigned char * buffer_end)
+{
+ unsigned short * phash_to_index;
+ unsigned char * buffer_ptr;
+ unsigned short total_sum = 0;
+ unsigned long byte_pair_hash; // Hash value of the byte pair
+ unsigned short byte_pair_offs; // Offset of the byte pair, relative to "work_buff"
+
+ // Zero the entire "phash_to_index" table
+ memset(pWork->phash_to_index, 0, sizeof(pWork->phash_to_index));
+
+ // Step 1: Count amount of each PAIR_HASH in the input buffer
+ // The table will look like this:
+ // offs 0x000: Number of occurences of PAIR_HASH 0
+ // offs 0x001: Number of occurences of PAIR_HASH 1
+ // ...
+ // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 (the highest hash value)
+ for(buffer_ptr = buffer_begin; buffer_ptr < buffer_end; buffer_ptr++)
+ pWork->phash_to_index[BYTE_PAIR_HASH(buffer_ptr)]++;
+
+ // Step 2: Convert the table to the array of PAIR_HASH amounts.
+ // Each element contains count of PAIR_HASHes that is less or equal
+ // to element index
+ // The table will look like this:
+ // offs 0x000: Number of occurences of PAIR_HASH 0 or lower
+ // offs 0x001: Number of occurences of PAIR_HASH 1 or lower
+ // ...
+ // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 or lower
+ for(phash_to_index = pWork->phash_to_index; phash_to_index < &pWork->phash_to_index_end; phash_to_index++)
+ {
+ total_sum = total_sum + phash_to_index[0];
+ phash_to_index[0] = total_sum;
+ }
+
+ // Step 3: Convert the table to the array of indexes.
+ // Now, each element contains index to the first occurence of given PAIR_HASH
+ for(buffer_end--; buffer_end >= buffer_begin; buffer_end--)
+ {
+ byte_pair_hash = BYTE_PAIR_HASH(buffer_end);
+ byte_pair_offs = (unsigned short)(buffer_end - pWork->work_buff);
+
+ pWork->phash_to_index[byte_pair_hash]--;
+ pWork->phash_offs[pWork->phash_to_index[byte_pair_hash]] = byte_pair_offs;
+ }
+}
+
+static void FlushBuf(TCmpStruct * pWork)
+{
+ unsigned char save_ch1;
+ unsigned char save_ch2;
+ unsigned int size = 0x800;
+
+ pWork->write_buf(pWork->out_buff, &size, pWork->param);
+
+ save_ch1 = pWork->out_buff[0x800];
+ save_ch2 = pWork->out_buff[pWork->out_bytes];
+ pWork->out_bytes -= 0x800;
+
+ memset(pWork->out_buff, 0, sizeof(pWork->out_buff));
+
+ if(pWork->out_bytes != 0)
+ pWork->out_buff[0] = save_ch1;
+ if(pWork->out_bits != 0)
+ pWork->out_buff[pWork->out_bytes] = save_ch2;
+}
+
+static void OutputBits(TCmpStruct * pWork, unsigned int nbits, unsigned long bit_buff)
+{
+ unsigned int out_bits;
+
+ // If more than 8 bits to output, do recursion
+ if(nbits > 8)
+ {
+ OutputBits(pWork, 8, bit_buff);
+ bit_buff >>= 8;
+ nbits -= 8;
+ }
+
+ // Add bits to the last out byte in out_buff;
+ out_bits = pWork->out_bits;
+ pWork->out_buff[pWork->out_bytes] |= (unsigned char)(bit_buff << out_bits);
+ pWork->out_bits += nbits;
+
+ // If 8 or more bits, increment number of bytes
+ if(pWork->out_bits > 8)
+ {
+ pWork->out_bytes++;
+ bit_buff >>= (8 - out_bits);
+
+ pWork->out_buff[pWork->out_bytes] = (unsigned char)bit_buff;
+ pWork->out_bits &= 7;
+ }
+ else
+ {
+ pWork->out_bits &= 7;
+ if(pWork->out_bits == 0)
+ pWork->out_bytes++;
+ }
+
+ // If there is enough compressed bytes, flush them
+ if(pWork->out_bytes >= 0x800)
+ FlushBuf(pWork);
+}
+
+// This function searches for a repetition
+// (a previous occurence of the current byte sequence)
+// Returns length of the repetition, and stores the backward distance
+// to pWork structure.
+static unsigned int FindRep(TCmpStruct * pWork, unsigned char * input_data)
+{
+ unsigned short * phash_to_index; // Pointer into pWork->phash_to_index table
+ unsigned short * phash_offs; // Pointer to the table containing offsets of each PAIR_HASH
+ unsigned char * repetition_limit; // An eventual repetition must be at position below this pointer
+ unsigned char * prev_repetition; // Pointer to the previous occurence of the current PAIR_HASH
+ unsigned char * prev_rep_end; // End of the previous repetition
+ unsigned char * input_data_ptr;
+ unsigned short phash_offs_index; // Index to the table with PAIR_HASH positions
+ unsigned short min_phash_offs; // The lowest allowed hash offset
+ unsigned short offs_in_rep; // Offset within found repetition
+ unsigned int equal_byte_count; // Number of bytes that are equal to the previous occurence
+ unsigned int rep_length = 1; // Length of the found repetition
+ unsigned int rep_length2; // Secondary repetition
+ unsigned char pre_last_byte; // Last but one byte from a repetion
+ unsigned short di_val;
+
+ // Calculate the previous position of the PAIR_HASH
+ phash_to_index = pWork->phash_to_index + BYTE_PAIR_HASH(input_data);
+ min_phash_offs = (unsigned short)((input_data - pWork->work_buff) - pWork->dsize_bytes + 1);
+ phash_offs_index = phash_to_index[0];
+
+ // If the PAIR_HASH offset is below the limit, find a next one
+ phash_offs = pWork->phash_offs + phash_offs_index;
+ if(*phash_offs < min_phash_offs)
+ {
+ while(*phash_offs < min_phash_offs)
+ {
+ phash_offs_index++;
+ phash_offs++;
+ }
+ *phash_to_index = phash_offs_index;
+ }
+
+ // Get the first location of the PAIR_HASH,
+ // and thus the first eventual location of byte repetition
+ phash_offs = pWork->phash_offs + phash_offs_index;
+ prev_repetition = pWork->work_buff + phash_offs[0];
+ repetition_limit = input_data - 1;
+
+ // If the current PAIR_HASH was not encountered before,
+ // we haven't found a repetition.
+ if(prev_repetition >= repetition_limit)
+ return 0;
+
+ // We have found a match of a PAIR_HASH. Now we have to make sure
+ // that it is also a byte match, because PAIR_HASH is not unique.
+ // We compare the bytes and count the length of the repetition
+ input_data_ptr = input_data;
+ for(;;)
+ {
+ // If the first byte of the repetition and the so-far-last byte
+ // of the repetition are equal, we will compare the blocks.
+ if(*input_data_ptr == *prev_repetition && input_data_ptr[rep_length-1] == prev_repetition[rep_length-1])
+ {
+ // Skip the current byte
+ prev_repetition++;
+ input_data_ptr++;
+ equal_byte_count = 2;
+
+ // Now count how many more bytes are equal
+ while(equal_byte_count < MAX_REP_LENGTH)
+ {
+ prev_repetition++;
+ input_data_ptr++;
+
+ // Are the bytes different ?
+ if(*prev_repetition != *input_data_ptr)
+ break;
+
+ equal_byte_count++;
+ }
+
+ // If we found a repetition of at least the same length, take it.
+ // If there are multiple repetitions in the input buffer, this will
+ // make sure that we find the most recent one, which in turn allows
+ // us to store backward length in less amount of bits
+ input_data_ptr = input_data;
+ if(equal_byte_count >= rep_length)
+ {
+ // Calculate the backward distance of the repetition.
+ // Note that the distance is stored as decremented by 1
+ pWork->distance = (unsigned int)(input_data - prev_repetition + equal_byte_count - 1);
+
+ // Repetitions longer than 10 bytes will be stored in more bits,
+ // so they need a bit different handling
+ if((rep_length = equal_byte_count) > 10)
+ break;
+ }
+ }
+
+ // Move forward in the table of PAIR_HASH repetitions.
+ // There might be a more recent occurence of the same repetition.
+ phash_offs_index++;
+ phash_offs++;
+ prev_repetition = pWork->work_buff + phash_offs[0];
+
+ // If the next repetition is beyond the minimum allowed repetition, we are done.
+ if(prev_repetition >= repetition_limit)
+ {
+ // A repetition must have at least 2 bytes, otherwise it's not worth it
+ return (rep_length >= 2) ? rep_length : 0;
+ }
+ }
+
+ // If the repetition has max length of 0x204 bytes, we can't go any fuhrter
+ if(equal_byte_count == MAX_REP_LENGTH)
+ {
+ pWork->distance--;
+ return equal_byte_count;
+ }
+
+ // Check for possibility of a repetition that occurs at more recent position
+ phash_offs = pWork->phash_offs + phash_offs_index;
+ if(pWork->work_buff + phash_offs[1] >= repetition_limit)
+ return rep_length;
+
+ //
+ // The following part checks if there isn't a longer repetition at
+ // a latter offset, that would lead to better compression.
+ //
+ // Example of data that can trigger this optimization:
+ //
+ // "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEQQQQQQQQQQQQ"
+ // "XYZ"
+ // "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ";
+ //
+ // Description of data in this buffer
+ // [0x00] Single byte "E"
+ // [0x01] Single byte "E"
+ // [0x02] Repeat 0x1E bytes from [0x00]
+ // [0x20] Single byte "X"
+ // [0x21] Single byte "Y"
+ // [0x22] Single byte "Z"
+ // [0x23] 17 possible previous repetitions of length at least 0x10 bytes:
+ // - Repetition of 0x10 bytes from [0x00] "EEEEEEEEEEEEEEEE"
+ // - Repetition of 0x10 bytes from [0x01] "EEEEEEEEEEEEEEEE"
+ // - Repetition of 0x10 bytes from [0x02] "EEEEEEEEEEEEEEEE"
+ // ...
+ // - Repetition of 0x10 bytes from [0x0F] "EEEEEEEEEEEEEEEE"
+ // - Repetition of 0x1C bytes from [0x10] "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ"
+ // The last repetition is the best one.
+ //
+
+ pWork->offs09BC[0] = 0xFFFF;
+ pWork->offs09BC[1] = 0x0000;
+ di_val = 0;
+
+ // Note: I failed to figure out what does the table "offs09BC" mean.
+ // If anyone has an idea, let me know to zezula_at_volny_dot_cz
+ for(offs_in_rep = 1; offs_in_rep < rep_length; )
+ {
+ if(input_data[offs_in_rep] != input_data[di_val])
+ {
+ di_val = pWork->offs09BC[di_val];
+ if(di_val != 0xFFFF)
+ continue;
+ }
+ pWork->offs09BC[++offs_in_rep] = ++di_val;
+ }
+
+ //
+ // Now go through all the repetitions from the first found one
+ // to the current input data, and check if any of them migh be
+ // a start of a greater sequence match.
+ //
+
+ prev_repetition = pWork->work_buff + phash_offs[0];
+ prev_rep_end = prev_repetition + rep_length;
+ rep_length2 = rep_length;
+
+ for(;;)
+ {
+ rep_length2 = pWork->offs09BC[rep_length2];
+ if(rep_length2 == 0xFFFF)
+ rep_length2 = 0;
+
+ // Get the pointer to the previous repetition
+ phash_offs = pWork->phash_offs + phash_offs_index;
+
+ // Skip those repetitions that don't reach the end
+ // of the first found repetition
+ do
+ {
+ phash_offs++;
+ phash_offs_index++;
+ prev_repetition = pWork->work_buff + *phash_offs;
+ if(prev_repetition >= repetition_limit)
+ return rep_length;
+ }
+ while(prev_repetition + rep_length2 < prev_rep_end);
+
+ // Verify if the last but one byte from the repetition matches
+ // the last but one byte from the input data.
+ // If not, find a next repetition
+ pre_last_byte = input_data[rep_length - 2];
+ if(pre_last_byte == prev_repetition[rep_length - 2])
+ {
+ // If the new repetition reaches beyond the end
+ // of previously found repetition, reset the repetition length to zero.
+ if(prev_repetition + rep_length2 != prev_rep_end)
+ {
+ prev_rep_end = prev_repetition;
+ rep_length2 = 0;
+ }
+ }
+ else
+ {
+ phash_offs = pWork->phash_offs + phash_offs_index;
+ do
+ {
+ phash_offs++;
+ phash_offs_index++;
+ prev_repetition = pWork->work_buff + *phash_offs;
+ if(prev_repetition >= repetition_limit)
+ return rep_length;
+ }
+ while(prev_repetition[rep_length - 2] != pre_last_byte || prev_repetition[0] != input_data[0]);
+
+ // Reset the length of the repetition to 2 bytes only
+ prev_rep_end = prev_repetition + 2;
+ rep_length2 = 2;
+ }
+
+ // Find out how many more characters are equal to the first repetition.
+ while(*prev_rep_end == input_data[rep_length2])
+ {
+ if(++rep_length2 >= 0x204)
+ break;
+ prev_rep_end++;
+ }
+
+ // Is the newly found repetion at least as long as the previous one ?
+ if(rep_length2 >= rep_length)
+ {
+ // Calculate the distance of the new repetition
+ pWork->distance = (unsigned int)(input_data - prev_repetition - 1);
+ if((rep_length = rep_length2) == 0x204)
+ return rep_length;
+
+ // Update the additional elements in the "offs09BC" table
+ // to reflect new rep length
+ while(offs_in_rep < rep_length2)
+ {
+ if(input_data[offs_in_rep] != input_data[di_val])
+ {
+ di_val = pWork->offs09BC[di_val];
+ if(di_val != 0xFFFF)
+ continue;
+ }
+ pWork->offs09BC[++offs_in_rep] = ++di_val;
+ }
+ }
+ }
+}
+
+static void WriteCmpData(TCmpStruct * pWork)
+{
+ unsigned char * input_data_end; // Pointer to the end of the input data
+ unsigned char * input_data = pWork->work_buff + pWork->dsize_bytes + 0x204;
+ unsigned int input_data_ended = 0; // If 1, then all data from the input stream have been already loaded
+ unsigned int save_rep_length; // Saved length of current repetition
+ unsigned int save_distance = 0; // Saved distance of current repetition
+ unsigned int rep_length; // Length of the found repetition
+ unsigned int phase = 0; //
+
+ // Store the compression type and dictionary size
+ pWork->out_buff[0] = (char)pWork->ctype;
+ pWork->out_buff[1] = (char)pWork->dsize_bits;
+ pWork->out_bytes = 2;
+
+ // Reset output buffer to zero
+ memset(&pWork->out_buff[2], 0, sizeof(pWork->out_buff) - 2);
+ pWork->out_bits = 0;
+
+ while(input_data_ended == 0)
+ {
+ unsigned int bytes_to_load = 0x1000;
+ int total_loaded = 0;
+ int bytes_loaded;
+
+ // Load the bytes from the input stream, up to 0x1000 bytes
+ while(bytes_to_load != 0)
+ {
+ bytes_loaded = pWork->read_buf((char *)pWork->work_buff + pWork->dsize_bytes + 0x204 + total_loaded,
+ &bytes_to_load,
+ pWork->param);
+ if(bytes_loaded == 0)
+ {
+ if(total_loaded == 0 && phase == 0)
+ goto __Exit;
+ input_data_ended = 1;
+ break;
+ }
+ else
+ {
+ bytes_to_load -= bytes_loaded;
+ total_loaded += bytes_loaded;
+ }
+ }
+
+ input_data_end = pWork->work_buff + pWork->dsize_bytes + total_loaded;
+ if(input_data_ended)
+ input_data_end += 0x204;
+
+ //
+ // Warning: The end of the buffer passed to "SortBuffer" is actually 2 bytes beyond
+ // valid data. It is questionable if this is actually a bug or not,
+ // but it might cause the compressed data output to be dependent on random bytes
+ // that are in the buffer.
+ // To prevent that, the calling application must always zero the compression
+ // buffer before passing it to "implode"
+ //
+
+ // Search the PAIR_HASHes of the loaded blocks. Also, include
+ // previously compressed data, if any.
+ switch(phase)
+ {
+ case 0:
+ SortBuffer(pWork, input_data, input_data_end + 1);
+ phase++;
+ if(pWork->dsize_bytes != 0x1000)
+ phase++;
+ break;
+
+ case 1:
+ SortBuffer(pWork, input_data - pWork->dsize_bytes + 0x204, input_data_end + 1);
+ phase++;
+ break;
+
+ default:
+ SortBuffer(pWork, input_data - pWork->dsize_bytes, input_data_end + 1);
+ break;
+ }
+
+ // Perform the compression of the current block
+ while(input_data < input_data_end)
+ {
+ // Find if the current byte sequence wasn't there before.
+ rep_length = FindRep(pWork, input_data);
+ while(rep_length != 0)
+ {
+ // If we found repetition of 2 bytes, that is 0x100 or fuhrter back,
+ // don't bother. Storing the distance of 0x100 bytes would actually
+ // take more space than storing the 2 bytes as-is.
+ if(rep_length == 2 && pWork->distance >= 0x100)
+ break;
+
+ // When we are at the end of the input data, we cannot allow
+ // the repetition to go past the end of the input data.
+ if(input_data_ended && input_data + rep_length > input_data_end)
+ {
+ // Shorten the repetition length so that it only covers valid data
+ rep_length = (unsigned long)(input_data_end - input_data);
+ if(rep_length < 2)
+ break;
+
+ // If we got repetition of 2 bytes, that is 0x100 or more backward, don't bother
+ if(rep_length == 2 && pWork->distance >= 0x100)
+ break;
+ goto __FlushRepetition;
+ }
+
+ if(rep_length >= 8 || input_data + 1 >= input_data_end)
+ goto __FlushRepetition;
+
+ // Try to find better repetition 1 byte later.
+ // Example: "ARROCKFORT" "AROCKFORT"
+ // When "input_data" points to the second string, FindRep
+ // returns the occurence of "AR". But there is longer repetition "ROCKFORT",
+ // beginning 1 byte after.
+ save_rep_length = rep_length;
+ save_distance = pWork->distance;
+ rep_length = FindRep(pWork, input_data + 1);
+
+ // Only use the new repetition if it's length is greater than the previous one
+ if(rep_length > save_rep_length)
+ {
+ // If the new repetition if only 1 byte better
+ // and the previous distance is less than 0x80 bytes, use the previous repetition
+ if(rep_length > save_rep_length + 1 || save_distance > 0x80)
+ {
+ // Flush one byte, so that input_data will point to the secondary repetition
+ OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]);
+ input_data++;
+ continue;
+ }
+ }
+
+ // Revert to the previous repetition
+ rep_length = save_rep_length;
+ pWork->distance = save_distance;
+
+ __FlushRepetition:
+
+ OutputBits(pWork, pWork->nChBits[rep_length + 0xFE], pWork->nChCodes[rep_length + 0xFE]);
+ if(rep_length == 2)
+ {
+ OutputBits(pWork, pWork->dist_bits[pWork->distance >> 2],
+ pWork->dist_codes[pWork->distance >> 2]);
+ OutputBits(pWork, 2, pWork->distance & 3);
+ }
+ else
+ {
+ OutputBits(pWork, pWork->dist_bits[pWork->distance >> pWork->dsize_bits],
+ pWork->dist_codes[pWork->distance >> pWork->dsize_bits]);
+ OutputBits(pWork, pWork->dsize_bits, pWork->dsize_mask & pWork->distance);
+ }
+
+ // Move the begin of the input data by the length of the repetition
+ input_data += rep_length;
+ goto _00402252;
+ }
+
+ // If there was no previous repetition for the current position in the input data,
+ // just output the 9-bit literal for the one character
+ OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]);
+ input_data++;
+_00402252:;
+ }
+
+ if(input_data_ended == 0)
+ {
+ input_data -= 0x1000;
+ memcpy(pWork->work_buff, pWork->work_buff + 0x1000, pWork->dsize_bytes + 0x204);
+ }
+ }
+
+__Exit:
+
+ // Write the termination literal
+ OutputBits(pWork, pWork->nChBits[0x305], pWork->nChCodes[0x305]);
+ if(pWork->out_bits != 0)
+ pWork->out_bytes++;
+ pWork->write_buf(pWork->out_buff, &pWork->out_bytes, pWork->param);
+ return;
+}
+
+//-----------------------------------------------------------------------------
+// Main imploding function
+
+unsigned int PKEXPORT implode(
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
+ void (*write_buf)(char *buf, unsigned int *size, void *param),
+ char *work_buf,
+ void *param,
+ unsigned int *type,
+ unsigned int *dsize)
+{
+ TCmpStruct * pWork = (TCmpStruct *)work_buf;
+ unsigned int nChCode;
+ unsigned int nCount;
+ unsigned int i;
+ int nCount2;
+
+ // Fill the work buffer information
+ // Note: The caller must zero the "work_buff" before passing it to implode
+ pWork->read_buf = read_buf;
+ pWork->write_buf = write_buf;
+ pWork->dsize_bytes = *dsize;
+ pWork->ctype = *type;
+ pWork->param = param;
+ pWork->dsize_bits = 4;
+ pWork->dsize_mask = 0x0F;
+
+ // Test dictionary size
+ switch(*dsize)
+ {
+ case CMP_IMPLODE_DICT_SIZE3: // 0x1000 bytes
+ pWork->dsize_bits++;
+ pWork->dsize_mask |= 0x20;
+ // No break here !!!
+
+ case CMP_IMPLODE_DICT_SIZE2: // 0x800 bytes
+ pWork->dsize_bits++;
+ pWork->dsize_mask |= 0x10;
+ // No break here !!!
+
+ case CMP_IMPLODE_DICT_SIZE1: // 0x400
+ break;
+
+ default:
+ return CMP_INVALID_DICTSIZE;
+ }
+
+ // Test the compression type
+ switch(*type)
+ {
+ case CMP_BINARY: // We will compress data with binary compression type
+ for(nChCode = 0, nCount = 0; nCount < 0x100; nCount++)
+ {
+ pWork->nChBits[nCount] = 9;
+ pWork->nChCodes[nCount] = (unsigned short)nChCode;
+ nChCode = (nChCode & 0x0000FFFF) + 2;
+ }
+ break;
+
+
+ case CMP_ASCII: // We will compress data with ASCII compression type
+ for(nCount = 0; nCount < 0x100; nCount++)
+ {
+ pWork->nChBits[nCount] = (unsigned char )(ChBitsAsc[nCount] + 1);
+ pWork->nChCodes[nCount] = (unsigned short)(ChCodeAsc[nCount] * 2);
+ }
+ break;
+
+ default:
+ return CMP_INVALID_MODE;
+ }
+
+ for(i = 0; i < 0x10; i++)
+ {
+ if(1 << ExLenBits[i])
+ {
+ for(nCount2 = 0; nCount2 < (1 << ExLenBits[i]); nCount2++)
+ {
+ pWork->nChBits[nCount] = (unsigned char)(ExLenBits[i] + LenBits[i] + 1);
+ pWork->nChCodes[nCount] = (unsigned short)((nCount2 << (LenBits[i] + 1)) | ((LenCode[i] & 0xFFFF00FF) * 2) | 1);
+ nCount++;
+ }
+ }
+ }
+
+ // Copy the distance codes and distance bits and perform the compression
+ memcpy(&pWork->dist_codes, DistCode, sizeof(DistCode));
+ memcpy(&pWork->dist_bits, DistBits, sizeof(DistBits));
+ WriteCmpData(pWork);
+ return CMP_NO_ERROR;
+}
diff --git a/src/pklib/pklib.h b/src/pklib/pklib.h
new file mode 100644
index 0000000..f43da15
--- /dev/null
+++ b/src/pklib/pklib.h
@@ -0,0 +1,148 @@
+/*****************************************************************************/
+/* pklib.h Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Header file for PKWARE Data Compression Library */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 31.03.03 1.00 Lad The first version of pkware.h */
+/*****************************************************************************/
+
+#ifndef __PKLIB_H__
+#define __PKLIB_H__
+
+#include "../StormPort.h"
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define CMP_BINARY 0 // Binary compression
+#define CMP_ASCII 1 // Ascii compression
+
+#define CMP_NO_ERROR 0
+#define CMP_INVALID_DICTSIZE 1
+#define CMP_INVALID_MODE 2
+#define CMP_BAD_DATA 3
+#define CMP_ABORT 4
+
+#define CMP_IMPLODE_DICT_SIZE1 1024 // Dictionary size of 1024
+#define CMP_IMPLODE_DICT_SIZE2 2048 // Dictionary size of 2048
+#define CMP_IMPLODE_DICT_SIZE3 4096 // Dictionary size of 4096
+
+//-----------------------------------------------------------------------------
+// Define calling convention
+
+#ifndef PKEXPORT
+#ifdef WIN32
+#define PKEXPORT __cdecl // Use for normal __cdecl calling
+#else
+#define PKEXPORT
+#endif
+#endif
+
+//-----------------------------------------------------------------------------
+// Internal structures
+
+// Compression structure
+typedef struct
+{
+ unsigned int distance; // 0000: Backward distance of the currently found repetition, decreased by 1
+ unsigned int out_bytes; // 0004: # bytes available in out_buff
+ unsigned int out_bits; // 0008: # of bits available in the last out byte
+ unsigned int dsize_bits; // 000C: Number of bits needed for dictionary size. 4 = 0x400, 5 = 0x800, 6 = 0x1000
+ unsigned int dsize_mask; // 0010: Bit mask for dictionary. 0x0F = 0x400, 0x1F = 0x800, 0x3F = 0x1000
+ unsigned int ctype; // 0014: Compression type (CMP_ASCII or CMP_BINARY)
+ unsigned int dsize_bytes; // 0018: Dictionary size in bytes
+ unsigned char dist_bits[0x40]; // 001C: Distance bits
+ unsigned char dist_codes[0x40]; // 005C: Distance codes
+ unsigned char nChBits[0x306]; // 009C: Table of literal bit lengths to be put to the output stream
+ unsigned short nChCodes[0x306]; // 03A2: Table of literal codes to be put to the output stream
+ unsigned short offs09AE; // 09AE:
+
+ void * param; // 09B0: User parameter
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // 9B4
+ void (*write_buf)(char *buf, unsigned int *size, void *param); // 9B8
+
+ unsigned short offs09BC[0x204]; // 09BC:
+ unsigned long offs0DC4; // 0DC4:
+ unsigned short phash_to_index[0x900]; // 0DC8: Array of indexes (one for each PAIR_HASH) to the "pair_hash_offsets" table
+ unsigned short phash_to_index_end; // 1FC8: End marker for "phash_to_index" table
+ char out_buff[0x802]; // 1FCA: Compressed data
+ unsigned char work_buff[0x2204]; // 27CC: Work buffer
+ // + DICT_OFFSET => Dictionary
+ // + UNCMP_OFFSET => Uncompressed data
+ unsigned short phash_offs[0x2204]; // 49D0: Table of offsets for each PAIR_HASH
+} TCmpStruct;
+
+#define CMP_BUFFER_SIZE sizeof(TCmpStruct) // Size of compression structure.
+ // Defined as 36312 in pkware header file
+
+
+// Decompression structure
+typedef struct
+{
+ unsigned long offs0000; // 0000
+ unsigned long ctype; // 0004: Compression type (CMP_BINARY or CMP_ASCII)
+ unsigned long outputPos; // 0008: Position in output buffer
+ unsigned long dsize_bits; // 000C: Dict size (4, 5, 6 for 0x400, 0x800, 0x1000)
+ unsigned long dsize_mask; // 0010: Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000)
+ unsigned long bit_buff; // 0014: 16-bit buffer for processing input data
+ unsigned long extra_bits; // 0018: Number of extra (above 8) bits in bit buffer
+ unsigned int in_pos; // 001C: Position in in_buff
+ unsigned long in_bytes; // 0020: Number of bytes in input buffer
+ void * param; // 0024: Custom parameter
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // Pointer to function that reads data from the input stream
+ void (*write_buf)(char *buf, unsigned int *size, void *param);// Pointer to function that writes data to the output stream
+
+ unsigned char out_buff[0x2204]; // 0030: Output circle buffer.
+ // 0x0000 - 0x0FFF: Previous uncompressed data, kept for repetitions
+ // 0x1000 - 0x1FFF: Currently decompressed data
+ // 0x2000 - 0x2203: Reserve space for the longest possible repetition
+ unsigned char in_buff[0x800]; // 2234: Buffer for data to be decompressed
+ unsigned char DistPosCodes[0x100]; // 2A34: Table of distance position codes
+ unsigned char LengthCodes[0x100]; // 2B34: Table of length codes
+ unsigned char offs2C34[0x100]; // 2C34: Buffer for
+ unsigned char offs2D34[0x100]; // 2D34: Buffer for
+ unsigned char offs2E34[0x80]; // 2EB4: Buffer for
+ unsigned char offs2EB4[0x100]; // 2EB4: Buffer for
+ unsigned char ChBitsAsc[0x100]; // 2FB4: Buffer for
+ unsigned char DistBits[0x40]; // 30B4: Numbers of bytes to skip copied block length
+ unsigned char LenBits[0x10]; // 30F4: Numbers of bits for skip copied block length
+ unsigned char ExLenBits[0x10]; // 3104: Number of valid bits for copied block
+ unsigned short LenBase[0x10]; // 3114: Buffer for
+} TDcmpStruct;
+
+#define EXP_BUFFER_SIZE sizeof(TDcmpStruct) // Size of decompression structure
+ // Defined as 12596 in pkware headers
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+unsigned int PKEXPORT implode(
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
+ void (*write_buf)(char *buf, unsigned int *size, void *param),
+ char *work_buf,
+ void *param,
+ unsigned int *type,
+ unsigned int *dsize);
+
+
+unsigned int PKEXPORT explode(
+ unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
+ void (*write_buf)(char *buf, unsigned int *size, void *param),
+ char *work_buf,
+ void *param);
+
+// The original name "crc32" was changed to "crc32pk" due
+// to compatibility with zlib
+unsigned long PKEXPORT crc32_pklib(char *buffer, unsigned int *size, unsigned long *old_crc);
+
+#ifdef __cplusplus
+ } // End of 'extern "C"' declaration
+#endif
+
+#endif // __PKLIB_H__