📄 unzip.c
字号:
/* * 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"/* * 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)#endifstatic int fill_inbuf(void);static void flush_window(void);static void error(char *m);static void gzip_mark(void **);static void gzip_release(void **);extern 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 */}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. */ printf("failed\nDecompression error: ran out of input data\n"); die();}/* =========================================================================== * 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){ printf("failed\nDecompression error: %s\n", x); die();}/* 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;void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes, uint32_t orig_crc, void *target){ /* Set up the heap; it's the 64K after the bounce buffer */ free_mem_ptr = (ulg)sys_bounce + 0x10000; free_mem_end_ptr = free_mem_ptr + 0x10000; /* 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -