Home | History | Annotate | Download | only in memdisk
      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 */
     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 */
     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 
    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 
    125 static void free(void *where)
    126 {
    127     /* Don't care */
    128     (void)where;
    129 }
    130 
    131 static void gzip_mark(void **ptr)
    132 {
    133     *ptr = (void *)free_mem_ptr;
    134 }
    135 
    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  */
    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  */
    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 
    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. */
    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 
    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