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:
parent
61d9cd644f
commit
05ee017a06
5 changed files with 112 additions and 82 deletions
|
|
@ -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*/;
|
||||
}
|
||||
|
|
|
|||
21
src/tinf.h
21
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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue