123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- /*
- * tinflate - tiny inflate
- *
- * Copyright (c) 2003 by Joergen Ibsen / Jibz
- * All Rights Reserved
- * http://www.ibsensoftware.com/
- *
- * Copyright (c) 2014-2016 by Paul Sokolovsky
- *
- * 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.
- */
- #include "tinf.h"
- uint32_t tinf_get_le_uint32(TINF_DATA *d);
- uint32_t tinf_get_be_uint32(TINF_DATA *d);
- /* --------------------------------------------------- *
- * -- uninitialized global data (static structures) -- *
- * --------------------------------------------------- */
- #ifdef RUNTIME_BITS_TABLES
- /* extra bits and base tables for length codes */
- unsigned char length_bits[30];
- unsigned short length_base[30];
- /* extra bits and base tables for distance codes */
- unsigned char dist_bits[30];
- unsigned short dist_base[30];
- #else
- const unsigned char length_bits[30] = {
- 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
- };
- const unsigned short length_base[30] = {
- 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
- };
- const unsigned char dist_bits[30] = {
- 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
- };
- const unsigned short dist_base[30] = {
- 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
- };
- #endif
- /* special ordering of code length codes */
- const unsigned char clcidx[] = {
- 16, 17, 18, 0, 8, 7, 9, 6,
- 10, 5, 11, 4, 12, 3, 13, 2,
- 14, 1, 15
- };
- /* ----------------------- *
- * -- utility functions -- *
- * ----------------------- */
- #ifdef RUNTIME_BITS_TABLES
- /* build extra bits and base tables */
- static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)
- {
- int i, sum;
- /* build bits table */
- for (i = 0; i < delta; ++i) bits[i] = 0;
- for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta;
- /* build base table */
- for (sum = first, i = 0; i < 30; ++i)
- {
- base[i] = sum;
- sum += 1 << bits[i];
- }
- }
- #endif
- /* build the fixed huffman trees */
- static void tinf_build_fixed_trees(volatile TINF_TREE *lt, volatile TINF_TREE *dt)
- {
- int i;
- /* build fixed length tree */
- for (i = 0; i < 7; ++i) lt->table[i] = 0;
- lt->table[7] = 24;
- lt->table[8] = 152;
- lt->table[9] = 112;
- for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i;
- for (i = 0; i < 144; ++i) lt->trans[24 + i] = i;
- for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i;
- for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i;
- /* build fixed distance tree */
- for (i = 0; i < 5; ++i) dt->table[i] = 0;
- dt->table[5] = 32;
- for (i = 0; i < 32; ++i) dt->trans[i] = i;
- }
- /* given an array of code lengths, build a tree */
- static void tinf_build_tree(volatile TINF_TREE *t, const unsigned char *lengths, unsigned int num)
- {
- unsigned short offs[16];
- unsigned int i, sum;
- /* clear code length count table */
- for (i = 0; i < 16; ++i) t->table[i] = 0;
- /* scan symbol lengths, and sum code length counts */
- for (i = 0; i < num; ++i) t->table[lengths[i]]++;
- t->table[0] = 0;
- /* compute offset table for distribution sort */
- for (sum = 0, i = 0; i < 16; ++i)
- {
- offs[i] = sum;
- sum += t->table[i];
- }
- /* create code->symbol translation table (symbols sorted by code) */
- for (i = 0; i < num; ++i)
- {
- if (lengths[i]) t->trans[offs[lengths[i]]++] = i;
- }
- }
- /* ---------------------- *
- * -- decode functions -- *
- * ---------------------- */
- unsigned char uzlib_get_byte(volatile TINF_DATA *d)
- {
- if (d->source) {
- return *d->source++;
- }
- return d->readSource(d);
- }
- uint32_t tinf_get_le_uint32(TINF_DATA *d)
- {
- uint32_t val = 0;
- int i;
- for (i = 4; i--;) {
- val = val >> 8 | uzlib_get_byte(d) << 24;
- }
- return val;
- }
- uint32_t tinf_get_be_uint32(TINF_DATA *d)
- {
- uint32_t val = 0;
- int i;
- for (i = 4; i--;) {
- val = val << 8 | uzlib_get_byte(d);
- }
- return val;
- }
- /* get one bit from source stream */
- static int tinf_getbit(volatile TINF_DATA *d)
- {
- unsigned int bit;
- /* check if tag is empty */
- if (!d->bitcount--)
- {
- /* load next tag */
- d->tag = uzlib_get_byte(d);
- d->bitcount = 7;
- }
- /* shift bit out of tag */
- bit = d->tag & 0x01;
- d->tag >>= 1;
- return bit;
- }
- /* read a num bit value from a stream and add base */
- static unsigned int tinf_read_bits(volatile TINF_DATA *d, int num, int base)
- {
- unsigned int val = 0;
- /* read num bits */
- if (num)
- {
- unsigned int limit = 1 << (num);
- unsigned int mask;
- for (mask = 1; mask < limit; mask *= 2)
- if (tinf_getbit(d)) val += mask;
- }
- return val + base;
- }
- /* given a data stream and a tree, decode a symbol */
- static int tinf_decode_symbol(volatile TINF_DATA *d, volatile TINF_TREE *t)
- {
- int sum = 0, cur = 0, len = 0;
- /* get more bits while code value is above sum */
- do {
- cur = 2*cur + tinf_getbit(d);
- ++len;
- sum += t->table[len];
- cur -= t->table[len];
- } while (cur >= 0);
- return t->trans[sum + cur];
- }
- /* given a data stream, decode dynamic trees from it */
- static void tinf_decode_trees(volatile TINF_DATA *d, volatile TINF_TREE *lt, volatile TINF_TREE *dt)
- {
- 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, temporarily use length tree */
- tinf_build_tree(lt, lengths, 19);
- /* decode code lengths for the dynamic trees */
- for (num = 0; num < hlit + hdist; )
- {
- int sym = tinf_decode_symbol(d, lt);
- 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);
- }
- /* ----------------------------- *
- * -- block inflate functions -- *
- * ----------------------------- */
- /* given a stream and two trees, inflate a block of data */
- static int tinf_inflate_block_data(volatile TINF_DATA *d, volatile TINF_TREE *lt, volatile 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);
- /* 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);
- /* possibly get more bits from distance code */
- offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
- d->lzOff = -offs;
- }
- /* copy next byte from dict substring */
- d->dest[0] = d->dest[d->lzOff];
- d->dest++;
- d->curlen--;
- return TINF_OK;
- }
- /* inflate an uncompressed block of data */
- static int tinf_inflate_uncompressed_block(volatile TINF_DATA *d)
- {
- if (d->curlen == 0) {
- unsigned int length, invlength;
- /* get length */
- length = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
- /* get one's complement of length */
- invlength = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
- /* check length */
- if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
- /* increment length to properly return TINF_DONE below, without
- producing data at the same time */
- d->curlen = length + 1;
- /* make sure we start next block on a byte boundary */
- d->bitcount = 0;
- }
- if (--d->curlen == 0) {
- return TINF_DONE;
- }
- unsigned char c = uzlib_get_byte(d);
- TINF_PUT(d, c);
- return TINF_OK;
- }
- /* ---------------------- *
- * -- public functions -- *
- * ---------------------- */
- /* initialize global (static) data */
- void uzlib_init(void)
- {
- #ifdef RUNTIME_BITS_TABLES
- /* build extra bits and base tables */
- tinf_build_bits_base(length_bits, length_base, 4, 3);
- tinf_build_bits_base(dist_bits, dist_base, 2, 1);
- /* fix a special case */
- length_bits[28] = 0;
- length_base[28] = 258;
- #endif
- }
- /* inflate next byte of compressed stream */
- int uzlib_uncompress(volatile 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 */
- tinf_decode_trees(d, &d->ltree, &d->dtree);
- }
- }
- /* 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/dyanamic 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;
- }
|