diff --git a/src/crc32.c b/src/crc32.c index fce7d33..1be54b6 100644 --- a/src/crc32.c +++ b/src/crc32.c @@ -45,14 +45,12 @@ static const unsigned int tinf_crc32tab[16] = { 0xbdbdf21c }; -unsigned int tinf_crc32(const void *data, unsigned int length) +/* crc is previous value for incremental computation, 0xffffffff initially */ +unsigned int tinf_crc32(const void *data, unsigned int length, unsigned int crc) { const unsigned char *buf = (const unsigned char *)data; - unsigned int crc = 0xffffffff; unsigned int i; - if (length == 0) return 0; - for (i = 0; i < length; ++i) { crc ^= buf[i]; @@ -60,5 +58,6 @@ unsigned int tinf_crc32(const void *data, unsigned int length) crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4); } - return crc ^ 0xffffffff; + // return value suitable for passing in next time, for final value invert it + return crc/* ^ 0xffffffff*/; } diff --git a/src/tinf.h b/src/tinf.h index 826b32e..c07d6e6 100644 --- a/src/tinf.h +++ b/src/tinf.h @@ -31,7 +31,12 @@ extern "C" { /* end of compressed stream reached */ #define TINF_DONE 1 #define TINF_DATA_ERROR (-3) -#define TINF_DEST_OVERFLOW (-4) +#define TINF_CHKSUM_ERROR (-4) + +/* checksum types */ +#define TINF_CHKSUM_NONE 0 +#define TINF_CHKSUM_ADLER 1 +#define TINF_CHKSUM_CRC 2 /* data structures */ @@ -61,6 +66,7 @@ typedef struct TINF_DATA { /* Accumulating checksum */ unsigned int checksum; + char checksum_type; int btype; int bfinal; @@ -92,27 +98,22 @@ typedef struct TINF_DATA { void tinf_uncompress_dyn_init(TINF_DATA *d, void *dict, unsigned int dictLen); int TINFCC tinf_uncompress_dyn(TINF_DATA *d); +int TINFCC tinf_uncompress_dyn_chksum(TINF_DATA *d); int TINFCC tinf_zlib_parse_header(TINF_DATA *d); -int TINFCC tinf_zlib_uncompress_dyn(TINF_DATA *d); /* high-level API */ void TINFCC tinf_init(void); -typedef struct TINF_GZIP_INFO { - unsigned int dlen; - unsigned int crc32; -} TINF_GZIP_INFO; - -int tinf_gzip_parse_header(TINF_GZIP_INFO *gz, const unsigned char **source, unsigned int sourceLen); -int tinf_gzip_parse_trailer(TINF_GZIP_INFO *gz, const unsigned char **source, unsigned int sourceLen); +int TINFCC tinf_gzip_parse_header(TINF_DATA *d); unsigned char TINFCC tinf_read_src_byte(TINF_DATA *d); unsigned int TINFCC tinf_adler32(const void *data, unsigned int length, unsigned int prev_sum /* 1 */); -unsigned int TINFCC tinf_crc32(const void *data, unsigned int length); +/* crc is previous value for incremental computation, 0xffffffff initially */ +unsigned int TINFCC tinf_crc32(const void *data, unsigned int length, unsigned int crc); /* compression API */ diff --git a/src/tinfgzip.c b/src/tinfgzip.c index c13dbac..9331a75 100644 --- a/src/tinfgzip.c +++ b/src/tinfgzip.c @@ -39,78 +39,67 @@ #define FNAME 8 #define FCOMMENT 16 -int tinf_gzip_parse_header(TINF_GZIP_INFO *gz, const unsigned char **source, unsigned int sourceLen) +void tinf_skip_bytes(TINF_DATA *d, int num) +{ + while (num--) tinf_read_src_byte(d); +} + +uint16_t tinf_get_uint16(TINF_DATA *d) +{ + unsigned int v = tinf_read_src_byte(d); + v = (tinf_read_src_byte(d) << 8) | v; + return v; +} + +int tinf_gzip_parse_header(TINF_DATA *d) { - const unsigned char *src = *source; - const unsigned char *start; unsigned char flg; /* -- check format -- */ /* check id bytes */ - if (src[0] != 0x1f || src[1] != 0x8b) return TINF_DATA_ERROR; + if (tinf_read_src_byte(d) != 0x1f || tinf_read_src_byte(d) != 0x8b) return TINF_DATA_ERROR; /* check method is deflate */ - if (src[2] != 8) return TINF_DATA_ERROR; + if (tinf_read_src_byte(d) != 8) return TINF_DATA_ERROR; /* get flag byte */ - flg = src[3]; + flg = tinf_read_src_byte(d); /* check that reserved bits are zero */ if (flg & 0xe0) return TINF_DATA_ERROR; /* -- find start of compressed data -- */ - /* skip base header of 10 bytes */ - start = src + 10; + /* skip rest of base header of 10 bytes */ + tinf_skip_bytes(d, 6); /* skip extra data if present */ if (flg & FEXTRA) { - unsigned int xlen = start[1]; - xlen = 256*xlen + start[0]; - start += xlen + 2; + unsigned int xlen = tinf_get_uint16(d); + tinf_skip_bytes(d, xlen); } /* skip file name if present */ - if (flg & FNAME) { while (*start) ++start; ++start; } + if (flg & FNAME) { while (tinf_read_src_byte(d)); } /* skip file comment if present */ - if (flg & FCOMMENT) { while (*start) ++start; ++start; } + if (flg & FCOMMENT) { while (tinf_read_src_byte(d)); } /* check header crc if present */ if (flg & FHCRC) { - unsigned int hcrc = start[1]; - hcrc = 256*hcrc + start[0]; + unsigned int hcrc = tinf_get_uint16(d); - if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff)) - return TINF_DATA_ERROR; - - start += 2; + // TODO: Check! +// if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff)) +// return TINF_DATA_ERROR; } - *source = start; - return TINF_OK; -} - -int tinf_gzip_parse_trailer(TINF_GZIP_INFO *gz, const unsigned char **source, unsigned int sourceLen) { - unsigned int dlen, crc32; - const unsigned char *src = *source; - - dlen = src[7]; - dlen = 256*dlen + src[6]; - dlen = 256*dlen + src[5]; - dlen = 256*dlen + src[4]; - - /* -- get crc32 of decompressed data -- */ - - crc32 = src[3]; - crc32 = 256*crc32 + src[2]; - crc32 = 256*crc32 + src[1]; - crc32 = 256*crc32 + src[0]; - - gz->dlen = dlen; - gz->crc32 = crc32; + /* initialize for crc32 checksum */ + d->checksum_type = TINF_CHKSUM_CRC; + d->checksum = ~0; + return TINF_OK; } diff --git a/src/tinflate.c b/src/tinflate.c index a6f6e66..8ea8b64 100644 --- a/src/tinflate.c +++ b/src/tinflate.c @@ -174,6 +174,26 @@ unsigned char tinf_read_src_byte(TINF_DATA *d) 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 | tinf_read_src_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 | tinf_read_src_byte(d); + } + return val; +} + /* get one bit from source stream */ static int tinf_getbit(TINF_DATA *d) { @@ -477,3 +497,49 @@ next_blk: return TINF_OK; } + +int tinf_uncompress_dyn_chksum(TINF_DATA *d) +{ + int res; + unsigned char *data = d->dest; + + res = tinf_uncompress_dyn(d); + + if (res < 0) return res; + + switch (d->checksum_type) { + + case TINF_CHKSUM_ADLER: + d->checksum = tinf_adler32(data, d->dest - data, d->checksum); + break; + + case TINF_CHKSUM_CRC: + d->checksum = tinf_crc32(data, d->dest - data, d->checksum); + break; + } + + if (res == TINF_DONE) { + unsigned int val; + + switch (d->checksum_type) { + + case TINF_CHKSUM_ADLER: + val = tinf_get_be_uint32(d); + if (d->checksum != val) { + return TINF_CHKSUM_ERROR; + } + break; + + case TINF_CHKSUM_CRC: + val = tinf_get_le_uint32(d); + if (~d->checksum != val) { + return TINF_CHKSUM_ERROR; + } + // Uncompressed size. TODO: Check + val = tinf_get_le_uint32(d); + break; + } + } + + return res; +} diff --git a/src/tinfzlib.c b/src/tinfzlib.c index 40485b0..5db83a1 100644 --- a/src/tinfzlib.c +++ b/src/tinfzlib.c @@ -57,33 +57,8 @@ int tinf_zlib_parse_header(TINF_DATA *d) if (flg & 0x20) return TINF_DATA_ERROR; /* initialize for adler32 checksum */ + d->checksum_type = TINF_CHKSUM_ADLER; d->checksum = 1; return cmf >> 4; } - -int tinf_zlib_uncompress_dyn(TINF_DATA *d) -{ - int res; - unsigned char *data = d->dest; - - res = tinf_uncompress_dyn(d); - - if (res < 0) return res; - - d->checksum = tinf_adler32(data, d->dest - data, d->checksum); - - if (res == TINF_DONE) { - /* -- get adler32 checksum -- */ - unsigned int a32 = 0; - int i; - for (i = 4; i--;) { - a32 = a32 << 8 | tinf_read_src_byte(d); - } - if (d->checksum != a32) { - return TINF_DATA_ERROR; - } - } - - return res; -}