tinf: Add tinf_uncompress_dyn_chksum() handling zlib/gzip chksum calc.

If tinf_zlib_parse_header()/tinf_gzip_parse_header() were called,
tinf_uncompress_dyn_chksum() will calculate corresponding checksum
(adler32/crc32) incrementally, and at EOF check it (separate error
code return for checksum mismatch).
This commit is contained in:
Paul Sokolovsky 2016-08-10 02:01:55 +03:00
parent 61d9cd644f
commit 05ee017a06
5 changed files with 112 additions and 82 deletions

View file

@ -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*/;
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}