4 * This is a collection of several routines from gzip-1.0.3
7 * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
8 * puts by Nick Holloway 1993, better puts by Martin Mares 1995
9 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
11 * Adapted for MEMDISK by H. Peter Anvin, April 2003
25 #define memzero(s, n) memset ((s), 0, (n))
31 #define WSIZE 0x8000 /* Window size must be at least 32k, */
32 /* and a power of two */
34 static uch *inbuf; /* input pointer */
35 static uch window[WSIZE]; /* sliding output window buffer */
37 static unsigned insize; /* total input bytes read */
38 static unsigned inbytes; /* valid bytes in inbuf */
39 static unsigned outcnt; /* bytes in output buffer */
42 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
43 #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
44 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
45 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
46 #define COMMENT 0x10 /* bit 4 set: file comment present */
47 #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
48 #define RESERVED 0xC0 /* bit 6,7: reserved */
50 /* Diagnostic functions */
52 # define Assert(cond,msg) {if(!(cond)) error(msg);}
53 # define Trace(x) fprintf x
54 # define Tracev(x) {if (verbose) fprintf x ;}
55 # define Tracevv(x) {if (verbose>1) fprintf x ;}
56 # define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
57 # define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
59 # define Assert(cond,msg)
67 static int fill_inbuf(void);
68 static void flush_window(void);
69 static void error(char *m);
70 static void gzip_mark(void **);
71 static void gzip_release(void **);
73 /* Get byte from input buffer */
74 static inline uch get_byte(void)
81 return fill_inbuf(); /* Input buffer underrun */
85 /* Unget byte from input buffer */
86 static inline void unget_byte(void)
92 static ulg bytes_out = 0; /* Number of bytes output */
93 static uch *output_data; /* Output data pointer */
94 static ulg output_size; /* Number of output bytes expected */
96 static void *malloc(int size);
97 static void free(void *where);
99 static ulg free_mem_ptr, free_mem_end_ptr;
103 static void *malloc(int size)
107 if (size < 0) error("malloc error");
109 free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
111 p = (void *)free_mem_ptr;
112 free_mem_ptr += size;
114 if (free_mem_ptr >= free_mem_end_ptr)
115 error("out of memory");
120 static void free(void *where)
126 static void gzip_mark(void **ptr)
128 *ptr = (void *) free_mem_ptr;
131 static void gzip_release(void **ptr)
133 free_mem_ptr = (long) *ptr;
136 /* ===========================================================================
137 * Fill the input buffer. This is called only when the buffer is empty
138 * and at least one byte is really needed.
140 static int fill_inbuf(void)
142 /* This should never happen. We have already pointed the algorithm
143 to all the data we have. */
144 printf("failed\nDecompression error: ran out of input data\n");
148 /* ===========================================================================
149 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
150 * (Used for the decompressed data only.)
152 static void flush_window(void)
154 ulg c = crc; /* temporary variable */
158 if ( bytes_out+outcnt > output_size )
159 error("output buffer overrun");
163 for (n = 0; n < outcnt; n++) {
165 c = crc_32_tab[(c ^ ch) & 0xff] ^ (c >> 8);
169 bytes_out += (ulg)outcnt;
173 static void error(char *x)
175 printf("failed\nDecompression error: %s\n", x);
187 } __attribute__ ((packed));
188 /* (followed by optional and variable length "extra", "original name",
189 and "comment" fields) */
191 struct gzip_trailer {
194 } __attribute__ ((packed));
197 * <http://www.pkware.com/products/enterprise/white_papers/appnote.html>.
199 struct pkzip_header {
204 uint16_t modified_time;
205 uint16_t modified_date;
209 uint16_t filename_len;
211 } __attribute__ ((packed));
212 /* (followed by optional and variable length "filename" and "extra"
216 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
217 #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
218 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
219 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
220 #define COMMENT 0x10 /* bit 4 set: file comment present */
221 #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
222 #define RESERVED 0xC0 /* bit 6,7: reserved */
224 /* pkzip flag byte */
225 #define PK_ENCRYPTED 0x01 /* bit 0 set: file is encrypted */
226 #define PK_DATADESC 0x08 /* bit 3 set: file has trailing "data
228 #define PK_UNSUPPORTED 0xFFF0 /* All other bits must be zero */
231 /* Return 0 if (indata, size) points to a ZIP file, and fill in
232 compressed data size, uncompressed data size, CRC, and offset of
235 If indata is not a ZIP file, return -1. */
236 int check_zip(void *indata, uint32_t size, uint32_t *zbytes_p,
237 uint32_t *dbytes_p, uint32_t *orig_crc, uint32_t *offset_p) {
238 struct gzip_header *gzh = (struct gzip_header *)indata;
239 struct pkzip_header *pkzh = (struct pkzip_header *)indata;
242 if (gzh->magic == 0x8b1f) {
243 struct gzip_trailer *gzt = indata + size - sizeof (struct gzip_trailer);
244 /* We only support method #8, DEFLATED */
245 if (gzh->method != 8) {
246 error("gzip file uses invalid method");
249 if (gzh->flags & ENCRYPTED) {
250 error("gzip file is encrypted; not supported");
253 if (gzh->flags & CONTINUATION) {
254 error("gzip file is a continuation file; not supported");
257 if (gzh->flags & RESERVED) {
258 error("gzip file has unsupported flags");
261 offset = sizeof (*gzh);
262 if (gzh->flags & EXTRA_FIELD) {
263 /* Skip extra field */
264 unsigned len = *(unsigned *)(indata + offset);
267 if (gzh->flags & ORIG_NAME) {
268 /* Discard the old name */
270 while (p[offset] != 0 && offset < size) {
276 if (gzh->flags & COMMENT) {
277 /* Discard the comment */
279 while (p[offset] != 0 && offset < size) {
286 error ("gzip file corrupt");
289 *zbytes_p = size - offset - sizeof (struct gzip_trailer);
290 *dbytes_p = gzt->dbytes;
291 *orig_crc = gzt->crc;
295 else if (pkzh->magic == 0x04034b50UL) {
296 /* Magic number matches pkzip file. */
298 offset = sizeof (*pkzh);
299 if (pkzh->flags & PK_ENCRYPTED) {
300 error("pkzip file is encrypted; not supported");
303 if (pkzh->flags & PK_DATADESC) {
304 error("pkzip file uses data_descriptor field; not supported");
307 if (pkzh->flags & PK_UNSUPPORTED) {
308 error("pkzip file has unsupported flags");
312 /* We only support method #8, DEFLATED */
313 if (pkzh->method != 8) {
314 error("pkzip file uses invalid method");
318 offset = sizeof (*pkzh);
320 offset += pkzh->filename_len;
321 /* skip extra field */
322 offset += pkzh->extra_len;
324 if (offset + pkzh->zbytes > size) {
325 error ("pkzip file corrupt");
329 *zbytes_p = pkzh->zbytes;
330 *dbytes_p = pkzh->dbytes;
331 *orig_crc = pkzh->crc;
336 /* Magic number does not match. */
340 error ("Internal error in check_zip");
345 * Decompress the image, trying to flush the end of it as close
346 * to end_mem as possible. Return a pointer to the data block,
347 * and change datalen.
351 void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes,
352 uint32_t orig_crc, void *target)
354 /* Set up the heap; it's the 64K after the bounce buffer */
355 free_mem_ptr = (ulg)sys_bounce + 0x10000;
356 free_mem_end_ptr = free_mem_ptr + 0x10000;
358 /* Set up input buffer */
360 /* Sometimes inflate() looks beyond the end of the compressed data,
361 but it always backs up before it is done. So we give it 4 bytes
363 insize = inbytes = zbytes + 4;
365 /* Set up output buffer */
367 output_data = target;
368 output_size = dbytes;
374 /* Verify that gunzip() consumed the entire input. */
376 error("compressed data length error");
378 /* Check the uncompressed data length and CRC. */
379 if ( bytes_out != dbytes )
380 error("uncompressed data length error");
382 if (orig_crc != CRC_VALUE)