diff options
Diffstat (limited to 'package/aboot/src/zip/unzip.c')
-rw-r--r-- | package/aboot/src/zip/unzip.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/package/aboot/src/zip/unzip.c b/package/aboot/src/zip/unzip.c new file mode 100644 index 000000000..81813da5d --- /dev/null +++ b/package/aboot/src/zip/unzip.c @@ -0,0 +1,139 @@ +/* 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 */ +} |