]>
Commit | Line | Data |
---|---|---|
f6bcfd97 BP |
1 | /* funzip.c -- put in the public domain by Mark Adler */ |
2 | ||
3 | #define VERSION "3.93 of 21 November 1998" | |
4 | ||
5 | ||
6 | /* You can do whatever you like with this source file, though I would | |
7 | prefer that if you modify it and redistribute it that you include | |
8 | comments to that effect with your name and the date. Thank you. | |
9 | ||
10 | History: | |
11 | vers date who what | |
12 | ---- --------- -------------- ------------------------------------ | |
13 | 1.0 13 Aug 92 M. Adler really simple unzip filter. | |
14 | 1.1 13 Aug 92 M. Adler cleaned up somewhat, give help if | |
15 | stdin not redirected, warn if more | |
16 | zip file entries after the first. | |
17 | 1.2 15 Aug 92 M. Adler added check of lengths for stored | |
18 | entries, added more help. | |
19 | 1.3 16 Aug 92 M. Adler removed redundant #define's, added | |
20 | decryption. | |
21 | 1.4 27 Aug 92 G. Roelofs added exit(0). | |
22 | 1.5 1 Sep 92 K. U. Rommel changed read/write modes for OS/2. | |
23 | 1.6 6 Sep 92 G. Roelofs modified to use dummy crypt.c and | |
24 | crypt.h instead of -DCRYPT. | |
25 | 1.7 23 Sep 92 G. Roelofs changed to use DOS_OS2; included | |
26 | crypt.c under MS-DOS. | |
27 | 1.8 9 Oct 92 M. Adler improved inflation error msgs. | |
28 | 1.9 17 Oct 92 G. Roelofs changed ULONG/UWORD/byte to ulg/ush/uch; | |
29 | renamed inflate_entry() to inflate(); | |
30 | adapted to use new, in-place zdecode. | |
31 | 2.0 22 Oct 92 M. Adler allow filename argument, prompt for | |
32 | passwords and don't echo, still allow | |
33 | command-line password entry, but as an | |
34 | option. | |
35 | 2.1 23 Oct 92 J-l. Gailly fixed crypt/store bug, | |
36 | G. Roelofs removed crypt.c under MS-DOS, fixed | |
37 | decryption check to compare single byte. | |
38 | 2.2 28 Oct 92 G. Roelofs removed declaration of key. | |
39 | 2.3 14 Dec 92 M. Adler replaced fseek (fails on stdin for SCO | |
40 | Unix V.3.2.4). added quietflg for | |
41 | inflate.c. | |
42 | 3.0 11 May 93 M. Adler added gzip support | |
43 | 3.1 9 Jul 93 K. U. Rommel fixed OS/2 pipe bug (PIPE_ERROR) | |
44 | 3.2 4 Sep 93 G. Roelofs moved crc_32_tab[] to tables.h; used FOPx | |
45 | from unzip.h; nuked OUTB macro and outbuf; | |
46 | replaced flush(); inlined FlushOutput(); | |
47 | renamed decrypt to encrypted | |
48 | 3.3 29 Sep 93 G. Roelofs replaced ReadByte() with NEXTBYTE macro; | |
49 | revised (restored?) flush(); added FUNZIP | |
50 | 3.4 21 Oct 93 G. Roelofs renamed quietflg to qflag; changed outcnt, | |
51 | H. Gessau second updcrc() arg and flush() arg to ulg; | |
52 | added inflate_free(); added "g =" to null | |
53 | getc(in) to avoid compiler warnings | |
54 | 3.5 31 Oct 93 H. Gessau changed DOS_OS2 to DOS_NT_OS2 | |
55 | 3.6 6 Dec 93 H. Gessau added "near" to mask_bits[] | |
56 | 3.7 9 Dec 93 G. Roelofs added extent typecasts to fwrite() checks | |
57 | 3.8 28 Jan 94 GRR/JlG initialized g variable in main() for gcc | |
58 | 3.81 22 Feb 94 M. Hanning-Lee corrected usage message | |
59 | 3.82 27 Feb 94 G. Roelofs added some typecasts to avoid warnings | |
60 | 3.83 22 Jul 94 G. Roelofs changed fprintf to macro for DLLs | |
61 | - 2 Aug 94 - public release with UnZip 5.11 | |
62 | - 28 Aug 94 - public release with UnZip 5.12 | |
63 | 3.84 1 Oct 94 K. U. Rommel changes for Metaware High C | |
64 | 3.85 29 Oct 94 G. Roelofs changed fprintf macro to Info | |
65 | 3.86 7 May 95 K. Davis RISCOS patches; | |
66 | P. Kienitz Amiga patches | |
67 | 3.87 12 Aug 95 G. Roelofs inflate_free(), DESTROYGLOBALS fixes | |
68 | 3.88 4 Sep 95 C. Spieler reordered macro to work around MSC 5.1 bug | |
69 | 3.89 22 Nov 95 PK/CS ifdef'd out updcrc() for ASM_CRC | |
70 | 3.9 17 Dec 95 G. Roelofs modified for USE_ZLIB (new fillinbuf()) | |
71 | - 30 Apr 96 - public release with UnZip 5.2 | |
72 | 3.91 17 Aug 96 G. Roelofs main() -> return int (Peter Seebach) | |
73 | 3.92 13 Apr 97 G. Roelofs minor cosmetic fixes to messages | |
74 | - 22 Apr 97 - public release with UnZip 5.3 | |
75 | - 31 May 97 - public release with UnZip 5.31 | |
76 | 3.93 20 Sep 97 G. Roelofs minor cosmetic fixes to messages | |
77 | - 3 Nov 97 - public release with UnZip 5.32 | |
78 | - 28 Nov 98 - public release with UnZip 5.4 | |
79 | */ | |
80 | ||
81 | ||
82 | /* | |
83 | ||
84 | All funzip does is take a zipfile from stdin and decompress the | |
85 | first entry to stdout. The entry has to be either deflated or | |
86 | stored. If the entry is encrypted, then the decryption password | |
87 | must be supplied on the command line as the first argument. | |
88 | ||
89 | funzip needs to be linked with inflate.o and crypt.o compiled from | |
90 | the unzip source. If decryption is desired, the full version of | |
91 | crypt.c (and crypt.h) from zcrypt21.zip or later must be used. | |
92 | ||
93 | */ | |
94 | ||
95 | #define FUNZIP | |
96 | #define UNZIP_INTERNAL | |
97 | #include "unzip.h" | |
98 | #include "crypt.h" | |
99 | #include "ttyio.h" | |
100 | ||
101 | #ifdef EBCDIC | |
102 | # undef EBCDIC /* don't need ebcdic[] */ | |
103 | #endif | |
104 | #include "tables.h" /* crc_32_tab[] */ | |
105 | ||
106 | #ifndef USE_ZLIB /* zlib's function is called inflate(), too */ | |
107 | # define UZinflate inflate | |
108 | #endif | |
109 | ||
110 | /* PKZIP header definitions */ | |
111 | #define ZIPMAG 0x4b50 /* two-byte zip lead-in */ | |
112 | #define LOCREM 0x0403 /* remaining two bytes in zip signature */ | |
113 | #define LOCSIG 0x04034b50L /* full signature */ | |
114 | #define LOCFLG 4 /* offset of bit flag */ | |
115 | #define CRPFLG 1 /* bit for encrypted entry */ | |
116 | #define EXTFLG 8 /* bit for extended local header */ | |
117 | #define LOCHOW 6 /* offset of compression method */ | |
118 | #define LOCTIM 8 /* file mod time (for decryption) */ | |
119 | #define LOCCRC 12 /* offset of crc */ | |
120 | #define LOCSIZ 16 /* offset of compressed size */ | |
121 | #define LOCLEN 20 /* offset of uncompressed length */ | |
122 | #define LOCFIL 24 /* offset of file name field length */ | |
123 | #define LOCEXT 26 /* offset of extra field length */ | |
124 | #define LOCHDR 28 /* size of local header, including LOCREM */ | |
125 | #define EXTHDR 16 /* size of extended local header, inc sig */ | |
126 | ||
127 | /* GZIP header definitions */ | |
128 | #define GZPMAG 0x8b1f /* two-byte gzip lead-in */ | |
129 | #define GZPHOW 0 /* offset of method number */ | |
130 | #define GZPFLG 1 /* offset of gzip flags */ | |
131 | #define GZPMUL 2 /* bit for multiple-part gzip file */ | |
132 | #define GZPISX 4 /* bit for extra field present */ | |
133 | #define GZPISF 8 /* bit for filename present */ | |
134 | #define GZPISC 16 /* bit for comment present */ | |
135 | #define GZPISE 32 /* bit for encryption */ | |
136 | #define GZPTIM 2 /* offset of Unix file modification time */ | |
137 | #define GZPEXF 6 /* offset of extra flags */ | |
138 | #define GZPCOS 7 /* offset of operating system compressed on */ | |
139 | #define GZPHDR 8 /* length of minimal gzip header */ | |
140 | ||
141 | /* Macros for getting two-byte and four-byte header values */ | |
142 | #define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)) | |
143 | #define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)) | |
144 | ||
145 | /* Function prototypes */ | |
146 | void err OF((int, char *)); | |
147 | int main OF((int, char **)); | |
148 | ||
149 | /* Globals */ | |
150 | FILE *out; /* output file (*in moved to G struct) */ | |
151 | ulg outsiz; /* total bytes written to out */ | |
152 | int encrypted; /* flag to turn on decryption */ | |
153 | ||
154 | /* Masks for inflate.c */ | |
155 | ZCONST ush near mask_bits[] = { | |
156 | 0x0000, | |
157 | 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, | |
158 | 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff | |
159 | }; | |
160 | ||
161 | ||
162 | #ifdef USE_ZLIB | |
163 | ||
164 | int fillinbuf(__G) | |
165 | __GDEF | |
166 | /* Fill input buffer for pull-model inflate() in zlib. Return the number of | |
167 | * bytes in inbuf. */ | |
168 | { | |
169 | /* GRR: check return value from fread(): same as read()? check errno? */ | |
170 | if ((G.incnt = fread((char *)G.inbuf, 1, INBUFSIZ, G.in)) <= 0) | |
171 | return 0; | |
172 | G.inptr = G.inbuf; | |
173 | ||
174 | #if CRYPT | |
175 | if (encrypted) { | |
176 | uch *p; | |
177 | int n; | |
178 | ||
179 | for (n = G.incnt, p = G.inptr; n--; p++) | |
180 | zdecode(*p); | |
181 | } | |
182 | #endif /* CRYPT */ | |
183 | ||
184 | return G.incnt; | |
185 | ||
186 | } | |
187 | ||
188 | #endif /* USE_ZLIB */ | |
189 | ||
190 | ||
191 | #if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB)) | |
192 | #ifdef USE_ZLIB | |
193 | ZCONST uLongf *get_crc_table() | |
194 | { | |
195 | return (ZCONST uLongf *)crc_32_tab; | |
196 | } | |
197 | #else /* !USE_ZLIB */ | |
198 | ZCONST ulg near *get_crc_table() | |
199 | { | |
200 | return crc_32_tab; | |
201 | } | |
202 | #endif /* ?USE_ZLIB */ | |
203 | #endif /* !USE_ZLIB || USE_OWN_CRCTAB */ | |
204 | ||
205 | ||
206 | void err(n, m) | |
207 | int n; | |
208 | char *m; | |
209 | /* Exit on error with a message and a code */ | |
210 | { | |
211 | Info(slide, 1, ((char *)slide, "funzip error: %s\n", m)); | |
212 | DESTROYGLOBALS() | |
213 | EXIT(n); | |
214 | } | |
215 | ||
216 | ||
217 | int flush(w) /* used by inflate.c (FLUSH macro) */ | |
218 | ulg w; /* number of bytes to flush */ | |
219 | { | |
220 | G.crc32val = crc32(G.crc32val, slide, (extent)w); | |
221 | if (fwrite((char *)slide,1,(extent)w,out) != (extent)w && !PIPE_ERROR) | |
222 | err(9, "out of space on stdout"); | |
223 | outsiz += w; | |
224 | return 0; | |
225 | } | |
226 | ||
227 | ||
228 | int main(argc, argv) | |
229 | int argc; | |
230 | char **argv; | |
231 | /* Given a zipfile on stdin, decompress the first entry to stdout. */ | |
232 | { | |
233 | ush n; | |
234 | uch h[LOCHDR]; /* first local header (GZPHDR < LOCHDR) */ | |
235 | int g = 0; /* true if gzip format */ | |
236 | #if CRYPT | |
237 | char *s = " [-password]"; | |
238 | char *p; /* password */ | |
239 | #else /* !CRYPT */ | |
240 | char *s = ""; | |
241 | #endif /* ?CRYPT */ | |
242 | CONSTRUCTGLOBALS(); | |
243 | ||
244 | /* skip executable name */ | |
245 | argc--; | |
246 | argv++; | |
247 | ||
248 | #if CRYPT | |
249 | /* get the command line password, if any */ | |
250 | p = (char *)NULL; | |
251 | if (argc && **argv == '-') | |
252 | { | |
253 | argc--; | |
254 | p = 1 + *argv++; | |
255 | } | |
256 | #endif /* CRYPT */ | |
257 | ||
258 | #ifdef MALLOC_WORK | |
259 | G.area.Slide = (uch *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char)); | |
260 | #endif | |
261 | ||
262 | /* if no file argument and stdin not redirected, give the user help */ | |
263 | if (argc == 0 && isatty(0)) | |
264 | { | |
265 | Info(slide, 1, ((char *)slide, "fUnZip (filter UnZip), version %s\n", | |
266 | VERSION)); | |
267 | Info(slide, 1, ((char *)slide, "usage: ... | funzip%s | ...\n", s)); | |
268 | Info(slide, 1, ((char *)slide, " ... | funzip%s > outfile\n", s)); | |
269 | Info(slide, 1, ((char *)slide, " funzip%s infile.zip > outfile\n",s)); | |
270 | Info(slide, 1, ((char *)slide, " funzip%s infile.gz > outfile\n", s)); | |
271 | Info(slide, 1, ((char *)slide, "Extracts to stdout the gzip file or first\ | |
272 | zip entry of stdin or the given file.\n")); | |
273 | DESTROYGLOBALS() | |
274 | EXIT(3); | |
275 | } | |
276 | ||
277 | /* prepare to be a binary filter */ | |
278 | if (argc) | |
279 | { | |
280 | if ((G.in = fopen(*argv, FOPR)) == (FILE *)NULL) | |
281 | err(2, "cannot find input file"); | |
282 | } | |
283 | else | |
284 | { | |
285 | #ifdef DOS_FLX_H68_OS2_W32 | |
286 | #if (defined(__HIGHC__) && !defined(FLEXOS)) | |
287 | setmode(stdin, _BINARY); | |
288 | #else | |
289 | setmode(0, O_BINARY); /* some buggy C libraries require BOTH setmode() */ | |
290 | #endif /* call AND the fdopen() in binary mode :-( */ | |
291 | #endif /* DOS_FLX_H68_OS2_W32 */ | |
292 | ||
293 | #ifdef RISCOS | |
294 | G.in = stdin; | |
295 | #else | |
296 | if ((G.in = fdopen(0, FOPR)) == (FILE *)NULL) | |
297 | err(2, "cannot find stdin"); | |
298 | #endif | |
299 | } | |
300 | ||
301 | #ifdef DOS_FLX_H68_OS2_W32 | |
302 | #if (defined(__HIGHC__) && !defined(FLEXOS)) | |
303 | setmode(stdout, _BINARY); | |
304 | #else | |
305 | setmode(1, O_BINARY); | |
306 | #endif | |
307 | #endif /* DOS_FLX_H68_OS2_W32 */ | |
308 | ||
309 | #ifdef RISCOS | |
310 | out = stdout; | |
311 | #else | |
312 | if ((out = fdopen(1, FOPW)) == (FILE *)NULL) | |
313 | err(2, "cannot write to stdout"); | |
314 | #endif | |
315 | ||
316 | /* read local header, check validity, and skip name and extra fields */ | |
317 | n = getc(G.in); n |= getc(G.in) << 8; | |
318 | if (n == ZIPMAG) | |
319 | { | |
320 | if (fread((char *)h, 1, LOCHDR, G.in) != LOCHDR || SH(h) != LOCREM) | |
321 | err(3, "invalid zipfile"); | |
322 | if (SH(h + LOCHOW) != STORED && SH(h + LOCHOW) != DEFLATED) | |
323 | err(3, "first entry not deflated or stored--cannot unpack"); | |
324 | for (n = SH(h + LOCFIL); n--; ) g = getc(G.in); | |
325 | for (n = SH(h + LOCEXT); n--; ) g = getc(G.in); | |
326 | g = 0; | |
327 | encrypted = h[LOCFLG] & CRPFLG; | |
328 | } | |
329 | else if (n == GZPMAG) | |
330 | { | |
331 | if (fread((char *)h, 1, GZPHDR, G.in) != GZPHDR) | |
332 | err(3, "invalid gzip file"); | |
333 | if (h[GZPHOW] != DEFLATED) | |
334 | err(3, "gzip file not deflated"); | |
335 | if (h[GZPFLG] & GZPMUL) | |
336 | err(3, "cannot handle multi-part gzip files"); | |
337 | if (h[GZPFLG] & GZPISX) | |
338 | { | |
339 | n = getc(G.in); n |= getc(G.in) << 8; | |
340 | while (n--) g = getc(G.in); | |
341 | } | |
342 | if (h[GZPFLG] & GZPISF) | |
343 | while ((g = getc(G.in)) != 0 && g != EOF) ; | |
344 | if (h[GZPFLG] & GZPISC) | |
345 | while ((g = getc(G.in)) != 0 && g != EOF) ; | |
346 | g = 1; | |
347 | encrypted = h[GZPFLG] & GZPISE; | |
348 | } | |
349 | else | |
350 | err(3, "input not a zip or gzip file"); | |
351 | ||
352 | /* if entry encrypted, decrypt and validate encryption header */ | |
353 | if (encrypted) | |
354 | #if CRYPT | |
355 | { | |
356 | ush i, e; | |
357 | ||
358 | if (p == (char *)NULL) { | |
359 | if ((p = (char *)malloc(IZ_PWLEN+1)) == (char *)NULL) | |
360 | err(1, "out of memory"); | |
361 | else if ((p = getp("Enter password: ", p, IZ_PWLEN+1)) == (char *)NULL) | |
362 | err(1, "no tty to prompt for password"); | |
363 | } | |
364 | #if (defined(USE_ZLIB) && !defined(USE_OWN_CRCTAB)) | |
365 | /* initialize crc_32_tab pointer for decryption */ | |
366 | CRC_32_TAB = (ZCONST ulg Far *)get_crc_table(); | |
367 | #endif | |
368 | init_keys(p); | |
369 | for (i = 0; i < RAND_HEAD_LEN; i++) | |
370 | e = NEXTBYTE; | |
371 | if (e != (ush)(h[LOCFLG] & EXTFLG ? h[LOCTIM + 1] : h[LOCCRC + 3])) | |
372 | err(3, "incorrect password for first entry"); | |
373 | } | |
374 | #else /* !CRYPT */ | |
375 | err(3, "cannot decrypt entry (need to recompile with full crypt.c)"); | |
376 | #endif /* ?CRYPT */ | |
377 | ||
378 | /* prepare output buffer and crc */ | |
379 | G.outptr = slide; | |
380 | G.outcnt = 0L; | |
381 | outsiz = 0L; | |
382 | G.crc32val = CRCVAL_INITIAL; | |
383 | ||
384 | /* decompress */ | |
385 | if (g || h[LOCHOW]) | |
386 | { /* deflated entry */ | |
387 | int r; | |
388 | ||
389 | #ifdef USE_ZLIB | |
390 | /* need to allocate and prepare input buffer */ | |
391 | if ((G.inbuf = (uch *)malloc(INBUFSIZ)) == (uch *)NULL) | |
392 | err(1, "out of memory"); | |
393 | #endif /* USE_ZLIB */ | |
394 | if ((r = UZinflate(__G)) != 0) { | |
395 | if (r == 3) | |
396 | err(1, "out of memory"); | |
397 | else | |
398 | err(4, "invalid compressed data--format violated"); | |
399 | } | |
400 | inflate_free(__G); | |
401 | } | |
402 | else | |
403 | { /* stored entry */ | |
404 | register ulg n; | |
405 | ||
406 | n = LG(h + LOCLEN); | |
407 | #if CRYPT | |
408 | if (n != LG(h + LOCSIZ) - (encrypted ? RAND_HEAD_LEN : 0)) { | |
409 | #else | |
410 | if (n != LG(h + LOCSIZ)) { | |
411 | #endif | |
412 | Info(slide, 1, ((char *)slide, "len %ld, siz %ld\n", n, LG(h + LOCSIZ))); | |
413 | err(4, "invalid compressed data--length mismatch"); | |
414 | } | |
415 | while (n--) { | |
416 | ush c = getc(G.in); | |
417 | #if CRYPT | |
418 | if (encrypted) | |
419 | zdecode(c); | |
420 | #endif | |
421 | *G.outptr++ = (uch)c; | |
422 | if (++G.outcnt == WSIZE) /* do FlushOutput() */ | |
423 | { | |
424 | G.crc32val = crc32(G.crc32val, slide, (extent)G.outcnt); | |
425 | if (fwrite((char *)slide, 1,(extent)G.outcnt,out) != (extent)G.outcnt | |
426 | && !PIPE_ERROR) | |
427 | err(9, "out of space on stdout"); | |
428 | outsiz += G.outcnt; | |
429 | G.outptr = slide; | |
430 | G.outcnt = 0L; | |
431 | } | |
432 | } | |
433 | } | |
434 | if (G.outcnt) /* flush one last time; no need to reset G.outptr/outcnt */ | |
435 | { | |
436 | G.crc32val = crc32(G.crc32val, slide, (extent)G.outcnt); | |
437 | if (fwrite((char *)slide, 1,(extent)G.outcnt,out) != (extent)G.outcnt | |
438 | && !PIPE_ERROR) | |
439 | err(9, "out of space on stdout"); | |
440 | outsiz += G.outcnt; | |
441 | } | |
442 | fflush(out); | |
443 | ||
444 | /* if extended header, get it */ | |
445 | if (g) | |
446 | { | |
447 | if (fread((char *)h + LOCCRC, 1, 8, G.in) != 8) | |
448 | err(3, "gzip file ended prematurely"); | |
449 | } | |
450 | else | |
451 | if ((h[LOCFLG] & EXTFLG) && | |
452 | fread((char *)h + LOCCRC - 4, 1, EXTHDR, G.in) != EXTHDR) | |
453 | err(3, "zipfile ended prematurely"); | |
454 | ||
455 | /* validate decompression */ | |
456 | if (LG(h + LOCCRC) != G.crc32val) | |
457 | err(4, "invalid compressed data--crc error"); | |
458 | if (LG((g ? (h + LOCSIZ) : (h + LOCLEN))) != outsiz) | |
459 | err(4, "invalid compressed data--length error"); | |
460 | ||
461 | /* check if there are more entries */ | |
462 | if (!g && fread((char *)h, 1, 4, G.in) == 4 && LG(h) == LOCSIG) | |
463 | Info(slide, 1, ((char *)slide, | |
464 | "funzip warning: zipfile has more than one entry--rest ignored\n")); | |
465 | ||
466 | DESTROYGLOBALS() | |
467 | RETURN (0); | |
468 | } |