/** * ============================================================================= * 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); }