syslinux/memdisk/unzip.c
<<
>>
Prefs
   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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.