Current News
Archived News
Search News
Discussion Forum


Old Forum
Install Programs More Downloads...
Troubleshooting
Source Code
Format Specs.
Misc. Information
Non-SF Stuff
Links




ShadowFlare [Fri, 4 Jul 2008 02:53:33 +0000 (20:53 -0600)]
19 files changed:
SComp.cpp [new file with mode: 0644]
SComp.h [new file with mode: 0644]
SErr.cpp [new file with mode: 0644]
SErr.h [new file with mode: 0644]
SMem.cpp [new file with mode: 0644]
SMem.h [new file with mode: 0644]
ZLib_Static_min.lib [new file with mode: 0644]
crc32.c [new file with mode: 0644]
explode.c [new file with mode: 0644]
huffman.cpp [new file with mode: 0644]
huffman.h [new file with mode: 0644]
implode.c [new file with mode: 0644]
license.txt [new file with mode: 0644]
pklib.h [new file with mode: 0644]
wave.cpp [new file with mode: 0644]
wave.h [new file with mode: 0644]
wintypes.h [new file with mode: 0644]
zconf.h [new file with mode: 0644]
zlib.h [new file with mode: 0644]

diff --git a/SComp.cpp b/SComp.cpp
new file mode 100644 (file)
index 0000000..34b5ddd
--- /dev/null
+++ b/SComp.cpp
@@ -0,0 +1,638 @@
+// SComp.cpp - Main compression/decompression and wrapper routines
+//
+// Requires Zlib for Warcraft III files (not included).
+// Get it at http://www.gzip.org/zlib/
+//
+// Converted from assembly to C++ by ShadowFlare.
+// E-mail  : blakflare@hotmail.com
+// Webpage : http://sfsrealm.hopto.org/
+// License information for this code is in license.txt
+
+
+// Define NO_WINDOWS_H globally if compiling for
+// Windows to disable calling Windows functions.
+
+// Comment this out to disable Zlib compression support.
+#define USE_ZLIB
+
+#include "SComp.h"
+#include "SErr.h"
+#include "SMem.h"
+#include "wave.h"
+#include "huffman.h"
+#ifdef USE_ZLIB
+#ifndef __SYS_ZLIB
+#include "zlib.h"
+#else
+#include <zlib.h>
+#endif
+#endif
+#include "pklib.h"
+
+typedef void (__fastcall *FCOMPRESS)(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel);
+typedef void (__fastcall *FDECOMPRESS)(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
+
+struct CompressFunc {
+       DWORD dwFlag;
+       FCOMPRESS fnCompress;
+};
+
+struct DecompressFunc {
+       DWORD dwFlag;
+       FDECOMPRESS fnDecompress;
+};
+
+void __fastcall CompressWaveMono(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel);
+void __fastcall CompressWaveStereo(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel);
+void __fastcall HuffmanCompress(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel);
+#ifdef USE_ZLIB
+void __fastcall Deflate(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel);
+#endif
+void __fastcall Implode(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel);
+
+void __fastcall DecompressWaveMono(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
+void __fastcall DecompressWaveStereo(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
+void __fastcall HuffmanDecompress(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
+#ifdef USE_ZLIB
+void __fastcall Inflate(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
+#endif
+void __fastcall Explode(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
+
+void __fastcall InitWaveCompress(DWORD dwCompressLevel, LPDWORD *lplpdwCompressionSubType, LPDWORD lpdwCompressionSubType);
+
+typedef struct {
+       LPVOID lpvDestinationMem;
+       DWORD dwDestStart;
+       DWORD dwDestLen;
+       LPVOID lpvSourceMem;
+       DWORD dwSrcStart;
+       DWORD dwSrcLen;
+} BUFFERINFO;
+
+unsigned int FillInput(char *lpvBuffer, unsigned int *lpdwSize, void *param);
+void FillOutput(char *lpvBuffer, unsigned int *lpdwSize, void *param);
+
+CompressFunc CompressionFunctions[] =
+{
+       {0x40, CompressWaveMono},
+       {0x80, CompressWaveStereo},
+       {0x01, HuffmanCompress},
+#ifdef USE_ZLIB
+       {0x02, Deflate},
+#endif
+       {0x08, Implode}
+};
+
+DecompressFunc DecompressionFunctions[] =
+{
+       {0x40, DecompressWaveMono},
+       {0x80, DecompressWaveStereo},
+       {0x01, HuffmanDecompress},
+#ifdef USE_ZLIB
+       {0x02, Inflate},
+#endif
+       {0x08, Explode}
+};
+
+const DWORD nCompFunctions = sizeof(CompressionFunctions) / sizeof(CompressionFunctions[0]);
+const DWORD nDecompFunctions = sizeof(DecompressionFunctions) / sizeof(DecompressionFunctions[0]);
+
+CompressFunc *lpLastCompressMethod = &CompressionFunctions[nCompFunctions-1];
+DecompressFunc *lpLastDecompressMethod = &DecompressionFunctions[nDecompFunctions-1];
+
+BOOL WINAPI SCompCompress(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, DWORD dwCompressionType, DWORD dwCompressionSubType, DWORD dwCompressLevel)
+{
+       DWORD dwCompressCount,dwCurFlag,dwTempFlags,dwInSize,dwOutSize;
+       LPVOID lpvInBuffer,lpvOutBuffer,lpvWorkBuffer,lpvAllocBuffer;
+       CompressFunc *lpCFuncTable;
+
+       if (!lpdwCompressedSize) {
+         SErrSetLastError(ERROR_INVALID_PARAMETER);
+         return FALSE;
+       }
+       if (*lpdwCompressedSize < dwDecompressedSize || !lpvDestinationMem || !lpvSourceMem) {
+         SErrSetLastError(ERROR_INVALID_PARAMETER);
+         return FALSE;
+       }
+
+       dwCompressCount = 0;
+       dwTempFlags = dwCompressionType;
+       lpCFuncTable = CompressionFunctions;
+
+       do {
+         dwCurFlag = lpCFuncTable->dwFlag;
+
+         if (dwCompressionType & dwCurFlag) {
+           dwCompressCount++;
+         }
+
+         lpCFuncTable++;
+         dwTempFlags &= ~dwCurFlag;
+       } while (lpCFuncTable <= lpLastCompressMethod);
+
+       if (dwTempFlags) {
+         return FALSE;
+       }
+
+       dwInSize = dwDecompressedSize;
+       lpvAllocBuffer = 0;
+
+       if (dwCompressCount >= 2
+         || !((LPBYTE)lpvDestinationMem+dwInSize <= (LPBYTE)lpvSourceMem
+           || (LPBYTE)lpvSourceMem+dwInSize <= (LPBYTE)lpvDestinationMem
+           || !dwCompressCount))
+       {
+         lpvWorkBuffer = SMemAlloc(dwInSize);
+
+         if (!lpvWorkBuffer) {
+           SErrSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+           return FALSE;
+         }
+
+         lpvAllocBuffer = lpvWorkBuffer;
+       }
+
+       lpvInBuffer = lpvSourceMem;
+       lpCFuncTable = CompressionFunctions;
+
+       do {
+         dwTempFlags = dwCompressionType;
+         dwCurFlag = lpCFuncTable->dwFlag;
+
+         if (dwTempFlags & dwCurFlag) {
+           dwCompressCount--;
+
+           if (dwCompressCount & 1) {
+             lpvOutBuffer = lpvWorkBuffer;
+           }
+           else {
+             lpvOutBuffer = (LPVOID)((LPBYTE)lpvDestinationMem+1);
+           }
+
+           if ((LPBYTE)lpvOutBuffer+dwInSize > (LPBYTE)lpvInBuffer
+            && (LPBYTE)lpvInBuffer+dwInSize > (LPBYTE)lpvOutBuffer)
+           {
+             if ((LPBYTE)lpvOutBuffer+dwInSize > (LPBYTE)lpvWorkBuffer
+              && (LPBYTE)lpvWorkBuffer+dwInSize > (LPBYTE)lpvOutBuffer)
+             {
+               lpvWorkBuffer = lpvDestinationMem;
+               lpvOutBuffer = (LPVOID)((LPBYTE)lpvWorkBuffer+1);
+             }
+             else {
+               lpvOutBuffer = lpvWorkBuffer;
+             }
+           }
+
+           dwDecompressedSize = dwInSize-1;
+           lpCFuncTable->fnCompress(lpvOutBuffer,&dwDecompressedSize,lpvInBuffer,dwInSize,&dwCompressionSubType,dwCompressLevel);
+           dwOutSize = dwDecompressedSize+1;
+
+           if (dwOutSize < dwInSize) {
+             lpvInBuffer = lpvOutBuffer;
+             dwInSize = dwDecompressedSize;
+           }
+           else {
+             dwCurFlag = lpCFuncTable->dwFlag;
+             dwCompressionType = dwCompressionType & (~dwCurFlag);
+           }
+
+           lpvWorkBuffer = lpvAllocBuffer;
+         }
+
+         lpCFuncTable++;
+       } while (lpCFuncTable <= lpLastCompressMethod);
+
+       lpvOutBuffer = lpvDestinationMem;
+
+       if (lpvInBuffer != lpvOutBuffer) {
+         if ((LPBYTE)lpvInBuffer == (LPBYTE)lpvOutBuffer+1) {
+           *(LPBYTE)lpvOutBuffer = (BYTE)dwCompressionType;
+           dwInSize++;
+         }
+         else {
+           if (dwCompressionType) {
+             SMemCopy((LPBYTE)lpvOutBuffer+1,lpvInBuffer,dwInSize);
+             dwInSize++;
+             *(LPBYTE)lpvOutBuffer = (BYTE)dwCompressionType;
+           }
+           else {
+             SMemCopy(lpvOutBuffer,lpvInBuffer,dwInSize);
+           }
+
+           lpvWorkBuffer = lpvAllocBuffer;
+         }
+       }
+
+       *lpdwCompressedSize = dwInSize;
+
+       if (lpvWorkBuffer) {
+         SMemFree(lpvWorkBuffer);
+       }
+
+       return TRUE;
+}
+
+BOOL WINAPI SCompDecompress(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize)
+{
+       DWORD dwDecompressedSize, dwOutSize, dwCompressTypes, dwCurFlag, dwTempFlags,dwCompressCount;
+       LPVOID lpvInBuffer,lpvOutBuffer,lpvWorkBuffer,lpvTempBuffer;
+       DecompressFunc *lpCFuncTable;
+
+       if (!lpdwDecompressedSize) {
+         SErrSetLastError(ERROR_INVALID_PARAMETER);
+         return FALSE;
+       }
+
+       dwDecompressedSize = *lpdwDecompressedSize;
+
+       if (dwDecompressedSize < dwCompressedSize || !lpvDestinationMem || !lpvSourceMem || dwCompressedSize < 1) {
+         SErrSetLastError(ERROR_INVALID_PARAMETER);
+         return FALSE;
+       }
+
+       if (dwCompressedSize == dwDecompressedSize) {
+         if (lpvDestinationMem == lpvSourceMem)
+           return TRUE;
+
+         SMemCopy(lpvDestinationMem,lpvSourceMem,dwCompressedSize);
+         return TRUE;
+       }
+
+       dwCompressCount = 0;
+       dwCompressTypes = *(LPBYTE)lpvSourceMem;
+       lpvInBuffer = (LPVOID)((LPBYTE)lpvSourceMem+1);
+       dwCompressedSize--;
+       dwTempFlags = dwCompressTypes;
+       lpCFuncTable = lpLastDecompressMethod;
+
+       do {
+         dwCurFlag = lpCFuncTable->dwFlag;
+
+         if (dwCompressTypes & dwCurFlag) {
+           dwCompressCount++;
+         }
+
+         dwTempFlags &= ~dwCurFlag;
+         lpCFuncTable--;;
+       } while (lpCFuncTable >= DecompressionFunctions);
+
+       if (dwTempFlags) {
+         return FALSE;
+       }
+
+       lpvWorkBuffer = 0;
+
+       if (dwCompressCount >= 2
+         || !((LPBYTE)lpvDestinationMem+dwCompressedSize <= (LPBYTE)lpvInBuffer
+           || (LPBYTE)lpvInBuffer+dwCompressedSize <= (LPBYTE)lpvDestinationMem
+           || !dwCompressCount))
+       {
+         lpvWorkBuffer = SMemAlloc(dwDecompressedSize);
+
+         if (!lpvWorkBuffer) {
+           SErrSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+           return FALSE;
+         }
+       }
+
+       lpCFuncTable = lpLastDecompressMethod;
+
+       do {
+         if (dwCompressTypes & lpCFuncTable->dwFlag) {
+           lpvOutBuffer = lpvWorkBuffer;
+           dwCompressCount--;
+
+           if (!(dwCompressCount & 1)) {
+             lpvOutBuffer = lpvDestinationMem;
+           }
+
+           if ((LPBYTE)lpvOutBuffer+dwCompressedSize > (LPBYTE)lpvInBuffer
+            && (LPBYTE)lpvInBuffer+dwCompressedSize > (LPBYTE)lpvOutBuffer)
+           {
+             if ((LPBYTE)lpvOutBuffer+dwCompressedSize <= (LPBYTE)lpvWorkBuffer) {
+               lpvOutBuffer = lpvWorkBuffer;
+             }
+             else {
+               lpvTempBuffer = lpvOutBuffer;
+               lpvOutBuffer = lpvDestinationMem;
+
+               if ((LPBYTE)lpvWorkBuffer+dwCompressedSize <= (LPBYTE)lpvTempBuffer)
+                 lpvOutBuffer = lpvWorkBuffer;
+             }
+           }
+
+           dwOutSize = dwDecompressedSize;
+           lpCFuncTable->fnDecompress(lpvOutBuffer,&dwOutSize,lpvInBuffer,dwCompressedSize);
+           dwCompressedSize = dwOutSize;
+           lpvInBuffer = lpvOutBuffer;
+         }
+
+         lpCFuncTable--;
+       } while (lpCFuncTable >= DecompressionFunctions);
+
+       if (lpvInBuffer != lpvDestinationMem) {
+         SMemCopy(lpvDestinationMem,lpvInBuffer,dwCompressedSize);
+       }
+
+       *lpdwDecompressedSize = dwCompressedSize;
+
+       if (lpvWorkBuffer) {
+         SMemFree(lpvWorkBuffer);
+       }
+
+       return TRUE;
+}
+
+void __fastcall InitWaveCompress(DWORD dwCompressLevel, LPDWORD *lplpdwCompressionSubType, LPDWORD lpdwCompressionSubType)
+{
+       if (dwCompressLevel) {
+         if (dwCompressLevel <= 2) {
+           *(LPBYTE)lplpdwCompressionSubType = 4;
+           *lpdwCompressionSubType = 6;
+           return;
+         }
+         else if (dwCompressLevel == 3) {
+           *(LPBYTE)lplpdwCompressionSubType = 6;
+           *lpdwCompressionSubType = 8;
+           return;
+         }
+       }
+
+       *(LPBYTE)lplpdwCompressionSubType = 5;
+       *lpdwCompressionSubType = 7;
+}
+
+void __fastcall CompressWaveMono(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel)
+{
+       InitWaveCompress(dwCompressLevel,&lpdwCompressionSubType,lpdwCompressionSubType);
+       *lpdwCompressedSize = CompressWave((LPBYTE)lpvDestinationMem,*lpdwCompressedSize,(short *)lpvSourceMem,dwDecompressedSize,1,(unsigned int)lpdwCompressionSubType & 0xFF);
+}
+
+void __fastcall CompressWaveStereo(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel)
+{
+       InitWaveCompress(dwCompressLevel,&lpdwCompressionSubType,lpdwCompressionSubType);
+       *lpdwCompressedSize = CompressWave((LPBYTE)lpvDestinationMem,*lpdwCompressedSize,(short *)lpvSourceMem,dwDecompressedSize,2,(unsigned int)lpdwCompressionSubType & 0xFF);
+}
+
+void __fastcall HuffmanCompress(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel)
+{
+       THuffmannTree *ht;                  // Huffmann tree for compression
+       TOutputStream os;                   // Output stream
+       THTreeItem * pItem;
+       int nCount;
+
+       ht = (THuffmannTree *)SMemAlloc(sizeof(THuffmannTree));
+
+       if (!ht) {
+         SErrSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+         return;
+       }
+
+       // Initialize output stream
+       os.pbOutBuffer = (unsigned char *)lpvDestinationMem;
+       os.dwOutSize   = *lpdwCompressedSize;
+       os.pbOutPos    = (unsigned char *)lpvDestinationMem;
+       os.dwBitBuff   = 0;
+       os.nBits       = 0;
+
+       // Clear links for all the items in the tree
+       for(pItem = ht->items0008, nCount = 0x203; nCount != 0; nCount--, pItem++)
+         pItem->ClearItemLinks();
+
+       ht->pItem3054 = NULL;
+       ht->pItem3054 = PTR_PTR(&ht->pItem3054);
+       ht->pItem3058 = PTR_NOT(&ht->pItem3054);
+
+       ht->pItem305C = NULL;
+       ht->pFirst    = PTR_PTR(&ht->pFirst);
+       ht->pLast     = PTR_NOT(&ht->pFirst);
+
+       ht->offs0004  = 1;
+       ht->nItems    = 0;
+
+       *lpdwCompressedSize = ht->DoCompression(&os, (unsigned char *)lpvSourceMem, dwDecompressedSize, *lpdwCompressionSubType);
+/*
+       // The following code is not necessary to run, because it has no
+       // effect on the output data. It only clears the huffmann tree, but when
+       // the tree is on the stack, who cares ?
+       while(PTR_INT(ht.pLast) > 0)
+       {
+         pItem = ht.pItem305C->Call1501DB70(ht.pLast);
+         pItem->RemoveItem();
+       }
+
+       for(pItem = ht.pFirst; PTR_INT(ht.pItem3058) > 0; pItem = ht.pItem3058)
+         pItem->RemoveItem();
+       PTR_PTR(&ht.pItem3054)->RemoveItem();
+
+       for(pItem = ht.items0008 + 0x203, nCount = 0x203; nCount != 0; nCount--)
+       {
+         pItem--;
+         pItem->RemoveItem();
+         pItem->RemoveItem();
+       }
+*/
+}
+
+#ifdef USE_ZLIB
+
+void __fastcall Deflate(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel)
+{
+       if (*lpdwCompressionSubType == 0) {
+               switch (dwCompressLevel) {
+                       case 1:
+                               dwCompressLevel = Z_BEST_COMPRESSION;
+                               break;
+                       case 2:
+                               dwCompressLevel = Z_BEST_SPEED;
+                               break;
+                       default:
+                               dwCompressLevel = (DWORD)Z_DEFAULT_COMPRESSION;
+               }
+       }
+
+       compress2((LPBYTE)lpvDestinationMem,lpdwCompressedSize,(LPBYTE)lpvSourceMem,dwDecompressedSize,dwCompressLevel);
+       *lpdwCompressionSubType = 0;
+}
+
+#endif
+
+void __fastcall Implode(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, LPDWORD lpdwCompressionSubType, DWORD dwCompressLevel)
+{
+       BUFFERINFO BufferInfo;
+       unsigned int dwCompType, dwDictSize;
+       LPVOID lpvWorkBuffer;
+
+       lpvWorkBuffer = SMemAlloc(CMP_BUFFER_SIZE);
+
+       if (!lpvWorkBuffer) {
+         SErrSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+         return;
+       }
+
+       BufferInfo.lpvSourceMem = lpvSourceMem;
+       BufferInfo.dwSrcStart = 0;
+       BufferInfo.dwSrcLen = dwDecompressedSize;
+       BufferInfo.lpvDestinationMem = lpvDestinationMem;
+       BufferInfo.dwDestStart = 0;
+       BufferInfo.dwDestLen = *lpdwCompressedSize;
+
+       dwCompType = (*lpdwCompressionSubType==2)?CMP_ASCII:CMP_BINARY;
+
+       if (dwDecompressedSize >= 0xC00) {
+         dwDictSize = 0x1000;
+       }
+       else if (dwDecompressedSize < 0x600) {
+         dwDictSize = 0x400;
+       }
+       else {
+         dwDictSize = 0x800;
+       }
+
+       implode(FillInput,FillOutput,(char *)lpvWorkBuffer,&BufferInfo,&dwCompType,&dwDictSize);
+       *lpdwCompressedSize = BufferInfo.dwDestStart;
+       *lpdwCompressionSubType = 0;
+
+       SMemFree(lpvWorkBuffer);
+}
+
+void __fastcall DecompressWaveMono(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize)
+{
+       *lpdwDecompressedSize = DecompressWave((LPBYTE)lpvDestinationMem,*lpdwDecompressedSize,(LPBYTE)lpvSourceMem,dwCompressedSize,1);
+}
+
+void __fastcall DecompressWaveStereo(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize)
+{
+       *lpdwDecompressedSize = DecompressWave((LPBYTE)lpvDestinationMem,*lpdwDecompressedSize,(LPBYTE)lpvSourceMem,dwCompressedSize,2);
+}
+
+void __fastcall HuffmanDecompress(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize)
+{
+       THuffmannTree *ht;
+       TInputStream  is;
+       THTreeItem * pItem;
+       unsigned int nCount;
+
+       ht = (THuffmannTree *)SMemAlloc(sizeof(THuffmannTree));
+
+       if (!ht) {
+         SErrSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+         return;
+       }
+
+       // Initialize input stream
+       is.pbInBuffer  = (unsigned char *)lpvSourceMem;
+       is.dwBitBuff   = *(unsigned long *)lpvSourceMem;
+       is.pbInBuffer    += sizeof(unsigned long);
+       is.nBits       = 32;
+
+       // Initialize the Huffman tree
+       for(pItem  = ht->items0008, nCount = 0x203; nCount != 0; pItem++, nCount--)
+         pItem->ClearItemLinks();
+
+       ht->pItem3050 = NULL;
+       ht->pItem3054 = PTR_PTR(&ht->pItem3054);
+       ht->pItem3058 = PTR_NOT(ht->pItem3054);
+
+       ht->pItem305C = NULL;
+       ht->pFirst    = PTR_PTR(&ht->pFirst);
+       ht->pLast     = PTR_NOT(ht->pFirst);
+
+       ht->offs0004  = 1;
+       ht->nItems    = 0;
+
+       // Clear all TQDecompress items
+       for(nCount = 0; nCount < sizeof(ht->qd3474) / sizeof(TQDecompress); nCount++)
+         ht->qd3474[nCount].offs00 = 0;
+
+       *lpdwDecompressedSize = ht->DoDecompression((unsigned char *)lpvDestinationMem, *lpdwDecompressedSize, &is);
+/*
+       // The following code is not necessary to run, because it has no
+       // effect on the output data. It only clears the huffmann tree, but when
+       // the tree is on the stack, who cares ?
+       while(PTR_INT(ht.pLast) > 0)
+       {
+         pItem = ht.pItem305C->Call1501DB70(ht.pLast);
+         pItem->RemoveItem();
+       }
+
+       for(pItem = ht.pFirst; PTR_INT(ht.pItem3058) > 0; pItem = ht.pItem3058)
+         pItem->RemoveItem();
+       PTR_PTR(&ht.pItem3054)->RemoveItem();
+
+       for(pItem = ht.items0008 + 0x203, nCount = 0x203; nCount != 0; nCount--)
+       {
+         pItem--;
+         pItem->RemoveItem();
+         pItem->RemoveItem();
+       }
+*/
+
+       SMemFree(ht);
+}
+
+#ifdef USE_ZLIB
+
+void __fastcall Inflate(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize)
+{
+       uncompress((LPBYTE)lpvDestinationMem,lpdwDecompressedSize,(LPBYTE)lpvSourceMem,dwCompressedSize);
+}
+
+#endif
+
+void __fastcall Explode(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize)
+{
+       BUFFERINFO BufferInfo;
+       LPVOID lpvWorkBuffer;
+
+       lpvWorkBuffer = SMemAlloc(EXP_BUFFER_SIZE);
+
+       if (!lpvWorkBuffer) {
+         SErrSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+         return;
+       }
+
+       BufferInfo.lpvSourceMem = lpvSourceMem;
+       BufferInfo.dwSrcStart = 0;
+       BufferInfo.dwSrcLen = dwCompressedSize;
+       BufferInfo.lpvDestinationMem = lpvDestinationMem;
+       BufferInfo.dwDestStart = 0;
+       BufferInfo.dwDestLen = *lpdwDecompressedSize;
+
+       explode(FillInput,FillOutput,(char *)lpvWorkBuffer,&BufferInfo);
+       *lpdwDecompressedSize = BufferInfo.dwDestStart;
+
+       SMemFree(lpvWorkBuffer);
+}
+
+unsigned int FillInput(char *lpvBuffer, unsigned int *lpdwSize, void *param)
+{
+       DWORD dwBufferSize;
+       BUFFERINFO *lpBufferInfo = (BUFFERINFO *)param;
+
+       dwBufferSize = *lpdwSize;
+
+       if (dwBufferSize >= lpBufferInfo->dwSrcLen - lpBufferInfo->dwSrcStart) {
+         dwBufferSize = lpBufferInfo->dwSrcLen - lpBufferInfo->dwSrcStart;
+       }
+
+       SMemCopy(lpvBuffer,(LPBYTE)lpBufferInfo->lpvSourceMem+lpBufferInfo->dwSrcStart,dwBufferSize);
+       lpBufferInfo->dwSrcStart += dwBufferSize;
+       return dwBufferSize;
+}
+
+void FillOutput(char *lpvBuffer, unsigned int *lpdwSize, void *param)
+{
+       DWORD dwBufferSize;
+       BUFFERINFO *lpBufferInfo = (BUFFERINFO *)param;
+
+       dwBufferSize = *lpdwSize;
+
+       if (dwBufferSize >= lpBufferInfo->dwDestLen - lpBufferInfo->dwDestStart) {
+         dwBufferSize = lpBufferInfo->dwDestLen - lpBufferInfo->dwDestStart;
+       }
+
+       SMemCopy((LPBYTE)lpBufferInfo->lpvDestinationMem+lpBufferInfo->dwDestStart,lpvBuffer,dwBufferSize);
+       lpBufferInfo->dwDestStart += dwBufferSize;
+}
+
diff --git a/SComp.h b/SComp.h
new file mode 100644 (file)
index 0000000..37a8e93
--- /dev/null
+++ b/SComp.h
@@ -0,0 +1,25 @@
+// SComp.h - Header for main compression/decompression routines
+// License information for this code is in license.txt
+
+#ifndef S_COMP_INCLUDED
+#define S_COMP_INCLUDED
+
+#if (defined(_WIN32) || defined(WIN32)) && !defined(NO_WINDOWS_H)
+#include <windows.h>
+#else
+#include "wintypes.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BOOL WINAPI SCompCompress(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, DWORD dwCompressionType, DWORD dwCompressionSubType, DWORD dwCompressLevel);
+BOOL WINAPI SCompDecompress(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
+
+#ifdef __cplusplus
+};  // extern "C" 
+#endif
+
+#endif
+
diff --git a/SErr.cpp b/SErr.cpp
new file mode 100644 (file)
index 0000000..63c9c08
--- /dev/null
+++ b/SErr.cpp
@@ -0,0 +1,35 @@
+// SErr.cpp - SetLastError routine
+//
+// Converted from assembly to C++ by ShadowFlare.
+// E-mail  : blakflare@hotmail.com
+// Webpage : http://sfsrealm.hopto.org/
+// License information for this code is in license.txt
+
+
+#include "SErr.h"
+
+DWORD dwLastError;
+
+#if (defined(_WIN32) || defined(WIN32)) && !defined(NO_WINDOWS_H)
+
+DWORD WINAPI SErrSetLastError(DWORD dwErrorCode)
+{
+       dwLastError = dwErrorCode;
+       SetLastError(dwErrorCode);
+       return dwErrorCode;
+}
+
+#else
+
+DWORD WINAPI SErrSetLastError(DWORD dwErrorCode)
+{
+       return (dwLastError = dwErrorCode);
+}
+
+#endif
+
+DWORD WINAPI SErrGetLastError(VOID)
+{
+       return dwLastError;
+}
+
diff --git a/SErr.h b/SErr.h
new file mode 100644 (file)
index 0000000..25dae28
--- /dev/null
+++ b/SErr.h
@@ -0,0 +1,25 @@
+// SErr.h - Header for SetLastError routine
+// License information for this code is in license.txt
+
+#ifndef S_ERR_INCLUDED
+#define S_ERR_INCLUDED
+
+#if (defined(_WIN32) || defined(WIN32)) && !defined(NO_WINDOWS_H)
+#include <windows.h>
+#else
+#include "wintypes.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+DWORD WINAPI SErrSetLastError(DWORD dwErrorCode);
+DWORD WINAPI SErrGetLastError(VOID);
+
+#ifdef __cplusplus
+};  // extern "C" 
+#endif
+
+#endif
+
diff --git a/SMem.cpp b/SMem.cpp
new file mode 100644 (file)
index 0000000..aeea895
--- /dev/null
+++ b/SMem.cpp
@@ -0,0 +1,66 @@
+// SMem.cpp - Memory functions
+//
+// Converted from assembly to C++ by ShadowFlare.
+// E-mail  : blakflare@hotmail.com
+// Webpage : http://sfsrealm.hopto.org/
+// License information for this code is in license.txt
+
+
+#include "SMem.h"
+#include <malloc.h>
+
+LPVOID WINAPI SMemAlloc(DWORD dwSize)
+{
+       LPVOID lpMemory = malloc(dwSize);
+       if (lpMemory) SMemZero(lpMemory,dwSize);
+       return lpMemory;
+}
+
+void WINAPI SMemFree(LPVOID lpvMemory)
+{
+       if (lpvMemory) free(lpvMemory);
+}
+
+DWORD WINAPI SMemCopy(LPVOID lpDestination, LPCVOID lpSource, DWORD dwLength)
+{
+       DWORD dwPrevLen = dwLength;
+       LPDWORD lpdwDestination = (LPDWORD)lpDestination,lpdwSource = (LPDWORD)lpSource;
+       LPBYTE lpbyDestination,lpbySource;
+
+       dwLength >>= 2;
+
+       while (dwLength--)
+               *lpdwDestination++ = *lpdwSource++;
+
+       lpbyDestination = (LPBYTE)lpdwDestination;
+       lpbySource = (LPBYTE)lpdwSource;
+
+       dwLength = dwPrevLen;
+       dwLength &= 3;
+
+       while (dwLength--)
+               *lpbyDestination++ = *lpbySource++;
+
+       return dwPrevLen;
+}
+
+void WINAPI SMemZero(LPVOID lpDestination, DWORD dwLength)
+{
+       DWORD dwPrevLen = dwLength;
+       LPDWORD lpdwDestination = (LPDWORD)lpDestination;
+       LPBYTE lpbyDestination;
+
+       dwLength >>= 2;
+
+       while (dwLength--)
+               *lpdwDestination++ = 0;
+
+       lpbyDestination = (LPBYTE)lpdwDestination;
+
+       dwLength = dwPrevLen;
+       dwLength &= 3;
+
+       while (dwLength--)
+               *lpbyDestination++ = 0;
+}
+
diff --git a/SMem.h b/SMem.h
new file mode 100644 (file)
index 0000000..9238a4d
--- /dev/null
+++ b/SMem.h
@@ -0,0 +1,27 @@
+// SMem.h - Header for memory functions
+// License information for this code is in license.txt
+
+#ifndef S_MEM_INCLUDED
+#define S_MEM_INCLUDED
+
+#if (defined(_WIN32) || defined(WIN32)) && !defined(NO_WINDOWS_H)
+#include <windows.h>
+#else
+#include "wintypes.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LPVOID WINAPI SMemAlloc(DWORD dwSize);
+void WINAPI SMemFree(LPVOID lpvMemory);
+DWORD WINAPI SMemCopy(LPVOID lpDestination, LPCVOID lpSource, DWORD dwLength);
+void WINAPI SMemZero(LPVOID lpDestination, DWORD dwLength);
+
+#ifdef __cplusplus
+};  // extern "C" 
+#endif
+
+#endif
+
diff --git a/ZLib_Static_min.lib b/ZLib_Static_min.lib
new file mode 100644 (file)
index 0000000..dce1150
Binary files /dev/null and b/ZLib_Static_min.lib differ
diff --git a/crc32.c b/crc32.c
new file mode 100644 (file)
index 0000000..a7f5210
--- /dev/null
+++ b/crc32.c
@@ -0,0 +1,72 @@
+/*****************************************************************************/
+/* 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 char CopyRight[] = "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";
+
+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 crc32pk(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/explode.c b/explode.c
new file mode 100644 (file)
index 0000000..50cde3a
--- /dev/null
+++ b/explode.c
@@ -0,0 +1,503 @@
+/*****************************************************************************/
+/* explode.c                              Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Explode 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                                     */
+/*****************************************************************************/
+
+#include "pklib.h"
+#include "SMem.h"
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+// Compression structure (Size 12596 bytes)
+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); // 0028
+    void         (*write_buf)(char *buf, unsigned  int *size, void *param);// 002C
+    unsigned char out_buff[0x2000];     // 0030 - Output circle buffer. Starting position is 0x1000
+    unsigned char offs2030[0x204];      // 2030 - ???
+    unsigned char in_buff[0x800];       // 2234 - Buffer for data to be decompressed
+    unsigned char position1[0x100];     // 2A34 - Positions in buffers
+    unsigned char position2[0x100];     // 2B34 - Positions in buffers
+    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;
+
+//-----------------------------------------------------------------------------
+// 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 variables
+
+static char Copyright[] = "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";
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static void GenDecodeTabs(long count, unsigned char * bits, unsigned char * pCode, unsigned char * buffer2)
+{
+    long i;
+
+    for(i = count-1; i >= 0; i--)             // EBX - count
+    {
+        unsigned long idx1 = pCode[i];
+        unsigned long idx2 = 1 << bits[i];
+
+        do
+        {
+            buffer2[idx1] = (unsigned char)i;
+            idx1         += idx2;
+        }
+        while(idx1 < 0x100);
+    }
+}
+
+static void GenAscTabs(TDcmpStruct * pWork)
+{
+    unsigned short * pChCodeAsc = &ChCodeAsc[0xFF];
+    unsigned long  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);
+        }
+    }
+}
+
+//-----------------------------------------------------------------------------
+// Skips given number of bits in bit buffer. Result is stored in pWork->bit_buff
+// If no data in input buffer, returns true
+
+static int WasteBits(TDcmpStruct * pWork, unsigned long 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 0;
+    }
+
+    // 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 1;
+        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 0;
+}
+
+//-----------------------------------------------------------------------------
+// Returns : 0x000 - 0x0FF : One byte from compressed file.
+//           0x100 - 0x305 : Copy previous block (0x100 = 1 byte)
+//           0x306         : Out of buffer (?)
+
+static unsigned long DecodeLit(TDcmpStruct * pWork)
+{
+    unsigned long nBits;                // Number of bits to skip
+    unsigned long value;                // Position in buffers
+
+    // Test the current bit in byte buffer. If is not set, simply return the next byte.
+    if(pWork->bit_buff & 1)
+    {
+        // Skip current bit in the buffer
+        if(WasteBits(pWork, 1))
+            return 0x306;   
+
+        // The next bits are position in buffers
+        value = pWork->position2[(pWork->bit_buff & 0xFF)];
+        
+        // Get number of bits to skip
+        if(WasteBits(pWork, pWork->LenBits[value]))
+            return 0x306;
+
+        if((nBits = pWork->ExLenBits[value]) != 0)
+        {
+            unsigned long val2 = pWork->bit_buff & ((1 << nBits) - 1);
+
+            if(WasteBits(pWork, nBits))
+            {
+                if((value + val2) != 0x10E)
+                    return 0x306;
+            }
+            value = pWork->LenBase[value] + val2;
+        }
+        return value + 0x100;           // Return number of bytes to repeat
+    }
+
+    // Waste one bit
+    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)
+    {
+        value = pWork->bit_buff & 0xFF;
+        if(WasteBits(pWork, 8))
+            return 0x306;
+        return value;
+    }
+
+    // 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;
+}
+
+//-----------------------------------------------------------------------------
+// Retrieves the number of bytes to move back 
+
+static unsigned long DecodeDist(TDcmpStruct * pWork, unsigned long dwLength)
+{
+    unsigned long pos   = pWork->position1[(pWork->bit_buff & 0xFF)];
+    unsigned long nSkip = pWork->DistBits[pos];     // Number of bits to skip
+
+    // Skip the appropriate number of bits
+    if(WasteBits(pWork, nSkip) == 1)
+        return 0;
+
+    if(dwLength == 2)
+    {
+        pos = (pos << 2) | (pWork->bit_buff & 0x03);
+
+        if(WasteBits(pWork, 2) == 1)
+            return 0;
+    }
+    else
+    {
+        pos = (pos << pWork->dsize_bits) | (pWork->bit_buff & pWork->dsize_mask);
+
+        // Skip the bits
+        if(WasteBits(pWork, pWork->dsize_bits) == 1)
+            return 0;
+    }
+    return pos+1;
+}
+
+static unsigned long Expand(TDcmpStruct * pWork)
+{
+    unsigned int  copyBytes;            // Number of bytes to copy
+    unsigned long oneByte;              // One byte from compressed file
+    unsigned long dwResult;
+
+    pWork->outputPos = 0x1000;          // Initialize output buffer position
+
+    // If end of data or error, terminate decompress
+    while((dwResult = oneByte = DecodeLit(pWork)) < 0x305)
+    {
+        // If one byte is greater than 0x100, means "Repeat n - 0xFE bytes"
+        if(oneByte >= 0x100)
+        {
+            unsigned char * source;          // ECX
+            unsigned char * target;          // EDX
+            unsigned long  copyLength = oneByte - 0xFE;
+            unsigned long  moveBack;
+
+            // Get length of data to copy
+            if((moveBack = DecodeDist(pWork, copyLength)) == 0)
+            {
+                dwResult = 0x306;
+                break;
+            }
+
+            // Target and source pointer
+            target = &pWork->out_buff[pWork->outputPos];
+            source = target - moveBack;
+            pWork->outputPos += copyLength;
+
+            while(copyLength-- > 0)
+                *target++ = *source++;
+        }
+        else
+            pWork->out_buff[pWork->outputPos++] = (unsigned char)oneByte;
+    
+        // If number of extracted bytes has reached 1/2 of output buffer,
+        // flush output buffer.
+        if(pWork->outputPos >= 0x2000)
+        {
+            // Copy decompressed data into user buffer
+            copyBytes = 0x1000;
+            pWork->write_buf((char *)&pWork->out_buff[0x1000], &copyBytes, pWork->param);
+
+            // If there are some data left, keep them alive
+            SMemCopy(pWork->out_buff, &pWork->out_buff[0x1000], pWork->outputPos - 0x1000);
+            pWork->outputPos -= 0x1000;
+        }
+    }
+
+       copyBytes = pWork->outputPos - 0x1000;
+    pWork->write_buf((char *)&pWork->out_buff[0x1000], &copyBytes, pWork->param);
+    return dwResult;
+}
+
+
+//-----------------------------------------------------------------------------
+// Main exploding function.
+
+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)
+{
+    TDcmpStruct * pWork = (TDcmpStruct *)work_buf;
+
+    // Initialize work struct and load compressed data
+    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
+    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;
+
+        SMemCopy(pWork->ChBitsAsc, ChBitsAsc, sizeof(pWork->ChBitsAsc));
+        GenAscTabs(pWork);
+    }
+
+    SMemCopy(pWork->LenBits, LenBits, sizeof(pWork->LenBits));
+    GenDecodeTabs(0x10, pWork->LenBits, LenCode, pWork->position2);
+    SMemCopy(pWork->ExLenBits, ExLenBits, sizeof(pWork->ExLenBits));
+    SMemCopy(pWork->LenBase, LenBase, sizeof(pWork->LenBase));
+    SMemCopy(pWork->DistBits, DistBits, sizeof(pWork->DistBits));
+    GenDecodeTabs(0x40, pWork->DistBits, DistCode, pWork->position1);
+    if(Expand(pWork) != 0x306)
+        return CMP_NO_ERROR;
+        
+    return CMP_ABORT;
+}
diff --git a/huffman.cpp b/huffman.cpp
new file mode 100644 (file)
index 0000000..1fd9ba3
--- /dev/null
@@ -0,0 +1,1387 @@
+/*****************************************************************************/
+/* huffman.cpp                       Copyright (c) Ladislav Zezula 1998-2003 */
+/*---------------------------------------------------------------------------*/
+/* This module contains Huffmann (de)compression methods                     */
+/*                                                                           */
+/* Authors : Ladislav Zezula (ladik.zezula.net)                              */
+/*           ShadowFlare     (BlakFlare@hotmail.com)                         */
+/*                                                                           */
+/*---------------------------------------------------------------------------*/
+/*   Date    Ver   Who  Comment                                              */
+/* --------  ----  ---  -------                                              */
+/* xx.xx.xx  1.00  Lad  The first version of dcmp.cpp                        */
+/* 03.05.03  1.00  Lad  Added compression methods                            */
+/*****************************************************************************/
+
+#include "huffman.h"
+#include "SMem.h"
+
+//-----------------------------------------------------------------------------
+// Methods of the THTreeItem struct
+
+// 1501DB70
+THTreeItem * THTreeItem::Call1501DB70(THTreeItem * pLast)
+{
+    if(pLast == NULL)
+        pLast = this + 1;
+    return pLast;
+}
+
+// Gets previous Huffman tree item (?)
+THTreeItem * THTreeItem::GetPrevItem(long value)
+{
+    if(PTR_INT(prev) < 0)
+        return PTR_NOT(prev);
+
+    if(value < 0)
+        value = this - next->prev;
+    return prev + value;
+
+// OLD VERSION
+//  if(PTR_INT(value) < 0)
+//      value = PTR_INT((item - item->next->prev));
+//  return (THTreeItem *)((char *)prev + value);
+}
+
+// 1500F5E0
+void THTreeItem::ClearItemLinks()
+{
+    next = prev = NULL;
+}
+
+// 1500BC90
+void THTreeItem::RemoveItem()
+{
+    THTreeItem * pTemp;                // EDX
+
+    if(next != NULL)
+    {
+        pTemp = prev;
+        
+        if(PTR_INT(pTemp) <= 0)
+            pTemp = PTR_NOT(pTemp);
+        else
+            pTemp += (this - next->prev);
+
+        pTemp->next = next;
+        next->prev  = prev;
+        next = prev = NULL;
+    }
+}
+
+/*
+// OLD VERSION : Removes item from the tree (?)
+static void RemoveItem(THTreeItem * item)
+{
+    THTreeItem * next = item->next;     // ESI
+    THTreeItem * prev = item->prev;     // EDX
+
+    if(next == NULL)
+        return;
+
+    if(PTR_INT(prev) < 0)
+        prev = PTR_NOT(prev);
+    else
+        // ??? usually item == next->prev, so what is it ?
+        prev = (THTreeItem *)((unsigned char *)prev + (unsigned long)((unsigned char *)item - (unsigned char *)(next->prev)));
+
+    // Remove HTree item from the chain
+    prev->next = next;                  // Sets the 'first' pointer
+    next->prev = item->prev;
+
+    // Invalidate pointers
+    item->next = NULL;
+    item->prev = NULL;
+}
+*/
+
+//-----------------------------------------------------------------------------
+// TOutputStream functions
+
+void TOutputStream::PutBits(unsigned long dwBuff, unsigned int nPutBits)
+{
+    dwBitBuff |= (dwBuff << nBits);
+    nBits     += nPutBits;
+
+    // Flush completed bytes
+    while(nBits >= 8)
+    {
+        if(dwOutSize != 0)
+        {
+            *pbOutPos++ = (unsigned char)dwBitBuff;
+            dwOutSize--;
+        }
+
+        dwBitBuff >>= 8;
+        nBits      -= 8;
+    }
+}
+
+//-----------------------------------------------------------------------------
+// TInputStream functions
+
+// Gets one bit from input stream
+unsigned long TInputStream::GetBit()
+{
+    unsigned long dwBit = (dwBitBuff & 1);
+
+    dwBitBuff >>= 1;
+    if(--nBits == 0)
+    {
+        dwBitBuff   = *(unsigned long *)pbInBuffer;
+        pbInBuffer += sizeof(unsigned long);
+        nBits       = 32;
+    }
+    return dwBit;
+}    
+
+// Gets 7 bits from the stream
+unsigned long TInputStream::Get7Bits()
+{
+    if(nBits <= 7)
+    {
+        dwBitBuff  |= *(unsigned short *)pbInBuffer << nBits;
+        pbInBuffer += sizeof(unsigned short);
+        nBits      += 16;
+    }
+
+    // Get 7 bits from input stream
+    return (dwBitBuff & 0x7F);
+}
+
+// Gets the whole byte from the input stream.
+unsigned long TInputStream::Get8Bits()
+{
+    unsigned long dwOneByte;
+
+    if(nBits <= 8)
+    {
+        dwBitBuff  |= *(unsigned short *)pbInBuffer << nBits;
+        pbInBuffer += sizeof(unsigned short);
+        nBits      += 16;
+    }
+    
+    dwOneByte   = (dwBitBuff & 0xFF);
+    dwBitBuff >>= 8;
+    nBits      -= 8;
+    return dwOneByte;
+}
+
+//-----------------------------------------------------------------------------
+// Functions for huffmann tree items
+
+// Inserts item into the tree (?)
+static void InsertItem(THTreeItem ** itemPtr, THTreeItem * item, unsigned long where, THTreeItem * item2)
+{
+    THTreeItem * next = item->next;     // EDI - next to the first item
+    THTreeItem * prev = item->prev;     // ESI - prev to the first item
+    long next2;                         // Pointer to the next item
+    THTreeItem * prev2;                 // Pointer to previous item
+    
+    // The same code like in RemoveItem(item);
+    if(next != 0)                       // If the first item already has next one
+    {
+        if(PTR_INT(prev) < 0)
+            prev = PTR_NOT(prev);
+        else
+            prev += (item - next->prev);
+
+        // 150083C1
+        // Remove the item from the tree
+        prev->next = next;
+        next->prev = prev;
+
+        // Invalidate 'prev' and 'next' pointer
+        item->next = 0;
+        item->prev = 0;
+    }
+
+    if(item2 == NULL)                   // EDX - If the second item is not entered,
+        item2 = PTR_PTR(&itemPtr[1]);   // take the first tree item
+
+    switch(where)
+    {
+        case SWITCH_ITEMS :             // Switch the two items
+            item->next  = item2->next;  // item2->next (Pointer to pointer to first)
+            item->prev  = item2->next->prev;
+            item2->next->prev = item;
+            item2->next = item;         // Set the first item
+            return;
+        
+        case INSERT_ITEM:               // Insert as the last item
+            item->next = item2;         // Set next item (or pointer to pointer to first item)
+            item->prev = item2->prev;   // Set prev item (or last item in the tree)
+
+            next2 = PTR_INT(itemPtr[0]);// Usually NULL
+            prev2 = item2->prev;        // Prev item to the second (or last tree item)
+            
+            if(PTR_INT(prev2) < 0)
+            {
+                prev2 = PTR_NOT(prev);
+
+                prev2->next = item;
+                item2->prev = item;     // Next after last item
+                return;
+            }
+
+            if(next2 < 0)
+                next2 = item2 - item2->next->prev;
+//              next2 = (THTreeItem *)(unsigned long)((unsigned char *)item2 - (unsigned char *)(item2->next->prev));
+
+//          prev2 = (THTreeItem *)((char *)prev2 + (unsigned long)next2);// ???
+            prev2 += next2;
+            prev2->next = item;
+            item2->prev = item;         // Set the next/last item
+            return;
+
+        default:
+            return;
+    }
+}
+
+//-----------------------------------------------------------------------------
+// THuffmannTree class functions
+
+// Builds Huffman tree. Called with the first 8 bits loaded from input stream
+void THuffmannTree::BuildTree(unsigned int nCmpType)
+{
+    unsigned long   maxByte;            // [ESP+10] - The greatest character found in table
+    THTreeItem   ** itemPtr;            // [ESP+14] - Pointer to Huffman tree item pointer array
+    unsigned char * byteArray;          // [ESP+1C] - Pointer to unsigned char in Table1502A630
+    THTreeItem    * child1;
+    unsigned long   i;                  // egcs in linux doesn't like multiple for loops without an explicit i
+
+    // Loop while pointer has a negative value
+    while(PTR_INT(pLast) > 0)           // ESI - Last entry
+    {
+        THTreeItem * temp;              // EAX
+
+        if(pLast->next != NULL)         // ESI->next
+            pLast->RemoveItem();
+                                        // EDI = &offs3054
+        pItem3058   = PTR_PTR(&pItem3054);// [EDI+4]
+        pLast->prev = pItem3058;  // EAX
+
+        temp = PTR_PTR(&pItem3054)->GetPrevItem(PTR_INT(&pItem3050));
+
+        temp->next = pLast;
+        pItem3054  = pLast;
+    }
+
+    // Clear all pointers in HTree item array
+    SMemZero(items306C, sizeof(items306C));
+
+    maxByte = 0;                        // Greatest character found init to zero.
+    itemPtr = (THTreeItem **)&items306C; // Pointer to current entry in HTree item pointer array
+
+    // Ensure we have low 8 bits only
+    nCmpType &= 0xFF;
+    byteArray  = Table1502A630 + nCmpType * 258; // EDI also
+
+    for(i = 0; i < 0x100; i++, itemPtr++)
+    {
+        THTreeItem * item   = pItem3058;    // Item to be created
+        THTreeItem * pItem3 = pItem3058;
+        unsigned char         oneByte = byteArray[i];
+
+        // Skip all the bytes which are zero.
+        if(byteArray[i] == 0)
+            continue;
+
+        // If not valid pointer, take the first available item in the array
+        if(PTR_INT(item) <= 0)    
+            item = &items0008[nItems++];
+
+        // Insert this item as the top of the tree
+        InsertItem(&pItem305C, item, SWITCH_ITEMS, NULL);
+
+        item->parent    = NULL;                 // Invalidate child and parent
+        item->child     = NULL;
+        *itemPtr        = item;                 // Store pointer into pointer array
+
+        item->dcmpByte  = i;                    // Store counter
+        item->byteValue = oneByte;              // Store byte value
+        if(oneByte >= maxByte)
+        {
+            maxByte = oneByte;
+            continue;
+        }
+
+        // Find the first item which has byte value greater than current one byte
+        if(PTR_INT((pItem3 = pLast)) > 0)        // EDI - Pointer to the last item
+        {
+            // 15006AF7
+            if(pItem3 != NULL)
+            {
+                do  // 15006AFB
+                {
+                    if(pItem3->byteValue >= oneByte)
+                        goto _15006B09;
+                    pItem3 = pItem3->prev;
+                }
+                while(PTR_INT(pItem3) > 0);
+            }
+        }
+        pItem3 = NULL;
+
+        // 15006B09
+        _15006B09:
+        if(item->next != NULL)
+            item->RemoveItem();
+
+        // 15006B15
+        if(pItem3 == NULL)
+            pItem3 = PTR_PTR(&pFirst);
+
+        // 15006B1F
+        item->next = pItem3->next;
+        item->prev = pItem3->next->prev;
+        pItem3->next->prev = item;
+        pItem3->next = item;
+    }
+
+    // 15006B4A
+    for(; i < 0x102; i++)
+    {
+        THTreeItem ** itemPtr = &items306C[i];  // EDI
+
+        // 15006B59
+        THTreeItem * item = pItem3058;          // ESI
+        if(PTR_INT(item) <= 0)
+            item = &items0008[nItems++];
+
+        InsertItem(&pItem305C, item, INSERT_ITEM, NULL);
+
+        // 15006B89
+        item->dcmpByte   = i;
+        item->byteValue  = 1;
+        item->parent     = NULL;
+        item->child      = NULL;
+        *itemPtr++ = item;
+    }
+
+    // 15006BAA
+    if(PTR_INT((child1 = pLast)) > 0)               // EDI - last item (first child to item
+    {
+        THTreeItem * child2;                        // EBP
+        THTreeItem * item;                          // ESI
+
+        // 15006BB8
+        while(PTR_INT((child2 = child1->prev)) > 0)
+        {
+            if(PTR_INT((item = pItem3058)) <= 0)
+                item = &items0008[nItems++];
+
+            // 15006BE3
+            InsertItem(&pItem305C, item, SWITCH_ITEMS, NULL);
+
+            // 15006BF3
+            item->parent = NULL;
+            item->child  = NULL;
+
+            //EDX = child2->byteValue + child1->byteValue;
+            //EAX = child1->byteValue;
+            //ECX = maxByte;                        // The greatest character (0xFF usually)
+
+            item->byteValue = child1->byteValue + child2->byteValue; // 0x02
+            item->child     = child1;                                // Prev item in the 
+            child1->parent  = item;
+            child2->parent  = item;
+
+            // EAX = item->byteValue;
+            if(item->byteValue >= maxByte)
+                maxByte = item->byteValue;
+            else
+            {
+                THTreeItem * pItem2 = child2->prev;   // EDI
+
+                if(PTR_INT(pItem2) > 0)
+                {
+                    // 15006C2D
+                    do
+                    {
+                        if(pItem2->byteValue >= item->byteValue)
+                            goto _15006C3B;
+                        pItem2 = pItem2->prev;
+                    }
+                    while(PTR_INT(pItem2) > 0);
+                }
+                pItem2 = NULL;
+
+                _15006C3B:
+                if(item->next != 0)
+                {
+                    THTreeItem * temp4 = item->GetPrevItem(-1);
+                                                                    
+                    temp4->next      = item->next;                 // The first item changed
+                    item->next->prev = item->prev;                 // First->prev changed to negative value
+                    item->next = NULL;
+                    item->prev = NULL;
+                }
+
+                // 15006C62
+                if(pItem2 == NULL)
+                    pItem2 = PTR_PTR(&pFirst);
+
+                item->next = pItem2->next;                           // Set item with 0x100 byte value
+                item->prev = pItem2->next->prev;                     // Set item with 0x17 byte value
+                pItem2->next->prev = item;                           // Changed prev of item with
+                pItem2->next = item;
+            }
+            // 15006C7B
+            if(PTR_INT((child1 = child2->prev)) <= 0)
+                break;
+        }
+    }
+    // 15006C88
+    offs0004 = 1;
+}
+/*
+// Modifies Huffman tree. Adds new item and changes
+void THuffmannTree::ModifyTree(unsigned long dwIndex)
+{
+    THTreeItem * pItem1 = pItem3058;                              // ESI
+    THTreeItem * pSaveLast = (PTR_INT(pLast) <= 0) ? NULL : pLast;  // EBX
+    THTreeItem * temp;                                              // EAX 
+
+    // Prepare the first item to insert to the tree
+    if(PTR_INT(pItem1) <= 0)
+        pItem1 = &items0008[nItems++];
+
+    // If item has any next item, remove it from the chain
+    if(pItem1->next != NULL)
+    {
+        THTreeItem * temp = pItem1->GetPrevItem(-1);                  // EAX
+
+        temp->next = pItem1->next;
+        pItem1->next->prev = pItem1->prev;
+        pItem1->next = NULL;
+        pItem1->prev = NULL;
+    }
+
+    pItem1->next = PTR_PTR(&pFirst);
+    pItem1->prev = pLast;
+    temp = pItem1->next->GetPrevItem(PTR_INT(pItem305C));
+
+    // 150068E9
+    temp->next = pItem1;
+    pLast  = pItem1;
+
+    pItem1->parent = NULL;
+    pItem1->child  = NULL;
+
+    // 150068F6
+    pItem1->dcmpByte  = pSaveLast->dcmpByte;   // Copy item index
+    pItem1->byteValue = pSaveLast->byteValue;  // Copy item byte value
+    pItem1->parent    = pSaveLast;             // Set parent to last item
+    items306C[pSaveLast->dcmpByte] = pItem1;  // Insert item into item pointer array
+
+    // Prepare the second item to insert into the tree
+    if(PTR_INT((pItem1 = pItem3058)) <= 0)
+        pItem1 = &items0008[nItems++];
+
+    // 1500692E
+    if(pItem1->next != NULL)
+    {
+        temp = pItem1->GetPrevItem(-1);   // EAX
+
+        temp->next = pItem1->next;
+        pItem1->next->prev = pItem1->prev;
+        pItem1->next = NULL;
+        pItem1->prev = NULL;
+    }
+    // 1500694C
+    pItem1->next = PTR_PTR(&pFirst);
+    pItem1->prev = pLast;
+    temp = pItem1->next->GetPrevItem(PTR_INT(pItem305C));
+
+    // 15006968
+    temp->next = pItem1;
+    pLast      = pItem1;
+
+    // 1500696E
+    pItem1->child     = NULL;
+    pItem1->dcmpByte  = dwIndex;
+    pItem1->byteValue = 0;
+    pItem1->parent    = pSaveLast;
+    pSaveLast->child   = pItem1;
+    items306C[dwIndex] = pItem1;
+
+    do
+    {
+        THTreeItem  * pItem2 = pItem1;
+        THTreeItem  * pItem3;
+        unsigned long byteValue;
+
+        // 15006993
+        byteValue = ++pItem1->byteValue;
+
+        // Pass through all previous which have its value greater than byteValue
+        while(PTR_INT((pItem3 = pItem2->prev)) > 0)  // EBX
+        {
+            if(pItem3->byteValue >= byteValue)
+                goto _150069AE;
+
+            pItem2 = pItem2->prev;
+        }
+        // 150069AC
+        pItem3 = NULL;
+
+        _150069AE:
+        if(pItem2 == pItem1)
+            continue;
+
+        // 150069B2
+        // Switch pItem2 with item
+        InsertItem(&pItem305C, pItem2, SWITCH_ITEMS, pItem1);
+        InsertItem(&pItem305C, pItem1, SWITCH_ITEMS, pItem3);
+
+        // 150069D0
+        // Switch parents of pItem1 and pItem2
+        temp = pItem2->parent->child;
+        if(pItem1 == pItem1->parent->child)
+            pItem1->parent->child = pItem2;
+
+        if(pItem2 == temp)
+            pItem2->parent->child = pItem1;
+
+        // 150069ED
+        // Switch parents of pItem1 and pItem3
+        temp = pItem1->parent;
+        pItem1 ->parent = pItem2->parent;
+        pItem2->parent = temp;
+        offs0004++;
+    }
+    while(PTR_INT((pItem1 = pItem1->parent)) > 0);
+}
+*/
+
+THTreeItem * THuffmannTree::Call1500E740(unsigned int nValue)
+{
+    THTreeItem * pItem1 = pItem3058;    // EDX
+    THTreeItem * pItem2;                // EAX
+    THTreeItem * pNext;
+    THTreeItem * pPrev;
+    THTreeItem ** ppItem;
+
+    if(PTR_INT(pItem1) <= 0 || (pItem2 = pItem1) == NULL)
+    {
+        if((pItem2 = &items0008[nItems++]) != NULL)
+            pItem1 = pItem2;
+        else
+            pItem1 = pFirst;
+    }
+    else
+        pItem1 = pItem2;
+
+    pNext = pItem1->next;
+    if(pNext != NULL)
+    {
+        pPrev = pItem1->prev;
+        if(PTR_INT(pPrev) <= 0)
+            pPrev = PTR_NOT(pPrev);
+        else
+            pPrev += (pItem1 - pItem1->next->prev);
+
+        pPrev->next = pNext;
+        pNext->prev = pPrev;
+        pItem1->next = NULL;
+        pItem1->prev = NULL;
+    }
+
+    ppItem = &pFirst;       // esi
+    if(nValue > 1)
+    {
+        // ecx = pFirst->next;
+        pItem1->next = *ppItem;
+        pItem1->prev = (*ppItem)->prev;
+
+        (*ppItem)->prev = pItem2;
+        *ppItem = pItem1;
+
+        pItem2->parent = NULL;
+        pItem2->child  = NULL;
+    }
+    else
+    {
+        pItem1->next = (THTreeItem *)ppItem;
+        pItem1->prev = ppItem[1];
+        // edi = pItem305C;
+        pPrev = ppItem[1];      // ecx
+        if(pPrev <= 0)
+        {
+            pPrev = PTR_NOT(pPrev);
+            pPrev->next = pItem1;
+            pPrev->prev = pItem2;
+
+            pItem2->parent = NULL;
+            pItem2->child  = NULL;
+        }
+        else
+        {
+            if(PTR_INT(pItem305C) < 0)
+                pPrev += (THTreeItem *)ppItem - (*ppItem)->prev;
+            else
+                pPrev += PTR_INT(pItem305C);
+
+            pPrev->next    = pItem1;
+            ppItem[1]      = pItem2;
+            pItem2->parent = NULL;
+            pItem2->child  = NULL;
+        }
+    }
+    return pItem2;
+}
+
+void THuffmannTree::Call1500E820(THTreeItem * pItem)
+{
+    THTreeItem * pItem1;                // edi
+    THTreeItem * pItem2 = NULL;         // eax
+    THTreeItem * pItem3;                // edx
+    THTreeItem * pPrev;                 // ebx
+
+    for(; pItem != NULL; pItem = pItem->parent)
+    {
+        pItem->byteValue++;
+        
+        for(pItem1 = pItem; ; pItem1 = pPrev)
+        {
+            pPrev = pItem1->prev;
+            if(PTR_INT(pPrev) <= 0)
+            {
+                pPrev = NULL;
+                break;
+            }
+
+            if(pPrev->byteValue >= pItem->byteValue)
+                break;
+        }
+
+        if(pItem1 == pItem)
+            continue;
+
+        if(pItem1->next != NULL)
+        {
+            pItem2 = pItem1->GetPrevItem(-1);
+            pItem2->next = pItem1->next;
+            pItem1->next->prev = pItem1->prev;
+            pItem1->next = NULL;
+            pItem1->prev = NULL;
+        }
+
+        pItem2 = pItem->next;
+        pItem1->next = pItem2;
+        pItem1->prev = pItem2->prev;
+        pItem2->prev = pItem1;
+        pItem->next = pItem1;
+        if((pItem2 = pItem1) != NULL)
+        {
+            pItem2 = pItem->GetPrevItem(-1);
+            pItem2->next = pItem->next;
+            pItem->next->prev = pItem->prev;
+            pItem->next = NULL;
+            pItem->prev = NULL;
+        }
+
+        if(pPrev == NULL)
+            pPrev = PTR_PTR(&pFirst);
+
+        pItem2       = pPrev->next;
+        pItem->next  = pItem2;
+        pItem->prev  = pItem2->prev;
+        pItem2->prev = pItem;
+        pPrev->next  = pItem;
+
+        pItem3 = pItem1->parent->child;
+        pItem2 = pItem->parent;
+        if(pItem2->child == pItem)
+            pItem2->child = pItem1;
+        if(pItem3 == pItem1)
+            pItem1->parent->child = pItem;
+
+        pItem2 = pItem->parent;
+        pItem->parent  = pItem1->parent;
+        pItem1->parent = pItem2;
+        offs0004++;
+    }
+}
+
+// 1500E920
+unsigned int THuffmannTree::DoCompression(TOutputStream * os, unsigned char * pbInBuffer, int nInLength, int nCmpType)
+{
+    THTreeItem  * pItem1;
+    THTreeItem  * pItem2;
+    THTreeItem  * pItem3;
+    THTreeItem  * pTemp;
+    unsigned long dwBitBuff;
+    unsigned int  nBits;
+    unsigned int  nBit;
+
+    BuildTree(nCmpType);
+    bIsCmp0 = (nCmpType == 0);
+
+    // Store the compression type into output buffer
+    os->dwBitBuff |= (nCmpType << os->nBits);
+    os->nBits     += 8;
+
+    // Flush completed bytes
+    while(os->nBits >= 8)
+    {
+        if(os->dwOutSize != 0)
+        {
+            *os->pbOutPos++ = (unsigned char)os->dwBitBuff;
+            os->dwOutSize--;
+        }
+
+        os->dwBitBuff >>= 8;
+        os->nBits      -= 8;
+    }
+
+    for(; nInLength != 0; nInLength--)
+    {
+        unsigned char bOneByte = *pbInBuffer++;
+
+        if((pItem1 = items306C[bOneByte]) == NULL)
+        {
+            pItem2    = items306C[0x101];  // ecx
+            pItem3    = pItem2->parent;    // eax
+            dwBitBuff = 0;
+            nBits     = 0;
+
+            for(; pItem3 != NULL; pItem3 = pItem3->parent)
+            {
+                nBit      = (pItem3->child != pItem2) ? 1 : 0;
+                dwBitBuff = (dwBitBuff << 1) | nBit;
+                nBits++;
+                pItem2  = pItem3;
+            }
+            os->PutBits(dwBitBuff, nBits);
+
+            // Store the loaded byte into output stream
+            os->dwBitBuff |= (bOneByte << os->nBits);
+            os->nBits     += 8;
+
+            // Flush the whole byte(s)
+            while(os->nBits >= 8)
+            {
+                if(os->dwOutSize != 0)
+                {
+                    *os->pbOutPos++ = (unsigned char)os->dwBitBuff;
+                    os->dwOutSize--;
+                }
+                os->dwBitBuff >>= 8;
+                os->nBits -= 8;
+            }
+
+            pItem1 = (PTR_INT(pLast) <= 0) ? NULL : pLast;
+            pItem2 = Call1500E740(1);
+            pItem2->dcmpByte  = pItem1->dcmpByte;
+            pItem2->byteValue = pItem1->byteValue;
+            pItem2->parent    = pItem1;
+            items306C[pItem2->dcmpByte] = pItem2;
+
+            pItem2 = Call1500E740(1);
+            pItem2->dcmpByte  = bOneByte;
+            pItem2->byteValue = 0;
+            pItem2->parent    = pItem1;
+            items306C[pItem2->dcmpByte] = pItem2;
+            pItem1->child = pItem2;
+
+            Call1500E820(pItem2);
+
+            if(bIsCmp0 != 0)
+            {
+                Call1500E820(items306C[bOneByte]);
+                continue;
+            }
+
+            for(pItem1 = items306C[bOneByte]; pItem1 != NULL; pItem1 = pItem1->parent)
+            {
+                pItem1->byteValue++;
+                pItem2 = pItem1;
+
+                for(;;)
+                {
+                    pItem3 = pItem2->prev;
+                    if(PTR_INT(pItem3) <= 0)
+                    {
+                        pItem3 = NULL;
+                        break;
+                    }
+                    if(pItem3->byteValue >= pItem1->byteValue)
+                        break;
+                    pItem2 = pItem3;
+                }
+
+                if(pItem2 != pItem1)
+                {
+                    InsertItem(&pItem305C, pItem2, SWITCH_ITEMS, pItem1);
+                    InsertItem(&pItem305C, pItem1, SWITCH_ITEMS, pItem3);
+
+                    pItem3 = pItem2->parent->child;
+                    if(pItem1->parent->child == pItem1)
+                        pItem1->parent->child = pItem2;
+
+                    if(pItem3 == pItem2)
+                        pItem2->parent->child = pItem1;
+
+                    pTemp = pItem1->parent;
+                    pItem1->parent = pItem2->parent;
+                    pItem2->parent = pTemp;
+                    offs0004++;
+                }
+            }
+        }
+// 1500EB62
+        else
+        {
+            dwBitBuff = 0;
+            nBits = 0;
+            for(pItem2 = pItem1->parent; pItem2 != NULL; pItem2 = pItem2->parent)
+            {
+                nBit      = (pItem2->child != pItem1) ? 1 : 0;
+                dwBitBuff = (dwBitBuff << 1) | nBit;
+                nBits++;
+                pItem1    = pItem2;
+            }
+            os->PutBits(dwBitBuff, nBits);
+        }
+
+// 1500EB98
+        if(bIsCmp0 != 0)
+            Call1500E820(items306C[bOneByte]);  // 1500EB9D
+// 1500EBAF
+    } // for(; nInLength != 0; nInLength--)
+
+// 1500EBB8
+    pItem1 = items306C[0x100];
+    dwBitBuff = 0;
+    nBits = 0;
+    for(pItem2 = pItem1->parent; pItem2 != NULL; pItem2 = pItem2->parent)
+    {
+        nBit      = (pItem2->child != pItem1) ? 1 : 0;
+        dwBitBuff = (dwBitBuff << 1) | nBit;
+        nBits++;
+        pItem1    = pItem2;
+    }
+
+// 1500EBE6
+    os->PutBits(dwBitBuff, nBits);
+
+// 1500EBEF
+    // Flush the remaining bits
+    while(os->nBits != 0)
+    {
+        if(os->dwOutSize != 0)
+        {
+            *os->pbOutPos++ = (unsigned char)os->dwBitBuff;
+            os->dwOutSize--;
+        }
+        os->dwBitBuff >>= 8;
+        os->nBits -= ((os->nBits > 8) ? 8 : os->nBits);
+    }
+
+    return (os->pbOutPos - os->pbOutBuffer);
+}
+
+// Decompression using Huffman tree (1500E450)
+unsigned int THuffmannTree::DoDecompression(unsigned char * pbOutBuffer, unsigned int dwOutLength, TInputStream * is)
+{
+    TQDecompress  * qd;
+    THTreeItem    * pItem1;
+    THTreeItem    * pItem2;
+    unsigned char * pbOutPos = pbOutBuffer;
+    unsigned long nBitCount;
+    unsigned int nDcmpByte = 0;
+    unsigned int n8Bits;                // 8 bits loaded from input stream
+    unsigned int n7Bits;                // 7 bits loaded from input stream
+    bool bHasQdEntry;
+    
+    // Test the output length. Must not be NULL.
+    if(dwOutLength == 0)
+        return 0;
+
+    // Get the compression type from the input stream
+    n8Bits = is->Get8Bits();
+
+    // Build the Huffman tree
+    BuildTree(n8Bits);     
+    bIsCmp0 = (n8Bits == 0) ? 1 : 0;
+
+    for(;;)
+    {
+        n7Bits = is->Get7Bits();            // Get 7 bits from input stream
+
+        // Try to use quick decompression. Check TQDecompress array for corresponding item.
+        // If found, ise the result byte instead.
+        qd = &qd3474[n7Bits];
+
+        // If there is a quick-pass possible (ebx)
+        bHasQdEntry = (qd->offs00 >= offs0004) ? true : false;
+
+        // If we can use quick decompress, use it.
+        if(bHasQdEntry)
+        {
+            if(qd->nBits > 7)
+            {
+                is->dwBitBuff >>= 7;
+                is->nBits -= 7;
+                pItem1 = qd->pItem;
+                goto _1500E549;
+            }
+            is->dwBitBuff >>= qd->nBits;
+            is->nBits -= qd->nBits;
+            nDcmpByte = qd->dcmpByte;
+        }
+        else
+        {
+            pItem1 = pFirst->next->prev;
+            if(PTR_INT(pItem1) <= 0)
+                pItem1 = NULL;
+_1500E549:            
+            nBitCount = 0;
+            pItem2 = NULL;
+
+            do
+            {
+                pItem1 = pItem1->child;     // Move down by one level
+                if(is->GetBit())            // If current bit is set, move to previous
+                    pItem1 = pItem1->prev;
+
+                if(++nBitCount == 7)        // If we are at 7th bit, save current HTree item.
+                    pItem2 = pItem1;
+            }
+            while(pItem1->child != NULL);   // Walk until tree has no deeper level
+
+            if(bHasQdEntry == false)
+            {
+                if(nBitCount > 7)
+                {
+                    qd->offs00 = offs0004;
+                    qd->nBits  = nBitCount;
+                    qd->pItem  = pItem2;
+                }
+                else
+                {
+                    unsigned long nIndex = n7Bits & (0xFFFFFFFF >> (32 - nBitCount));
+                    unsigned long nAdd   = (1 << nBitCount);
+                    
+                    for(qd = &qd3474[nIndex]; nIndex <= 0x7F; nIndex += nAdd, qd += nAdd)
+                    {
+                        qd->offs00   = offs0004;
+                        qd->nBits    = nBitCount;
+                        qd->dcmpByte = pItem1->dcmpByte;
+                    }
+                }
+            }
+            nDcmpByte = pItem1->dcmpByte;
+        }
+
+        if(nDcmpByte == 0x101)          // Huffman tree needs to be modified
+        {
+            n8Bits = is->Get8Bits();
+            pItem1 = (pLast <= 0) ? NULL : pLast;
+
+            pItem2 = Call1500E740(1);
+            pItem2->parent    = pItem1;
+            pItem2->dcmpByte  = pItem1->dcmpByte;
+            pItem2->byteValue = pItem1->byteValue;
+            items306C[pItem2->dcmpByte] = pItem2;
+
+            pItem2 = Call1500E740(1);
+            pItem2->parent    = pItem1;
+            pItem2->dcmpByte  = n8Bits;
+            pItem2->byteValue = 0;
+            items306C[pItem2->dcmpByte] = pItem2;
+
+            pItem1->child = pItem2;
+            Call1500E820(pItem2);
+            if(bIsCmp0 == 0)
+                Call1500E820(items306C[n8Bits]);
+
+            nDcmpByte = n8Bits;
+        }
+
+        if(nDcmpByte == 0x100)
+            break;
+
+        *pbOutPos++ = (unsigned char)nDcmpByte;
+        if(--dwOutLength == 0)
+            break;
+
+        if(bIsCmp0)
+            Call1500E820(items306C[nDcmpByte]);
+    }
+
+    return (pbOutPos - pbOutBuffer);
+}
+
+/* OLD VERSION
+unsigned int THuffmannTree::DoDecompression(unsigned char * pbOutBuffer, unsigned int dwOutLength, TInputStream * is)
+{
+    THTreeItem  * pItem1;               // Current item if walking HTree
+    unsigned long bitCount;             // Bit counter if walking HTree
+    unsigned long oneByte;              // 8 bits from bit stream/Pointer to target
+    unsigned char * outPtr;             // Current pointer to output buffer
+    bool          hasQDEntry;           // true if entry for quick decompression if filled
+    THTreeItem  * itemAt7 = NULL;       // HTree item found at 7th bit
+    THTreeItem  * temp;                 // For every use
+    unsigned long dcmpByte = 0;         // Decompressed byte value
+    bool          bFlag = 0;
+    
+    // Test the output length. Must not be NULL.
+    if(dwOutLength == 0)
+        return 0;
+
+    // If too few bits in input bit buffer, we have to load next 16 bits
+    is->EnsureHasMoreThan8Bits();
+
+    // Get 8 bits from input stream
+    oneByte = is->Get8Bits();
+
+    // Build the Huffman tree
+    BuildTree(oneByte);     
+
+    bIsCmp0 = (oneByte == 0) ? 1 : 0;
+    outPtr  = pbOutBuffer;              // Copy pointer to output data
+
+    for(;;)
+    {
+        TQDecompress * qd;              // For quick decompress
+        unsigned long sevenBits = is->Get7Bits();// 7 bits from input stream
+
+        // Try to use quick decompression. Check TQDecompress array for corresponding item.
+        // If found, ise the result byte instead.
+        qd = &qd3474[sevenBits];
+
+        // If there is a quick-pass possible
+        hasQDEntry = (qd->offs00 == offs0004) ? 1 : 0;
+
+        // Start passing the Huffman tree. Set item to tree root item
+        pItem1 = pFirst;
+
+        // If we can use quick decompress, use it.
+        bFlag = 1;
+        if(hasQDEntry == 1)
+        {
+            // Check the bit count is greater than 7, move item to 7 levels deeper
+            if((bitCount = qd->bitCount) > 7)
+            {
+                is->dwBitBuff >>= 7;
+                is->nBits  -= 7;
+                pItem1      = qd->item; // Don't start with root item, but with some deeper-laying
+            }
+            else
+            {
+                // If OK, use their byte value
+                is->dwBitBuff >>= bitCount;
+                is->nBits  -= bitCount;
+                dcmpByte    = qd->dcmpByte;
+                bFlag       = 0;
+            }
+        }
+        else
+        {
+            pItem1 = pFirst->next->prev;
+            if(PTR_INT(pItem1) <= 0)
+                pItem1 = NULL;
+        }
+
+        if(bFlag == 1)
+        {
+            // Walk through Huffman Tree
+            bitCount = 0;               // Clear bit counter
+            do
+            {
+                pItem1 = pItem1->child;     
+                if(is->GetBit() != 0)   // If current bit is set, move to previous
+                    pItem1 = pItem1->prev;  // item in current level
+
+                if(++bitCount == 7)     // If we are at 7th bit, store current HTree item.
+                    itemAt7 = pItem1;   // Store Huffman tree item
+            }
+            while(pItem1->child != NULL); // Walk until tree has no deeper level
+
+            // If quick decompress entry is not filled yet, fill it.
+            if(hasQDEntry == 0)
+            {
+                if(bitCount > 7)        // If we passed more than 7 bits, store bitCount and item
+                {
+                    qd->offs00   = offs0004;   // Value indicates that entry is resolved
+                    qd->bitCount = bitCount;   // Number of bits passed
+                    qd->item     = itemAt7;    // Store item at 7th bit
+                }
+                // If we passed less than 7 bits, fill entry and bit count multipliers
+                else                    
+                {
+                    unsigned long index = sevenBits & (0xFFFFFFFF >> (32 - bitCount)); // Index for quick-decompress entry
+                    unsigned long addIndex = (1 << bitCount);                          // Add value for index
+
+                    qd = &qd3474[index];
+
+                    do
+                    {
+                        qd->offs00   = offs0004;
+                        qd->bitCount = bitCount;
+                        qd->dcmpByte = pItem1->dcmpByte;
+
+                        index += addIndex;
+                        qd    += addIndex;
+                    }
+                    while(index <= 0x7F);
+                }
+            }
+            dcmpByte = pItem1->dcmpByte;
+        }
+
+        if(dcmpByte == 0x101)        // Huffman tree needs to be modified
+        {
+            // Check if there is enough bits in the buffer
+            is->EnsureHasMoreThan8Bits();
+
+            // Get 8 bits from the buffer
+            oneByte = is->Get8Bits();
+
+            // Modify Huffman tree
+            ModifyTree(oneByte);
+
+            // Get lastly added tree item
+            pItem1 = items306C[oneByte];
+
+            if(bIsCmp0 == 0 && pItem1 != NULL)
+            {
+                // 15006F15
+                do
+                {
+                    THTreeItem * pItem2 = pItem1;
+                    THTreeItem * pItem3;
+                    unsigned long byteValue;
+
+                    byteValue = ++pItem1->byteValue;
+
+                    while(PTR_INT((pItem3 = pItem2->prev)) > 0)
+                    {
+                        if(pItem3->byteValue >= byteValue)
+                            goto _15006F30;
+
+                        pItem2 = pItem2->prev;
+                    }
+                    pItem3 = NULL;
+
+                    _15006F30:
+                    if(pItem2 == pItem1)
+                        continue;
+
+                    InsertItem(&pItem305C, pItem2, SWITCH_ITEMS, pItem1);
+                    InsertItem(&pItem305C, pItem1, SWITCH_ITEMS, pItem3);
+
+                    temp = pItem2->parent->child;
+                    if(pItem1 == pItem1->parent->child)
+                        pItem1->parent->child = pItem2;
+
+                    if(pItem2 == temp)
+                        pItem2->parent->child = pItem1;
+
+                    // Switch parents of pItem1 and pItem3
+                    temp = pItem1->parent;
+                    pItem1->parent = pItem2->parent;
+                    pItem2->parent = temp;
+                    offs0004++;
+                }
+                while(PTR_INT((pItem1 = pItem1->parent)) > 0);
+            }
+            dcmpByte = oneByte;
+        }
+
+        if(dcmpByte != 0x100)        // Not at the end of data ?
+        {
+            *outPtr++ = (unsigned char)dcmpByte;
+            if(--dwOutLength > 0)
+            {
+                if(bIsCmp0 != 0)
+                    Call1500E820(items306C[pItem1->byteValue]);
+            }                    
+            else
+                break;
+        }
+        else
+            break;
+    }
+    return (unsigned long)(outPtr - pbOutBuffer);
+}
+*/
+
+// Table for (de)compression. Every compression type has 258 entries
+unsigned char THuffmannTree::Table1502A630[] = 
+{
+    // Data for compression type 0x00
+    0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00,
+    
+    // Data for compression type 0x01
+    0x54, 0x16, 0x16, 0x0D, 0x0C, 0x08, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x04, 0x04, 0x03, 0x05, 
+    0x0E, 0x0B, 0x14, 0x13, 0x13, 0x09, 0x0B, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 
+    0x0D, 0x07, 0x09, 0x06, 0x06, 0x04, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 
+    0x09, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04, 
+    0x08, 0x03, 0x04, 0x07, 0x09, 0x05, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 
+    0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 
+    0x06, 0x0A, 0x08, 0x08, 0x06, 0x07, 0x04, 0x03, 0x04, 0x04, 0x02, 0x02, 0x04, 0x02, 0x03, 0x03, 
+    0x04, 0x03, 0x07, 0x07, 0x09, 0x06, 0x04, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 
+    0x0A, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x03, 0x05, 0x02, 0x03, 
+    0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01, 
+    0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x09, 0x08, 0x0C, 0x02, 
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 
+    0x04, 0x01, 0x02, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 
+    0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+    0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+    0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x4B, 
+    0x00, 0x00,
+    
+    // Data for compression type 0x02
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00, 0x23, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x06, 0x0E, 0x10, 0x04, 
+    0x06, 0x08, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01, 
+    0x01, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x03, 0x02, 
+    0x03, 0x01, 0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 
+    0x01, 0x29, 0x07, 0x16, 0x12, 0x40, 0x0A, 0x0A, 0x11, 0x25, 0x01, 0x03, 0x17, 0x10, 0x26, 0x2A, 
+    0x10, 0x01, 0x23, 0x23, 0x2F, 0x10, 0x06, 0x07, 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00,
+    
+    // Data for compression type 0x03
+    0xFF, 0x0B, 0x07, 0x05, 0x0B, 0x02, 0x02, 0x02, 0x06, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x03, 
+    0x09, 0x01, 0x01, 0x01, 0x03, 0x04, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 
+    0x05, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+    0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 
+    0x0A, 0x04, 0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 
+    0x05, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03, 
+    0x01, 0x03, 0x01, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x03, 0x05, 0x01, 0x03, 0x01, 0x03, 0x03, 
+    0x02, 0x01, 0x04, 0x03, 0x0A, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+    0x02, 0x02, 0x01, 0x0A, 0x02, 0x05, 0x01, 0x01, 0x02, 0x07, 0x02, 0x17, 0x01, 0x05, 0x01, 0x01, 
+    0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+    0x06, 0x02, 0x01, 0x04, 0x05, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 
+    0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 
+    0x00, 0x00,
+    
+    // Data for compression type 0x04
+    0xFF, 0xFB, 0x98, 0x9A, 0x84, 0x85, 0x63, 0x64, 0x3E, 0x3E, 0x22, 0x22, 0x13, 0x13, 0x18, 0x17, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00,
+    
+    // Data for compression type 0x05
+    0xFF, 0xF1, 0x9D, 0x9E, 0x9A, 0x9B, 0x9A, 0x97, 0x93, 0x93, 0x8C, 0x8E, 0x86, 0x88, 0x80, 0x82, 
+    0x7C, 0x7C, 0x72, 0x73, 0x69, 0x6B, 0x5F, 0x60, 0x55, 0x56, 0x4A, 0x4B, 0x40, 0x41, 0x37, 0x37, 
+    0x2F, 0x2F, 0x27, 0x27, 0x21, 0x21, 0x1B, 0x1C, 0x17, 0x17, 0x13, 0x13, 0x10, 0x10, 0x0D, 0x0D, 
+    0x0B, 0x0B, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x04, 0x19, 0x18, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00,
+    
+    // Data for compression type 0x06
+    0xC3, 0xCB, 0xF5, 0x41, 0xFF, 0x7B, 0xF7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0xBF, 0xCC, 0xF2, 0x40, 0xFD, 0x7C, 0xF7, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x7A, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00,
+    
+    // Data for compression type 0x07
+    0xC3, 0xD9, 0xEF, 0x3D, 0xF9, 0x7C, 0xE9, 0x1E, 0xFD, 0xAB, 0xF1, 0x2C, 0xFC, 0x5B, 0xFE, 0x17, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0xBD, 0xD9, 0xEC, 0x3D, 0xF5, 0x7D, 0xE8, 0x1D, 0xFB, 0xAE, 0xF0, 0x2C, 0xFB, 0x5C, 0xFF, 0x18, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x70, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00,
+    
+    // Data for compression type 0x08
+    0xBA, 0xC5, 0xDA, 0x33, 0xE3, 0x6D, 0xD8, 0x18, 0xE5, 0x94, 0xDA, 0x23, 0xDF, 0x4A, 0xD1, 0x10, 
+    0xEE, 0xAF, 0xE4, 0x2C, 0xEA, 0x5A, 0xDE, 0x15, 0xF4, 0x87, 0xE9, 0x21, 0xF6, 0x43, 0xFC, 0x12, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0xB0, 0xC7, 0xD8, 0x33, 0xE3, 0x6B, 0xD6, 0x18, 0xE7, 0x95, 0xD8, 0x23, 0xDB, 0x49, 0xD0, 0x11, 
+    0xE9, 0xB2, 0xE2, 0x2B, 0xE8, 0x5C, 0xDD, 0x15, 0xF1, 0x87, 0xE7, 0x20, 0xF7, 0x44, 0xFF, 0x13, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x5F, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00
+};
diff --git a/huffman.h b/huffman.h
new file mode 100644 (file)
index 0000000..f13104c
--- /dev/null
+++ b/huffman.h
@@ -0,0 +1,133 @@
+/*****************************************************************************/
+/* huffman.h                              Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Description :                                                             */
+/*---------------------------------------------------------------------------*/
+/*   Date    Ver   Who  Comment                                              */
+/* --------  ----  ---  -------                                              */
+/* xx.xx.xx  1.00  Lad  The first version of huffman.h                       */
+/* 03.05.03  2.00  Lad  Added compression                                    */
+/*****************************************************************************/
+
+#ifndef __HUFFMAN_H__
+#define __HUFFMAN_H__
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define INSERT_ITEM    1                    
+#define SWITCH_ITEMS   2                    // Switch the item1 and item2
+
+#define PTR_NOT(ptr)  (THTreeItem *)(~(unsigned long)(ptr))
+#define PTR_PTR(ptr)  ((THTreeItem *)(ptr))
+#define PTR_INT(ptr)  (long)(ptr)
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+//-----------------------------------------------------------------------------
+// Structures and classes
+
+// Input stream for Huffmann decompression
+class TInputStream
+{
+    public:
+
+    unsigned long GetBit();
+    unsigned long Get7Bits();
+    unsigned long Get8Bits();
+
+    unsigned char * pbInBuffer;         // 00 - Input data
+    unsigned long   dwBitBuff;          // 04 - Input bit buffer
+    unsigned int    nBits;              // 08 - Number of bits remaining in 'dwValue'
+};
+
+// Output stream for Huffmann compression
+class TOutputStream
+{
+    public:
+  
+    void PutBits(unsigned long dwBuff, unsigned int nPutBits);
+
+    unsigned char * pbOutBuffer;        // 00 : Output buffer
+    unsigned long   dwOutSize;          // 04 : Size of output buffer
+    unsigned char * pbOutPos;           // 08 : Current output position
+    unsigned long   dwBitBuff;          // 0C : Bit buffer
+    unsigned long   nBits;              // 10 : Number of bits in the bit buffer
+};
+
+// Huffmann tree item (?)
+struct THTreeItem
+{
+    public:
+
+    THTreeItem * Call1501DB70(THTreeItem * pLast);
+    THTreeItem * GetPrevItem(long value);
+    void         ClearItemLinks();
+    void         RemoveItem();
+
+    THTreeItem  * next;                 // 00 - Pointer to next THTreeItem
+    THTreeItem  * prev;                 // 04 - Pointer to prev THTreeItem (< 0 if none)
+    unsigned long dcmpByte;             // 08 - Index of this item in item pointer array, decompressed byte value
+    unsigned long byteValue;            // 0C - Some byte value
+    THTreeItem  * parent;               // 10 - Pointer to parent THTreeItem (NULL if none)
+    THTreeItem  * child;                // 14 - Pointer to child  THTreeItem
+};
+
+// Structure used for quick decompress. The 'bitCount' contains number of bits
+// and byte value contains result decompressed byte value.
+// After each walk through Huffman tree are filled all entries which are
+// multiplies of number of bits loaded from input stream. These entries
+// contain number of bits and result value. At the next 7 bits is tested this
+// structure first. If corresponding entry found, decompression routine will
+// not walk through Huffman tree and directly stores output byte to output stream.
+struct TQDecompress
+{
+    unsigned long offs00;               // 00 - 1 if resolved
+    unsigned long nBits;                // 04 - Bit count
+    union
+    {
+        unsigned long dcmpByte;         // 08 - Byte value for decompress (if bitCount <= 7)
+        THTreeItem  * pItem;            // 08 - THTreeItem (if number of bits is greater than 7
+    };
+};
+
+// Structure for Huffman tree (Size 0x3674 bytes). Because I'm not expert
+// for the decompression, I do not know actually if the class is really a Hufmann 
+// tree. If someone knows the decompression details, please let me know
+class THuffmannTree
+{
+    public: 
+
+    void  BuildTree(unsigned int nCmpType);
+//  void  ModifyTree(unsigned long dwIndex);
+//  void  Call15007010(Bit32 dwInLength, THTreeItem * item);
+    THTreeItem * Call1500E740(unsigned int nValue);
+    void         Call1500E820(THTreeItem * pItem);
+    unsigned int DoCompression(TOutputStream * os, unsigned char * pbInBuffer, int nInLength, int nCmpType);
+    unsigned int DoDecompression(unsigned char * pbOutBuffer, unsigned int dwOutLength, TInputStream * is);
+
+    unsigned long bIsCmp0;              // 0000 - 1 if compression type 0
+    unsigned long offs0004;             // 0004 - Some flag
+    THTreeItem    items0008[0x203];     // 0008 - HTree items
+
+    //- Sometimes used as HTree item -----------
+    THTreeItem  * pItem3050;            // 3050 - Always NULL (?)
+    THTreeItem  * pItem3054;            // 3054 - Pointer to Huffman tree item
+    THTreeItem  * pItem3058;            // 3058 - Pointer to Huffman tree item (< 0 if invalid)
+
+    //- Sometimes used as HTree item -----------
+    THTreeItem  * pItem305C;            // 305C - Usually NULL
+    THTreeItem  * pFirst;               // 3060 - Pointer to top (first) Huffman tree item
+    THTreeItem  * pLast;                // 3064 - Pointer to bottom (last) Huffman tree item (< 0 if invalid)
+    unsigned long nItems;               // 3068 - Number of used HTree items
+
+    //-------------------------------------------
+    THTreeItem * items306C[0x102];      // 306C - THTreeItem pointer array
+    TQDecompress qd3474[0x80];          // 3474 - Array for quick decompression
+
+    static unsigned char Table1502A630[];// Some table
+};
+
+#endif // __HUFFMAN_H__
diff --git a/implode.c b/implode.c
new file mode 100644 (file)
index 0000000..bfdea1e
--- /dev/null
+++ b/implode.c
@@ -0,0 +1,660 @@
+/*****************************************************************************/
+/* implode.c                              Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Implode function of PKWARE Data Compression library                       */
+/*---------------------------------------------------------------------------*/
+/*   Date    Ver   Who              Comment                                  */
+/* --------  ----  ---              -------                                  */
+/* 11.04.03  1.00  Ladislav Zezula  First version of implode.c               */
+/* 02.05.03  1.00  Ladislav Zezula  Stress test done                         */
+/* 12.06.03  1.00  ShadowFlare      Fixed error in WriteCmpData that caused  */
+/*                                  different output to be produced          */
+/*****************************************************************************/
+
+#include "pklib.h"
+#include "SMem.h"
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define DICT_OFFSET   0x204
+#define UNCMP_OFFSET  (pWork->dsize_bytes + DICT_OFFSET)
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+// Compression structure (Size 36312 bytes)
+typedef struct
+{
+    unsigned int   offs0000;            // 0000 : 
+    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 : Dict size : 4=0x400, 5=0x800, 6=0x1000
+    unsigned int   dsize_mask;          // 0010 : Dict size : 0x0F=0x400, 0x1F=0x800, 0x3F=0x1000
+    unsigned int   ctype;               // 0014 : Compression type (Ascii or 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 : 
+    unsigned short nChCodes[0x306];     // 03A2 : 
+    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 offs0DC8[0x900];     // 0DC8 :
+    unsigned short offs1FC8;            // 1FC8 : 
+    char           out_buff[0x802];     // 1FCA : Output (compressed) data
+    unsigned char  work_buff[0x2204];   // 27CC : Work buffer
+                                        //  + DICT_OFFSET  => Dictionary
+                                        //  + UNCMP_OFFSET => Uncompressed data
+    unsigned short offs49D0[0x2000];    // 49D0 : 
+} TCmpStruct;
+
+//-----------------------------------------------------------------------------
+// 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  
+};
+
+//-----------------------------------------------------------------------------
+// Local variables
+
+static char Copyright[] = "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";
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static void SortBuffer(TCmpStruct * pWork, unsigned char * uncmp_data, unsigned char * work_end)
+{
+    unsigned short * pin0DC8;
+    unsigned char  * puncmp;
+    unsigned long    offs1, offs2;
+    unsigned long    ndwords;
+    unsigned int     add;
+
+    // Fill 0x480 dwords (0x1200 bytes)
+    ndwords = (pWork->out_buff - (char *)pWork->offs0DC8 + 1) >> 2;
+    if(ndwords <= 1)
+        ndwords = 1;
+    SMemZero(pWork->offs0DC8, ndwords << 2);
+
+    for(puncmp = uncmp_data; work_end > puncmp; puncmp++)
+        pWork->offs0DC8[(puncmp[0] * 4) + (puncmp[1] * 5)]++;
+
+    add = 0;
+    for(pin0DC8 = pWork->offs0DC8; pin0DC8 < &pWork->offs1FC8; pin0DC8++)
+    {
+        add     += *pin0DC8;
+        *pin0DC8 = (unsigned short)add;
+    }
+
+    for(work_end--; work_end >= uncmp_data; work_end--)
+    {
+        offs1 = (work_end[0] * 4) + (work_end[1] * 5);  // EAX
+        offs2 = (work_end - pWork->work_buff);          // EDI
+
+        pWork->offs0DC8[offs1]--;
+        pWork->offs49D0[pWork->offs0DC8[offs1]] = (unsigned short)offs2;
+    }
+}
+
+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;
+
+    SMemZero(pWork->out_buff, 0x802);
+
+    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);
+}
+
+static unsigned long FindRep(TCmpStruct * pWork, unsigned char * srcbuff)
+{
+    unsigned short  esp12;
+    unsigned char * esp14;
+    unsigned short  esp18;
+    unsigned char * srcbuff2;
+    unsigned char   esp20;
+
+    unsigned char  * srcbuff3;
+    unsigned short * pin0DC8;
+    unsigned char  * pin27CC;
+    unsigned short * pin49D0;
+    unsigned long    nreps = 1;         // EAX
+    unsigned long    ebx, esi;
+    unsigned short   di;
+
+    pin0DC8 = pWork->offs0DC8 + (srcbuff[0] * 4) + (srcbuff[1] * 5);
+    esi     = (srcbuff - pWork->dsize_bytes) - pWork->work_buff + 1;
+    esp18   = *pin0DC8;
+    pin49D0 = pWork->offs49D0 + esp18;
+
+    if(*pin49D0 < esi)
+    {
+        while(*pin49D0 < esi)
+        {
+            pin49D0++;
+            esp18++;
+        }
+        *pin0DC8 = esp18;
+    }
+//---------------------------------------------------------------------------
+    srcbuff2 = srcbuff - 1;
+    pin49D0  = pWork->offs49D0 + esp18;
+    pin27CC  = pWork->work_buff + *pin49D0;
+    if(srcbuff2 <= pin27CC)
+        return 0;
+//---------------------------------------------------------------------------
+    srcbuff3 = srcbuff;
+    for(;;)
+    {
+        if(srcbuff3[nreps-1] == pin27CC[nreps-1] && *srcbuff3 == *pin27CC)
+        {
+            pin27CC++;
+            srcbuff3++;
+            for(ebx = 2; ebx < DICT_OFFSET; ebx++)
+            {
+                pin27CC++;
+                srcbuff3++;
+                if(*pin27CC != *srcbuff3)
+                    break;
+            }
+
+            srcbuff3 = srcbuff;
+            if(ebx >= nreps)
+            {
+                pWork->offs0000 = srcbuff3 - pin27CC + ebx - 1;
+                if((nreps = ebx) > 10)
+                    break;
+            }
+        }
+
+        pin49D0++;
+        esp18++;
+        pin27CC = pWork->work_buff + *pin49D0;
+
+        if(srcbuff2 > pin27CC)
+            continue;
+
+        return (nreps >= 2) ? nreps : 0;
+    }
+//---------------------------------------------------------------------------
+    if(ebx == DICT_OFFSET)
+    {
+        pWork->offs0000--;
+        return ebx;
+    }
+//---------------------------------------------------------------------------
+    pin49D0 = pWork->offs49D0 + esp18;
+    if(pWork->work_buff + pin49D0[1] >= srcbuff2)
+        return nreps;
+//---------------------------------------------------------------------------
+    di = 0;
+    pWork->offs09BC[0] = 0xFFFF;
+    pWork->offs09BC[1] = di;
+    esp12 = 1;
+
+    do
+    {
+        esi = di;
+        if(srcbuff[esp12] != srcbuff[esi])
+        {
+            di = pWork->offs09BC[esi];
+            if(di != 0xFFFF)
+                continue;
+        }
+        pWork->offs09BC[++esp12] = ++di;
+    }
+    while(esp12 < nreps);
+//---------------------------------------------------------------------------
+    esi     = nreps;
+    pin27CC = pWork->work_buff + pin49D0[0] + nreps;
+    esp14   = pin27CC;
+    
+    for(;;)   // 0040268B
+    {
+        esi = pWork->offs09BC[esi];
+        if(esi == 0xFFFF)
+            esi = 0;
+
+        pin49D0 = pWork->offs49D0 + esp18;
+        do
+        {
+            pin49D0++;
+            esp18++;
+            pin27CC = pWork->work_buff + pin49D0[0];
+            if(pin27CC >= srcbuff2)
+                return nreps;
+        }
+        while(pin27CC + esi < esp14);
+//---------------------------------------------------------------------------
+        esp20 = srcbuff[nreps - 2];
+        if(esp20 == pin27CC[nreps - 2])
+        {
+            if(pin27CC + esi != esp14)
+            {
+                esp14 = pin27CC;
+                esi = 0;
+            }
+        }
+        else
+        {
+            pin49D0 = pWork->offs49D0 + esp18;
+            do
+            {
+                pin49D0++;
+                esp18++;
+                pin27CC = pWork->work_buff + pin49D0[0];
+                if(pin27CC >= srcbuff2)
+                    return nreps;
+            }
+            while(pin27CC[nreps - 2] != esp20 || pin27CC[0] != *srcbuff);
+
+            esp14 = pin27CC + 2;
+            esi   = 2;
+        }
+//---------------------------------------------------------------------------
+        for(; esp14[0] == srcbuff[esi]; esp14++)
+        {
+            if(++esi >= DICT_OFFSET)
+                break;
+        }
+
+        if(esi < nreps)
+            continue;
+        pWork->offs0000 = srcbuff - pin27CC - 1;
+        if(esi <= nreps)
+            continue;
+        nreps = esi;
+        if(esi == DICT_OFFSET)
+            return nreps;
+
+        do
+        {
+            if(srcbuff[esp12] != srcbuff[di])
+            {
+                di = pWork->offs09BC[di];
+                if(di != 0xFFFF)
+                    continue;
+            }
+            pWork->offs09BC[++esp12] = ++di;
+        }
+        while(esp12 < esi);
+    }
+}
+
+static void WriteCmpData(TCmpStruct * pWork)
+{
+    unsigned int    nreps = 0;          // ESP+10 : Number of repeats
+    unsigned char * uncmp_end;          // ESP+14 : End of uncompressed data
+    unsigned int    esp18 = 0;          // ESP+18 :
+    unsigned int    bytes_required;     // ESP+1C : Number of bytes required to read
+    unsigned int    esp20 = 0;          // ESP+20 :
+    unsigned char * uncmp_begin = &pWork->work_buff[UNCMP_OFFSET]; // EDI
+    unsigned long   nreps1;
+    unsigned long   save_offs0000 = 0;
+    int total_loaded = 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
+    SMemZero(&pWork->out_buff[2], sizeof(pWork->out_buff) - 2);
+    pWork->out_bits = 0;
+
+    do {
+        total_loaded = 0;
+        bytes_required = 0x1000;
+
+        do {
+            int loaded = pWork->read_buf(&pWork->work_buff[UNCMP_OFFSET + total_loaded], &bytes_required, pWork->param);
+
+            if (loaded == 0) {
+                if (total_loaded == 0 && esp20 == 0) {
+                    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;
+                }
+
+                esp18 = 1;
+                break;
+            }
+
+            total_loaded += loaded;
+            bytes_required -= loaded;
+        } while (bytes_required);
+
+        uncmp_end = &pWork->work_buff[pWork->dsize_bytes + total_loaded];
+
+        if (esp18 != 0)
+            uncmp_end += DICT_OFFSET;
+
+        if (esp20) {
+            if (esp20 == 1) {
+                SortBuffer(pWork, uncmp_begin - pWork->dsize_bytes + DICT_OFFSET, uncmp_end + 1);
+                ++esp20;
+            }
+            else {
+                SortBuffer(pWork, uncmp_begin - pWork->dsize_bytes, uncmp_end + 1);
+            }
+        }
+        else {
+            SortBuffer(pWork, uncmp_begin, uncmp_end + 1);
+            ++esp20;
+
+            if (pWork->dsize_bytes != 0x1000)
+                ++esp20;
+        }
+
+        while (uncmp_end > uncmp_begin) {
+            nreps1 = FindRep(pWork, uncmp_begin);
+
+            while (nreps1) {
+                if (nreps1 == 2 && pWork->offs0000 >= 0x100)
+                    break;
+
+                if (esp18 != 0 && uncmp_begin + nreps1 > uncmp_end) {
+                    if ((nreps1 = uncmp_end - uncmp_begin) < 2)
+                        break;
+
+                    if (nreps1 != 2 || pWork->offs0000 < 0x100)
+                        goto loc_15036C7F;
+
+                    break;
+                }
+
+                if (nreps1 >= 8 || uncmp_begin + 1 >= uncmp_end)
+                    goto loc_15036C7F;
+
+                save_offs0000 = pWork->offs0000;    // ebp
+                nreps = nreps1;
+                nreps1 = FindRep(pWork, uncmp_begin + 1);
+
+                if (nreps >= nreps1)
+                    goto loc_15036C79;
+
+                if (nreps + 1 >= nreps1 && save_offs0000 <= 0x80)
+                    goto loc_15036C79;
+
+                OutputBits(pWork, pWork->nChBits[*uncmp_begin], pWork->nChCodes[*uncmp_begin]);
+                ++uncmp_begin;
+            }
+
+            OutputBits(pWork, pWork->nChBits[*uncmp_begin], pWork->nChCodes[*uncmp_begin]);
+            ++uncmp_begin;
+            continue;
+
+loc_15036C79:
+            nreps1 = nreps;
+            pWork->offs0000 = save_offs0000;
+
+loc_15036C7F:
+            OutputBits(pWork, pWork->nChBits[nreps1 + 0xFE], pWork->nChCodes[nreps1 + 0xFE]);
+
+            if (nreps1 == 2) {
+                OutputBits(pWork, pWork->dist_bits[pWork->offs0000 >> 2], pWork->dist_codes[pWork->offs0000 >> 2]);
+                OutputBits(pWork, 2, pWork->offs0000 & 3);
+            }
+            else {
+                OutputBits(pWork, pWork->dist_bits[pWork->offs0000 >> pWork->dsize_bits], pWork->dist_codes[pWork->offs0000 >> pWork->dsize_bits]);
+                OutputBits(pWork, pWork->dsize_bits, pWork->offs0000 & pWork->dsize_mask);
+            }
+
+            uncmp_begin += nreps1;
+        }
+
+        if (esp18 != 0) {
+            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;
+        }
+
+        uncmp_begin -= 0x1000;
+        SMemCopy(pWork->work_buff, &pWork->work_buff[0x1000], UNCMP_OFFSET);
+    } while (esp18 == 0);
+}
+
+//-----------------------------------------------------------------------------
+// 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;
+
+    // Fill the work buffer information
+    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 0x1000 :
+            pWork->dsize_bits++;
+            pWork->dsize_mask |= 0x20;
+            // No break here !!!
+
+        case 0x0800 :
+            pWork->dsize_bits++;
+            pWork->dsize_mask |= 0x10;
+            // No break here !!!
+
+        case 0x0400 :
+            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++)
+    {
+        int nCount2 = 0;    // EBX 
+
+        if((1 << ExLenBits[i]) == 0)
+            continue;
+
+        do
+        {
+            pWork->nChBits[nCount]  = (unsigned char)(ExLenBits[i] + LenBits[i] + 1);
+            pWork->nChCodes[nCount] = (unsigned short)((nCount2 << (LenBits[i] + 1)) | ((LenCode[i] & 0xFFFF00FF) * 2) | 1);
+
+            nCount2++;
+            nCount++;
+        }
+        while((1 << ExLenBits[i]) > nCount2);
+    }
+
+    // Copy the distance codes and distance bits and perform the compression
+    SMemCopy(&pWork->dist_codes, DistCode, sizeof(DistCode));
+    SMemCopy(&pWork->dist_bits, DistBits, sizeof(DistBits));
+    WriteCmpData(pWork);
+    return CMP_NO_ERROR;
+}
diff --git a/license.txt b/license.txt
new file mode 100644 (file)
index 0000000..94d5ecb
--- /dev/null
@@ -0,0 +1,24 @@
+Copyright (c) 2002-2008, ShadowFlare <blakflare@hotmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
\ No newline at end of file
diff --git a/pklib.h b/pklib.h
new file mode 100644 (file)
index 0000000..bbc345b
--- /dev/null
+++ b/pklib.h
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/* 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__
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define CMP_BUFFER_SIZE    36312        // Size of compression buffer
+#define EXP_BUFFER_SIZE    12596        // Size of decompress buffer
+
+#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 calling convention
+
+#define PKEXPORT
+//#define PKEXPORT  __cdecl               // Use for normal __cdecl calling 
+//#define PKEXPORT  __stdcall
+//#define PKEXPORT  __fastcall
+
+//-----------------------------------------------------------------------------
+// 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 crc32pk(char *buffer, unsigned int *size, unsigned long *old_crc);
+
+#ifdef __cplusplus
+   }                         // End of 'extern "C"' declaration
+#endif
+
+#endif // __PKLIB_H__
diff --git a/wave.cpp b/wave.cpp
new file mode 100644 (file)
index 0000000..374b07a
--- /dev/null
+++ b/wave.cpp
@@ -0,0 +1,360 @@
+/*****************************************************************************/
+/* wave.cpp                               Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* This module contains decompression methods used by Storm.dll to decompress*/
+/* WAVe files. Thanks to Tom Amigo for releasing his sources.                */
+/*---------------------------------------------------------------------------*/
+/*   Date    Ver   Who  Comment                                              */
+/* --------  ----  ---  -------                                              */
+/* 11.03.03  1.00  Lad  Splitted from Pkware.cpp                             */
+/* 20.05.03  2.00  Lad  Added compression                                    */
+/*****************************************************************************/
+
+#include "wave.h"
+
+//------------------------------------------------------------------------------
+// Structures
+
+union TByteAndWordPtr
+{
+    unsigned short * pw;
+    unsigned char  * pb;
+};
+
+//-----------------------------------------------------------------------------
+// Tables necessary dor decompression
+
+static unsigned long Table1503F120[] =
+{
+    0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000006,
+    0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
+    0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,  
+    0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000006, 0xFFFFFFFF, 0x00000008  
+};
+
+static unsigned long Table1503F1A0[] =
+{
+    0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E,
+    0x00000010, 0x00000011, 0x00000013, 0x00000015, 0x00000017, 0x00000019, 0x0000001C, 0x0000001F,
+    0x00000022, 0x00000025, 0x00000029, 0x0000002D, 0x00000032, 0x00000037, 0x0000003C, 0x00000042,
+    0x00000049, 0x00000050, 0x00000058, 0x00000061, 0x0000006B, 0x00000076, 0x00000082, 0x0000008F,
+    0x0000009D, 0x000000AD, 0x000000BE, 0x000000D1, 0x000000E6, 0x000000FD, 0x00000117, 0x00000133,
+    0x00000151, 0x00000173, 0x00000198, 0x000001C1, 0x000001EE, 0x00000220, 0x00000256, 0x00000292,
+    0x000002D4, 0x0000031C, 0x0000036C, 0x000003C3, 0x00000424, 0x0000048E, 0x00000502, 0x00000583,
+    0x00000610, 0x000006AB, 0x00000756, 0x00000812, 0x000008E0, 0x000009C3, 0x00000ABD, 0x00000BD0,
+    0x00000CFF, 0x00000E4C, 0x00000FBA, 0x0000114C, 0x00001307, 0x000014EE, 0x00001706, 0x00001954,
+    0x00001BDC, 0x00001EA5, 0x000021B6, 0x00002515, 0x000028CA, 0x00002CDF, 0x0000315B, 0x0000364B,
+    0x00003BB9, 0x000041B2, 0x00004844, 0x00004F7E, 0x00005771, 0x0000602F, 0x000069CE, 0x00007462,
+    0x00007FFF
+};
+
+//----------------------------------------------------------------------------
+// CompressWave
+
+int CompressWave(unsigned char * pbOutBuffer, int dwOutLength, short * pwInBuffer, int dwInLength, int nChannels, int nCmpLevel)
+{
+    TByteAndWordPtr out;                // Output buffer
+    long     nArray3[2];                // EBP-48
+    long     nArray2[2];                // EBP-40
+    long     nArray1[2];                // EBP-38
+    long     nWords;                    // EBP-30
+    unsigned EBP2C;                     // EBP-2C
+    long     nRemains = dwOutLength;    // EBP-28 : Number of bytes remaining
+    long     nCmpType2;                 // EBP-24
+    unsigned dwStopBit;                 // EBP-20
+    long     EBP1C;                     // EBP-1C
+    unsigned dwBitBuff;                 // EBP-18
+//  char   * pbOutPos = pbOutBuffer;    // EBP-14 : Saved pointer to the output buffer
+    long     nLength;                   // EBP-10 :
+    long     nIndex;                    // EBP-0C : 
+//  short  * pwOutPos = pwInBuffer;     // EBP-08 : Current output pointer
+                                        // EBP-04 :
+    unsigned short wCmp;                // EBP-02 : 
+    unsigned dwBit;                     // EBP+08 : A Bit
+    long    nTableValue;
+    long    nOneWord;
+    long    nValue;
+
+    if(dwInLength < 2)
+        return 2;
+
+    // ebx = nChannels;
+    wCmp = (unsigned char)(nCmpLevel - 1);
+    out.pb = pbOutBuffer;
+    *out.pb++ = 0;
+    *out.pb++ = (unsigned char)wCmp;
+
+    if((out.pb - pbOutBuffer + nChannels * 2) > nRemains)
+        return out.pb - pbOutBuffer + nChannels * 2;
+
+    nArray1[0] = nArray1[1] = 0x2C;
+
+    if(nChannels > 0)
+    {
+        for(int i = 0; i < nChannels; i++)
+        {
+            nOneWord = *pwInBuffer++;
+            *out.pw++ = (unsigned short)nOneWord;
+            nArray2[i] = nOneWord;
+        }
+    }
+
+    nLength = dwInLength;
+    if(nLength < 0)      // mov eax, dwInLength; cdq; sub eax, edx;
+        nLength++;
+    nLength   = (nLength / 2) - (out.pb - pbOutBuffer);
+    nLength   = (nLength < 0) ? 0 : nLength;
+    nCmpType2 = nChannels;
+
+    nIndex    = nChannels - 1;         // edi
+    nWords    = dwInLength / 2;       // eax
+    if(nWords <= nChannels)
+        return out.pb - pbOutBuffer;
+
+    // ebx - nChannels
+    // ecx - pwOutPos
+    do // 1500F02D
+    {
+        if((out.pb - pbOutBuffer + 2) > nRemains)
+            return out.pb - pbOutBuffer + 2;
+
+        if(nChannels == 2)
+            nIndex = (nIndex == 0) ? 1 : 0;
+
+        nOneWord = *pwInBuffer++;   // ecx - nOneWord
+        // esi - nArray2[nIndex]
+        nValue   = nOneWord - nArray2[nIndex];
+        if(nValue < 0)
+            nValue = ~nValue + 1;   // eax
+
+        unsigned ebx = (nOneWord >= nArray2[nIndex]) ? 1 : 0;
+        // esi - nArray1[nIndex]
+        // edx - Table1503F1A0[nArray1[nIndex]]
+        nArray3[nIndex] = nOneWord;
+
+        // edi - Table1503F1A0[nArray1[nIndex]] >> nCmpLevel
+        ebx = (ebx - 1) & 0x40;
+        dwStopBit = nCmpLevel;
+
+        // edi - nIndex;
+        nTableValue = Table1503F1A0[nArray1[nIndex]];
+        if(nValue < (nTableValue >> nCmpLevel))
+        {
+            if(nArray1[nIndex] != 0)
+                nArray1[nIndex]--;
+            *out.pb++ = 0x80;
+        }
+        else
+        {
+            while(nValue > nTableValue * 2)
+            { // 1500F0C0
+                if(nArray1[nIndex] >= 0x58 || nLength == 0)
+                    break;
+
+                nArray1[nIndex] += 8;
+                if(nArray1[nIndex] > 0x58)
+                    nArray1[nIndex] = 0x58;
+
+                nTableValue = Table1503F1A0[nArray1[nIndex]];
+                *out.pb++ = 0x81;
+                nLength--;
+            }
+
+            dwBitBuff = 0;
+            EBP2C     = nTableValue >> wCmp;
+            unsigned esi = 1 << (dwStopBit - 2);
+            EBP1C     = 0;
+            dwBit     = 1;
+            dwStopBit = 0x20;
+
+            if(esi <= 0x20)
+                dwStopBit = esi;
+            for(;;)
+            {
+//              esi = EBP1C + nTableValue;
+                if((EBP1C + nTableValue) <= nValue)
+                {
+                    EBP1C += nTableValue;
+                    dwBitBuff |= dwBit;
+                }
+                if(dwBit == dwStopBit)
+                    break;
+
+                nTableValue >>= 1;
+                dwBit       <<= 1;
+            }
+
+            nValue = nArray2[nIndex];
+            if(ebx != 0)
+            {
+                nValue -= (EBP1C + EBP2C);
+                if(nValue < (int)0xFFFF8000)
+                    nValue = (int)0xFFFF8000;
+            }
+            else
+            {
+                nValue += (EBP1C + EBP2C);
+                if(nValue > 0x00007FFF)
+                    nValue = 0x00007FFF;
+            }
+
+            nArray2[nIndex]  = nValue;
+            *out.pb++ = (unsigned char)(dwBitBuff | ebx);
+            nTableValue      = Table1503F120[dwBitBuff & 0x1F];
+            nArray1[nIndex] += nTableValue; 
+            if(nArray1[nIndex] < 0)
+                nArray1[nIndex] = 0;
+            else if(nArray1[nIndex] > 0x58)
+                nArray1[nIndex] = 0x58;
+        }
+        // 1500F1D8
+    }
+    while(++nCmpType2 < nWords);
+    
+    return out.pb - pbOutBuffer;
+}
+
+//----------------------------------------------------------------------------
+// DecompressWave
+
+// 1500F230
+int DecompressWave(unsigned char * pbOutBuffer, int dwOutLength, unsigned char * pbInBuffer, int dwInLength, int nChannels)
+{
+    TByteAndWordPtr out;
+    TByteAndWordPtr in;
+    unsigned char * pbInEnd = pbInBuffer + dwInLength;  // End on input buffer
+    unsigned long index;
+    long nArray1[2];
+    long nArray2[2];
+
+    out.pb     = pbOutBuffer;
+    in.pb      = pbInBuffer;
+    nArray1[0] = 0x2C;
+    nArray1[1] = 0x2C;
+    in.pw++;
+
+    // 15007AD7
+    if(nChannels > 0)
+    {
+        for(int count = 0; count < nChannels; count++)
+        {
+            long temp;
+
+            temp = *(short *)in.pw++;
+            nArray2[count] = temp;
+
+            if(dwOutLength < 2)
+                return out.pb - pbOutBuffer;
+
+            *out.pw++    = (unsigned short)temp;
+            dwOutLength -= 2;
+        }
+    }
+
+    index = nChannels - 1;
+    while(in.pb < pbInEnd)
+    {
+        unsigned char oneByte = *in.pb++;
+
+        if(nChannels == 2)
+            index = (index == 0) ? 1 : 0;
+
+        // Get one byte from input buffer
+        // 15007B25
+        if(oneByte & 0x80)
+        {
+            // 15007B32
+            switch(oneByte & 0x7F)
+            {
+                case 0:     // 15007B8E
+                    if(nArray1[index] != 0)
+                        nArray1[index]--;
+
+                    if(dwOutLength < 2)
+                        break;
+
+                    *out.pw++ = (unsigned short)nArray2[index];
+                    dwOutLength -= 2;
+                    continue;
+
+                case 1:     // 15007B72
+                    nArray1[index] += 8;   // EBX also
+                    if(nArray1[index] > 0x58)
+                        nArray1[index] = 0x58;
+                    if(nChannels == 2)
+                        index = (index == 0) ? 1 : 0;
+                    continue;
+
+                case 2:
+                    continue;
+
+                default:
+                    nArray1[index] -= 8;
+                    if(nArray1[index] < 0)
+                        nArray1[index] = 0;
+
+                    if(nChannels != 2)
+                        continue;
+
+                    index = (index == 0) ? 1 : 0;
+                    continue;
+            }
+        }
+        else
+        {
+            unsigned long temp1 = Table1503F1A0[nArray1[index]]; // EDI
+            unsigned long temp2 = temp1 >> pbInBuffer[1];      // ESI
+            long  temp3 = nArray2[index];                // ECX
+
+            if(oneByte & 0x01)          // EBX = oneByte
+                temp2 += (temp1 >> 0);
+
+            if(oneByte & 0x02)
+                temp2 += (temp1 >> 1);
+
+            if(oneByte & 0x04)
+                temp2 += (temp1 >> 2);
+
+            if(oneByte & 0x08)
+                temp2 += (temp1 >> 3);
+
+            if(oneByte & 0x10)
+                temp2 += (temp1 >> 4);
+
+            if(oneByte & 0x20)
+                temp2 += (temp1 >> 5);
+
+            if(oneByte & 0x40)
+            {
+                temp3 -= temp2;
+                if(temp3 <= (long)0xFFFF8000)
+                    temp3 = (long)0xFFFF8000;
+            }
+            else
+            {
+                temp3 += temp2;
+                if(temp3 >= 0x7FFF)
+                    temp3 = 0x7FFF;
+            }
+            nArray2[index] = temp3;
+            if(dwOutLength < 2)
+                break;
+
+            temp2 = nArray1[index];
+            oneByte &= 0x1F;
+            
+            *out.pw++ = (unsigned short)temp3;
+            dwOutLength -= 2;
+
+            temp2 += Table1503F120[oneByte];
+            nArray1[index] = temp2;
+
+            if(nArray1[index] < 0)
+                nArray1[index] = 0;
+            else if(nArray1[index] > 0x58)
+                nArray1[index] = 0x58;
+        }
+    }
+    return (out.pb - pbOutBuffer);
+}
+
diff --git a/wave.h b/wave.h
new file mode 100644 (file)
index 0000000..f4ae687
--- /dev/null
+++ b/wave.h
@@ -0,0 +1,20 @@
+/*****************************************************************************/
+/* Wave.h                                 Copyright (c) Ladislav Zezula 2003 */
+/*---------------------------------------------------------------------------*/
+/* Header file for WAVe unplode functions                                    */
+/*---------------------------------------------------------------------------*/
+/*   Date    Ver   Who  Comment                                              */
+/* --------  ----  ---  -------                                              */
+/* 31.03.03  1.00  Lad  The first version of Wave.h                          */
+/*****************************************************************************/
+
+#ifndef __WAVE_H__
+#define __WAVE_H__
+
+//-----------------------------------------------------------------------------
+// Functions
+
+int  CompressWave  (unsigned char * pbOutBuffer, int dwOutLength, short * pwInBuffer, int dwInLength, int nChannels, int nCmpLevel);
+int  DecompressWave(unsigned char * pbOutBuffer, int dwOutLength, unsigned char * pbInBuffer, int dwInLength, int nChannels);
+
+#endif // __WAVE_H__
diff --git a/wintypes.h b/wintypes.h
new file mode 100644 (file)
index 0000000..dd411d3
--- /dev/null
@@ -0,0 +1,38 @@
+// wintypes.h - Windows data types
+// (when not compiling for Windows)
+// License information for this code is in license.txt
+
+#ifndef WIN_TYPES_INCLUDED
+#define WIN_TYPES_INCLUDED
+
+#define WINAPI
+#define CDECL
+#define __fastcall
+
+#define CONST const
+
+typedef void VOID;
+typedef void *LPVOID;
+typedef CONST void *LPCVOID;
+typedef const char *LPCSTR;
+typedef unsigned char BYTE;
+typedef BYTE *LPBYTE;
+typedef unsigned short WORD;
+typedef WORD *LPWORD;
+typedef short SHORT;
+typedef unsigned long DWORD;
+typedef DWORD *LPDWORD;
+typedef long LONG;
+typedef LONG *LPLONG;
+
+typedef int BOOL;
+typedef int (WINAPI *FARPROC)();
+
+#define FALSE 0
+#define TRUE 1
+
+#define ERROR_NOT_ENOUGH_MEMORY          8L
+#define ERROR_INVALID_PARAMETER          87L
+
+#endif
+
diff --git a/zconf.h b/zconf.h
new file mode 100644 (file)
index 0000000..eb0ae2e
--- /dev/null
+++ b/zconf.h
@@ -0,0 +1,279 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_ z_deflateInit_
+#  define deflate      z_deflate
+#  define deflateEnd   z_deflateEnd
+#  define inflateInit_         z_inflateInit_
+#  define inflate      z_inflate
+#  define inflateEnd   z_inflateEnd
+#  define deflateInit2_        z_deflateInit2_
+#  define deflateSetDictionary z_deflateSetDictionary
+#  define deflateCopy  z_deflateCopy
+#  define deflateReset z_deflateReset
+#  define deflateParams        z_deflateParams
+#  define inflateInit2_        z_inflateInit2_
+#  define inflateSetDictionary z_inflateSetDictionary
+#  define inflateSync  z_inflateSync
+#  define inflateSyncPoint z_inflateSyncPoint
+#  define inflateReset z_inflateReset
+#  define compress     z_compress
+#  define compress2    z_compress2
+#  define uncompress   z_uncompress
+#  define adler32      z_adler32
+#  define crc32                z_crc32
+#  define get_crc_table z_get_crc_table
+
+#  define Byte         z_Byte
+#  define uInt         z_uInt
+#  define uLong                z_uLong
+#  define Bytef                z_Bytef
+#  define charf                z_charf
+#  define intf         z_intf
+#  define uIntf                z_uIntf
+#  define uLongf       z_uLongf
+#  define voidpf       z_voidpf
+#  define voidp                z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#  define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
+#  define STDC
+#endif
+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
+#  ifndef STDC
+#    define STDC
+#  endif
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Old Borland C incorrectly complains about missing returns: */
+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+#  define NEED_DUMMY_RETURN
+#endif
+
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+   /* MSC small or medium model */
+#  define SMALL_MEDIUM
+#  ifdef _MSC_VER
+#    define FAR _far
+#  else
+#    define FAR far
+#  endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+#  ifndef __32BIT__
+#    define SMALL_MEDIUM
+#    define FAR _far
+#  endif
+#endif
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if defined(ZLIB_DLL)
+#  if defined(_WINDOWS) || defined(WINDOWS)
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+#    define ZEXPORT  WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA  WINAPIV
+#    else
+#      define ZEXPORTVA  FAR _cdecl _export
+#    endif
+#  endif
+#  if defined (__BORLANDC__)
+#    if (__BORLANDC__ >= 0x0500) && defined (WIN32)
+#      include <windows.h>
+#      define ZEXPORT __declspec(dllexport) WINAPI
+#      define ZEXPORTRVA __declspec(dllexport) WINAPIV
+#    else
+#      if defined (_Windows) && defined (__DLL__)
+#        define ZEXPORT _export
+#        define ZEXPORTVA _export
+#      endif
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  if defined (ZLIB_DLL)
+#    define ZEXTERN extern __declspec(dllexport)
+#  else
+#    define ZEXTERN extern __declspec(dllimport)
+#  endif
+#endif
+
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+
+#ifndef FAR
+#   define FAR
+#endif
+
+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  define z_off_t  off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define  z_off_t long
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(inflate_blocks,"INBL")
+#   pragma map(inflate_blocks_new,"INBLNE")
+#   pragma map(inflate_blocks_free,"INBLFR")
+#   pragma map(inflate_blocks_reset,"INBLRE")
+#   pragma map(inflate_codes_free,"INCOFR")
+#   pragma map(inflate_codes,"INCO")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_flush,"INFLU")
+#   pragma map(inflate_mask,"INMA")
+#   pragma map(inflate_set_dictionary,"INSEDI2")
+#   pragma map(inflate_copyright,"INCOPY")
+#   pragma map(inflate_trees_bits,"INTRBI")
+#   pragma map(inflate_trees_dynamic,"INTRDY")
+#   pragma map(inflate_trees_fixed,"INTRFI")
+#   pragma map(inflate_trees_free,"INTRFR")
+#endif
+
+#endif /* _ZCONF_H */
diff --git a/zlib.h b/zlib.h
new file mode 100644 (file)
index 0000000..52cb529
--- /dev/null
+++ b/zlib.h
@@ -0,0 +1,893 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.4, March 11th, 2002
+
+  Copyright (C) 1995-2002 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 ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.4"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/* 
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  the compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+  
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/* 
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may some
+  introduce some output latency (reading input without producing any output)
+  except when forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+  output as possible to the output buffer. The flushing behavior of inflate is
+  not specified for values of the flush parameter other than Z_SYNC_FLUSH
+  and Z_FINISH, but the current implementation actually flushes as much output
+  as possible anyway.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+     If a preset dictionary is needed at this point (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the
+  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
+  it sets strm->adler to the adler32 checksum of all output produced
+  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+  an error code as described below. At the end of the stream, inflate()
+  checks that its computed adler32 checksum is equal to that saved by the
+  compressor and returns Z_STREAM_END only if the checksum is correct.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect
+  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+  case, the application may then call inflateSync to look for a good
+  compression block.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*   
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+                            
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                     int level,
+                                     int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+/*   
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. If a compressed stream with a larger window size is given as
+   input, inflate() will return with the error code Z_DATA_ERROR instead of
+   trying to allocate a larger window.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate
+   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the Adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/* 
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least 0.1% larger than
+   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h". (See the description
+   of deflateInit2 for more information about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file, 
+                                  const voidp buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
+                                     z_off_t offset, int whence));
+/* 
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running crc with the bytes buf[0..len-1] and return the updated
+   crc. If buf is NULL, this function returns the required initial value
+   for the crc. Pre- and post-conditioning (one's complement) is performed
+   within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int err));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */