Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / i386 / boot / kzipboot / unzip.c
1 /*
2  * unzip.c -- decompress files in gzip or pkzip format.
3  * Copyright (C) 1992-1993 Jean-loup Gailly
4  *
5  * Adapted for Linux booting by Hannu Savolainen 1993
6  * Adapted for FreeBSD booting by Serge Vakulenko
7  *
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.
10  *
11  * The code in this file is derived from the file funzip.c written
12  * and put in the public domain by Mark Adler.
13  */
14
15 /*
16  * This version can extract files in gzip or pkzip format.
17  * For the latter, only the first entry is extracted, and it has to be
18  * either deflated or stored.
19  */
20
21 #include "gzip.h"
22
23 #include <sys/types.h>
24 #include <sys/inflate.h>
25
26 /* PKZIP header definitions */
27 #define LOCSIG  0x04034b50L     /* four-byte lead-in (lsb first) */
28 #define LOCFLG  6               /* offset of bit flag */
29 #define  CRPFLG 1               /*  bit for encrypted entry */
30 #define  EXTFLG 8               /*  bit for extended local header */
31 #define LOCHOW  8               /* offset of compression method */
32 #define LOCTIM  10              /* file mod time (for decryption) */
33 #define LOCCRC  14              /* offset of crc */
34 #define LOCSIZ  18              /* offset of compressed size */
35 #define LOCLEN  22              /* offset of uncompressed length */
36 #define LOCFIL  26              /* offset of file name field length */
37 #define LOCEXT  28              /* offset of extra field length */
38 #define LOCHDR  30              /* size of local header, including sig */
39 #define EXTHDR  16              /* size of extended local header, inc sig */
40
41 int pkzip;                      /* set for a pkzip file */
42 int extended;                   /* set if extended local header */
43
44 /* Macros for getting two-byte and four-byte header values */
45 #define SH(p) ((ushort)(uchar)((p)[0]) | ((ushort)(uchar)((p)[1]) << 8))
46 #define LG(p) ((ulong)(SH(p)) | ((ulong)(SH((p)+2)) << 16))
47
48 /*
49  * Check zip file and advance inptr to the start of the compressed data.
50  * Get ofname from the local header if necessary.
51  */
52 void check_zipfile()
53 {
54         uchar *h = inbuf + inptr;       /* first local header */
55
56         /* Check validity of local header, and skip name and extra fields */
57         inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
58
59         if (inptr > insize || LG(h) != LOCSIG)
60                 error("input not a zip");
61
62         method = h[LOCHOW];
63         if (method != STORED && method != DEFLATED)
64                 error("first entry not deflated or stored--can't extract");
65
66         /* If entry encrypted, decrypt and validate encryption header */
67         if (h[LOCFLG] & CRPFLG)
68                 error("encrypted file");
69
70         /* Save flags for unzip() */
71         extended = (h[LOCFLG] & EXTFLG) != 0;
72         pkzip = 1;
73 }
74
75 int
76 Flush (void *nu, u_char *buf, u_long cnt)
77 {
78         outcnt = cnt;
79         flush_window();
80         return 0;
81 }
82
83 int
84 NextByte (void *nu)
85 {
86         return ((int) get_byte ());
87 }
88
89 struct inflate infl; /* put it into the BSS */
90
91 /*
92  * Unzip in to out.  This routine works on both gzip and pkzip files.
93  *
94  * IN assertions: the buffer inbuf contains already the beginning of
95  * the compressed data, from offsets inptr to insize-1 included.
96  * The magic header has already been checked. The output buffer is cleared.
97  */
98
99 void unzip()
100 {
101         ulong orig_crc = 0;     /* original crc */
102         ulong orig_len = 0;     /* original uncompressed length */
103         uchar buf[EXTHDR];      /* extended local header */
104         int n, res;
105
106         crc = 0xffffffffL;      /* initialize crc */
107
108         if (pkzip && !extended) { /* crc and length at the end otherwise */
109                 orig_crc = LG(inbuf + LOCCRC);
110                 orig_len = LG(inbuf + LOCLEN);
111         }
112
113         if (method != DEFLATED)
114                 error("internal error, invalid method");
115         infl.gz_input = NextByte;
116         infl.gz_output = Flush;
117         infl.gz_slide = window;
118         res = inflate (&infl);
119         if (res == 3)
120                 error("out of memory");
121         else if (res != 0)
122                 error("invalid compressed format");
123
124         /* Get the crc and original length */
125         if (!pkzip) {
126                 /* crc32 (see algorithm.doc)
127                  * uncompressed input size modulo 2^32
128                  */
129                 for (n = 0; n < 8; n++)
130                         buf[n] = get_byte();    /* may cause an error if EOF */
131                 orig_crc = LG(buf);
132                 orig_len = LG(buf+4);
133
134         } else if (extended) {          /* If extended header, check it */
135                 /* signature - 4bytes: 0x50 0x4b 0x07 0x08
136                  * CRC-32 value
137                  * compressed size 4-bytes
138                  * uncompressed size 4-bytes
139                  */
140                 for (n = 0; n < EXTHDR; n++)
141                         buf[n] = get_byte();    /* may cause an error if EOF */
142                 orig_crc = LG(buf+4);
143                 orig_len = LG(buf+12);
144         }
145
146         /* Validate decompression */
147         if (orig_crc != (crc ^ 0xffffffffL))
148                 error("crc error");
149         if (orig_len != output_ptr)
150                 error("length error");
151
152         /* Check if there are more entries in a pkzip file */
153         if (pkzip && inptr+4 < insize && LG(inbuf+inptr) == LOCSIG)
154                 error("zip file has more than one entry");
155 }