/* given a stream and two trees, inflate a block of data */ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) { if (d->curlen == 0) { unsigned int offs; int dist; int sym = tinf_decode_symbol(d, lt); //printf("huff sym: %02x\n", sym); if (d->eof) { return TINF_DATA_ERROR; } /* literal byte */ if (sym < 256) { TINF_PUT(d, sym); return TINF_OK; } /* end of block */ if (sym == 256) { return TINF_DONE; } /* substring from sliding dictionary */ sym -= 257; /* possibly get more bits from length code */ d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]); dist = tinf_decode_symbol(d, dt); if (dist < 0) { return dist; } /* possibly get more bits from distance code */ offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); if (d->dict_ring) { if (offs > d->dict_size) { return TINF_DICT_ERROR; } d->lzOff = d->dict_idx - offs; if (d->lzOff < 0) { d->lzOff += d->dict_size; } } else { d->lzOff = -offs; } } /* copy next byte from dict substring */ if (d->dict_ring) { TINF_PUT(d, d->dict_ring[d->lzOff]); if ((unsigned)++d->lzOff == d->dict_size) { d->lzOff = 0; } } else { d->dest[0] = d->dest[d->lzOff]; d->dest++; } d->curlen--; return TINF_OK; }
/* inflate next byte of compressed stream */ int uzlib_uncompress(TINF_DATA *d) { do { int res; /* start a new block */ if (d->btype == -1) { next_blk: /* read final block flag */ d->bfinal = tinf_getbit(d); /* read block type (2 bits) */ d->btype = tinf_read_bits(d, 2, 0); //printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal); if (d->btype == 1) { /* build fixed huffman trees */ tinf_build_fixed_trees(&d->ltree, &d->dtree); } else if (d->btype == 2) { /* decode trees from stream */ res = tinf_decode_trees(d, &d->ltree, &d->dtree); if (res != TINF_OK) { return res; } } } /* process current block */ switch (d->btype) { case 0: /* decompress uncompressed block */ res = tinf_inflate_uncompressed_block(d); break; case 1: case 2: /* decompress block with fixed/dynamic huffman trees */ /* trees were decoded previously, so it's the same routine for both */ res = tinf_inflate_block_data(d, &d->ltree, &d->dtree); break; default: return TINF_DATA_ERROR; } if (res == TINF_DONE && !d->bfinal) { /* the block has ended (without producing more data), but we can't return without data, so start procesing next block */ goto next_blk; } if (res != TINF_OK) { return res; } } while (--d->destSize); return TINF_OK; }
/* given a stream and two trees, inflate a block of data */ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) { /* remember current output position */ unsigned char *start = d->dest; while (1) { int sym = tinf_decode_symbol(d, lt); /* check for end of block */ if (sym == 256) { *d->destLen += d->dest - start; return TINF_OK; } if (sym < 256) { *d->dest++ = sym; } else { int length, dist, offs; int i; sym -= 257; /* possibly get more bits from length code */ length = tinf_read_bits(d, length_bits[sym], length_base[sym]); dist = tinf_decode_symbol(d, dt); /* possibly get more bits from distance code */ offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); /* copy match */ for (i = 0; i < length; ++i) { d->dest[i] = d->dest[i - offs]; } d->dest += length; } } }
/* given a stream and two trees, inflate a block of data */ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) { while (1) { int sym = tinf_decode_symbol(d, lt); /* check for end of block */ if (sym == 256) break; if (sym < 256) { if ((*d->destLen + 1) > d->destSize) return TINF_DATA_ERROR; *d->dest++ = sym; *d->destLen += 1; } else { int length, dist, offs; int i; sym -= 257; /* possibly get more bits from length code */ length = tinf_read_bits(d, length_bits[sym], length_base[sym]); dist = tinf_decode_symbol(d, dt); /* possibly get more bits from distance code */ offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); /* copy match */ if ((*d->destLen + length) > d->destSize) return TINF_DATA_ERROR; for (i = 0; i < length; ++i) { d->dest[i] = d->dest[i - offs]; } d->dest += length; *d->destLen += length; } } return TINF_OK; }
/* inflate stream from source to dest */ int tinf_uncompress(void *dest, unsigned int *destLen, const void *source, unsigned int sourceLen) { TINF_DATA d; int bfinal; d.source = (const unsigned char *)source; d.bitcount = 0; d.dest = (unsigned char *)dest; d.destLen = destLen; *destLen = 0; do { unsigned int btype; int res; /* read final block flag */ bfinal = tinf_getbit(&d); /* read block type (2 bits) */ btype = tinf_read_bits(&d, 2, 0); /* decompress block */ switch (btype) { case 0: /* decompress uncompressed block */ res = tinf_inflate_uncompressed_block(&d); break; case 1: /* decompress block with fixed huffman trees */ res = tinf_inflate_fixed_block(&d,&tbl); break; case 2: /* decompress block with dynamic huffman trees */ res = tinf_inflate_dynamic_block(&d,&tbl); break; default: return TINF_DATA_ERROR; } if (res != TINF_OK) return TINF_DATA_ERROR; if (d.source > (unsigned char *)source + sourceLen) return TINF_DATA_ERROR; } while (!bfinal); return TINF_OK; }
/* inflate stream from source to dest */ int tinf_uncompress(void *dest, unsigned int *destLen, const void *source, unsigned int sourceLen, const unsigned int swapped_btype[3]) { TINF_DATA d; int bfinal; /* initialise data */ d.source = (const unsigned char *)source; d.bitcount = 0; d.dest = (unsigned char *)dest; d.destLen = destLen; d.sourceLen = 0; d.sourceSize = sourceLen; d.destSize = *destLen; *destLen = 0; do { unsigned int btype; int res; /* read final block flag */ bfinal = tinf_getbit(&d); /* read block type (2 bits) */ btype = tinf_read_bits(&d, 2, 0); /* decompress block */ if(btype == swapped_btype[0]) { /* decompress uncompressed block */ res = tinf_inflate_uncompressed_block(&d); } else if(btype == swapped_btype[1]) { /* decompress block with fixed huffman trees */ res = tinf_inflate_fixed_block(&d); } else if(btype == swapped_btype[2]) { /* decompress block with dynamic huffman trees */ res = tinf_inflate_dynamic_block(&d); } else { return TINF_DATA_ERROR; } if (res != TINF_OK) return TINF_DATA_ERROR; } while (!bfinal); return TINF_OK; }
/* inflate stream from source to dest */ int tinf_uncompress(void *dest, unsigned int *destLen, const void *source, unsigned int sourceLen) { TINF_DATA d; int bfinal; /* initialise data */ d.source = (const unsigned char *)source; d.bitcount = 0; d.dest = (unsigned char *)dest; d.destLen = destLen; *destLen = 0; do { unsigned int btype; int res; /* read block type (2 bits) */ btype = tinf_read_bits(&d, 3, 0); /* read final block flag */ bfinal = tinf_getbit(&d); /* decompress block */ switch (btype) { case 7: /* decompress uncompressed block */ res = tinf_inflate_uncompressed_block(&d); break; case 5: /* decompress block with fixed huffman trees */ res = tinf_inflate_fixed_block(&d); break; case 6: /* decompress block with dynamic huffman trees */ res = tinf_inflate_dynamic_block(&d); break; default: return -1; } if (res != TINF_OK) return -1; } while (!bfinal); return ((char*)d.source - (char *)source); }
/* given a data stream, decode dynamic trees from it */ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) { unsigned char lengths[288+32]; unsigned int hlit, hdist, hclen, hlimit; unsigned int i, num, length; /* get 5 bits HLIT (257-286) */ hlit = tinf_read_bits(d, 5, 257); /* get 5 bits HDIST (1-32) */ hdist = tinf_read_bits(d, 5, 1); /* get 4 bits HCLEN (4-19) */ hclen = tinf_read_bits(d, 4, 4); for (i = 0; i < 19; ++i) lengths[i] = 0; /* read code lengths for code length alphabet */ for (i = 0; i < hclen; ++i) { /* get 3 bits code length (0-7) */ unsigned int clen = tinf_read_bits(d, 3, 0); lengths[clcidx[i]] = clen; } /* build code length tree, temporarily use length tree */ tinf_build_tree(lt, lengths, 19); /* decode code lengths for the dynamic trees */ hlimit = hlit + hdist; for (num = 0; num < hlimit; ) { int sym = tinf_decode_symbol(d, lt); unsigned char fill_value = 0; int lbits, lbase = 3; /* error decoding */ if (sym < 0) return sym; switch (sym) { case 16: if (num == 0) { return TINF_DATA_ERROR; } /* copy previous code length 3-6 times (read 2 bits) */ fill_value = lengths[num - 1]; lbits = 2; break; case 17: /* repeat code length 0 for 3-10 times (read 3 bits) */ lbits = 3; break; case 18: /* repeat code length 0 for 11-138 times (read 7 bits) */ lbits = 7; lbase = 11; break; default: /* values 0-15 represent the actual code lengths */ lengths[num++] = sym; /* continue the for loop */ continue; } /* special code length 16-18 are handled here */ length = tinf_read_bits(d, lbits, lbase); if (num + length >= hlimit) return TINF_DATA_ERROR; for (; length; --length) { lengths[num++] = fill_value; } } /* build dynamic trees */ tinf_build_tree(lt, lengths, hlit); tinf_build_tree(dt, lengths + hlit, hdist); return TINF_OK; }
/* given a data stream, decode dynamic trees from it */ static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) { TINF_TREE code_tree; unsigned char lengths[288+32]; unsigned int hlit, hdist, hclen; unsigned int i, num, length; /* get 5 bits HLIT (257-286) */ hlit = tinf_read_bits(d, 5, 257); /* get 5 bits HDIST (1-32) */ hdist = tinf_read_bits(d, 5, 1); /* get 4 bits HCLEN (4-19) */ hclen = tinf_read_bits(d, 4, 4); for (i = 0; i < 19; ++i) lengths[i] = 0; /* read code lengths for code length alphabet */ for (i = 0; i < hclen; ++i) { /* get 3 bits code length (0-7) */ unsigned int clen = tinf_read_bits(d, 3, 0); lengths[clcidx[i]] = clen; } /* build code length tree */ tinf_build_tree(&code_tree, lengths, 19); /* decode code lengths for the dynamic trees */ for (num = 0; num < hlit + hdist; ) { int sym = tinf_decode_symbol(d, &code_tree); switch (sym) { case 16: /* copy previous code length 3-6 times (read 2 bits) */ { unsigned char prev = lengths[num - 1]; for (length = tinf_read_bits(d, 2, 3); length; --length) { lengths[num++] = prev; } } break; case 17: /* repeat code length 0 for 3-10 times (read 3 bits) */ for (length = tinf_read_bits(d, 3, 3); length; --length) { lengths[num++] = 0; } break; case 18: /* repeat code length 0 for 11-138 times (read 7 bits) */ for (length = tinf_read_bits(d, 7, 11); length; --length) { lengths[num++] = 0; } break; default: /* values 0-15 represent the actual code lengths */ lengths[num++] = sym; break; } } /* build dynamic trees */ tinf_build_tree(lt, lengths, hlit); tinf_build_tree(dt, lengths + hlit, hdist); }