flate

deflate implementation
git clone git://git.suckless.org/flate
Log | Files | Refs | README

commit 29637fae613ae2ef326c64b4270ade27ea1ca61f
parent 66633eca00f4329f7cb3f4fc635e8afb9f66b989
Author: nsz <nszabolcs@gmail.com>
Date:   Wed, 22 Apr 2009 13:00:07 +0200

inflate_simple
Diffstat:
Makefile | 6++++--
inflate_simple.c | 322+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 326 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,12 +1,14 @@ #CFLAGS=-g -Wall -ansi -pedantic CFLAGS=-Os -Wall -ansi -pedantic LDFLAGS= -SRC=inflate.c +SRC=inflate.c inflate_simple.c OBJ=${SRC:.c=.o} -all: inflate +all: inflate inflate_simple inflate: inflate.o ${CC} -o $@ $^ ${LDFLAGS} +inflate_simple: inflate_simple.o + ${CC} -o $@ $^ ${LDFLAGS} ${OBJ}: Makefile .c.o: ${CC} -c ${CFLAGS} $< diff --git a/inflate_simple.c b/inflate_simple.c @@ -0,0 +1,322 @@ +/* no input validation and bounds check */ + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum { + HuffBits = 16, /* max number of bits in a code */ + Nlit = 256, /* number of lit codes */ + Nlen = 29, /* number of len codes */ + Nlitlen = Nlit+Nlen+3, /* litlen codes + block end + 2 unused */ + Ndist = 30, /* number of distance codes */ + Nclen = 19 /* number of code length codes */ +}; + +typedef struct { + ushort count[HuffBits]; /* code length -> count */ + ushort symbol[Nlitlen]; /* symbols ordered by code length */ +} HuffTree; + +typedef struct { + uchar *src; + + uchar *dst; + uchar *dstbegin; + + uint bits; + uint nbits; + + HuffTree ltree; /* dynamic lit/len tree */ + HuffTree dtree; /* dynamic distance tree */ +} FlateStream; + + +static HuffTree ltree; /* fixed lit/len tree */ +static HuffTree dtree; /* fixed distance tree */ + +/* base offsets */ +static ushort lenbase[Nlen]; +static ushort distbase[Ndist]; + +/* extra bits */ +static uchar lenbits[Nlen] = { + 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 uchar distbits[Ndist] = { + 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 +}; + +/* ordering of code lengths */ +static uchar clenorder[Nclen] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + +static void init_base_tables(void) { + uint base; + int i; + + for (base = 3, i = 0; i < Nlen; i++) { + lenbase[i] = base; + base += 1 << lenbits[i]; + } + lenbase[Nlen-1]--; /* deflate bug */ + + for (base = 1, i = 0; i < Ndist; i++) { + distbase[i] = base; + base += 1 << distbits[i]; + } +} + +static void init_fixed_trees(void) { + int i; + + ltree.count[7] = 24; + ltree.count[8] = 152; + ltree.count[9] = 112; + for (i = 0; i < 24; i++) + ltree.symbol[i] = 256 + i; + for (i = 0; i < 144; i++) + ltree.symbol[24 + i] = i; + for (i = 0; i < 8; i++) + ltree.symbol[24 + 144 + i] = 280 + i; + for (i = 0; i < 112; i++) + ltree.symbol[24 + 144 + 8 + i] = 144 + i; + + dtree.count[5] = Ndist; + for (i = 0; i < Ndist; i++) + dtree.symbol[i] = i; +} + +/* build huffman code tree from code lengths */ +static void build_tree(HuffTree *t, const uchar *lens, int n) { + int offs[HuffBits]; + int i, sum; + + for (i = 0; i < HuffBits; i++) + t->count[i] = 0; + + /* count code lengths and calc first code for each length */ + for (i = 0; i < n; i++) + t->count[lens[i]]++; + t->count[0] = 0; + + for (sum = 0, i = 0; i < HuffBits; i++) { + offs[i] = sum; + sum += t->count[i]; + } + + /* sort symbols by code length */ + for (i = 0; i < n; i++) + if (lens[i]) + t->symbol[offs[lens[i]]++] = i; +} + +/* get one bit from s->src stream */ +static uint getbit(FlateStream *s) { + uint bit; + + if (!s->nbits--) { + s->bits = *s->src++; + s->nbits = 7; + } + bit = s->bits & 1; + s->bits >>= 1; + return bit; +} + +/* get n bits from s->src stream */ +static uint getbits(FlateStream *s, int n) { + uint bits = 0; + int i; + + for (i = 0; i < n; i++) + bits |= getbit(s) << i; + return bits; +} + +/* decode a symbol from stream with tree */ +static uint decode_symbol(FlateStream *s, HuffTree *t) { + int sum = 0, cur = 0; + ushort *count = t->count + 1; + + for (;;) { + cur |= getbit(s); + sum += *count; + cur -= *count; + if (cur < 0) + break; + cur <<= 1; + count++; + } + return t->symbol[sum + cur]; +} + +/* decode dynamic trees from stream */ +static void decode_trees(FlateStream *s, HuffTree *lt, HuffTree *dt) { + HuffTree ctree; + uchar lens[Nlitlen+Ndist]; + uint nlit, ndist, nclen; + uint i; + + nlit = 257 + getbits(s, 5); + ndist = 1 + getbits(s, 5); + nclen = 4 + getbits(s, 4); + + /* build code length tree */ + for (i = 0; i < Nclen; i++) + lens[i] = 0; + for (i = 0; i < nclen; i++) + lens[clenorder[i]] = getbits(s, 3); + build_tree(&ctree, lens, Nclen); + + /* decode code lengths for the dynamic trees */ + for (i = 0; i < nlit + ndist; ) { + uint sym = decode_symbol(s, &ctree); + uint len; + uchar c; + + if (sym < 16) { + lens[i++] = sym; + } else if (sym == 16) { + /* copy previous code length 3-6 times */ + c = lens[i - 1]; + for (len = 3 + getbits(s, 2); len; len--) + lens[i++] = c; + } else if (sym == 17) { + /* repeat 0 for 3-10 times */ + for (len = 3 + getbits(s, 3); len; len--) + lens[i++] = 0; + } else if (sym == 18) { + /* repeat 0 for 11-138 times */ + for (len = 11 + getbits(s, 7); len; len--) + lens[i++] = 0; + } + } + /* build dynamic huffman trees */ + build_tree(lt, lens, nlit); + build_tree(dt, lens + nlit, ndist); +} + +/* decode a block of data from stream with trees */ +static void decode_block(FlateStream *s, HuffTree *lt, HuffTree *dt) { + uint sym; + + for (;;) { + sym = decode_symbol(s, lt); + + if (sym == 256) + return; + if (sym < 256) + *s->dst++ = sym; + else { + int len, dist; + + sym -= 257; + len = lenbase[sym] + getbits(s, lenbits[sym]); + sym = decode_symbol(s, dt); + dist = distbase[sym] + getbits(s, distbits[sym]); + /* copy match */ + while (len--) { + *s->dst = *(s->dst - dist); + s->dst++; + } + } + } +} + +static void inflate_uncompressed_block(FlateStream *s) { + uint len; + + len = (s->src[1] << 8) | s->src[0]; + s->src += 4; + + /* start next block on a byte boundary */ + s->nbits = 0; + + while (len--) + *s->dst++ = *s->src++; +} + +static void inflate_fixed_block(FlateStream *s) { + decode_block(s, &ltree, &dtree); +} + +static void inflate_dynamic_block(FlateStream *s) { + decode_trees(s, &s->ltree, &s->dtree); + decode_block(s, &s->ltree, &s->dtree); +} + + +/* extern functions */ + +/* initialize global (static) data */ +void inflate_init(void) { + init_fixed_trees(); + init_base_tables(); +} + +/* inflate stream from src to dst */ +uint inflate(void *dst, void *src) { + FlateStream s; + uint final; + + s.src = src; + s.dst = s.dstbegin = dst; + s.nbits = 0; + do { + uint blocktype; + + final = getbit(&s); + blocktype = getbits(&s, 2); + + /* decompress block */ + switch (blocktype) { + case 0: + inflate_uncompressed_block(&s); + break; + case 1: + inflate_fixed_block(&s); + break; + case 2: + inflate_dynamic_block(&s); + break; + } + } while (!final); + return s.dst - s.dstbegin; +} + + +/* simple test */ + +#include <stdlib.h> +#include <stdio.h> + +void *readall(FILE *in) { + uint len = 1 << 22; + void *buf; + + buf = malloc(len); + fread(buf, 1, len, in); + fclose(in); + return buf; +} + +int main(int argc, char **argv) { + uchar *src, *dst; + uint len = 1<<24; + + inflate_init(); + src = readall(argc < 2 ? stdin : fopen(argv[1], "r")); + dst = malloc(len); + len = inflate(dst, src); + fprintf(stderr, "inflate_simple: uncompressed %u bytes\n", len); + fwrite(dst, 1, len, stdout); + free(dst); + free(src); + return 0; +}