]> git.saurik.com Git - wxWidgets.git/blob - utils/Install/sfxzip/funzip.c
Menuing and statusbar updates
[wxWidgets.git] / utils / Install / sfxzip / funzip.c
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 }