/**
* =============================================================================
* Yak's gunzip // Stripped down to inflate algorithm only. Reading and writing to array. -- Peace-Maker
* - inflate algorithm ported from Mark Adler's puff.c (zlib/contrib/puff)
* Copyright (C) 2011 Zach "theY4Kman" Kanzler
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see .
*/
#define GZ_STATE_OUTLEN 0
#define GZ_STATE_OUTPOS 1
#define GZ_STATE_INLEN 2
#define GZ_STATE_INPOS 3
#define GZ_STATE_BITBUF 4
#define GZ_STATE_BITCNT 5
#define GZ_STATE_ERROR 6
#define GZ_STATE_SIZE 7
#define GZ_STATE _state
#define GZ_STATE_DEF GZ_STATE[GZ_STATE_SIZE]
#define GZ_HUFF_COUNT huff_count
#define GZ_HUFF_SYMBOL huff_symbol
#define GZ_HUFF_DEF GZ_HUFF_COUNT[], GZ_HUFF_SYMBOL[]
// =============================================================================
// INFLATE-related defines
// =============================================================================
#define GZ_LAST_BLOCK 1
#define GZ_BLOCK_STORED 0
#define GZ_BLOCK_FIXED 1
#define GZ_BLOCK_DYNAMIC 2
#define GZ_BLOCK_RESERVED 3
#define GZ_MAXBITS 15 /* max bits in a code */
#define GZ_MAXLCODES 286 /* max number of literal/length codes */
#define GZ_MAXDCODES 30 /* max number of distance codes */
#define GZ_MAXCODES (GZ_MAXLCODES+GZ_MAXDCODES)
#define GZ_FIXLCODES 288 /* number of fixed literal/length codes */
// =============================================================================
// Error codes (see GetErrorMessage for messages)
// =============================================================================
#define GZ_ERROR_SUCCESS 0000
// 1-999: gzip errors
#define GZ_ERROR_BAD_MEMBER_HEADER 0001
#define GZ_ERROR_UNIMPLEMENTED_CM 0002
#define GZ_ERROR_BAD_BLOCK 0003
// 1000-1999: INFLATE-related errors
#define GZ_ERROR_HUFF_OUT_OF_CODES 1000
#define GZ_ERROR_INVALID_FIXED_CODE 1001
#define GZ_ERROR_HUFF_BAD_COUNTS 1002
#define GZ_ERROR_REQUIRE_COMPLETE_SET 1003
#define GZ_ERROR_TOO_MANY_LENGTHS 1004
#define GZ_ERROR_NO_END_OF_BLOCK_CODE 1005
#define GZ_ERROR_INCOMPLETE_ONLY_ONE 1006
#define GZ_ERROR_NO_LAST_LENGTH 1007
// >= 9000: library errors
#define GZ_ERROR_END_OF_FILE 9000
#define GZ_ERROR_INPUT_FILE_BAD 9001
#define GZ_ERROR_OUTPUT_FILE_BAD 9002
#define GZ_ERROR_NOT_IMPLEMENTED 9003
#if defined DEBUG
new Handle:g_hDbgFile;
#endif
stock UncompressBinary(iInput[], &length, iOutput[], &maxlength)
{
#if defined DEBUG
decl String:sPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, sizeof(sPath), "data/dbg.log");
g_hDbgFile = OpenFile(sPath, "w");
#endif
new GZ_STATE_DEF;
GZ_STATE[GZ_STATE_OUTLEN] = maxlength;
GZ_STATE[GZ_STATE_OUTPOS] = 0;
GZ_STATE[GZ_STATE_INLEN] = length;
GZ_STATE[GZ_STATE_INPOS] = 0;
GZ_STATE[GZ_STATE_BITBUF] = 0;
GZ_STATE[GZ_STATE_BITCNT] = 0;
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_SUCCESS;
#if defined DEBUG
#define __GZ_ERROR(%1) \
{ \
decl String:sError[256]; \
GetErrorMessage(%1, sError, sizeof(sError)); \
WriteFileLine(g_hDbgFile, sError); \
return -1; \
}
#else
#define __GZ_ERROR(%1) \
{ \
return -1; \
}
#endif
new iLast, iType, iErr;
new True = true;
while(True)
{
iLast = _gz_bits(_state, 1, iInput, iOutput);
if (iLast == -1 && GZ_STATE[GZ_STATE_ERROR])
__GZ_ERROR(GZ_STATE[GZ_STATE_ERROR])
iType = _gz_bits(_state, 2, iInput, iOutput);
if (iType == -1 && _state[GZ_STATE_ERROR])
__GZ_ERROR(GZ_STATE[GZ_STATE_ERROR])
switch (iType)
{
case GZ_BLOCK_STORED: iErr = _gz_stored(_state, iInput, iOutput);
case GZ_BLOCK_FIXED: iErr = _gz_fixed(_state, iInput, iOutput);
case GZ_BLOCK_DYNAMIC: iErr = _gz_dynamic(_state, iInput, iOutput);
default: {iErr = -1; GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_BAD_BLOCK;}
}
if(iErr == -1)
__GZ_ERROR(GZ_STATE[GZ_STATE_ERROR])
if(iLast)
break;
}
#if defined DEBUG
CloseHandle(g_hDbgFile);
#endif
if(iErr <= 0)
{
length = GZ_STATE[GZ_STATE_INPOS];
maxlength = GZ_STATE[GZ_STATE_OUTPOS];
}
return iErr;
}
/**
* Get the human-readable version of an error code.
*
* @param errcode The error code
* @param message A buffer to hold the error message
* @param maxlength The max number of chars to write to the buffer
* @return The number of characters written to the buffer.
*/
stock GetErrorMessage(errcode, String:message[], maxlength)
{
#define __GZ_ERRCPY(%1) return strcopy(message, maxlength, %1)
#define GZERR(%1,%2) case (%1): __GZ_ERRCPY(%2)
switch (errcode)
{
GZERR(GZ_ERROR_SUCCESS,"Success");
// Gzip errors
GZERR(GZ_ERROR_BAD_MEMBER_HEADER,"Bad member header");
GZERR(GZ_ERROR_UNIMPLEMENTED_CM,"Compression method not implemented");
GZERR(GZ_ERROR_BAD_BLOCK,"Bad compressed block");
// INFLATE-related errors
GZERR(GZ_ERROR_HUFF_OUT_OF_CODES,"Huffman decode: ran out of codes");
GZERR(GZ_ERROR_INVALID_FIXED_CODE,"Invalid fixed code");
GZERR(GZ_ERROR_HUFF_BAD_COUNTS,"Bad counts in dynamic block");
GZERR(GZ_ERROR_REQUIRE_COMPLETE_SET,"Require complete code set");
GZERR(GZ_ERROR_TOO_MANY_LENGTHS,"Too many lengths");
GZERR(GZ_ERROR_NO_END_OF_BLOCK_CODE,"No end-of-block code");
GZERR(GZ_ERROR_INCOMPLETE_ONLY_ONE,"Incomplete codes only allowed if just one code");
GZERR(GZ_ERROR_NO_LAST_LENGTH,"");
// Library errors
GZERR(GZ_ERROR_END_OF_FILE,"EOF reached unexpectedly");
GZERR(GZ_ERROR_INPUT_FILE_BAD,"Could not open input file");
GZERR(GZ_ERROR_OUTPUT_FILE_BAD,"Could not open output file");
GZERR(GZ_ERROR_NOT_IMPLEMENTED,"Feature not implemented");
}
__GZ_ERRCPY("Not an error");
}
#define _GZ_BITS(%1,%2,%3,%4) \
%1 = _gz_bits(_state, (%2), (%3), (%4)); \
if (%1 == -1 && GZ_STATE[GZ_STATE_ERROR]) \
return -1
stock _gz_bits(GZ_STATE_DEF, need, iInput[], iOutput[])
{
////////////////////////////////////////////////////////////////////////
#if defined DEBUG
WriteFileLine(g_hDbgFile, "bits(%d)", need);
#endif
decl val;
// Load at least `need` bits into val
val = GZ_STATE[GZ_STATE_BITBUF];
while (GZ_STATE[GZ_STATE_BITCNT] < need)
{
if (GZ_STATE[GZ_STATE_INPOS] >= GZ_STATE[GZ_STATE_INLEN])
{
/* Out of input */
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_END_OF_FILE;
return -1;
}
/////////////////////////////////////////////////////////////////////////
#if defined DEBUG2
new String:bitbuf[] = " ";
new String:valstr[] = " ";
for (new i=7; i>=0; i--)
{
bitbuf[7-i] = '0' + ((GZ_STATE[GZ_STATE_BITBUF] & (1<> i);
valstr[7-i] = '0' + ((val & (1<> i);
}
WriteFileLine(g_hDbgFile, " %-10s%-10s%-10s(%d)", "preread", valstr, bitbuf, GZ_STATE[GZ_STATE_BITCNT]);
#endif
/* Load eight bits */
val |= iInput[GZ_STATE[GZ_STATE_INPOS]++] << GZ_STATE[GZ_STATE_BITCNT];
GZ_STATE[GZ_STATE_BITCNT] += 8;
/////////////////////////////////////////////////////////////////////////
#if defined DEBUG2
for (new i=7; i>=0; i--)
{
bitbuf[7-i] = '0' + ((GZ_STATE[GZ_STATE_BITBUF] & (1<> i);
valstr[7-i] = '0' + ((val & (1<> i);
}
WriteFileLine(g_hDbgFile, " %-10s%-10s%-10s(%d)", "postread", valstr, bitbuf, GZ_STATE[GZ_STATE_BITCNT]);
#endif
}
/* Drop `need` bits and update buffer, always zero to seven bits left */
GZ_STATE[GZ_STATE_BITBUF] = (val >> need) & 0xFF;
GZ_STATE[GZ_STATE_BITCNT] -= need;
/* Return `need` bits, zeroing the bits above that */
new bits = val & ((1 << need) - 1);
/////////////////////////////////////////
new String:bin[] = " ";
new String:bitbuf[] = " ";
new String:valstr[] = " ";
for (new i=7; i>=0; i--)
{
bin[7-i] = i == need ? ' ' : '0' + ((bits & (1<> i);
bitbuf[7-i] = '0' + ((GZ_STATE[GZ_STATE_BITBUF] & (1<> i);
valstr[7-i] = '0' + ((val & (1<> i);
}
#if defined DEBUG2
WriteFileLine(g_hDbgFile, " %-10s%-10s%-10s(%-4d) (value: %d)", bin, valstr, bitbuf,
GZ_STATE[GZ_STATE_BITCNT], bits);
#endif
////////////////////////////////////////////////////////////////
#if defined DEBUG
WriteFileLine(g_hDbgFile, "ret: %d", bits);
#endif
return bits;
}
#define _GZ_BYTE(%1,%2,%3) \
%1 = _gz_byte(_state, false, (%2), (%3)); \
if (%1 == -1 && GZ_STATE[GZ_STATE_ERROR]) \
return -1
#define _GZ_BYTE_PEEK(%1,%2,%3) \
%1 = _gz_byte(_state, true, (%2), (%3)); \
if (%1 == -1 && GZ_STATE[GZ_STATE_ERROR]) \
return -1
stock _gz_byte(GZ_STATE_DEF, peek, iInput[], iOutput[])
{
//////////////////////////////////////////////////////////
#if defined DEBUG
WriteFileLine(g_hDbgFile, "byte at %d", GZ_STATE[GZ_STATE_INPOS]);
#endif
decl buf[1];
decl loc;
if (peek)
loc = GZ_STATE[GZ_STATE_INPOS];
if(GZ_STATE[GZ_STATE_INPOS] > GZ_STATE[GZ_STATE_INLEN])
{
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_END_OF_FILE;
return -1;
}
buf[0] = iInput[GZ_STATE[GZ_STATE_INPOS]];
GZ_STATE[GZ_STATE_INPOS]++;
if (peek)
GZ_STATE[GZ_STATE_INPOS] = loc;
return buf[0];
}
/*#define _GZ_BYTE_GET(%1,%2,%3,%4,%5,%6) \
%1 = _gz_byte_get(_state, (%2), (%3), (%4), (%5), (%6)); \
if (%1 == -1 && _state[GZ_STATE_ERROR]) \
return -1
stock _gz_byte_get(GZ_STATE_DEF, loc, seek, allow_invalid_distance, iInput[], iOutput[])
{
/////////////////////////////////////////////////////////////////////////////
#if defined DEBUG
WriteFileLine(g_hDbgFile, "byte_get(%d,%d) at %d", loc, seek,
GZ_STATE[GZ_STATE_INPOS]);////////////////////////////////////
#endif
// Initialize buf to 0
new buf[1];
new orig_loc = GZ_STATE[GZ_STATE_INPOS];
if(seek == SEEK_CUR)
GZ_STATE[GZ_STATE_INPOS] += loc;
else if(seek == SEEK_SET)
GZ_STATE[GZ_STATE_INPOS] = loc;
if(GZ_STATE[GZ_STATE_INPOS] > GZ_STATE[GZ_STATE_INLEN])
{
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_END_OF_FILE;
return -1;
}
buf[0] = iInput[GZ_STATE[GZ_STATE_INPOS]];
GZ_STATE[GZ_STATE_INPOS] = orig_loc;
return buf[0];
}*/
#define SLOW // FOR DEBUGGING PURPOSES ONLY
#if defined(SLOW)
stock _gz_decode(GZ_STATE_DEF, GZ_HUFF_DEF, iInput[], iOutput[])
{
#if defined DEBUG
WriteFileLine(g_hDbgFile, "decode");////////////////////////////////////
#endif
decl len, /* current number of bits in code */
count; /* number of codes of length `len` */
new code, /* `len` bits being decoded */
first, /* first code of length `len` */
index; /* index of first code of length `len` in symbol table */
for (len=1; len <= GZ_MAXBITS; len++)
{
decl bits;
_GZ_BITS(bits,1,iInput,iOutput);
/* get next bit */
code |= bits;
count = GZ_HUFF_COUNT[len];
if (code - count < first) /* if length `len`, return symbol */
return GZ_HUFF_SYMBOL[index + (code - first)];
index += count; /* else update for next length */
first += count;
first <<= 1;
code <<= 1;
}
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_HUFF_OUT_OF_CODES;
return -1; /* ran out of codes */
}
#endif
stock _gz_construct(GZ_HUFF_DEF, length[], n, iInput[], iOutput[])
{
#if defined DEBUG
WriteFileLine(g_hDbgFile, "construct n=%d", n);////////////////////////////////////
#endif
decl symbol; /* current symbol when stepping through length[] */
decl len; /* current length when stepping through GZ_HUFF_COUNT */
decl left; /* number of possible codes left of current length */
decl offs[GZ_MAXBITS + 1]; /* offsets in symbol table for each length */
/* count number of codes of each length */
for (len = 0; len <= GZ_MAXBITS; len++)
GZ_HUFF_COUNT[len] = 0;
for (symbol = 0; symbol < n; symbol++)
(GZ_HUFF_COUNT[length[symbol]])++; // assumes lengths are within bounds
/* No codes!*/
if (GZ_HUFF_COUNT[0] == n)
return 0; /* complete, but _gz_decode() will fail */
/* Check for an over-subscribed or incomplete set of lengths */
left = 1; /* one possible code of zero length */
for (len = 1; len <= GZ_MAXBITS; len++) {
left <<= 1; /* one more bit, double codes left */
left -= GZ_HUFF_COUNT[len]; /* deduct count from possible codes */
if (left < 0) return left; /* over-subscribed--return negative */
} /* left > 0 means incomplete */
/* generate offsets into symbol table for each length for sorting */
offs[1] = 0;
for (len = 1; len < GZ_MAXBITS; len++)
offs[len + 1] = offs[len] + GZ_HUFF_COUNT[len];
/* put symbols in table sorted by length, by symbol order within each
* length
*/
for (symbol = 0; symbol < n; symbol++)
if (length[symbol] != 0)
GZ_HUFF_SYMBOL[offs[length[symbol]]++] = symbol;
#if defined DEBUG
WriteFileLine(g_hDbgFile, "left=%d", left);////////////////////////////////////
#endif
/* return zero for complete set, positive for incomplete set */
return left;
}
/* represents two huffman struct { short *count; short *symbol; } */
#define GZ_HUFF_LEN_COUNT huff_len_count
#define GZ_HUFF_LEN_SYMBOL huff_len_symbol
#define GZ_HUFF_LEN_DEF GZ_HUFF_LEN_COUNT[], GZ_HUFF_LEN_SYMBOL[]
#define GZ_HUFF_DIST_COUNT huff_dist_count
#define GZ_HUFF_DIST_SYMBOL huff_dist_symbol
#define GZ_HUFF_DIST_DEF GZ_HUFF_DIST_COUNT[], GZ_HUFF_DIST_SYMBOL[]
stock _gz_codes(GZ_STATE_DEF, GZ_HUFF_LEN_DEF, GZ_HUFF_DIST_DEF, iInput[], iOutput[])
{
#if defined DEBUG
WriteFileLine(g_hDbgFile, "codes");////////////////////////////////////
#endif
decl symbol; /* decoded symbol */
decl len; /* length for copy */
decl dist; /* distance for copy */
static lens[29] = { /* Size base for length codes 257..285 */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 };
static lext[29] = { /* Extra bits for length codes 257..285 */
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static dists[30] = { /* Offset base for distance codes 0..29 */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577 };
static dext[30] = { /* Extra bits for distance codes 0..29 */
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13 };
/* decode literals and length/distance pairs */
do {
symbol = _gz_decode(GZ_STATE, GZ_HUFF_LEN_COUNT, GZ_HUFF_LEN_SYMBOL, iInput, iOutput);
if (symbol == -1 && GZ_STATE[GZ_STATE_ERROR])
return -1;
if (symbol < 0) return symbol; /* invalid symbol */
if (symbol < 256) { /* literal: symbol is the byte */
/* write out the literal */
decl b[1];
b[0] = symbol;
#if defined DEBUG
//WriteFileLine(g_hDbgFile, "write('%c')", symbol);///////////////////////////
#endif
if (GZ_STATE[GZ_STATE_OUTPOS] > GZ_STATE[GZ_STATE_OUTLEN]) {
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_OUTPUT_FILE_BAD;
return -1;
}
iOutput[GZ_STATE[GZ_STATE_OUTPOS]] = b[0];
GZ_STATE[GZ_STATE_OUTPOS]++;
}
else if (symbol > 256) { /* length */
/* get and compute length */
symbol -= 257;
if (symbol >= 29) { /* invalid fixed code */
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_INVALID_FIXED_CODE;
return -1;
}
decl bits;
_GZ_BITS(bits,lext[symbol], iInput, iOutput);
len = lens[symbol] + bits;
/* get and check distance */
symbol = _gz_decode(GZ_STATE, GZ_HUFF_DIST_COUNT,
GZ_HUFF_DIST_SYMBOL, iInput, iOutput);
if (symbol == -1 && GZ_STATE[GZ_STATE_ERROR])
return -1;
if (symbol < 0) return symbol; /* invalid symbol */
_GZ_BITS(bits, dext[symbol], iInput, iOutput);
dist = dists[symbol] + bits;
if(dist > GZ_STATE[GZ_STATE_OUTPOS]) { /* distance too far back */
return -1;
}
/* copy length bytes from distance bytes back */
for (new i=0; i GZ_STATE[GZ_STATE_OUTLEN]) {
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_OUTPUT_FILE_BAD;
return -1;
}
iOutput[GZ_STATE[GZ_STATE_OUTPOS]] = iOutput[GZ_STATE[GZ_STATE_OUTPOS]-dist];
GZ_STATE[GZ_STATE_OUTPOS]++;
}
}
} while (symbol != 256);
/* done with a valid fixed or dynamic block */
return 0;
}
stock _gz_stored(GZ_STATE_DEF, iInput[], iOutput[])
{
#if defined DEBUG
WriteFileLine(g_hDbgFile, "stored");////////////////////////////////////
#endif
decl len; /* Length of stored block */
/* Discard leftover bits from current byte (assumes BITCNT < 8) */
GZ_STATE[GZ_STATE_BITBUF] = 0;
GZ_STATE[GZ_STATE_BITCNT] = 0;
/* Get length */
_GZ_BYTE(len, iInput, iOutput);
decl _len;
_GZ_BYTE(_len, iInput, iOutput);
len |= _len << 8;
/* Check against its one's complement */
decl _byte1, _byte2;
_GZ_BYTE(_byte1, iInput, iOutput);
_GZ_BYTE(_byte2, iInput, iOutput);
if (_byte1 != (~len & 0xff) || _byte2 != (~_len & 0xff))
{
/* Didn't match complement! */
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_BAD_BLOCK;
return -1;
}
/* Copy `len` bytes from input to output */
decl buffer[len];
for(new i=0;i= GZ_STATE[GZ_STATE_INLEN]) {
/* Not enough input */
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_END_OF_FILE;
return -1;
}
buffer[i] = iInput[GZ_STATE[GZ_STATE_INPOS]];
GZ_STATE[GZ_STATE_INPOS]++;
}
for(new i=0;i GZ_STATE[GZ_STATE_OUTLEN]) {
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_OUTPUT_FILE_BAD;
return -1;
}
iOutput[GZ_STATE[GZ_STATE_OUTPOS]] = buffer[i];
GZ_STATE[GZ_STATE_OUTPOS]++;
}
return 0;
}
stock _gz_fixed(GZ_STATE_DEF, iInput[], iOutput[])
{
#if defined DEBUG
WriteFileLine(g_hDbgFile, "fixed");////////////////////////////////////
#endif
static virgin = 1;
static lencnt[GZ_MAXBITS + 1], lensym[GZ_FIXLCODES];
static distcnt[GZ_MAXBITS + 1], distsym[GZ_MAXDCODES];
if (virgin) {
decl symbol;
decl lengths[GZ_FIXLCODES];
/* literal/length table */
for (symbol = 0; symbol < 144; symbol++)
lengths[symbol] = 8;
for (; symbol < 256; symbol++)
lengths[symbol] = 9;
for (; symbol < 280; symbol++)
lengths[symbol] = 7;
for (; symbol < GZ_FIXLCODES; symbol++)
lengths[symbol] = 8;
if (_gz_construct(lencnt, lensym, lengths, GZ_FIXLCODES, iInput, iOutput) == -1
&& GZ_STATE[GZ_STATE_ERROR])
return -1;
/* distance table */
for (symbol = 0; symbol < GZ_MAXDCODES; symbol++)
lengths[symbol] = 5;
if (_gz_construct(distcnt, distsym, lengths, GZ_MAXDCODES, iInput, iOutput) == -1
&& GZ_STATE[GZ_STATE_ERROR])
return -1;
/* do this just once */
virgin = 0;
}
/* decode data until end-of-block code */
return _gz_codes(GZ_STATE, lencnt, lensym, distcnt, distsym, iInput, iOutput);
}
stock _gz_dynamic(GZ_STATE_DEF, iInput[], iOutput[])
{
#if defined DEBUG
WriteFileLine(g_hDbgFile, "dynamic");////////////////////////////////////
#endif
decl bits; /* buffer for _GZ_BITS calls */
decl nlen, ndist, ncode; /* number of lengths in descriptor */
decl index; /* index of lengths[] */
decl err; /* construct() return value */
decl lengths[GZ_MAXCODES]; /* descriptor code lengths */
decl lencnt[GZ_MAXBITS+1], lensym[GZ_MAXLCODES]; /* lencode memory */
decl distcnt[GZ_MAXBITS+1], distsym[GZ_MAXDCODES]; /* distcode memory */
decl order[19] = /* permutation of code length codes */
{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
/* get number of lengths in each table */
_GZ_BITS(bits,5, iInput, iOutput);
nlen = bits + 257;
_GZ_BITS(bits,5, iInput, iOutput);
ndist = bits + 1;
_GZ_BITS(bits,4, iInput, iOutput);
ncode = bits + 4;
/* check lengths */
if (nlen > GZ_MAXLCODES || ndist > GZ_MAXDCODES) {
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_HUFF_BAD_COUNTS;
return -1;
}
/* read code length code lengths (really), missing lengths are zero */
for (index = 0; index < ncode; index++) {
_GZ_BITS(bits,3, iInput, iOutput);
lengths[order[index]] = bits;
}
for (; index < 19; index++)
lengths[order[index]] = 0;
/* build huffman table for code lengths codes (use lencnt/sym
* temporarily)
*/
err = _gz_construct(lencnt, lensym, lengths, 19, iInput, iOutput);
if (err == -1 && GZ_STATE[GZ_STATE_ERROR])
return -1;
else if (err != 0) {
/* require complete code set here */
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_REQUIRE_COMPLETE_SET;
return -1;
}
/* read length/literal and distance code length tables */
index = 0;
while (index < (nlen + ndist)) {
decl symbol; /* decoded value */
decl len; /* last length to repeat */
symbol = _gz_decode(GZ_STATE, lencnt, lensym, iInput, iOutput);
if (symbol == -1 && GZ_STATE[GZ_STATE_ERROR])
return -1;
if (symbol < 16) /* length in 0..15 */
lengths[index++] = symbol;
else { /* repeat instruction */
len = 0; /* assume repeating zeros */
if (symbol == 16) { /* repeat last length 3..6 times */
if (index == 0) { /* no last length! */
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_NO_LAST_LENGTH;
return -1;
}
len = lengths[index - 1]; /* last length */
_GZ_BITS(bits,2, iInput, iOutput);
symbol = 3 + bits;
}
else if (symbol == 17) { /* repeat zero 3..10 times */
_GZ_BITS(bits,3, iInput, iOutput);
symbol = 3 + bits;
}
else { /* == 18, repeat zero 11..138 times */
_GZ_BITS(bits,7, iInput, iOutput);
symbol = 11 + bits;
}
if (index + symbol > nlen + ndist) {
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_TOO_MANY_LENGTHS;
return -1; /* too many lengths! */
}
while (symbol--) /* repeat last or zero symbol times */
lengths[index++] = len;
}
}
/* check for end-of-block code -- there better be one! */
if (lengths[256] == 0) {
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_NO_END_OF_BLOCK_CODE;
return -1;
}
/* build huffman table for literal/length codes */
err = _gz_construct(lencnt, lensym, lengths, nlen, iInput, iOutput);
if (err == -1 && GZ_STATE[GZ_STATE_ERROR])
return -1;
if (err < 0 || (err > 0 && nlen - lencnt[0] != 1)) {
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_INCOMPLETE_ONLY_ONE;
return -1; /* only allow incomplete codes if just one code */
}
/* build huffman table for distance codes */
err = _gz_construct(distcnt, distsym, lengths[nlen], ndist, iInput, iOutput);
if (err == -1 && GZ_STATE[GZ_STATE_ERROR])
return -1;
if (err < 0 || (err > 0 && ndist - distcnt[0] != 1)) {
GZ_STATE[GZ_STATE_ERROR] = GZ_ERROR_INCOMPLETE_ONLY_ONE;
return -1; /* only allow incomplete codes if just one code */
}
/* decode data until end-of-block code */
return _gz_codes(GZ_STATE, lencnt, lensym, distcnt, distsym, iInput, iOutput);
}