Woops, my gunzip fix broke unzip, these cant be static
[oweals/busybox.git] / archival / libunarchive / decompress_unzip.c
index d8d5b77b1f4281c18f5afafe6a97b4b1d0852e77..3a7334ce9e10760bfd26a1609680a312f40785cc 100644 (file)
@@ -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");
+       }
+
+}