kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / platform / pc32 / 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  * $DragonFly: src/sys/platform/pc32/boot/kzipboot/Attic/unzip.c,v 1.2 2003/08/07 21:17:20 dillon Exp $
15  */
16
17 /*
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.
21  */
22
23 #include "use_gzip.h"
24
25 #include <sys/types.h>
26 #include <sys/inflate.h>
27
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 */
42
43 int pkzip;                      /* set for a pkzip file */
44 int extended;                   /* set if extended local header */
45
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))
49
50 /*
51  * Check zip file and advance inptr to the start of the compressed data.
52  * Get ofname from the local header if necessary.
53  */
54 void check_zipfile()
55 {
56         uchar *h = inbuf + inptr;       /* first local header */
57
58         /* Check validity of local header, and skip name and extra fields */
59         inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
60
61         if (inptr > insize || LG(h) != LOCSIG)
62                 error("input not a zip");
63
64         method = h[LOCHOW];
65         if (method != STORED && method != DEFLATED)
66                 error("first entry not deflated or stored--can't extract");
67
68         /* If entry encrypted, decrypt and validate encryption header */
69         if (h[LOCFLG] & CRPFLG)
70                 error("encrypted file");
71
72         /* Save flags for unzip() */
73         extended = (h[LOCFLG] & EXTFLG) != 0;
74         pkzip = 1;
75 }
76
77 int
78 Flush (void *nu, u_char *buf, u_long cnt)
79 {
80         outcnt = cnt;
81         flush_window();
82         return 0;
83 }
84
85 int
86 NextByte (void *nu)
87 {
88         return ((int) get_byte ());
89 }
90
91 struct inflate infl; /* put it into the BSS */
92
93 /*
94  * Unzip in to out.  This routine works on both gzip and pkzip files.
95  *
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.
99  */
100
101 void unzip()
102 {
103         ulong orig_crc = 0;     /* original crc */
104         ulong orig_len = 0;     /* original uncompressed length */
105         uchar buf[EXTHDR];      /* extended local header */
106         int n, res;
107
108         crc = 0xffffffffL;      /* initialize crc */
109
110         if (pkzip && !extended) { /* crc and length at the end otherwise */
111                 orig_crc = LG(inbuf + LOCCRC);
112                 orig_len = LG(inbuf + LOCLEN);
113         }
114
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);
121         if (res == 3)
122                 error("out of memory");
123         else if (res != 0)
124                 error("invalid compressed format");
125
126         /* Get the crc and original length */
127         if (!pkzip) {
128                 /* crc32 (see algorithm.doc)
129                  * uncompressed input size modulo 2^32
130                  */
131                 for (n = 0; n < 8; n++)
132                         buf[n] = get_byte();    /* may cause an error if EOF */
133                 orig_crc = LG(buf);
134                 orig_len = LG(buf+4);
135
136         } else if (extended) {          /* If extended header, check it */
137                 /* signature - 4bytes: 0x50 0x4b 0x07 0x08
138                  * CRC-32 value
139                  * compressed size 4-bytes
140                  * uncompressed size 4-bytes
141                  */
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);
146         }
147
148         /* Validate decompression */
149         if (orig_crc != (crc ^ 0xffffffffL))
150                 error("crc error");
151         if (orig_len != output_ptr)
152                 error("length error");
153
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");
157 }