• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * unzip.c
3  *
4  * This is a collection of several routines from gzip-1.0.3
5  * adapted for Linux.
6  *
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
10  *
11  * Adapted for MEMDISK by H. Peter Anvin, April 2003
12  */
13 
14 #include <stdint.h>
15 #include "memdisk.h"
16 #include "conio.h"
17 
18 #undef DEBUG			/* Means something different for this file */
19 
20 /*
21  * gzip declarations
22  */
23 
24 #define OF(args)  args
25 #define STATIC static
26 
27 #define memzero(s, n)     memset ((s), 0, (n))
28 
29 typedef uint8_t uch;
30 typedef uint16_t ush;
31 typedef uint32_t ulg;
32 
33 #define WSIZE 0x8000		/* Window size must be at least 32k, */
34 				/* and a power of two */
35 
36 static uch *inbuf;		/* input pointer */
37 static uch window[WSIZE];	/* sliding output window buffer */
38 
39 static unsigned insize;		/* total input bytes read */
40 static unsigned inbytes;	/* valid bytes in inbuf */
41 static unsigned outcnt;		/* bytes in output buffer */
42 
43 /* gzip flag byte */
44 #define ASCII_FLAG   0x01	/* bit 0 set: file probably ASCII text */
45 #define CONTINUATION 0x02	/* bit 1 set: continuation of multi-part gzip file */
46 #define EXTRA_FIELD  0x04	/* bit 2 set: extra field present */
47 #define ORIG_NAME    0x08	/* bit 3 set: original file name present */
48 #define COMMENT      0x10	/* bit 4 set: file comment present */
49 #define ENCRYPTED    0x20	/* bit 5 set: file is encrypted */
50 #define RESERVED     0xC0	/* bit 6,7:   reserved */
51 
52 /* Diagnostic functions */
53 #ifdef DEBUG
54 #  define Assert(cond,msg) {if(!(cond)) error(msg);}
55 #  define Trace(x) fprintf x
56 #  define Tracev(x) {if (verbose) fprintf x ;}
57 #  define Tracevv(x) {if (verbose>1) fprintf x ;}
58 #  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
59 #  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
60 #else
61 #  define Assert(cond,msg)
62 #  define Trace(x)
63 #  define Tracev(x)
64 #  define Tracevv(x)
65 #  define Tracec(c,x)
66 #  define Tracecv(c,x)
67 #endif
68 
69 static int fill_inbuf(void);
70 static void flush_window(void);
71 static void error(char *m);
72 static void gzip_mark(void **);
73 static void gzip_release(void **);
74 
75 static ulg crc_32_tab[256];
76 
77 /* Get byte from input buffer */
get_byte(void)78 static inline uch get_byte(void)
79 {
80     if (inbytes) {
81 	uch b = *inbuf++;
82 	inbytes--;
83 	return b;
84     } else {
85 	return fill_inbuf();	/* Input buffer underrun */
86     }
87 }
88 
89 /* Unget byte from input buffer */
unget_byte(void)90 static inline void unget_byte(void)
91 {
92     inbytes++;
93     inbuf--;
94 }
95 
96 static ulg bytes_out = 0;	/* Number of bytes output */
97 static uch *output_data;	/* Output data pointer */
98 static ulg output_size;		/* Number of output bytes expected */
99 
100 static void *malloc(int size);
101 static void free(void *where);
102 
103 static ulg free_mem_ptr, free_mem_end_ptr;
104 
105 #include "inflate.c"
106 
malloc(int size)107 static void *malloc(int size)
108 {
109     void *p;
110 
111     if (size < 0)
112 	error("malloc error");
113 
114     free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
115 
116     p = (void *)free_mem_ptr;
117     free_mem_ptr += size;
118 
119     if (free_mem_ptr >= free_mem_end_ptr)
120 	error("out of memory");
121 
122     return p;
123 }
124 
free(void * where)125 static void free(void *where)
126 {
127     /* Don't care */
128     (void)where;
129 }
130 
gzip_mark(void ** ptr)131 static void gzip_mark(void **ptr)
132 {
133     *ptr = (void *)free_mem_ptr;
134 }
135 
gzip_release(void ** ptr)136 static void gzip_release(void **ptr)
137 {
138     free_mem_ptr = (long)*ptr;
139 }
140 
141 /* ===========================================================================
142  * Fill the input buffer. This is called only when the buffer is empty
143  * and at least one byte is really needed.
144  */
fill_inbuf(void)145 static int fill_inbuf(void)
146 {
147     /* This should never happen.  We have already pointed the algorithm
148        to all the data we have. */
149     die("failed\nDecompression error: ran out of input data\n");
150 }
151 
152 /* ===========================================================================
153  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
154  * (Used for the decompressed data only.)
155  */
flush_window(void)156 static void flush_window(void)
157 {
158     ulg c = crc;		/* temporary variable */
159     unsigned n;
160     uch *in, *out, ch;
161 
162     if (bytes_out + outcnt > output_size)
163 	error("output buffer overrun");
164 
165     in = window;
166     out = output_data;
167     for (n = 0; n < outcnt; n++) {
168 	ch = *out++ = *in++;
169 	c = crc_32_tab[(c ^ ch) & 0xff] ^ (c >> 8);
170     }
171     crc = c;
172     output_data = out;
173     bytes_out += (ulg) outcnt;
174     outcnt = 0;
175 }
176 
error(char * x)177 static void error(char *x)
178 {
179     die("failed\nDecompression error: %s\n", x);
180 }
181 
182 /* GZIP header */
183 struct gzip_header {
184     uint16_t magic;
185     uint8_t method;
186     uint8_t flags;
187     uint32_t timestamp;
188     uint8_t extra_flags;
189     uint8_t os_type;
190 } __attribute__ ((packed));
191 /* (followed by optional and variable length "extra", "original name",
192    and "comment" fields) */
193 
194 struct gzip_trailer {
195     uint32_t crc;
196     uint32_t dbytes;
197 } __attribute__ ((packed));
198 
199 /* PKZIP header.  See
200  * <http://www.pkware.com/products/enterprise/white_papers/appnote.html>.
201  */
202 struct pkzip_header {
203     uint32_t magic;
204     uint16_t version;
205     uint16_t flags;
206     uint16_t method;
207     uint16_t modified_time;
208     uint16_t modified_date;
209     uint32_t crc;
210     uint32_t zbytes;
211     uint32_t dbytes;
212     uint16_t filename_len;
213     uint16_t extra_len;
214 } __attribute__ ((packed));
215 /* (followed by optional and variable length "filename" and "extra"
216    fields) */
217 
218 /* gzip flag byte */
219 #define ASCII_FLAG   0x01	/* bit 0 set: file probably ASCII text */
220 #define CONTINUATION 0x02	/* bit 1 set: continuation of multi-part gzip file */
221 #define EXTRA_FIELD  0x04	/* bit 2 set: extra field present */
222 #define ORIG_NAME    0x08	/* bit 3 set: original file name present */
223 #define COMMENT      0x10	/* bit 4 set: file comment present */
224 #define ENCRYPTED    0x20	/* bit 5 set: file is encrypted */
225 #define RESERVED     0xC0	/* bit 6,7:   reserved */
226 
227 /* pkzip flag byte */
228 #define PK_ENCRYPTED     0x01	/* bit 0 set: file is encrypted */
229 #define PK_DATADESC       0x08	/* bit 3 set: file has trailing "data
230 				   descriptor" */
231 #define PK_UNSUPPORTED    0xFFF0	/* All other bits must be zero */
232 
233 /* Return 0 if (indata, size) points to a ZIP file, and fill in
234    compressed data size, uncompressed data size, CRC, and offset of
235    data.
236 
237    If indata is not a ZIP file, return -1. */
check_zip(void * indata,uint32_t size,uint32_t * zbytes_p,uint32_t * dbytes_p,uint32_t * orig_crc,uint32_t * offset_p)238 int check_zip(void *indata, uint32_t size, uint32_t * zbytes_p,
239 	      uint32_t * dbytes_p, uint32_t * orig_crc, uint32_t * offset_p)
240 {
241     struct gzip_header *gzh = (struct gzip_header *)indata;
242     struct pkzip_header *pkzh = (struct pkzip_header *)indata;
243     uint32_t offset;
244 
245     if (gzh->magic == 0x8b1f) {
246 	struct gzip_trailer *gzt = indata + size - sizeof(struct gzip_trailer);
247 	/* We only support method #8, DEFLATED */
248 	if (gzh->method != 8) {
249 	    error("gzip file uses invalid method");
250 	    return -1;
251 	}
252 	if (gzh->flags & ENCRYPTED) {
253 	    error("gzip file is encrypted; not supported");
254 	    return -1;
255 	}
256 	if (gzh->flags & CONTINUATION) {
257 	    error("gzip file is a continuation file; not supported");
258 	    return -1;
259 	}
260 	if (gzh->flags & RESERVED) {
261 	    error("gzip file has unsupported flags");
262 	    return -1;
263 	}
264 	offset = sizeof(*gzh);
265 	if (gzh->flags & EXTRA_FIELD) {
266 	    /* Skip extra field */
267 	    unsigned len = *(unsigned *)(indata + offset);
268 	    offset += 2 + len;
269 	}
270 	if (gzh->flags & ORIG_NAME) {
271 	    /* Discard the old name */
272 	    uint8_t *p = indata;
273 	    while (p[offset] != 0 && offset < size) {
274 		offset++;
275 	    }
276 	    offset++;
277 	}
278 
279 	if (gzh->flags & COMMENT) {
280 	    /* Discard the comment */
281 	    uint8_t *p = indata;
282 	    while (p[offset] != 0 && offset < size) {
283 		offset++;
284 	    }
285 	    offset++;
286 	}
287 
288 	if (offset > size) {
289 	    error("gzip file corrupt");
290 	    return -1;
291 	}
292 	*zbytes_p = size - offset - sizeof(struct gzip_trailer);
293 	*dbytes_p = gzt->dbytes;
294 	*orig_crc = gzt->crc;
295 	*offset_p = offset;
296 	return 0;
297     } else if (pkzh->magic == 0x04034b50UL) {
298 	/* Magic number matches pkzip file. */
299 
300 	offset = sizeof(*pkzh);
301 	if (pkzh->flags & PK_ENCRYPTED) {
302 	    error("pkzip file is encrypted; not supported");
303 	    return -1;
304 	}
305 	if (pkzh->flags & PK_DATADESC) {
306 	    error("pkzip file uses data_descriptor field; not supported");
307 	    return -1;
308 	}
309 	if (pkzh->flags & PK_UNSUPPORTED) {
310 	    error("pkzip file has unsupported flags");
311 	    return -1;
312 	}
313 
314 	/* We only support method #8, DEFLATED */
315 	if (pkzh->method != 8) {
316 	    error("pkzip file uses invalid method");
317 	    return -1;
318 	}
319 	/* skip header */
320 	offset = sizeof(*pkzh);
321 	/* skip filename */
322 	offset += pkzh->filename_len;
323 	/* skip extra field */
324 	offset += pkzh->extra_len;
325 
326 	if (offset + pkzh->zbytes > size) {
327 	    error("pkzip file corrupt");
328 	    return -1;
329 	}
330 
331 	*zbytes_p = pkzh->zbytes;
332 	*dbytes_p = pkzh->dbytes;
333 	*orig_crc = pkzh->crc;
334 	*offset_p = offset;
335 	return 0;
336     } else {
337 	/* Magic number does not match. */
338 	return -1;
339     }
340 
341     error("Internal error in check_zip");
342     return -1;
343 }
344 
345 /*
346  * Decompress the image, trying to flush the end of it as close
347  * to end_mem as possible.  Return a pointer to the data block,
348  * and change datalen.
349  */
350 extern void _end;
351 
352 static char heap[65536];
353 
unzip(void * indata,uint32_t zbytes,uint32_t dbytes,uint32_t orig_crc,void * target)354 void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes,
355 	    uint32_t orig_crc, void *target)
356 {
357     /* Set up the heap; it is simply a chunk of bss memory */
358     free_mem_ptr     = (size_t)heap;
359     free_mem_end_ptr = (size_t)heap + sizeof heap;
360 
361     /* Set up input buffer */
362     inbuf = indata;
363     /* Sometimes inflate() looks beyond the end of the compressed data,
364        but it always backs up before it is done.  So we give it 4 bytes
365        of slack. */
366     insize = inbytes = zbytes + 4;
367 
368     /* Set up output buffer */
369     outcnt = 0;
370     output_data = target;
371     output_size = dbytes;
372     bytes_out = 0;
373 
374     makecrc();
375     gunzip();
376 
377     /* Verify that gunzip() consumed the entire input. */
378     if (inbytes != 4)
379 	error("compressed data length error");
380 
381     /* Check the uncompressed data length and CRC. */
382     if (bytes_out != dbytes)
383 	error("uncompressed data length error");
384 
385     if (orig_crc != CRC_VALUE)
386 	error("crc error");
387 
388     puts("ok\n");
389 
390     return target;
391 }
392