X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=archival%2Flibunarchive%2Fdecompress_unzip.c;h=3a7334ce9e10760bfd26a1609680a312f40785cc;hb=826b48b624e3c02b432b8ffbb7809657ddb3a012;hp=d8d5b77b1f4281c18f5afafe6a97b4b1d0852e77;hpb=83bf47c02f95a9956eb4f6a185014ab0fb62670b;p=oweals%2Fbusybox.git diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libunarchive/decompress_unzip.c index d8d5b77b1..3a7334ce9 100644 --- a/archival/libunarchive/decompress_unzip.c +++ b/archival/libunarchive/decompress_unzip.c @@ -86,16 +86,11 @@ static int gunzip_src_fd; unsigned int gunzip_bytes_out; /* number of output bytes */ static unsigned int gunzip_outbuf_count; /* bytes in output buffer */ -/* This is used to sanify any unused bits from the bitbuffer - * so they arent skipped when reading trailers (trailing headers) */ -unsigned char gunzip_in_buffer_count; -unsigned char *gunzip_in_buffer; - /* gunzip_window size--must be a power of two, and * at least 32K for zip's deflate method */ static const int gunzip_wsize = 0x8000; - static unsigned char *gunzip_window; + static unsigned int *gunzip_crc_table; unsigned int gunzip_crc; @@ -103,9 +98,16 @@ unsigned int gunzip_crc; #define BMAX 16 /* maximum bit length of any code (16 for explode) */ #define N_MAX 288 /* maximum number of codes in any set */ +/* bitbuffer */ static unsigned int gunzip_bb; /* bit buffer */ static unsigned char gunzip_bk; /* bits in bit buffer */ +/* These control the size of the bytebuffer */ +#define BYTEBUFFER_MAX 0x8000 +static unsigned char *bytebuffer = NULL; +static unsigned int bytebuffer_offset = 0; +static unsigned int bytebuffer_size = 0; + static const unsigned short mask_bits[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff @@ -142,13 +144,25 @@ static const unsigned char border[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; +static void fill_bytebuffer(void) +{ + if (bytebuffer_offset >= bytebuffer_size) { + /* Leave the first 4 bytes empty so we can always unwind the bitbuffer + * to the front of the bytebuffer, leave 4 bytes free at end of tail + * so we can easily top up buffer in check_trailer_gzip() */ + bytebuffer_size = 4 + xread(gunzip_src_fd, &bytebuffer[4], BYTEBUFFER_MAX - 8); + bytebuffer_offset = 4; + } +} + static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current, const unsigned int required) { while (*current < required) { - bitbuffer |= ((unsigned int) xread_char(gunzip_src_fd)) << *current; + fill_bytebuffer(); + bitbuffer |= ((unsigned int) bytebuffer[bytebuffer_offset]) << *current; + bytebuffer_offset++; *current += 8; } - return(bitbuffer); } @@ -857,7 +871,10 @@ static int inflate_get_next_window(void) int ret; if (needAnotherBlock) { - if(e) { calculate_gunzip_crc(); return 0; } // Last block + if(e) { + calculate_gunzip_crc(); + return 0; + } // Last block method = inflate_block(&e); needAnotherBlock = 0; } @@ -875,6 +892,7 @@ static int inflate_get_next_window(void) return 1; // More data left } else needAnotherBlock = 1; // End of that block } + /* Doesnt get here */ } /* @@ -923,7 +941,8 @@ extern void GZ_gzReadOpen(int fd, void *unused, int nUnused) gunzip_bytes_out = 0; gunzip_src_fd = fd; - gunzip_in_buffer = malloc(8); + /* Input buffer */ + bytebuffer = xmalloc(BYTEBUFFER_MAX); /* initialize gunzip_window, bit buffer */ gunzip_bk = 0; @@ -940,12 +959,11 @@ extern void GZ_gzReadClose(void) free(gunzip_crc_table); /* Store unused bytes in a global buffer so calling applets can access it */ - gunzip_in_buffer_count = 0; if (gunzip_bk >= 8) { /* Undo too much lookahead. The next read will be byte aligned * so we can discard unused bits in the last meaningful byte. */ - gunzip_in_buffer[gunzip_in_buffer_count] = gunzip_bb & 0xff; - gunzip_in_buffer_count++; + bytebuffer_offset--; + bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff; gunzip_bb >>= 8; gunzip_bk -= 8; } @@ -990,3 +1008,33 @@ extern int inflate(int in, int out) GZ_gzReadClose(); return 0; } + +extern void check_trailer_gzip(int src_fd) +{ + unsigned int stored_crc = 0; + unsigned char count; + + /* top up the input buffer with the rest of the trailer */ + count = bytebuffer_size - bytebuffer_offset; + if (count < 8) { + xread_all(src_fd, &bytebuffer[bytebuffer_size], 8 - count); + bytebuffer_size += 8 - count; + } + for (count = 0; count != 4; count++) { + stored_crc |= (bytebuffer[bytebuffer_offset] << (count * 8)); + bytebuffer_offset++; + } + + /* Validate decompression - crc */ + if (stored_crc != (gunzip_crc ^ 0xffffffffL)) { + error_msg_and_die("crc error"); + } + + /* Validate decompression - size */ + if (gunzip_bytes_out != + (bytebuffer[bytebuffer_offset] | (bytebuffer[bytebuffer_offset+1] << 8) | + (bytebuffer[bytebuffer_offset+2] << 16) | (bytebuffer[bytebuffer_offset+3] << 24))) { + error_msg_and_die("Incorrect length, but crc is correct"); + } + +}