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} 392