diff options
Diffstat (limited to 'contrib/syslinux-4.02/memdisk/unzip.c')
-rw-r--r-- | contrib/syslinux-4.02/memdisk/unzip.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/memdisk/unzip.c b/contrib/syslinux-4.02/memdisk/unzip.c new file mode 100644 index 0000000..18a1df4 --- /dev/null +++ b/contrib/syslinux-4.02/memdisk/unzip.c @@ -0,0 +1,391 @@ +/* + * unzip.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * puts by Nick Holloway 1993, better puts by Martin Mares 1995 + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + * + * Adapted for MEMDISK by H. Peter Anvin, April 2003 + */ + +#include <stdint.h> +#include "memdisk.h" +#include "conio.h" + +#undef DEBUG /* Means something different for this file */ + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#define memzero(s, n) memset ((s), 0, (n)) + +typedef uint8_t uch; +typedef uint16_t ush; +typedef uint32_t ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input pointer */ +static uch window[WSIZE]; /* sliding output window buffer */ + +static unsigned insize; /* total input bytes read */ +static unsigned inbytes; /* valid bytes in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +static ulg crc_32_tab[256]; + +/* Get byte from input buffer */ +static inline uch get_byte(void) +{ + if (inbytes) { + uch b = *inbuf++; + inbytes--; + return b; + } else { + return fill_inbuf(); /* Input buffer underrun */ + } +} + +/* Unget byte from input buffer */ +static inline void unget_byte(void) +{ + inbytes++; + inbuf--; +} + +static ulg bytes_out = 0; /* Number of bytes output */ +static uch *output_data; /* Output data pointer */ +static ulg output_size; /* Number of output bytes expected */ + +static void *malloc(int size); +static void free(void *where); + +static ulg free_mem_ptr, free_mem_end_ptr; + +#include "inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size < 0) + error("malloc error"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("out of memory"); + + return p; +} + +static void free(void *where) +{ + /* Don't care */ + (void)where; +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *)free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long)*ptr; +} + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +static int fill_inbuf(void) +{ + /* This should never happen. We have already pointed the algorithm + to all the data we have. */ + die("failed\nDecompression error: ran out of input data\n"); +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, *out, ch; + + if (bytes_out + outcnt > output_size) + error("output buffer overrun"); + + in = window; + out = output_data; + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[(c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + output_data = out; + bytes_out += (ulg) outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + die("failed\nDecompression error: %s\n", x); +} + +/* GZIP header */ +struct gzip_header { + uint16_t magic; + uint8_t method; + uint8_t flags; + uint32_t timestamp; + uint8_t extra_flags; + uint8_t os_type; +} __attribute__ ((packed)); +/* (followed by optional and variable length "extra", "original name", + and "comment" fields) */ + +struct gzip_trailer { + uint32_t crc; + uint32_t dbytes; +} __attribute__ ((packed)); + +/* PKZIP header. See + * <http://www.pkware.com/products/enterprise/white_papers/appnote.html>. + */ +struct pkzip_header { + uint32_t magic; + uint16_t version; + uint16_t flags; + uint16_t method; + uint16_t modified_time; + uint16_t modified_date; + uint32_t crc; + uint32_t zbytes; + uint32_t dbytes; + uint16_t filename_len; + uint16_t extra_len; +} __attribute__ ((packed)); +/* (followed by optional and variable length "filename" and "extra" + fields) */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* pkzip flag byte */ +#define PK_ENCRYPTED 0x01 /* bit 0 set: file is encrypted */ +#define PK_DATADESC 0x08 /* bit 3 set: file has trailing "data + descriptor" */ +#define PK_UNSUPPORTED 0xFFF0 /* All other bits must be zero */ + +/* Return 0 if (indata, size) points to a ZIP file, and fill in + compressed data size, uncompressed data size, CRC, and offset of + data. + + If indata is not a ZIP file, return -1. */ +int check_zip(void *indata, uint32_t size, uint32_t * zbytes_p, + uint32_t * dbytes_p, uint32_t * orig_crc, uint32_t * offset_p) +{ + struct gzip_header *gzh = (struct gzip_header *)indata; + struct pkzip_header *pkzh = (struct pkzip_header *)indata; + uint32_t offset; + + if (gzh->magic == 0x8b1f) { + struct gzip_trailer *gzt = indata + size - sizeof(struct gzip_trailer); + /* We only support method #8, DEFLATED */ + if (gzh->method != 8) { + error("gzip file uses invalid method"); + return -1; + } + if (gzh->flags & ENCRYPTED) { + error("gzip file is encrypted; not supported"); + return -1; + } + if (gzh->flags & CONTINUATION) { + error("gzip file is a continuation file; not supported"); + return -1; + } + if (gzh->flags & RESERVED) { + error("gzip file has unsupported flags"); + return -1; + } + offset = sizeof(*gzh); + if (gzh->flags & EXTRA_FIELD) { + /* Skip extra field */ + unsigned len = *(unsigned *)(indata + offset); + offset += 2 + len; + } + if (gzh->flags & ORIG_NAME) { + /* Discard the old name */ + uint8_t *p = indata; + while (p[offset] != 0 && offset < size) { + offset++; + } + offset++; + } + + if (gzh->flags & COMMENT) { + /* Discard the comment */ + uint8_t *p = indata; + while (p[offset] != 0 && offset < size) { + offset++; + } + offset++; + } + + if (offset > size) { + error("gzip file corrupt"); + return -1; + } + *zbytes_p = size - offset - sizeof(struct gzip_trailer); + *dbytes_p = gzt->dbytes; + *orig_crc = gzt->crc; + *offset_p = offset; + return 0; + } else if (pkzh->magic == 0x04034b50UL) { + /* Magic number matches pkzip file. */ + + offset = sizeof(*pkzh); + if (pkzh->flags & PK_ENCRYPTED) { + error("pkzip file is encrypted; not supported"); + return -1; + } + if (pkzh->flags & PK_DATADESC) { + error("pkzip file uses data_descriptor field; not supported"); + return -1; + } + if (pkzh->flags & PK_UNSUPPORTED) { + error("pkzip file has unsupported flags"); + return -1; + } + + /* We only support method #8, DEFLATED */ + if (pkzh->method != 8) { + error("pkzip file uses invalid method"); + return -1; + } + /* skip header */ + offset = sizeof(*pkzh); + /* skip filename */ + offset += pkzh->filename_len; + /* skip extra field */ + offset += pkzh->extra_len; + + if (offset + pkzh->zbytes > size) { + error("pkzip file corrupt"); + return -1; + } + + *zbytes_p = pkzh->zbytes; + *dbytes_p = pkzh->dbytes; + *orig_crc = pkzh->crc; + *offset_p = offset; + return 0; + } else { + /* Magic number does not match. */ + return -1; + } + + error("Internal error in check_zip"); + return -1; +} + +/* + * Decompress the image, trying to flush the end of it as close + * to end_mem as possible. Return a pointer to the data block, + * and change datalen. + */ +extern void _end; + +static char heap[65536]; + +void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes, + uint32_t orig_crc, void *target) +{ + /* Set up the heap; it is simply a chunk of bss memory */ + free_mem_ptr = (size_t)heap; + free_mem_end_ptr = (size_t)heap + sizeof heap; + + /* Set up input buffer */ + inbuf = indata; + /* Sometimes inflate() looks beyond the end of the compressed data, + but it always backs up before it is done. So we give it 4 bytes + of slack. */ + insize = inbytes = zbytes + 4; + + /* Set up output buffer */ + outcnt = 0; + output_data = target; + output_size = dbytes; + bytes_out = 0; + + makecrc(); + gunzip(); + + /* Verify that gunzip() consumed the entire input. */ + if (inbytes != 4) + error("compressed data length error"); + + /* Check the uncompressed data length and CRC. */ + if (bytes_out != dbytes) + error("uncompressed data length error"); + + if (orig_crc != CRC_VALUE) + error("crc error"); + + puts("ok\n"); + + return target; +} |