/* unzip.c -- decompress files in gzip or pkzip format. * Copyright (C) 1992-1993 Jean-loup Gailly * * Adapted for Linux booting by Hannu Savolainen 1993 * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, see the file COPYING. * * The code in this file is derived from the file funzip.c written * and put in the public domain by Mark Adler. */ /* * This version can extract files in gzip or pkzip format. For the * latter, only the first entry is extracted, and it has to be either * deflated or stored. */ #include "gzip.h" /* PKZIP header definitions */ #define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */ #define LOCFLG 6 /* offset of bit flag */ #define CRPFLG 1 /* bit for encrypted entry */ #define EXTFLG 8 /* bit for extended local header */ #define LOCHOW 8 /* offset of compression method */ #define LOCTIM 10 /* file mod time (for decryption) */ #define LOCCRC 14 /* offset of crc */ #define LOCSIZ 18 /* offset of compressed size */ #define LOCLEN 22 /* offset of uncompressed length */ #define LOCFIL 26 /* offset of file name field length */ #define LOCEXT 28 /* offset of extra field length */ #define LOCHDR 30 /* size of local header, including sig */ #define EXTHDR 16 /* size of extended local header, inc sig */ /* Globals */ int pkzip = 0; /* set for a pkzip file */ int extended = 0; /* set if extended local header */ /* * Unzip in to out. This routine works on both gzip and pkzip files. * * IN assertions: the buffer inbuf contains already the beginning of * the compressed data, from offsets inptr to insize-1 included. * The magic header has already been checked. The output buffer is cleared. */ void unzip(in, out) int in, out; /* input and output file descriptors */ { unsigned long orig_crc = 0; /* original crc */ unsigned long orig_len = 0; /* original uncompressed length */ int n; unsigned char buf[EXTHDR]; /* extended local header */ /* ifd = in; ofd = out; */ updcrc(NULL, 0); /* initialize crc */ if (pkzip && !extended) { /* crc and length at the end otherwise */ orig_crc = LG(inbuf + LOCCRC); orig_len = LG(inbuf + LOCLEN); } /* Decompress */ if (method == DEFLATED) { int res = inflate(); if (res == 3) { unzip_error("out of memory"); } else if (res != 0) { unzip_error("invalid compressed format"); } } else if (pkzip && method == STORED) { register unsigned long n = LG(inbuf + LOCLEN); if (n != LG(inbuf + LOCSIZ)) { unzip_error("length mismatch"); } while (n--) { unsigned char c = get_byte(); put_char(c); } } else { unzip_error("internal error, invalid method"); } /* Get the crc and original length */ #ifdef DEBUG printf("getting CRC and length\n"); #endif if (!pkzip) { /* crc32 (see algorithm.doc) * uncompressed input size modulo 2^32 */ for (n = 0; n < 8; n++) { buf[n] = get_byte(); /* may cause an error if EOF */ #ifdef DEBUG printf("nonext: doing CRC, get_byte (ptr %d) returned %d\n", inptr, buf[n]); #endif } orig_crc = LG(buf); orig_len = LG(buf+4); } else if (extended) { /* If extended header, check it */ /* signature - 4bytes: 0x50 0x4b 0x07 0x08 * CRC-32 value * compressed size 4-bytes * uncompressed size 4-bytes */ for (n = 0; n < EXTHDR; n++) { buf[n] = get_byte(); /* may cause an error if EOF */ #ifdef DEBUG printf("ext: doing CRC, get_byte returned %d\n", buf[n]); #endif } orig_crc = LG(buf+4); orig_len = LG(buf+12); } /* Validate decompression */ if (orig_crc != updcrc(buf, 0)) { unzip_error("crc error"); } if (orig_len != bytes_out) { unzip_error("length error"); } /* Check if there are more entries in a pkzip file */ if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) { unzip_error("zip file has more than one entry"); } extended = pkzip = 0; /* for next file */ }