|
|
1.1 root 1: /*---------------------------------------------------------------------------
2:
3: unzip.c
4:
5: UnZip - a zipfile extraction utility. See below for make instructions, or
6: read the comments in Makefile and the various Contents files for more de-
7: tailed explanations. To report a bug, send a *complete* description to
8: [email protected]; include machine type, operating system and version,
9: compiler and version, and reasonably detailed error messages or problem
10: report. To join Info-ZIP, send a message to [email protected].
11:
12: UnZip 5.x is a greatly expanded and partially rewritten successor to 4.x,
13: which in turn was almost a complete rewrite of version 3.x. For a detailed
14: revision history, see UnzpHist.zip at Info-ZIP headquarters (below). For a
15: (partial) list of the many (near infinite) contributors, see "CONTRIBS" in
16: the UnZip source distribution.
17:
18: ---------------------------------------------------------------------------
19:
20: To compile (partial instructions):
21:
22: under Unix (cc): make <system name>
23: (type "make list" for a list of valid names, or read Makefile for
24: details. "make unzip" works for most systems. If you have a NEW
25: system, not covered by any of the existing targets, send FULL infor-
26: mation--hardware, OS, versions, etc.--to [email protected])
27:
28: under MS-DOS (MSC, Turbo C, or Borland C++): use the makefiles or
29: project files in the MSDOS sub-archive; edit or otherwise modify
30: as appropriate. For MSC, use NMAKE.
31:
32: under MS Windows 3.x: get wunz12sr.{zip | zoo | whatever} and use
33: the included makefile
34:
35: under OS/2 (MSC, gcc, IBM C Set/2, Watcom C): make -f makefile.os2
36: (from OS2 sub-archive; for MSC, use NMAKE)
37:
38: under VMS (VAX C or GNU C): @make_unzip_vaxc or @make_unzip_gcc
39: (from VMS sub-archive; can also use MMS or MAKE/VMS; see VMS.notes)
40:
41: under Macintosh OS: Double click on unzip.make. Press <Command>-M.
42: (from MAC sub-archive)
43:
44: under Windows NT: use makefile.nt (from NT sub-archive)
45:
46: under AmigaDOS: try one of the makefiles in the AMIGA sub-archive;
47: may need some work yet...
48:
49: under Atari TOS: needs considerable work yet...
50:
51: ---------------------------------------------------------------------------
52:
53: Version: unz50p1.{tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS, Windows,
54: Windows NT, Macintosh and Amiga. Decryption requires sources
55: in zcrypt19.zip, and Windows (not NT) support requires sources
56: in wunz12sr.zip. See accompanying file "Where" in the main
57: source distribution for ftp, uucp and mail-server sites.
58: Copyrights: see accompanying file "COPYING" in UnZip source distribution.
59:
60: ---------------------------------------------------------------------------*/
61:
62:
63:
64:
65:
66: #include "unzip.h" /* includes, defines, and macros */
67: #ifdef MSWIN
68: # include "wizunzip.h" /* see History.500 for version history */
69: #endif
70:
71: #define VERSION "5.0p1 of 12 January 1993"
72: /* #define VERSION "v5.0p BETA of 8-21-92" */ /* internal beta level */
73: #define PAKFIX /* temporary(?) solution to PAK-created zipfiles */
74:
75:
76:
77:
78:
79: /**********************/
80: /* Global Variables */
81: /**********************/
82:
83: int aflag=0; /* -a: do ASCII to EBCDIC translation, or CR-LF */
84: /* to CR or LF conversion of extracted files */
85: /* int bflag=0; RESERVED for -b: extract as binary */
86: int cflag=0; /* -c: output to stdout */
87: int fflag=0; /* -f: "freshen" (extract only newer files) */
88: int jflag=0; /* -j: junk pathnames */
89: int overwrite_none=0; /* -n: never overwrite files (no prompting) */
90: int overwrite_all=0; /* -o: OK to overwrite files without prompting */
91: int force_flag=0; /* (shares -o for now): force to override errors, etc. */
92: int quietflg=0; /* -q: produce a lot less output */
93: #ifdef DOS_OS2
94: int sflag=1; /* -s: allow spaces (blanks) in filenames */
95: #endif /* DOS_OS2 */
96: int tflag=0; /* -t: test */
97: int uflag=0; /* -u: "update" (extract only newer & brand-new files) */
98: static int U_flag=0; /* -U: leave filenames in upper or mixed case */
99: static int vflag=0; /* -v: view directory (only used in unzip.c) */
100: int V_flag=0; /* -V: don't strip VMS version numbers */
101: #ifdef VMS
102: int secinf=0; /* -X: keep owner/protection */
103: #endif /* VMS */
104: int zflag=0; /* -z: display only the archive comment */
105: int process_all_files=0;
106:
107: longint csize; /* used by list_files(), ReadByte(): must be signed */
108: longint ucsize; /* used by list_files(), unReduce(), explode() */
109:
110: char *fnames[2] = {"*", NULL}; /* default filenames vector */
111: char **fnv = fnames;
112: char sig[5];
113: char answerbuf[10];
114:
115: min_info info[DIR_BLKSIZ], *pInfo=info;
116:
117: #ifdef OS2
118: int longname; /* used in extract.c, mapname.c and file_io.c */
119: char longfilename[FILNAMSIZ];
120: #endif /* OS2 */
121:
122: #ifdef CRYPT
123: char *key = (char *)NULL; /* password with which to decrypt data, or NULL */
124: #endif /* CRYPT */
125:
126: /*---------------------------------------------------------------------------
127: unShrink/unReduce/explode/inflate working storage and globals:
128: ---------------------------------------------------------------------------*/
129:
130: union work area; /* see unzip.h for the definition of work */
131: ULONG crc32val;
132:
133: UWORD mask_bits[] = {
134: 0x0000,
135: 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
136: 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
137: };
138:
139: /*---------------------------------------------------------------------------
140: Input file variables:
141: ---------------------------------------------------------------------------*/
142:
143: byte *inbuf, *inptr; /* input buffer (any size is legal) and pointer */
144: int incnt;
145:
146: ULONG bitbuf;
147: int bits_left;
148: boolean zipeof;
149:
150: int zipfd; /* zipfile file handle */
151: #ifdef MSWIN
152: char *zipfn;
153: #else
154: char zipfn[FILNAMSIZ];
155: #endif
156:
157: char local_hdr_sig[5] = "\120"; /* remaining signature bytes come later */
158: char central_hdr_sig[5] = "\120"; /* (must initialize at runtime so unzip */
159: char end_central_sig[5] = "\120"; /* executable won't look like a zipfile) */
160: /* char extd_local_sig[5] = "\120"; NOT USED YET */
161:
162: cdir_file_hdr crec; /* used in unzip.c, extract.c, misc.c */
163: local_file_hdr lrec; /* used in unzip.c, extract.c */
164: ecdir_rec ecrec; /* used in unzip.c, extract.c */
165: struct stat statbuf; /* used by main(), mapped_name(), check_for_newer() */
166:
167: longint extra_bytes = 0; /* used in unzip.c, misc.c */
168: longint cur_zipfile_bufstart; /* extract_or_test_files, readbuf, ReadByte */
169:
170: #ifdef MACOS
171: short gnVRefNum;
172: long glDirID;
173: OSType gostCreator;
174: OSType gostType;
175: boolean fMacZipped;
176: boolean macflag;
177: CursHandle rghCursor[4]; /* status cursors */
178: short giCursor = 0;
179: #endif
180:
181: /*---------------------------------------------------------------------------
182: Output stream variables:
183: ---------------------------------------------------------------------------*/
184:
185: byte *outbuf; /* buffer for rle look-back */
186: byte *outptr;
187: #ifdef MSWIN
188: byte __far *outout;
189: char *filename;
190: #else /* !MSWIN */
191: byte *outout; /* scratch pad for ASCII-native trans */
192: char filename[FILNAMSIZ];
193: #endif /* ?MSWIN */
194: byte *extra_field = (byte *)NULL; /* used by VMS, Mac and OS/2 versions */
195: longint outpos; /* absolute position in outfile */
196: int outcnt; /* current position in outbuf */
197: int outfd;
198: int mem_mode = 0;
199: int disk_full;
200:
201: /*---------------------------------------------------------------------------
202: unzip.c static global variables (visible only within this file):
203: ---------------------------------------------------------------------------*/
204:
205: static byte *hold;
206: static char unkn[10];
207: static longint ziplen;
208: static UWORD methnum;
209:
210: /*---------------------------------------------------------------------------
211: unzip.c repeated error messages (we use all of these at least twice)
212: ---------------------------------------------------------------------------*/
213:
214: char *EndSigMsg = "\nwarning:\
215: didn't find end-of-central-dir signature at end of central dir.\n";
216: char *CentSigMsg =
217: "error: expected central file header signature not found (file #%u).\n";
218: char *SeekMsg =
219: "error: attempt to seek before beginning of zipfile\n%s";
220:
221: #ifdef VMS
222: char *ReportMsg = "\
223: (please check that you have transferred or created the zipfile in the\n\
224: appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n";
225: #else /* !VMS */
226: char *ReportMsg = "\
227: (please check that you have transferred or created the zipfile in the\n\
228: appropriate BINARY mode and that you have compiled unzip properly)\n";
229: #endif /* ?VMS */
230:
231:
232: #ifdef MSWIN
233: /* MS Windows Setup and Take-Down functions bracket calls to
234: * process_zipfile().
235: * These functions allocate and free the necessary buffers, set and clear
236: * any global variables so that process_zipfile() can be called multiple
237: * times in the same session of WizUnzip. You'll recognize some of the
238: * code from main() in SetUpToProcessZipFile().
239: */
240: HANDLE hOutBuf;
241: HANDLE hOutOut; /* added 04/03/92 for version 1.1 */
242: HANDLE hInBuf;
243: HANDLE hZipFN;
244: HANDLE hFileName;
245:
246: BOOL FSetUpToProcessZipFile(int ncflag, int ntflag, int nvflag, int nUflag,
247: int nzflag, int ndflag, int noflag, int naflag, int argc,
248: LPSTR lpszZipFN, PSTR *FNV)
249: {
250: /* clear all global flags -- need to or not. */
251:
252: tflag = vflag=cflag=aflag=U_flag=quietflg=zflag = 0;
253: overwrite_all=overwrite_none=0;
254: fnv = &fnames[0]; /* assign default file name vector */
255:
256: cflag = ncflag ; overwrite_all = noflag;
257: tflag = ntflag ; vflag = nvflag; zflag = nzflag; U_flag = nUflag;
258: aflag = naflag;
259: sflag = 1;
260:
261: local_hdr_sig[0] = central_hdr_sig[0] = end_central_sig[0] = '\120';
262: local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0';
263:
264: if (!(hZipFN = LocalAlloc(LMEM_MOVEABLE, FILNAMSIZ)))
265: return FALSE;
266:
267: zipfn = (char *)LocalLock(hZipFN);
268: lstrcpy(zipfn, lpszZipFN);
269: if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR)
270: strcat(zipfn, ZSUFX);
271:
272: if (stat(zipfn, &statbuf)) { /* try again */
273: fprintf(stderr, "error: can't find zipfile [ %s ]\n", zipfn);
274: return TRUE; /* 9: file not found */
275: } else
276: ziplen = statbuf.st_size;
277:
278: if (argc != 0) {
279: fnv = FNV;
280: process_all_files = FALSE;
281: } else
282: process_all_files = TRUE; /* for speed */
283:
284: /*---------------------------------------------------------------------------
285: Okey dokey, we have everything we need to get started. Let's roll.
286: ---------------------------------------------------------------------------*/
287:
288: if (hInBuf = LocalAlloc(LMEM_MOVEABLE, INBUFSIZ+4)) { /* 4 extra: hold[] */
289: inbuf = (byte *) LocalLock(hInBuf);
290: WinAssert(inbuf);
291: }
292: if (hOutBuf = LocalAlloc(LMEM_MOVEABLE, OUTBUFSIZ+1)) { /* extra: ASCIIZ */
293: outbuf = (byte *)LocalLock(hOutBuf);
294: WinAssert(outbuf);
295: if (aflag) { /* if LF => CR,LF translation */
296: if (hOutOut = GlobalAlloc(GMEM_MOVEABLE,OUTBUFSIZ)) {
297: outout = (byte _far *)GlobalLock(hOutOut);
298: WinAssert(outout);
299: }
300: } else /* no translation; just re-use output buffer */
301: outout = (byte _far *)outbuf; /* point to outbuf */
302: }
303: if ( hFileName = LocalAlloc(LMEM_MOVEABLE, FILNAMSIZ)) {
304: filename = (char *)LocalLock(hFileName);
305: WinAssert(filename);
306: }
307:
308: if ((inbuf == NULL) || (outbuf == NULL) || (outout == NULL) ||
309: (zipfn == NULL) || (filename == NULL))
310: return FALSE;
311:
312: hold = &inbuf[INBUFSIZ]; /* to check for boundary-spanning signatures */
313:
314: return TRUE; /* set up was OK */
315: }
316:
317: void TakeDownFromProcessZipFile(void)
318: {
319: if (inbuf) {
320: LocalUnlock(hInBuf);
321: inbuf = NULL;
322: }
323: if (hInBuf)
324: hInBuf = LocalFree(hInBuf);
325:
326: if (outbuf) {
327: LocalUnlock(hOutBuf);
328: outbuf = NULL;
329: }
330: if (hOutBuf)
331: hOutBuf = LocalFree(hOutBuf);
332:
333: if (aflag && outout) /* if doing LF => CR,LF translation */
334: GlobalUnlock(hOutOut);
335: outout = NULL; /* free now, translation or not */
336: if (hOutOut)
337: hOutOut = GlobalFree(hOutOut); /* mark buffer as freed */
338:
339: if (zipfn) {
340: LocalUnlock(hZipFN);
341: zipfn = NULL;
342: }
343: if (hZipFN)
344: hZipFN = LocalFree(hZipFN);
345:
346: if (filename) {
347: LocalUnlock(hFileName);
348: filename = NULL;
349: }
350: if (hFileName)
351: hFileName = LocalFree(hFileName);
352: }
353:
354: #else /* !MSWIN */
355:
356: /******************/
357: /* Main program */
358: /******************/
359:
360: int main(argc, argv) /* return PK-type error code (except under VMS) */
361: int argc;
362: char *argv[];
363: {
364: char *s;
365: int c, error=FALSE, negative=0;
366:
367:
368: /*---------------------------------------------------------------------------
369: Macintosh initialization code.
370: ---------------------------------------------------------------------------*/
371:
372: #ifdef MACOS
373: #ifdef THINK_C
374: # include <console.h>
375: static char *argstr[30], args[30*64];
376: Point p;
377: SFTypeList sfT;
378: EventRecord theEvent;
379: short eMask;
380: SFReply fileRep;
381: #endif /* THINK_C */
382: int a;
383:
384: for (a = 0; a < 4; ++a)
385: rghCursor[a] = GetCursor(a+128);
386: giCursor = 0;
387:
388: area.Slide = (byte *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char));
389: area.shrink.Prefix_of = (short *)area.Slide;
390: area.shrink.Suffix_of = area.Slide + (sizeof(short)*(HSIZE+1));
391: area.shrink.Stack = area.Slide + (sizeof(short) + sizeof(char))*(HSIZE+1);
392:
393: #ifdef THINK_C
394: for (a = 0; a < 30; ++a)
395: argstr[a] = &args[a*64];
396: start:
397: tflag=vflag=cflag=aflag=jflag=U_flag=quietflg=fflag=uflag=zflag = 0;
398: local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0';
399: /* extd_local_sig[1] = '\0'; */
400: error = FALSE;
401:
402: argc = ccommand(&argv);
403: SetPt(&p, 40, 40);
404:
405: SFGetFile(p, "\pSpecify ZIP file:", 0L, -1, sfT, 0L, &fileRep);
406: if (fileRep.good) {
407: macfstest(fileRep.vRefNum);
408: ResolveMacVol(fileRep.vRefNum, &gnVRefNum, &glDirID, NULL);
409: for (a = 1; a < argc; ++a)
410: if (argv[a][0] == '-')
411: BlockMove(argv[a], argstr[a], (strlen(argv[a]) > 63) ? 64 :
412: strlen(argv[a])+1);
413: else
414: break;
415: PtoCstr((char *)fileRep.fName);
416: strcpy(argstr[a], (char *)fileRep.fName);
417: for (; a < argc; ++a)
418: BlockMove(argv[a], argstr[a+1], (strlen(argv[a]) > 63) ? 64 :
419: strlen(argv[a])+1);
420: ++argc;
421: argv = argstr;
422:
423: if (hfsflag == FALSE) /* can't support directories: junk pathnames */
424: jflag = 1;
425: }
426: #endif /* THINK_C */
427: #endif /* MACOS */
428:
429: /*---------------------------------------------------------------------------
430: Set signal handler for restoring echo, warn of zipfile corruption, etc.
431: ---------------------------------------------------------------------------*/
432:
433: signal(SIGINT, handler);
434: signal(SIGTERM, handler);
435: #ifdef SIGBUS
436: signal(SIGBUS, handler);
437: #endif
438: #ifdef SIGSEGV
439: signal(SIGSEGV, handler);
440: #endif
441:
442: /*---------------------------------------------------------------------------
443: Debugging info for checking on structure padding:
444: ---------------------------------------------------------------------------*/
445:
446: #ifdef DEBUG_STRUC
447: printf("local_file_hdr size: %X\n",
448: sizeof(local_file_hdr));
449: printf("local_byte_hdr size: %X\n",
450: sizeof(local_byte_hdr));
451: printf("actual size of local headers: %X\n", LREC_SIZE);
452:
453: printf("central directory header size: %X\n",
454: sizeof(cdir_file_hdr));
455: printf("central directory byte header size: %X\n",
456: sizeof(cdir_byte_hdr));
457: printf("actual size of central dir headers: %X\n", CREC_SIZE);
458:
459: printf("end central dir record size: %X\n",
460: sizeof(ecdir_rec));
461: printf("end central dir byte record size: %X\n",
462: sizeof(ec_byte_rec));
463: printf("actual size of end-central-dir record: %X\n", ECREC_SIZE);
464: #endif /* DEBUG_STRUC */
465:
466: /*---------------------------------------------------------------------------
467: Put environment-variable options into the queue, then rip through any
468: command-line options lurking about...
469: ---------------------------------------------------------------------------*/
470:
471: envargs(&argc, &argv, ENV_UNZIP);
472:
473: while (--argc > 0 && (*++argv)[0] == '-') {
474: s = argv[0] + 1;
475: while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */
476: switch (c) {
477: case ('-'):
478: ++negative;
479: break;
480: case ('a'):
481: if (negative)
482: aflag = FALSE, negative = 0;
483: else
484: aflag = TRUE;
485: break;
486: #if 0
487: case ('b'): /* force binary mode */
488: if (negative)
489: bflag = FALSE, negative = 0;
490: else
491: bflag = TRUE;
492: break;
493: #endif
494: case ('c'):
495: if (negative) {
496: cflag = FALSE, negative = 0;
497: #ifdef NATIVE
498: aflag = FALSE;
499: #endif
500: } else {
501: cflag = TRUE;
502: #ifdef NATIVE
503: aflag = TRUE; /* so you can read it on the screen */
504: #endif
505: }
506: break;
507: case ('d'): /* re-create directory structure (default) */
508: if (negative)
509: jflag = TRUE, negative = 0;
510: break;
511: case ('e'): /* just ignore -e, -x options (extract) */
512: break;
513: case ('f'): /* "freshen" (extract only newer files) */
514: if (negative)
515: fflag = uflag = FALSE, negative = 0;
516: else
517: fflag = uflag = TRUE;
518: break;
519: case ('j'): /* junk pathnames/directory structure */
520: if (negative)
521: jflag = FALSE, negative = 0;
522: else
523: jflag = TRUE;
524: break;
525: case ('l'):
526: if (negative) {
527: vflag = MAX(vflag-negative,0);
528: negative = 0;
529: } else
530: ++vflag;
531: break;
532: case ('n'): /* don't overwrite any files */
533: if (negative)
534: overwrite_none = FALSE, negative = 0;
535: else
536: overwrite_none = TRUE;
537: break;
538: case ('o'): /* OK to overwrite files without prompting */
539: if (negative) {
540: overwrite_all = MAX(overwrite_all-negative,0);
541: force_flag = MAX(force_flag-negative,0);
542: negative = 0;
543: } else {
544: ++overwrite_all;
545: ++force_flag; /* (share -o for now) force to cont. */
546: }
547: break;
548: case ('p'): /* pipes: stdout, no tranlation, no messages */
549: if (negative) {
550: cflag = FALSE;
551: quietflg = MAX(quietflg-999,0);
552: negative = 0;
553: } else {
554: cflag = TRUE;
555: quietflg += 999;
556: }
557: break;
558: case ('q'): /* quiet: fewer comments/messages */
559: if (negative) {
560: quietflg = MAX(quietflg-negative,0);
561: negative = 0;
562: } else
563: ++quietflg;
564: break;
565: #ifdef DOS_OS2
566: case ('s'): /* spaces in filenames: allow by default */
567: if (negative)
568: sflag = TRUE, negative = 0;
569: else
570: sflag = FALSE;
571: break;
572: #endif
573: case ('t'):
574: if (negative)
575: tflag = FALSE, negative = 0;
576: else
577: tflag = TRUE;
578: break;
579: case ('U'): /* Uppercase (don't convert to all-lower) */
580: if (negative)
581: U_flag = FALSE, negative = 0;
582: else
583: U_flag = TRUE;
584: break;
585: case ('u'): /* update (extract only new and newer files) */
586: if (negative)
587: uflag = FALSE, negative = 0;
588: else
589: uflag = TRUE;
590: break;
591: case ('V'): /* Version (retain VMS/DEC-20 file versions) */
592: if (negative)
593: V_flag = FALSE, negative = 0;
594: else
595: V_flag = TRUE;
596: break;
597: case ('v'): /* verbose */
598: if (negative) {
599: vflag = MAX(vflag-negative,0);
600: negative = 0;
601: } else if (vflag)
602: ++vflag;
603: else
604: vflag = 2;
605: break;
606: #ifdef VMS
607: case ('X'): /* restore owner/protection info (need privs?) */
608: if (negative)
609: secinf = FALSE, negative = 0;
610: else
611: secinf = TRUE;
612: break;
613: #endif /* VMS */
614: case ('x'): /* extract: default */
615: break;
616: case ('z'): /* display only the archive comment */
617: if (negative) {
618: zflag = MAX(zflag-negative,0);
619: negative = 0;
620: } else
621: ++zflag;
622: break;
623: default:
624: error = TRUE;
625: break;
626:
627: } /* end switch */
628: } /* end while (not end of argument string) */
629: } /* end while (not done with switches) */
630:
631: /*---------------------------------------------------------------------------
632: Make sure we aren't trying to do too many things here. [This seems like
633: kind of a brute-force way to do things; but aside from that, isn't the
634: -a option useful when listing the directory (i.e., for reading zipfile
635: comments)? It's a modifier, not an action in and of itself, so perhaps
636: it should not be included in the test--certainly, in the case of zipfile
637: testing, it can just be ignored.]
638: ---------------------------------------------------------------------------*/
639:
640: if ((aflag && tflag) || (aflag && vflag) || (cflag && tflag) ||
641: (cflag && uflag) || (cflag && vflag) || (tflag && uflag) ||
642: (tflag && vflag) || (uflag && vflag) || (fflag && overwrite_none)) {
643: fprintf(stderr, "error:\
644: -at, -av, -ct, -cu, -cv, -fn, -tu, -tv, -uv combinations not allowed\n");
645: error = TRUE;
646: }
647: if (quietflg && zflag)
648: quietflg = 0;
649: if (overwrite_all && overwrite_none) {
650: fprintf(stderr, "caution: both -n and -o specified; ignoring -o\n");
651: overwrite_all = FALSE;
652: }
653: if ((argc-- == 0) || error)
654: RETURN(usage(error));
655:
656: /*---------------------------------------------------------------------------
657: Now get the zipfile name from the command line and see if it exists as a
658: regular (non-directory) file. If not, append the ".zip" suffix. We don't
659: immediately check to see if this results in a good name, but we will do so
660: later. In the meantime, see if there are any member filespecs on the com-
661: mand line, and if so, set the filename pointer to point at them.
662: ---------------------------------------------------------------------------*/
663:
664: strcpy(zipfn, *argv++);
665: if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR)
666: strcat(zipfn, ZSUFX);
667: #if (defined(UNIX) && !defined(VMS)) /* Unix executables have no extension-- */
668: else if (statbuf.st_mode & S_IXUSR) /* might find zip, not zip.zip; etc */
669: fprintf(stderr, "\nnote: file [ %s ] may be an executable\n\n", zipfn);
670: #endif /* UNIX && !VMS */
671:
672: if (stat(zipfn, &statbuf)) {/* try again */
673: fprintf(stderr, "error: can't find zipfile [ %s ]\n", zipfn);
674: RETURN(9); /* 9: file not found */
675: } else
676: ziplen = statbuf.st_size;
677:
678: if (argc != 0) {
679: fnv = argv;
680: process_all_files = FALSE;
681: } else
682: process_all_files = TRUE; /* for speed */
683:
684: /*---------------------------------------------------------------------------
685: Okey dokey, we have everything we need to get started. Let's roll.
686: ---------------------------------------------------------------------------*/
687:
688: inbuf = (byte *) malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */
689: outbuf = (byte *) malloc(OUTBUFSIZ + 1); /* 1 extra for string termin. */
690: #ifndef DOS_OS2
691: if (aflag) /* if need an ascebc scratch, */
692: outout = (byte *) malloc(OUTBUFSIZ);
693: else /* allocate it... */
694: #endif /* !DOS_OS2 */
695: outout = outbuf; /* else just point to outbuf */
696:
697: if ((inbuf == (byte *)NULL) || (outbuf == (byte *)NULL) ||
698: (outout == (byte *)NULL)) {
699: fprintf(stderr, "error: can't allocate unzip buffers\n");
700: RETURN(4); /* 4-8: insufficient memory */
701: }
702: hold = &inbuf[INBUFSIZ]; /* to check for boundary-spanning signatures */
703:
704: RETURN(process_zipfile()); /* keep passing errors back... */
705:
706: } /* end main() */
707:
708:
709:
710:
711:
712: /**********************/
713: /* Function usage() */
714: /**********************/
715:
716: int usage(error) /* return PK-type error code */
717: int error;
718: {
719: #ifdef NATIVE
720: #ifdef EBCDIC
721: char *astring = "-a convert ASCII to EBCDIC";
722: #else /* !EBCDIC */
723: char *astring = "-a convert ASCII to native chars";
724: #endif /* ?EBCDIC */
725: /* char *astring = "-a convert ASCII to " NATIVE; (ANSI C concatenation) */
726: char *loc_str = "";
727: #else /* !NATIVE */
728: #ifdef DOS_OS2
729: char *astring = "-a convert text (LF => CR LF)";
730: char *loc_str = "-s spaces in filenames => _";
731: #else /* !DOS_OS2 */
732: #ifdef MACOS
733: char *astring = "-a convert text (CR LF => CR)";
734: char *loc_str = "";
735: #else /* !MACOS: UNIX, VMS */
736: char *astring = "-a convert text (CR LF => LF)";
737: #ifdef VMS
738: char *loc_str = "-X restore owner/protection info";
739: #else /* !VMS */
740: char *loc_str = "";
741: #endif /* ?VMS */
742: #endif /* ?MACOS */
743: #endif /* ?DOS_OS2 */
744: #endif /* ?NATIVE */
745: FILE *usagefp;
746:
747:
748: /*---------------------------------------------------------------------------
749: If user requested usage, send it to stdout; else send to stderr.
750: ---------------------------------------------------------------------------*/
751:
752: if (error)
753: usagefp = (FILE *) stderr;
754: else
755: usagefp = (FILE *) stdout;
756:
757: fprintf(usagefp, "\
758: UnZip %s, by Info-ZIP. Portions (c) 1989 by S. H. Smith.\n\
759: Bug reports ONLY to zip-bugs%%[email protected]; see README for detail\
760: s\n\n", VERSION);
761:
762: fprintf(usagefp, "\
763: Usage: unzip [ -options[modifiers] ] file[.zip] [filespec...]\n\
764: -x extract files (default) -l list files (short format)\n\
765: -c extract files to stdout/screen (CRT) -v list files (verbose format)\n\
766: -f freshen existing files, create none -p extract to pipe, no messages\n\
767: -u update files, create if necessary -t test archive integrity\n\
768: -z display archive comment\n\
769: modifiers:\n\
770: -n never overwrite existing files %s\n", loc_str);
771: fprintf(usagefp, "\
772: -o overwrite files WITHOUT prompting %s\n\
773: -j junk paths (don't make directories) -U don't make names lowercase\n\
774: -q quiet mode (-qq => quieter) -V retain VMS version numbers\
775: \n\n\
776: Examples: (See manual for more information)\n\
777: unzip data1 ReadMe => extracts file ReadMe from zipfile data1.zip\n\
778: unzip -p foo | more => send contents of foo.zip via pipe into program more\n\
779: unzip -fo foo => quietly replace existing files if archive files newer\
780: \n", astring);
781:
782: #ifdef VMS
783: fprintf(usagefp, "\
784: unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS\
785: \n");
786: #endif
787:
788: if (error)
789: return 10; /* 10: bad or illegal parameters specified */
790: else
791: return 0; /* just wanted usage screen: no error */
792:
793: } /* end function usage() */
794:
795: #endif /* ?MSWIN */
796:
797:
798:
799:
800: /********************************/
801: /* Function process_zipfile() */
802: /********************************/
803:
804: int process_zipfile() /* return PK-type error code */
805: {
806: int error=0, error_in_archive;
807: longint real_ecrec_offset, expect_ecrec_offset;
808:
809:
810: /*---------------------------------------------------------------------------
811: Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
812: lation, which would corrupt the bitstreams.
813: ---------------------------------------------------------------------------*/
814:
815: #ifdef VMS
816: if (check_format()) /* check for variable-length format */
817: return 2; /* 2: error in zipfile */
818: #endif /* VMS */
819:
820: if (open_input_file()) /* this should never happen, given the */
821: return 9; /* stat() test in main(), but... */
822:
823: /*---------------------------------------------------------------------------
824: Reconstruct the various PK signature strings, and find and process the
825: end-of-central-directory header.
826: ---------------------------------------------------------------------------*/
827:
828: strcat(local_hdr_sig, LOCAL_HDR_SIG);
829: strcat(central_hdr_sig, CENTRAL_HDR_SIG);
830: strcat(end_central_sig, END_CENTRAL_SIG);
831: /* strcat(extd_local_sig, EXTD_LOCAL_SIG); */
832:
833: if (find_end_central_dir()) { /* not found; nothing to do */
834: close(zipfd);
835: return 2; /* 2: error in zipfile */
836: }
837:
838: real_ecrec_offset = cur_zipfile_bufstart+(inptr-inbuf);
839: #ifdef TEST
840: printf("\n found end-of-central-dir signature at offset %ld (%.8lXh)\n",
841: real_ecrec_offset, real_ecrec_offset);
842: printf(" from beginning of file; offset %d (%.4Xh) within block\n",
843: inptr-inbuf, inptr-inbuf);
844: #endif
845:
846: if ((error_in_archive = process_end_central_dir()) > 1) {
847: close(zipfd);
848: return error_in_archive;
849: }
850:
851: if (zflag) {
852: close(zipfd);
853: return 0;
854: }
855:
856: /*---------------------------------------------------------------------------
857: Test the end-of-central-directory info for incompatibilities and incon-
858: sistencies.
859: ---------------------------------------------------------------------------*/
860:
861: #ifndef PAKFIX
862: if (ecrec.number_this_disk == 0) {
863: #else /* PAKFIX */
864: error = ((ecrec.number_this_disk == 1) &&
865: (ecrec.num_disk_with_start_central_dir == 1));
866: if ((ecrec.number_this_disk == 0) || error) {
867: if (error) {
868: fprintf(stderr,
869: "\n Warning: zipfile claims to be disk 2 of a two-part archive;\n\
870: attempting to process anyway. If no further errors occur, this\n\
871: archive was probably created by PAK v2.51 or earlier. This bug\n\
872: was reported to NoGate in March 1991 and was supposed to have been\n\
873: fixed by mid-1991; as of mid-1992 it still hadn't been.\n\n");
874: error_in_archive = 1; /* 1: warning */
875: }
876: #endif /* ?PAKFIX */
877: expect_ecrec_offset = ecrec.offset_start_central_directory +
878: ecrec.size_central_directory;
879: if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) {
880: fprintf(stderr, "\nerror: missing %ld bytes in zipfile (\
881: attempting to process anyway)\n\n", -extra_bytes);
882: error_in_archive = 2; /* 2: (weak) error in zipfile */
883: } else if (extra_bytes > 0) {
884: if ((ecrec.offset_start_central_directory == 0) &&
885: (ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */
886: {
887: fprintf(stderr, "\nerror: NULL central directory offset (\
888: attempting to process anyway)\n\n");
889: ecrec.offset_start_central_directory = extra_bytes;
890: extra_bytes = 0;
891: error_in_archive = 2; /* 2: (weak) error in zipfile */
892: } else {
893: fprintf(stderr, "\nwarning: extra %ld bytes at beginning or\
894: within zipfile\n (attempting to process anyway)\n\n", extra_bytes);
895: error_in_archive = 1; /* 1: warning error */
896: }
897: }
898:
899: /*-----------------------------------------------------------------------
900: Check for empty zipfile and exit now if so.
901: -----------------------------------------------------------------------*/
902:
903: if (expect_ecrec_offset == 0L && ecrec.size_central_directory == 0) {
904: fprintf(stderr, "warning: zipfile is empty\n");
905: close(zipfd);
906: return (error_in_archive > 1)? error_in_archive : 1;
907: }
908:
909: /*-----------------------------------------------------------------------
910: Compensate for missing or extra bytes, and seek to where the start
911: of central directory should be. If header not found, uncompensate
912: and try again (necessary for at least some Atari archives created
913: with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT).
914: -----------------------------------------------------------------------*/
915:
916: LSEEK( ecrec.offset_start_central_directory )
917: if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
918: longint tmp = extra_bytes;
919:
920: extra_bytes = 0;
921: LSEEK( ecrec.offset_start_central_directory )
922: if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
923: fprintf(stderr,
924: "error: start of central directory not found; zipfile corrupt.\n");
925: fprintf(stderr, ReportMsg);
926: close(zipfd);
927: return 3; /* 3: severe error in zipfile */
928: }
929: fprintf(stderr, "error: reported length of central directory is \
930: %d bytes too\n long (Atari STZIP zipfile? J.H. Holm ZIPSPLIT zipfile?)\
931: .\n Compensating...\n\n", -tmp);
932: error_in_archive = 2; /* 2: (weak) error in zipfile */
933: }
934:
935: /*-----------------------------------------------------------------------
936: Seek to the start of the central directory one last time, since we
937: have just read the first entry's signature bytes; then list, extract
938: or test member files as instructed, and close the zipfile.
939: -----------------------------------------------------------------------*/
940:
941: LSEEK( ecrec.offset_start_central_directory )
942: if (vflag)
943: error = list_files(); /* LIST 'EM */
944: else
945: error = extract_or_test_files(); /* EXTRACT OR TEST 'EM */
946: if (error > error_in_archive) /* don't overwrite stronger error */
947: error_in_archive = error; /* with (for example) a warning */
948: } else {
949: fprintf(stderr, "\nerror: zipfile is part of multi-disk archive \
950: (sorry, not supported).\n");
951: /* fprintf(stderr, "Please report to [email protected]\n"); */
952: error_in_archive = 11; /* 11: no files found */
953: }
954:
955: close(zipfd);
956: return error_in_archive;
957:
958: } /* end function process_zipfile() */
959:
960:
961:
962:
963:
964: /************************************/
965: /* Function find_end_central_dir() */
966: /************************************/
967:
968: int find_end_central_dir() /* return 0 if found, 1 otherwise */
969: {
970: int i, numblks;
971: longint tail_len;
972:
973:
974:
975: /*---------------------------------------------------------------------------
976: Treat case of short zipfile separately.
977: ---------------------------------------------------------------------------*/
978:
979: if (ziplen <= INBUFSIZ) {
980: lseek(zipfd, 0L, SEEK_SET);
981: if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)ziplen)) ==
982: (int)ziplen)
983:
984: /* 'P' must be at least 22 bytes from end of zipfile */
985: for (inptr = inbuf+(int)ziplen-22; inptr >= inbuf; --inptr)
986: if ((ascii_to_native(*inptr) == 'P') &&
987: !strncmp((char *)inptr, end_central_sig, 4)) {
988: incnt -= inptr - inbuf;
989: return 0; /* found it! */
990: } /* ...otherwise fall through & fail */
991:
992: /*---------------------------------------------------------------------------
993: Zipfile is longer than INBUFSIZ: may need to loop. Start with short
994: block at end of zipfile (if not TOO short).
995: ---------------------------------------------------------------------------*/
996:
997: } else {
998: if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) {
999: cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
1000: if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)tail_len)) !=
1001: (int)tail_len)
1002: goto fail; /* shut up; it's expedient. */
1003:
1004: /* 'P' must be at least 22 bytes from end of zipfile */
1005: for (inptr = inbuf+(int)tail_len-22; inptr >= inbuf; --inptr)
1006: if ((ascii_to_native(*inptr) == 'P') &&
1007: !strncmp((char *)inptr, end_central_sig, 4)) {
1008: incnt -= inptr - inbuf;
1009: return 0; /* found it */
1010: } /* ...otherwise search next block */
1011: strncpy((char *)hold, (char *)inbuf, 3); /* sig may span block
1012: boundary */
1013: } else {
1014: cur_zipfile_bufstart = ziplen - tail_len;
1015: }
1016:
1017: /*-----------------------------------------------------------------------
1018: Loop through blocks of zipfile data, starting at the end and going
1019: toward the beginning. Need only check last 65557 bytes of zipfile:
1020: comment may be up to 65535 bytes long, end-of-central-directory rec-
1021: ord is 18 bytes (shouldn't hardcode this number, but what the hell:
1022: already did so above (22=18+4)), and sig itself is 4 bytes.
1023: -----------------------------------------------------------------------*/
1024:
1025: numblks = (int)
1026: ((MIN(ziplen,65557L) - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
1027: /* =amount to search= ==done== ==rounding== =blksiz= */
1028:
1029: for (i = 1; i <= numblks; ++i) {
1030: cur_zipfile_bufstart -= INBUFSIZ;
1031: lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
1032: if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) != INBUFSIZ)
1033: break; /* fall through and fail */
1034:
1035: for (inptr = inbuf+INBUFSIZ-1; inptr >= inbuf; --inptr)
1036: if ((ascii_to_native(*inptr) == 'P') &&
1037: !strncmp((char *)inptr, end_central_sig, 4)) {
1038: incnt -= inptr - inbuf;
1039: return 0; /* found it */
1040: }
1041: strncpy((char *)hold, (char *)inbuf, 3); /* sig may span block
1042: boundary */
1043: }
1044:
1045: } /* end if (ziplen > INBUFSIZ) */
1046:
1047: /*---------------------------------------------------------------------------
1048: Searched through whole region where signature should be without finding
1049: it. Print informational message and die a horrible death.
1050: ---------------------------------------------------------------------------*/
1051:
1052: fail:
1053: #ifdef MSWIN
1054: MessageBeep(1);
1055: #endif
1056:
1057: fprintf(stderr, "\nFile: %s\n\n\
1058: End-of-central-directory signature not found. Either this file is not\n\
1059: a zipfile, or it constitutes one disk of a multi-part archive. In the\n\
1060: latter case the central directory and zipfile comment will be found on\n\
1061: the last disk(s) of this archive.\n", zipfn);
1062: return 1;
1063:
1064: } /* end function find_end_central_dir() */
1065:
1066:
1067:
1068:
1069:
1070: /***************************************/
1071: /* Function process_end_central_dir() */
1072: /***************************************/
1073:
1074: int process_end_central_dir() /* return PK-type error code */
1075: {
1076: ec_byte_rec byterec;
1077: int error=0;
1078:
1079:
1080: /*---------------------------------------------------------------------------
1081: Read the end-of-central-directory record and do any necessary machine-
1082: type conversions (byte ordering, structure padding compensation) by
1083: reading data into character array, then copying to struct.
1084: ---------------------------------------------------------------------------*/
1085:
1086: if (readbuf((char *) byterec, ECREC_SIZE+4) <= 0)
1087: return 51;
1088:
1089: ecrec.number_this_disk =
1090: makeword(&byterec[NUMBER_THIS_DISK]);
1091: ecrec.num_disk_with_start_central_dir =
1092: makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
1093: ecrec.num_entries_centrl_dir_ths_disk =
1094: makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
1095: ecrec.total_entries_central_dir =
1096: makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
1097: ecrec.size_central_directory =
1098: makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
1099: ecrec.offset_start_central_directory =
1100: makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
1101: ecrec.zipfile_comment_length =
1102: makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
1103:
1104: /*---------------------------------------------------------------------------
1105: Get the zipfile comment, if any, and print it out. (Comment may be up
1106: to 64KB long. May the fleas of a thousand camels infest the armpits of
1107: anyone who actually takes advantage of this fact.) Then position the
1108: file pointer to the beginning of the central directory and fill buffer.
1109: ---------------------------------------------------------------------------*/
1110:
1111: #ifdef MSWIN
1112: cchComment = ecrec.zipfile_comment_length; /* save for comment button */
1113: if (ecrec.zipfile_comment_length && zflag) {
1114: #else /* !MSWIN */
1115: if (ecrec.zipfile_comment_length && !quietflg) {
1116: if (!zflag)
1117: printf("[%s] comment:\n", zipfn);
1118: #endif /* ?MSWIN */
1119: if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
1120: fprintf(stderr, "\ncaution: zipfile comment truncated\n");
1121: error = 1; /* 1: warning error */
1122: }
1123: }
1124:
1125: return error;
1126:
1127: } /* end function process_end_central_dir() */
1128:
1129:
1130:
1131:
1132:
1133: /* also referenced in UpdateListBox() in updatelb.c (Windows version) */
1134: char *Headers[][2] = {
1135: {" Length Date Time Name",
1136: " ------ ---- ---- ----"},
1137: {" Length Method Size Ratio Date Time CRC-32 Name",
1138: " ------ ------ ---- ----- ---- ---- ------ ----"}
1139: };
1140:
1141: /*************************/
1142: /* Function list_files() */
1143: /*************************/
1144:
1145: int list_files() /* return PK-type error code */
1146: {
1147: char **fnamev;
1148: int do_this_file=FALSE, ratio, error, error_in_archive=0;
1149: int which_hdr=(vflag>1), date_format;
1150: UWORD j, yr, mo, dy, hh, mm, members=0;
1151: ULONG tot_csize=0L, tot_ucsize=0L;
1152: #ifdef OS2
1153: ULONG tot_easize=0L, tot_eafiles=0L, ea_size;
1154: #endif
1155: #ifdef MSWIN
1156: PSTR psLBEntry; /* list box entry */
1157: #endif
1158: min_info info;
1159: static char *method[NUM_METHODS+1] =
1160: {"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4",
1161: "Implode", "Token", "Deflate", unkn};
1162:
1163:
1164:
1165: /*---------------------------------------------------------------------------
1166: Unlike extract_or_test_files(), this routine confines itself to the cen-
1167: tral directory. Thus its structure is somewhat simpler, since we can do
1168: just a single loop through the entire directory, listing files as we go.
1169:
1170: So to start off, print the heading line and then begin main loop through
1171: the central directory. The results will look vaguely like the following:
1172:
1173: Length Method Size Ratio Date Time CRC-32 Name ("^" ==> case
1174: ------ ------ ---- ----- ---- ---- ------ ---- conversion)
1175: 44004 Implode 13041 71% 11-02-89 19:34 8b4207f7 Makefile.UNIX
1176: 3438 Shrunk 2209 36% 09-15-90 14:07 a2394fd8 ^dos-file.ext
1177: ---------------------------------------------------------------------------*/
1178:
1179: pInfo = &info;
1180: date_format = dateformat();
1181:
1182: #ifndef MSWIN
1183: if (quietflg < 2)
1184: if (U_flag)
1185: printf("%s\n%s\n", Headers[which_hdr][0], Headers[which_hdr][1]);
1186: else
1187: printf("%s (\"^\" ==> case\n%s conversion)\n",
1188: Headers[which_hdr][0], Headers[which_hdr][1]);
1189: #endif /* !MSWIN */
1190:
1191: for (j = 0; j < ecrec.total_entries_central_dir; ++j) {
1192:
1193: if (readbuf(sig, 4) <= 0)
1194: return 51; /* 51: unexpected EOF */
1195: if (strncmp(sig, central_hdr_sig, 4)) { /* just to make sure */
1196: fprintf(stderr, CentSigMsg, j); /* sig not found */
1197: fprintf(stderr, ReportMsg); /* check binary transfers */
1198: return 3; /* 3: error in zipfile */
1199: }
1200: if ((error = process_cdir_file_hdr()) != 0) /* (sets pInfo->lcflag) */
1201: return error; /* only 51 (EOF) defined */
1202:
1203: /*
1204: * We could DISPLAY the filename instead of storing (and possibly trun-
1205: * cating, in the case of a very long name) and printing it, but that
1206: * has the disadvantage of not allowing case conversion--and it's nice
1207: * to be able to see in the listing precisely how you have to type each
1208: * filename in order for unzip to consider it a match. Speaking of
1209: * which, if member names were specified on the command line, check in
1210: * with match() to see if the current file is one of them, and make a
1211: * note of it if it is.
1212: */
1213:
1214: if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
1215: error_in_archive = error; /* ^--(uses pInfo->lcflag) */
1216: if (error > 1) /* fatal: can't continue */
1217: return error;
1218: }
1219: if (extra_field != (byte *)NULL)
1220: free(extra_field);
1221: extra_field = (byte *)NULL;
1222: if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0) {
1223: error_in_archive = error;
1224: if (error > 1) /* fatal: can't continue */
1225: return error;
1226: }
1227: if (!process_all_files) { /* check if specified on command line */
1228: do_this_file = FALSE;
1229: fnamev = fnv; /* don't destroy permanent filename ptr */
1230: for (--fnamev; *++fnamev;)
1231: if (match(filename, *fnamev)) {
1232: do_this_file = TRUE;
1233: break; /* found match, so stop looping */
1234: }
1235: }
1236: /*
1237: * If current file was specified on command line, or if no names were
1238: * specified, do the listing for this file. Otherwise, get rid of the
1239: * file comment and go back for the next file.
1240: */
1241:
1242: if (process_all_files || do_this_file) {
1243:
1244: yr = (((crec.last_mod_file_date >> 9) & 0x7f) + 80) % (unsigned)100;
1245: mo = (crec.last_mod_file_date >> 5) & 0x0f;
1246: dy = crec.last_mod_file_date & 0x1f;
1247:
1248: /* twist date so it displays according to national convention */
1249: switch (date_format) {
1250: case DF_YMD:
1251: hh = mo; mo = yr; yr = dy; dy = hh; break;
1252: case DF_DMY:
1253: hh = mo; mo = dy; dy = hh;
1254: }
1255: hh = (crec.last_mod_file_time >> 11) & 0x1f;
1256: mm = (crec.last_mod_file_time >> 5) & 0x3f;
1257:
1258: csize = (longint) crec.compressed_size;
1259: ucsize = (longint) crec.uncompressed_size;
1260: if (crec.general_purpose_bit_flag & 1)
1261: csize -= 12; /* if encrypted, don't count encrypt hdr */
1262:
1263: ratio = (ucsize == 0) ? 0 : /* .zip can have 0-length members */
1264: ((ucsize > 2000000L) ? /* risk signed overflow if mult. */
1265: (int) ((ucsize-csize) / (ucsize/1000L)) + 5 : /* big */
1266: (int) ((1000L*(ucsize-csize)) / ucsize) + 5); /* small */
1267:
1268: #if 0 /* GRR/Euro: add this? define p above */
1269: #if (defined(DOS_OS2) || (defined(UNIX) && !defined(VMS)))
1270: for (p = filename; *p; ++p)
1271: if (!isprint(*p))
1272: *p = '?'; /* change non-printable chars to '?' */
1273: #endif /* DOS_OS2 || UNIX */
1274: #endif /* 0 */
1275:
1276: #ifdef MSWIN
1277: #ifdef NEED_EARLY_REDRAW
1278: /* turn on listbox redrawing just before adding last line */
1279: if (j == (ecrec.total_entries_central_dir-1))
1280: (void)SendMessage(hWndList, WM_SETREDRAW, TRUE, 0L);
1281: #endif /* NEED_EARLY_REDRAW */
1282: psLBEntry =
1283: (PSTR)LocalAlloc(LMEM_FIXED, FILNAMSIZ+LONG_FORM_FNAME_INX);
1284: switch (which_hdr) {
1285: case 0: /* short form */
1286: OemToAnsi(filename, filename); /* translate to ANSI */
1287: wsprintf(psLBEntry, "%7ld %02u-%02u-%02u %02u:%02u %c%s",
1288: (long)ucsize, mo, dy, yr, hh, mm, (pInfo->lcflag?'^':' '),
1289: (LPSTR)filename);
1290: SendMessage(hWndList, LB_ADDSTRING, 0,
1291: (LONG)(LPSTR)psLBEntry);
1292: break;
1293: case 1: /* verbose */
1294: OemToAnsi(filename, filename); /* translate to ANSI */
1295: wsprintf(psLBEntry,
1296: "%7ld %-7s%7ld %3d%% %02u-%02u-%02u %02u:%02u %08lx %c%s",
1297: (long)ucsize, (LPSTR)method[methnum], (long)csize,
1298: ratio/10, mo, dy, yr, hh, mm, (unsigned long)crec.crc32,
1299: (pInfo->lcflag?'^':' '), (LPSTR)filename);
1300: SendMessage(hWndList, LB_ADDSTRING, 0,
1301: (LONG)(LPSTR)psLBEntry);
1302: }
1303: LocalFree((HANDLE)psLBEntry);
1304: #else /* !MSWIN */
1305: switch (which_hdr) {
1306: case 0: /* short form */
1307: printf("%7ld %02u-%02u-%02u %02u:%02u %c%s\n",
1308: ucsize, mo, dy, yr, hh, mm, (pInfo->lcflag?'^':' '),
1309: filename);
1310: break;
1311: case 1: /* verbose */
1312: printf(
1313: "%7ld %-7s%7ld %3d%% %02u-%02u-%02u %02u:%02u %08lx %c%s\n",
1314: ucsize, method[methnum], csize, ratio/10, mo, dy, yr,
1315: hh, mm, crec.crc32, (pInfo->lcflag?'^':' '), filename);
1316: }
1317: #endif /* ?MSWIN */
1318:
1319: error = do_string(crec.file_comment_length, (QCOND? DISPLAY:SKIP));
1320: if (error) {
1321: error_in_archive = error; /* might be just warning */
1322: if (error > 1) /* fatal */
1323: return error;
1324: }
1325: tot_ucsize += (ULONG) ucsize;
1326: tot_csize += (ULONG) csize;
1327: ++members;
1328: #ifdef OS2
1329: if ((ea_size = SizeOfEAs(extra_field)) != 0) {
1330: tot_easize += ea_size;
1331: tot_eafiles++;
1332: }
1333: #endif
1334: } else { /* not listing this file */
1335: SKIP_(crec.file_comment_length)
1336: }
1337: } /* end for-loop (j: files in central directory) */
1338:
1339: /*---------------------------------------------------------------------------
1340: Print footer line and totals (compressed size, uncompressed size, number
1341: of members in zipfile).
1342: ---------------------------------------------------------------------------*/
1343:
1344: ratio = (tot_ucsize == 0) ?
1345: 0 : ((tot_ucsize > 4000000L) ? /* risk unsigned overflow if mult. */
1346: (int) ((tot_ucsize - tot_csize) / (tot_ucsize/1000L)) + 5 :
1347: (int) ((tot_ucsize - tot_csize) * 1000L / tot_ucsize) + 5);
1348:
1349: if (quietflg < 2) {
1350: #ifdef MSWIN
1351: /* Display just the totals since the dashed lines get displayed
1352: * in UpdateListBox(). Get just enough space to display total.
1353: */
1354: switch (which_hdr) {
1355: case 0: /* short */
1356: wsprintf(lpumb->szTotalsLine, "%7lu %-7u",
1357: (ULONG)tot_ucsize, members);
1358: break;
1359: case 1: /* verbose */
1360: wsprintf(lpumb->szTotalsLine,
1361: "%7lu %7lu %3d%% %-7u",
1362: (ULONG)tot_ucsize, (ULONG)tot_csize, ratio / 10, members);
1363: break;
1364: }
1365: #else /* !MSWIN */
1366: switch (which_hdr) {
1367: case 0: /* short */
1368: printf("%s\n%7lu %-7u\n",
1369: " ------ -------",
1370: tot_ucsize, members);
1371: break;
1372: case 1: /* verbose */
1373: printf(
1374: "%s\n%7lu %7lu %3d%% %-7u\n",
1375: " ------ ------ --- -------",
1376: tot_ucsize, tot_csize, ratio / 10, members);
1377: }
1378: #endif /* ?MSWIN */
1379: #ifdef OS2
1380: if (tot_eafiles && tot_easize)
1381: printf("\n%ld file%s %ld bytes of EA's attached.\n", tot_eafiles,
1382: tot_eafiles == 1 ? " has" : "s have a total of", tot_easize);
1383: #endif
1384: }
1385: /*---------------------------------------------------------------------------
1386: Double check that we're back at the end-of-central-directory record.
1387: ---------------------------------------------------------------------------*/
1388:
1389: readbuf(sig, 4);
1390: if (strncmp(sig, end_central_sig, 4)) { /* just to make sure again */
1391: fprintf(stderr, EndSigMsg); /* didn't find end-of-central-dir sig */
1392: /* fprintf(stderr, ReportMsg); */
1393: error_in_archive = 1; /* 1: warning error */
1394: }
1395: return error_in_archive;
1396:
1397: } /* end function list_files() */
1398:
1399:
1400:
1401:
1402:
1403: /**************************************/
1404: /* Function process_cdir_file_hdr() */
1405: /**************************************/
1406:
1407: int process_cdir_file_hdr() /* return PK-type error code */
1408: {
1409: cdir_byte_hdr byterec;
1410:
1411:
1412: /*---------------------------------------------------------------------------
1413: Read the next central directory entry and do any necessary machine-type
1414: conversions (byte ordering, structure padding compensation--do so by
1415: copying the data from the array into which it was read (byterec) to the
1416: usable struct (crec)).
1417: ---------------------------------------------------------------------------*/
1418:
1419: if (readbuf((char *) byterec, CREC_SIZE) <= 0)
1420: return 51; /* 51: unexpected EOF */
1421:
1422: crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
1423: crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
1424: crec.version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
1425: crec.version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
1426:
1427: crec.general_purpose_bit_flag =
1428: makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
1429: crec.compression_method =
1430: makeword(&byterec[C_COMPRESSION_METHOD]);
1431: crec.last_mod_file_time =
1432: makeword(&byterec[C_LAST_MOD_FILE_TIME]);
1433: crec.last_mod_file_date =
1434: makeword(&byterec[C_LAST_MOD_FILE_DATE]);
1435: crec.crc32 =
1436: makelong(&byterec[C_CRC32]);
1437: crec.compressed_size =
1438: makelong(&byterec[C_COMPRESSED_SIZE]);
1439: crec.uncompressed_size =
1440: makelong(&byterec[C_UNCOMPRESSED_SIZE]);
1441: crec.filename_length =
1442: makeword(&byterec[C_FILENAME_LENGTH]);
1443: crec.extra_field_length =
1444: makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
1445: crec.file_comment_length =
1446: makeword(&byterec[C_FILE_COMMENT_LENGTH]);
1447: crec.disk_number_start =
1448: makeword(&byterec[C_DISK_NUMBER_START]);
1449: crec.internal_file_attributes =
1450: makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
1451: crec.external_file_attributes =
1452: makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */
1453: crec.relative_offset_local_header =
1454: makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
1455:
1456: pInfo->hostnum = MIN(crec.version_made_by[1], NUM_HOSTS);
1457: /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
1458: methnum = MIN(crec.compression_method, NUM_METHODS);
1459: if (methnum == NUM_METHODS)
1460: sprintf(unkn, "Unk:%03d", crec.compression_method);
1461:
1462: /*---------------------------------------------------------------------------
1463: Set flag for lowercase conversion of filename, depending on which OS the
1464: file is coming from. This section could be ifdef'd if some people have
1465: come to love DOS uppercase filenames under Unix...but really, guys, get
1466: a life. :) NOTE THAT ALL SYSTEM NAMES NOW HAVE TRAILING UNDERSCORES!!!
1467: This is to prevent interference with compiler command-line defines such
1468: as -DUNIX, for example, which are then used in "#ifdef UNIX" constructs.
1469: ---------------------------------------------------------------------------*/
1470:
1471: pInfo->lcflag = 0;
1472: if (!U_flag) /* as long as user hasn't specified case-preservation */
1473: switch (pInfo->hostnum) {
1474: case DOS_OS2_FAT_:
1475: /* case VMS_: VMS Zip converts filenames to lowercase */
1476: case VM_CMS_: /* all caps? */
1477: case CPM_: /* like DOS, right? */
1478: /* case ATARI_: ? */
1479: /* case Z_SYSTEM_: ? */
1480: /* case TOPS20_: (if we had such a thing...) */
1481: pInfo->lcflag = 1; /* convert filename to lowercase */
1482: break;
1483:
1484: default: /* AMIGA_, UNIX_, (ATARI_), OS2_HPFS_, */
1485: break; /* MAC_, (Z_SYSTEM_): no conversion */
1486: }
1487:
1488: return 0;
1489:
1490: } /* end function process_cdir_file_hdr() */
1491:
1492:
1493:
1494:
1495:
1496: /***************************************/
1497: /* Function process_local_file_hdr() */
1498: /***************************************/
1499:
1500: int process_local_file_hdr() /* return PK-type error code */
1501: {
1502: local_byte_hdr byterec;
1503:
1504:
1505: /*---------------------------------------------------------------------------
1506: Read the next local file header and do any necessary machine-type con-
1507: versions (byte ordering, structure padding compensation--do so by copy-
1508: ing the data from the array into which it was read (byterec) to the
1509: usable struct (lrec)).
1510: ---------------------------------------------------------------------------*/
1511:
1512: if (readbuf((char *) byterec, LREC_SIZE) <= 0)
1513: return 51; /* 51: unexpected EOF */
1514:
1515: lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
1516: lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
1517:
1518: lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
1519: lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
1520: lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
1521: lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
1522: lrec.crc32 = makelong(&byterec[L_CRC32]);
1523: lrec.compressed_size = makelong(&byterec[L_COMPRESSED_SIZE]);
1524: lrec.uncompressed_size = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
1525: lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
1526: lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
1527:
1528: csize = (longint) lrec.compressed_size;
1529: ucsize = (longint) lrec.uncompressed_size;
1530:
1531: if ((lrec.general_purpose_bit_flag & 8) != 0) {
1532: /* Can't trust local header, use central directory: */
1533: lrec.crc32 = pInfo->crc;
1534: lrec.compressed_size = pInfo->compr_size;
1535: csize = (longint) lrec.compressed_size;
1536: }
1537:
1538: return 0; /* 0: no error */
1539:
1540: } /* end function process_local_file_hdr() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.