2 * unzip.c -- decompress files in gzip or pkzip format.
3 * Copyright (C) 1992-1993 Jean-loup Gailly
5 * Adapted for Linux booting by Hannu Savolainen 1993
6 * Adapted for FreeBSD booting by Serge Vakulenko
8 * This is free software; you can redistribute it and/or modify it under the
9 * terms of the GNU General Public License, see the file COPYING.
11 * The code in this file is derived from the file funzip.c written
12 * and put in the public domain by Mark Adler.
14 * $DragonFly: src/sys/platform/pc32/boot/kzipboot/Attic/unzip.c,v 1.2 2003/08/07 21:17:20 dillon Exp $
18 * This version can extract files in gzip or pkzip format.
19 * For the latter, only the first entry is extracted, and it has to be
20 * either deflated or stored.
25 #include <sys/types.h>
26 #include <sys/inflate.h>
28 /* PKZIP header definitions */
29 #define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */
30 #define LOCFLG 6 /* offset of bit flag */
31 #define CRPFLG 1 /* bit for encrypted entry */
32 #define EXTFLG 8 /* bit for extended local header */
33 #define LOCHOW 8 /* offset of compression method */
34 #define LOCTIM 10 /* file mod time (for decryption) */
35 #define LOCCRC 14 /* offset of crc */
36 #define LOCSIZ 18 /* offset of compressed size */
37 #define LOCLEN 22 /* offset of uncompressed length */
38 #define LOCFIL 26 /* offset of file name field length */
39 #define LOCEXT 28 /* offset of extra field length */
40 #define LOCHDR 30 /* size of local header, including sig */
41 #define EXTHDR 16 /* size of extended local header, inc sig */
43 int pkzip; /* set for a pkzip file */
44 int extended; /* set if extended local header */
46 /* Macros for getting two-byte and four-byte header values */
47 #define SH(p) ((ushort)(uchar)((p)[0]) | ((ushort)(uchar)((p)[1]) << 8))
48 #define LG(p) ((ulong)(SH(p)) | ((ulong)(SH((p)+2)) << 16))
51 * Check zip file and advance inptr to the start of the compressed data.
52 * Get ofname from the local header if necessary.
56 uchar *h = inbuf + inptr; /* first local header */
58 /* Check validity of local header, and skip name and extra fields */
59 inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
61 if (inptr > insize || LG(h) != LOCSIG)
62 error("input not a zip");
65 if (method != STORED && method != DEFLATED)
66 error("first entry not deflated or stored--can't extract");
68 /* If entry encrypted, decrypt and validate encryption header */
69 if (h[LOCFLG] & CRPFLG)
70 error("encrypted file");
72 /* Save flags for unzip() */
73 extended = (h[LOCFLG] & EXTFLG) != 0;
78 Flush (void *nu, u_char *buf, u_long cnt)
88 return ((int) get_byte ());
91 struct inflate infl; /* put it into the BSS */
94 * Unzip in to out. This routine works on both gzip and pkzip files.
96 * IN assertions: the buffer inbuf contains already the beginning of
97 * the compressed data, from offsets inptr to insize-1 included.
98 * The magic header has already been checked. The output buffer is cleared.
103 ulong orig_crc = 0; /* original crc */
104 ulong orig_len = 0; /* original uncompressed length */
105 uchar buf[EXTHDR]; /* extended local header */
108 crc = 0xffffffffL; /* initialize crc */
110 if (pkzip && !extended) { /* crc and length at the end otherwise */
111 orig_crc = LG(inbuf + LOCCRC);
112 orig_len = LG(inbuf + LOCLEN);
115 if (method != DEFLATED)
116 error("internal error, invalid method");
117 infl.gz_input = NextByte;
118 infl.gz_output = Flush;
119 infl.gz_slide = window;
120 res = inflate (&infl);
122 error("out of memory");
124 error("invalid compressed format");
126 /* Get the crc and original length */
128 /* crc32 (see algorithm.doc)
129 * uncompressed input size modulo 2^32
131 for (n = 0; n < 8; n++)
132 buf[n] = get_byte(); /* may cause an error if EOF */
134 orig_len = LG(buf+4);
136 } else if (extended) { /* If extended header, check it */
137 /* signature - 4bytes: 0x50 0x4b 0x07 0x08
139 * compressed size 4-bytes
140 * uncompressed size 4-bytes
142 for (n = 0; n < EXTHDR; n++)
143 buf[n] = get_byte(); /* may cause an error if EOF */
144 orig_crc = LG(buf+4);
145 orig_len = LG(buf+12);
148 /* Validate decompression */
149 if (orig_crc != (crc ^ 0xffffffffL))
151 if (orig_len != output_ptr)
152 error("length error");
154 /* Check if there are more entries in a pkzip file */
155 if (pkzip && inptr+4 < insize && LG(inbuf+inptr) == LOCSIG)
156 error("zip file has more than one entry");