/* inflate routines for Palm OS (to inflate a deflated stream) * * Based heavily upon gunzip.c by Pasi Ojala * http://www.cs.tut.fi/~albert/Dev/gunzip/ * Many, many thanks for that code! * * Changes: * 2002-12-30 - Added #defines to use zlib's struct instead of mine, just * in case you want to compile it that way. * 2002-12-29 - Found out that this is VERY slow. ZLib is 3x faster. * Worked on speeding it up. Partially successful. Profiled * code and marked critical areas. 1932 bytes added to a * Palm program by linking in the .o file. Schweet! * 2002-12-21 - Finished surgery. Only one function to inflate dynamic and * fixed data. Rewrote table generation to be iterative. * Hacked and slashed my way through unnecessary code. * The size is now down to 3512 bytes. * 2002-12-20 - Started major surgery * 2002-12-19 - Looked at the code a bit more * 2002-12-17 - Continued work. Down to about 6k for the .o file * 2002-12-09 - Continued work, added z_stream_fid instead of globals * 2002-12-08 - Started work so that it decompresses up to 64k (one memory * chunk on the Palm. * 2002-12-07 - Removed bit reverse table. Removed unzip code. */ #include "libsys.h" #include "inflate.h" #ifdef VERBOSE #include // Just in case you put a printf() function back in #endif void Status(char *, int); typedef struct HufNode_struct { // b0 and b1 are either values in the tree array to jump to (branches) // or are literal values. // if (bX & 0x8000) // value = bX ^ 0x8000; // else // link_to_array_element = bX; unsigned int b0; // Bigger than 1 byte (2 is ideal) unsigned int b1; // Bigger than 1 byte (2 is ideal) } HufNode; // Not that rhobust anymore -- If out of data, this will // return a whole lot of 1 bits. // // This function consumes a large percentage of time (#1) char READBIT(z_stream *zs) { char carry; if (zs->reserved == 1) { if (zs->avail_in == 0) return 1; zs->reserved = *(zs->next_in ++) | 0x0100; zs->avail_in --; } carry = zs->reserved & 1; zs->reserved >>= 1; return carry; } // Make sure that [a] is <= 16 // If there are endian problems, force [a] to be <= 8 // Might be faster if all (up to [a] bits) of zs->reserved was read into res // right away. // // This function consumes a large percentage of time (#4) int READBITS(z_stream *zs, int a) { int res = 0, pos = 0; while (a --) { if (zs->reserved == 1) { if (zs->avail_in == 0) return 1; zs->reserved = *(zs->next_in ++) | 0x0100; zs->avail_in --; } res += (zs->reserved & 1) << pos; zs->reserved >>= 1; pos ++; } return res; } // Huffman tree structures, variables and related routines // // These routines are one-bit-at-a-time decode routines. They // are not as fast as multi-bit routines, but maybe a bit easier // to understand and use a lot less memory. // // The tree is created in an array // // currentTree = where to put the tree (in an array) // numval = Number of elements in the lengths array // lengths = array of lengths // // // This function consumes a large percentage of time (#5) int CreateTree(HufNode *currentTree, int numval, unsigned char *lengths) { int i, j, len; // basically scratch values int BlankNode; // Where is the next blank array index int this_code, mask, *bitData; // used in tree generation int bl_count[16] = { 0, }; // Counter of code lengths int next_code[16] = { 0, }; // Code for a specific length // 16 = (15 is max length of a code when inflating) + (1 for zero) // Step 1: Count the code lengths for (i = 0; i < numval; i ++) { j = lengths[i]; if (j > 15) return 1; bl_count[j] ++; } // Step 2: Find numerical value of the smallest code of each length // Also note that I've inserted some weak validation code here. I'm // not 100% sure that it is up to RFC specs, but it seems to work fine // in my tests // // The validation theory is that at the root node, you have 2 branches or // values possible. If you branch, you get 2 more potentials. If you // get a value, you lose one potential. So, if the root node has one of // each, the number of potentials at the next level is still two. If that // node just has branches, the number of potentials is four. If both of // the nodes on the following level just have values, the number of // potentials is 0, leaving us with a complete tree. // // If I don't validate and if an invalid tree gets generated, an // infinite loop is possible bl_count[0] = 0; j = 0; len = 2; for (i = 1; i < 16; i ++) { len -= bl_count[i]; len *= 2; j = (j + bl_count[i - 1]) << 1; next_code[i] = j; } if (len) return 1; // Step 3: Assign numerical values to all codes BlankNode = 1; currentTree[0].b0 = 0x0000; currentTree[0].b1 = 0x0000; for (i = 0; i < numval; i ++) { len = lengths[i]; if (len != 0) { this_code = next_code[len]; next_code[len] ++; mask = 1 << (len - 1); j = 0; while (mask > 1) { if (this_code & mask) bitData = &(currentTree[j].b1); else bitData = &(currentTree[j].b0); if (*bitData == 0x0000) { *bitData = BlankNode; j = BlankNode; BlankNode ++; currentTree[j].b0 = 0x0000; currentTree[j].b1 = 0x0000; } else j = *bitData; mask >>= 1; } if (this_code & 0x01) currentTree[j].b1 = 0x8000 | i; else currentTree[j].b0 = 0x8000 | i; } } #ifdef VERBOSE fprintf(stderr, "%d table entries used\n", BlankNode); if (numval < 20) { for (i = 0; i < BlankNode; i ++) { fprintf(stderr, "0x%03x - ", i); if (currentTree[i].b0 & 0x8000) fprintf(stderr, "value: 0x%03x ", currentTree[i].b0 ^ 0x8000); else fprintf(stderr, " link: 0x%03x ", currentTree[i].b0); if (currentTree[i].b1 & 0x8000) fprintf(stderr, "value: 0x%03x\n", currentTree[i].b1 ^ 0x8000); else fprintf(stderr, " link: 0x%03x\n", currentTree[i].b1); } } #endif return 0; } // Using the tree passed in, read bits from the data stream until we arrive // at the proper value // // This function consumes a large percentage of time (#2) int DecodeValue(z_stream *zs, HufNode *currentTree) { unsigned int i = 0; // decode one symbol of the data per iteration // Infinite loop detection code could go here. Maximum // bits to read is 15. while (i < 0x8000) { if (READBIT(zs)) i = currentTree[i].b1; else i = currentTree[i].b0; } return i & 0x7FFF; } int Decompress_Stored(z_stream *zs) { int blockLen, cSum; #ifdef VERBOSE fprintf(stderr, "Stored\n"); #endif zs->reserved = 1;; if (zs->avail_in < 4) return -1; zs->avail_in -= 4; blockLen = *(zs->next_in ++); blockLen |= *(zs->next_in ++) << 8; cSum = *(zs->next_in ++); cSum |= (*(zs->next_in ++) << 8); if ((blockLen + cSum) ^ 0xFFFF) return 1; if (zs->avail_in < blockLen || zs->avail_out < blockLen) return -1; zs->avail_in -= blockLen; zs->avail_out -= blockLen; while (blockLen --) { *(zs->next_out) = *(zs->next_in); zs->next_out ++; zs->next_in ++; } return 0; } int MakeTrees(z_stream *zs, char is_fixed, HufNode *literalTree, HufNode *distanceTree) { // Order of the bit length code lengths static const unsigned border[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; unsigned char ll[288+32]; int i, j, n, l, literalCodes, distCodes; if (is_fixed) { literalCodes = 288; // Set a large range to 8 for (i = 0; i < 288; i ++) ll[i] = 8; // In that range, set some to 9 and others to 7 // (smaller code, but slightly slower table generation) for (i = 144; i < 256; i ++) ll[i] = 9; for (; i < 280; i ++) ll[i] = 7; distCodes = 32; for (i = 288; i < 320; i ++) ll[i] = 5; } else { literalCodes = 257 + READBITS(zs, 5); distCodes = 1 + READBITS(zs, 5); l = 4 + READBITS(zs, 4); for (j = 0; j < 19; j ++) ll[j] = 0; // Get the decode tree code lengths // The decode tree is Huffman encoded for (j = 0; j < l; j++) { ll[border[j]] = READBITS(zs, 3); } if (CreateTree(distanceTree, 19, ll)) return 1; // read in literal and distance code lengths n = literalCodes + distCodes; i = 0; while (i < n) { j = DecodeValue(zs, distanceTree); if (j < 16) // length of code in bits (0..15) ll[i++] = j; else if (j == 16) { // repeat last length 3 to 6 times j = 3 + READBITS(zs, 2); if (i + j > n) return 1; l = i ? ll[i-1] : 0; while (j --) ll[i++] = l; } else { if (j == 17) // 3 to 10 zero length codes j = 3 + READBITS(zs, 3); else // j == 18: 11 to 138 zero length codes j = 11 + READBITS(zs, 7); if (i + j > n) return 1; while (j --) ll[i++] = 0; } } } // Can overwrite tree decode tree as it is not used anymore if (CreateTree(literalTree, literalCodes, &ll[0])) return 1; if(CreateTree(distanceTree, distCodes, &ll[literalCodes])) return 1; return 0; } // This function consumes a large percentage of time (#3) // Most output produced by gzip/zlib/etc is dynamic. int Decompress_DynamicOrFixed(z_stream *zs, char is_fixed) { // Copy lengths for literal codes 257..285 static const unsigned short cplens[] = { 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, 0, 0 }; // Extra bits for literal codes 257..285 static const unsigned short cplext[] = { 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, 99, 99 }; // 99==invalid // Copy offsets for distance codes 0..29 static const unsigned short cpdist[] = { 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d, 0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1, 0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01, 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001 }; // Extra bits for distance codes static const unsigned short cpdext[] = { 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 }; HufNode literalTree[288]; HufNode distanceTree[32]; int j, l, dist; #ifdef VERBOSE if (is_fixed) fprintf(stderr, "Fixed Huffman codes\n"); else fprintf(stderr, "Dynamic Huffman codes\n"); #endif if (MakeTrees(zs, is_fixed, literalTree, distanceTree)) return 1; while (1) { j = DecodeValue(zs, literalTree); if (j >= 256) { if (j == 256) // EOF break; //printf("%04x ", j); j -= 256 + 1; // bytes + EOF l = READBITS(zs, cplext[j]) + cplens[j]; //printf("%04x ", l); j = DecodeValue(zs, distanceTree); //printf("%02x ", j); dist = READBITS(zs, cpdext[j]) + cpdist[j]; //printf("%04x ", dist); //printf("LZ77 len %d dist %d @%04x\n", l, dist, bIdx); while(l--) { //printf("%02x ", c); if (! zs->avail_out --) return -1; *(zs->next_out ++) = *(zs->next_out - dist); } //printf("\n"); } else { //printf("%02x\n", j); if (! zs->avail_out --) return -1; *(zs->next_out ++) = (unsigned char) j; } } return 0; } // Returns 0 if success int InflateData(z_stream *zs) { int last, type; zs->reserved = 1;; do { last = READBIT(zs); #ifdef VERBOSE if (last) fprintf(stderr, "Last Block: "); else fprintf(stderr, "Not Last Block: "); #endif type = READBITS(zs, 2); if (type == 0) { #ifdef VERBOSE fprintf(stderr, "Decompress_Stored.."); #endif if (Decompress_Stored(zs)) return 1; } else if (type > 2) { #ifdef VERBOSE if (type == 3) fprintf(stderr, "Reserved block type!!\n"); else // the "else" should never happen fprintf(stderr, "Unexpected value %d!\n", type); #endif zs->reserved = 1;; return 1; } else { #ifdef VERBOSE fprintf(stderr, "Decompress_DynamicOrFixed.."); #endif if (Decompress_DynamicOrFixed(zs, type & 0x01)) return 1; } } while(!last); zs->reserved = 1;; return 0; }