source: bootcd/isolinux/syslinux-6.03/memdisk/unzip.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 9.7 KB
Line 
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
29typedef uint8_t uch;
30typedef uint16_t ush;
31typedef uint32_t ulg;
32
33#define WSIZE 0x8000            /* Window size must be at least 32k, */
34                                /* and a power of two */
35
36static uch *inbuf;              /* input pointer */
37static uch window[WSIZE];       /* sliding output window buffer */
38
39static unsigned insize;         /* total input bytes read */
40static unsigned inbytes;        /* valid bytes in inbuf */
41static 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
69static int fill_inbuf(void);
70static void flush_window(void);
71static void error(char *m);
72static void gzip_mark(void **);
73static void gzip_release(void **);
74
75static ulg crc_32_tab[256];
76
77/* Get byte from input buffer */
78static 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 */
90static inline void unget_byte(void)
91{
92    inbytes++;
93    inbuf--;
94}
95
96static ulg bytes_out = 0;       /* Number of bytes output */
97static uch *output_data;        /* Output data pointer */
98static ulg output_size;         /* Number of output bytes expected */
99
100static void *malloc(int size);
101static void free(void *where);
102
103static ulg free_mem_ptr, free_mem_end_ptr;
104
105#include "inflate.c"
106
107static 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
125static void free(void *where)
126{
127    /* Don't care */
128    (void)where;
129}
130
131static void gzip_mark(void **ptr)
132{
133    *ptr = (void *)free_mem_ptr;
134}
135
136static 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 */
145static 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 */
156static 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
177static void error(char *x)
178{
179    die("failed\nDecompression error: %s\n", x);
180}
181
182/* GZIP header */
183struct 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
194struct 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 */
202struct 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. */
238int 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 */
350extern void _end;
351
352static char heap[65536];
353
354void *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}
Note: See TracBrowser for help on using the repository browser.