home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / UNZP50P1.ZIP / unzip.c < prev    next >
C/C++ Source or Header  |  1993-01-23  |  60KB  |  1,541 lines

  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.   zip-bugs@cs.ucla.edu; 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 info-zip-request@cs.ucla.edu.
  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 zip-bugs@cs.ucla.edu)
  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:  unzip50.{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  "v5.0 of 21 August 1992"
  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:  Zipfile Extract %s;  (c) 1989 S.H.Smith and others\n\
  759. Versions 3.0 and later by Info-ZIP.  Bug reports ONLY to zip-bugs@cs.ucla.edu\
  760. \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 zip-bugs@cs.ucla.edu\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() */
  1541.