home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip51.zip / unzip.c < prev    next >
C/C++ Source or Header  |  1994-02-06  |  54KB  |  1,495 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@wkuvx1.wku.edu; include machine type, operating system and ver-
  9.   sion, compiler and version, and reasonably detailed error messages or prob-
  10.   lem report.  To join Info-ZIP, see the instructions in README.
  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 quest.jpl.nasa.gov.  For a list of
  15.   the many (near infinite) contributors, see "CONTRIBS" in the UnZip source
  16.   distribution.
  17.  
  18.   ---------------------------------------------------------------------------
  19.  
  20.   [from original zipinfo.c]
  21.  
  22.   This program reads great gobs of totally nifty information, including the
  23.   central directory stuff, from ZIP archives ("zipfiles" for short).  It
  24.   started as just a testbed for fooling with zipfiles, but at this point it
  25.   is actually a useful utility.  It also became the basis for the rewrite of
  26.   UnZip (3.16 -> 4.0), using the central directory for processing rather than
  27.   the individual (local) file headers.
  28.  
  29.   The author finds it convenient to define an alias "ii" (under Unix and VMS)
  30.   or to rename the executable to "ii.exe" (OS/2 and DOS).  This nicely comple-
  31.   ments the common Unix "ll" long-listing alias (ls -lF), since zipinfo's de-
  32.   fault action is to produce a Unix-like listing of the archive's contents.
  33.   "ii zipfile" is easier to type than "zipinfo zipfile"...
  34.  
  35.   As of ZipInfo v2.0 and UnZip v5.1, the two programs are combined into one.
  36.   If the executable is named "unzip" (or "unzip.exe", depending), it behaves
  37.   like UnZip by default; if it is named "zipinfo" or "ii", it behaves like
  38.   ZipInfo.  The ZipInfo behavior may also be triggered by use of unzip's -Z
  39.   option; for example, "unzip -Z [zipinfo_options] archive.zip".
  40.  
  41.   Another dandy product from your buddies at Newtware!
  42.  
  43.   Author:  Greg Roelofs, newt@uchicago.edu, 23 August 1990 -> ...
  44.            SizeOfEAs() by Kai Uwe Rommel.
  45.  
  46.   ---------------------------------------------------------------------------
  47.  
  48.   Quick compile instructions (see INSTALL file):  copy and/or rename appro-
  49.   priate makefile to main unzip directory, then:
  50.  
  51.      under Unix (cc):  make <system name>
  52.        (type "make list" for a list of valid names, or read Makefile for 
  53.         details.  "make unzip" works for most systems.  If you have a NEW
  54.         system, not covered by any of the existing targets, send FULL in-
  55.         formation--hardware, OS, versions, etc.--to zip-bugs)
  56.  
  57.      under VMS (VAX or Alpha C, or GNU C):  @make_vaxc  or  @make_gcc
  58.        (can also use MMS or MAKE/VMS; see [.vms]README.)
  59.  
  60.      under OS/2:  nmake -f makefile.os2 <compiler>
  61.        (type "nmake -f makefile.os2" for list of targets; Watcom, Borland,
  62.         IBM, Microsoft, emx+gcc compilers and nmake and dmake supported)
  63.  
  64.      under MS-DOS (MS or Quick C, Turbo or Borland C[++]):  make
  65.        (project files no longer supported; for Microsoft, use nmake; for
  66.         djgpp or cross-compiling, use appropriate targets in unix/Makefile)
  67.  
  68.      under MS Windows 3.1:  get wunz20sr.{zip | zoo | whatever} and use
  69.        the included makefile
  70.  
  71.      under Windows NT (MS Visual C++):  nmake
  72.  
  73.      under Macintosh OS (Think C):  un-BinHex the Think C project file and
  74.        UnZip resource file, then click on something or other :-) )
  75.  
  76.      under AmigaDOS (SAS/Lattice C or Aztec C):
  77.        with SAS C 6.x:  lmk -f amiga/SMakeFile all
  78.        with Aztec C:    make -f amiga/Makefile.AZT all
  79.  
  80.      under Atari TOS (MiNT libraries and gcc 2.4.5):  make
  81.        (see atari/README and atari/Makefile for info about other compilers)
  82.  
  83.      under TOPS-20:  use make.mic and "do make" [no longer fully ported]
  84.  
  85.   ---------------------------------------------------------------------------
  86.  
  87.   Version:  unzip51.{tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS, Windows,
  88.               Windows NT, Macintosh, Amiga, Atari and TOPS-20.  Decryption
  89.               requires sources in zcrypt20.zip, and Windows (not NT) support
  90.               requires sources in wunz20sr.zip.  See accompanying file "Where"
  91.               in the main source distribution for ftp, uucp and mail-server
  92.               sites.
  93.   Copyrights:  see accompanying file "COPYING" in UnZip source distribution.
  94.  
  95.   ---------------------------------------------------------------------------*/
  96.  
  97.  
  98.  
  99. #include "unzip.h"               /* includes, typedefs, macros, etc. */
  100. #ifdef MSWIN
  101. #  include "wizunzip.h"
  102. #endif
  103.  
  104.  
  105. #define RELEASE
  106. #ifdef RELEASE
  107. #  define UZ_VERSION  "5.1 of 7 February 1994"   /* official release version */
  108. #  define ZI_VERSION  "2.0 of 7 February 1994"
  109. #else
  110. #  define UZ_VERSION  "5.1p BETA of 6 Feb 94"   /* internal beta level */
  111. #  define ZI_VERSION  "1.99 BETA of 6 Feb 94"
  112. #endif
  113.  
  114.  
  115.  
  116. /**********************/
  117. /*  Global Variables  */
  118. /**********************/
  119.  
  120. #ifdef MACOS
  121.    extern char *unzip_version = UZ_VERSION;
  122.    extern char *zipinfo_version = ZI_VERSION;
  123. #endif
  124.  
  125. int zipinfo_mode;     /* behave like ZipInfo or like normal UnZip? */
  126.  
  127. int aflag=0;          /* -a: do ASCII-EBCDIC and/or end-of-line translation */
  128. int cflag=0;          /* -c: output to stdout */
  129. int dflag=0;          /* -d: all args are files/dirs to be extracted */
  130. int fflag=0;          /* -f: "freshen" (extract only newer files) */
  131. int hflag=0;          /* -h: header line (zipinfo) */
  132. int jflag=0;          /* -j: junk pathnames (unzip) */
  133. int lflag=(-1);       /* -12slmv: listing format (zipinfo) */
  134. int overwrite_none=0; /* -n: never overwrite files (no prompting) */
  135. int overwrite_all=0;  /* -o: OK to overwrite files without prompting */
  136. int force_flag=0;     /* (shares -o for now): force to override errors, etc. */
  137. int qflag=0;          /* -q: produce a lot less output */
  138. #ifdef DOS_NT_OS2
  139.    int sflag=0;       /* -s: convert filename spaces (blanks) to underscores */
  140.    int volflag=0;     /* -$: extract volume labels */
  141. #endif
  142. int tflag=0;          /* -t: test (unzip) or totals line (zipinfo) */
  143. int uflag=0;          /* -u: "update" (extract only newer & brand-new files) */
  144. int U_flag=0;         /* -U: preserve uppercase characters in filenames */
  145. int vflag=0;          /* -v: (verbosely) list directory */
  146. int V_flag=0;         /* -V: don't strip VMS version numbers */
  147. #ifdef VMS
  148.    int secinf=0;      /* -X: keep owner/protection */
  149. #endif
  150. int zflag=0;          /* -z: display the zipfile comment (only, for unzip) */
  151.  
  152. int filespecs;        /* number of real file specifications to be matched */
  153. int xfilespecs;       /* number of excluded filespecs to be matched */
  154. int process_all_files = 0;
  155. int create_dirs;      /* used by main(), mapname(), checkdir() */
  156. int extract_flag;
  157.  
  158. LONGINT real_ecrec_offset, expect_ecrec_offset;
  159.  
  160. long csize;           /* used by list_files(), ReadByte(): must be signed */
  161. long ucsize;          /* used by list_files(), unReduce(), explode() */
  162. long used_csize;      /* used by extract_or_test_member(), explode() */
  163.  
  164. static char *fnames[2] = {"*", NULL};   /* default filenames vector */
  165. char **pfnames = fnames, **pxnames = &fnames[1];
  166. char near sig[5];
  167. char near answerbuf[10];
  168.  
  169. min_info info[DIR_BLKSIZ], *pInfo=info;
  170.  
  171. /*---------------------------------------------------------------------------
  172.     unreduce/unshrink/explode/inflate working storage and globals:
  173.   ---------------------------------------------------------------------------*/
  174.  
  175. union work area;              /* see unzip.h for the definition of work */
  176. ulg crc32val;
  177.  
  178. ush near mask_bits[] = {
  179.     0x0000,
  180.     0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
  181.     0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
  182. };
  183.  
  184. /*---------------------------------------------------------------------------
  185.     Input file variables:
  186.   ---------------------------------------------------------------------------*/
  187.  
  188. uch *inbuf, *inptr;             /* input buffer (any size is OK) and pointer */
  189. int incnt;
  190.  
  191. ulg bitbuf;
  192. int bits_left;
  193. boolean zipeof;
  194.  
  195. char *wildzipfn, *zipfn;    /* GRR:  MSWIN:  must nuke any malloc'd zipfn... */
  196.  
  197. int zipfd;                      /* zipfile file handle */
  198. LONGINT ziplen;
  199.  
  200. uch *hold;
  201. char near local_hdr_sig[5];     /* initialize signatures at runtime so unzip */
  202. char near central_hdr_sig[5];   /*  executable won't look like a zipfile */
  203. char near end_central_sig[5];
  204. /* char extd_local_sig[5];  NOT USED YET */
  205.  
  206. cdir_file_hdr crec;             /* used in unzip.c, extract.c, misc.c */
  207. local_file_hdr lrec;            /* used in unzip.c, extract.c */
  208. ecdir_rec ecrec;                /* used in unzip.c, extract.c */
  209. struct stat statbuf;            /* used by main, mapname, check_for_newer */
  210.  
  211. LONGINT cur_zipfile_bufstart;   /* extract_or_test_files, readbuf, ReadByte */
  212. LONGINT extra_bytes = 0;        /* used in unzip.c, misc.c */
  213.  
  214. uch *extra_field = (uch *)NULL; /* used by VMS, Mac and OS/2 versions */
  215.  
  216. #ifdef MACOS
  217.    short  gnVRefNum;
  218.    long  glDirID;
  219.    OSType  gostCreator;
  220.    OSType  gostType;
  221.    boolean  fMacZipped;
  222.    boolean  macflag;
  223.    CursHandle  rghCursor[4];    /* status cursors */
  224.    short  giCursor = 0;
  225. #endif
  226.  
  227. /*---------------------------------------------------------------------------
  228.     Output stream variables:
  229.   ---------------------------------------------------------------------------*/
  230.  
  231. int mem_mode = 0;
  232. int disk_full;
  233. #ifdef SYMLINKS
  234.    int symlnk;
  235. #endif
  236. FILE *outfile;
  237. uch *outbuf;
  238. uch *outptr;
  239. ulg outcnt;                     /* number of chars stored in outbuf */
  240. #ifdef SMALL_MEM
  241.    uch *outbuf2;                /* initialized in main() (never changes) */
  242. #else
  243.    uch *outbuf2 = NULL;         /* malloc'd ONLY if unshrink and -a */
  244. #endif
  245. #ifdef MSWIN
  246.    char *filename;
  247. #else
  248.    char near filename[FILNAMSIZ];
  249. #endif
  250.  
  251. /*---------------------------------------------------------------------------
  252.     unzip.c repeated error messages (we use all of these at least twice)
  253.   ---------------------------------------------------------------------------*/
  254.  
  255. char *EndSigMsg = "\nnote:\
  256.   didn't find end-of-central-dir signature at end of central dir.\n";
  257. char *CentSigMsg =
  258.   "error:  expected central file header signature not found (file #%u).\n";
  259. char *SeekMsg =
  260.   "error [%s]:  attempt to seek before beginning of zipfile\n%s";
  261.  
  262. #ifdef VMS
  263.   char *ReportMsg = "\
  264.   (please check that you have transferred or created the zipfile in the\n\
  265.   appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n";
  266. #else
  267.   char *ReportMsg = "\
  268.   (please check that you have transferred or created the zipfile in the\n\
  269.   appropriate BINARY mode and that you have compiled unzip properly)\n";
  270. #endif
  271.  
  272.  
  273.  
  274.  
  275.  
  276. #ifdef MSWIN
  277. #  include "winsetup.c"   /* duplicates some code in main() */
  278. #else /* !MSWIN */
  279.  
  280. /******************/
  281. /*  Main program  */
  282. /******************/
  283.  
  284. #ifdef THINK_C
  285.  int unzip(argc, argv)
  286. #else
  287.  int main(argc, argv)   /* return PK-type error code (except under VMS) */
  288. #endif
  289.     int argc;
  290.     char *argv[];
  291. {
  292.     char *p;
  293.     int error=FALSE;
  294. #if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
  295.     extern void DebugMalloc(void);
  296.  
  297.  
  298.     atexit(DebugMalloc);
  299. #endif
  300.  
  301. /*---------------------------------------------------------------------------
  302.     Macintosh initialization code.
  303.   ---------------------------------------------------------------------------*/
  304.  
  305. #ifdef MACOS
  306.     int a;
  307.  
  308.     for (a = 0;  a < 4;  ++a)
  309.         rghCursor[a] = GetCursor(a+128);
  310.     giCursor = 0;
  311.  
  312.     aflag=cflag=dflag=fflag=jflag=qflag=tflag=U_flag=uflag=vflag=zflag = 0;
  313.     local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0';
  314. /*  extd_local_sig[1] = '\0';  */
  315.     error = FALSE;
  316.  
  317.     overwrite_none = overwrite_all = force_flag = 0;
  318. #endif /* MACOS */
  319.  
  320. #ifdef MALLOC_WORK
  321.     area.Slide = (uch *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char));
  322.     area.shrink.Prefix_of = (short *)area.Slide;
  323.     area.shrink.Suffix_of = area.Slide + (sizeof(short)*(HSIZE+1));
  324.     area.shrink.Stack = area.Slide + (sizeof(short) + sizeof(char))*(HSIZE+1);
  325. #endif
  326.  
  327. /*---------------------------------------------------------------------------
  328.     Human68K initialization code.
  329.   ---------------------------------------------------------------------------*/
  330.  
  331. #ifdef __human68k__
  332.     InitTwentyOne();
  333. #endif
  334.  
  335. /*---------------------------------------------------------------------------
  336.     Set signal handler for restoring echo, warn of zipfile corruption, etc.
  337.   ---------------------------------------------------------------------------*/
  338.  
  339.     signal(SIGINT, handler);
  340. #ifdef SIGTERM                 /* some systems really have no SIGTERM */
  341.     signal(SIGTERM, handler);
  342. #endif
  343. #ifdef SIGBUS
  344.     signal(SIGBUS, handler);
  345. #endif
  346. #ifdef SIGSEGV
  347.     signal(SIGSEGV, handler);
  348. #endif
  349.  
  350. /*---------------------------------------------------------------------------
  351.     Debugging info for checking on structure padding:
  352.   ---------------------------------------------------------------------------*/
  353.  
  354. #ifdef DEBUG_STRUC
  355.     printf("local_file_hdr size: %X\n",
  356.            sizeof(local_file_hdr));
  357.     printf("local_byte_hdr size: %X\n",
  358.            sizeof(local_byte_hdr));
  359.     printf("actual size of local headers: %X\n", LREC_SIZE);
  360.  
  361.     printf("central directory header size: %X\n",
  362.            sizeof(cdir_file_hdr));
  363.     printf("central directory byte header size: %X\n",
  364.            sizeof(cdir_byte_hdr));
  365.     printf("actual size of central dir headers: %X\n", CREC_SIZE);
  366.  
  367.     printf("end central dir record size: %X\n",
  368.            sizeof(ecdir_rec));
  369.     printf("end central dir byte record size: %X\n",
  370.            sizeof(ec_byte_rec));
  371.     printf("actual size of end-central-dir record: %X\n", ECREC_SIZE);
  372. #endif /* DEBUG_STRUC */
  373.  
  374. /*---------------------------------------------------------------------------
  375.     First figure out if we're running in UnZip mode or ZipInfo mode, and put
  376.     the appropriate environment-variable options into the queue.  Then rip
  377.     through any command-line options lurking about...
  378.   ---------------------------------------------------------------------------*/
  379.  
  380. #ifdef SFX
  381.     zipfn = argv[0];
  382. #endif
  383.  
  384. #ifndef NO_ZIPINFO
  385.     if ((p = strrchr(argv[0], DIR_END)) == NULL)
  386.         p = argv[0];
  387.     else
  388.         ++p;
  389.  
  390.     if (STRNICMP(p, "zipinfo", 7) == 0 || STRNICMP(p, "ii", 2) == 0 ||
  391.         (argc > 1 && strncmp(argv[1], "-Z", 2) == 0))
  392.     {
  393.         zipinfo_mode = TRUE;
  394.         envargs(&argc, &argv, ENV_ZIPINFO);
  395.         error = zi_opts(&argc, &argv);
  396.     } else
  397. #endif
  398.     {
  399.         zipinfo_mode = FALSE;
  400.         envargs(&argc, &argv, ENV_UNZIP);
  401.         error = uz_opts(&argc, &argv);
  402.     }
  403.  
  404. #ifdef MSDOS
  405.     /* extract MKS extended argument list from environment */
  406.     mksargs(&argc, &argv);
  407. #endif
  408.  
  409. #ifdef SFX
  410.     if (error)
  411. #else
  412.     if ((argc < 0) || error)
  413. #endif
  414.         RETURN(error);
  415.  
  416. /*---------------------------------------------------------------------------
  417.     Now get the zipfile name from the command line and see if it exists as a
  418.     regular (non-directory) file.  If not, append the ".zip" suffix.  We don't
  419.     immediately check to see if this results in a good name, but we will do so
  420.     later.  In the meantime, see if there are any member filespecs on the com-
  421.     mand line, and if so, set the filename pointer to point at them.
  422.   ---------------------------------------------------------------------------*/
  423.  
  424. #ifdef DOS_NT_OS2
  425.     /* convert MSDOS-style directory separators to Unix-style ones for
  426.      * user's convenience (include zipfile name itself)
  427.      */
  428.     pfnames = argv;
  429.     while (*pfnames != NULL) {
  430.         char *q;
  431.  
  432.         for (q = *pfnames;  *q;  ++q)
  433.             if (*q == '\\')
  434.                 *q = '/';
  435.         ++pfnames;
  436.     }
  437. #endif
  438.  
  439.     wildzipfn = *argv++;
  440.  
  441. #ifdef OLD_EXDIR
  442.  
  443.     if (argc > 0) {
  444.         /* -d:  "name/" immediately after zipfile name is a stored directory to
  445.          * be extracted--do NOT treat as directory to which to extract files
  446.          */
  447.         if (extract_flag && !dflag) {
  448.             create_dirs = !fflag;
  449.             if ((error = checkdir(*argv, ROOT)) > 2)  /* mem, or file in way */
  450.                 RETURN(error);
  451.             else if (!error) {   /* it IS extract-to dir, so adjust pointers */
  452.                 ++argv;
  453.                 --argc;
  454.             }
  455.         }
  456.     }
  457.  
  458.     filespecs = argc;
  459.     xfilespecs = 0;
  460.  
  461.     if (argc > 0) {
  462.         char **pp = argv-1;
  463.  
  464.         pfnames = argv;
  465.         while (*++pp)
  466.             if (strcmp(*pp, "-x") == 0) {
  467.                 if (pp > argv) {
  468.                     *pp = 0;           /* terminate pfnames */
  469.                     filespecs = pp - pfnames;
  470.                 } else {
  471.                     pfnames = fnames;  /* defaults */
  472.                     filespecs = 0;
  473.                 }
  474.                 pxnames = pp + 1;      /* excluded-names ptr starts after -x */
  475.                 xfilespecs = argc - filespecs - 1;
  476.                 break;                 /* skip rest of args */
  477.             }
  478.         process_all_files = FALSE;
  479.     } else
  480.         process_all_files = TRUE;       /* for speed */
  481.  
  482. #else /* !OLD_EXDIR */
  483.  
  484.     filespecs = argc;
  485.     xfilespecs = 0;
  486.  
  487.     if (argc > 0) {
  488.         int in_files=FALSE, in_xfiles=FALSE;
  489.         char **pp = argv-1;
  490.  
  491.         process_all_files = FALSE;
  492.         pfnames = argv;
  493.         while (*++pp) {
  494.             Trace((stderr, "pp - argv = %d\n", pp-argv));
  495.             if (!dflag && strcmp(*pp, "-d") == 0) {
  496.                 dflag = TRUE;
  497.                 if (in_files) {      /* ... zipfile ... -d exdir ... */
  498.                     *pp = 0;                    /* terminate pfnames */
  499.                     filespecs = pp - pfnames;
  500.                     in_files = FALSE;
  501.                 } else if (in_xfiles) {
  502.                     *pp = 0;                    /* terminate pxnames */
  503.                     xfilespecs = pp - pxnames;
  504.                     /* "... -x xlist -d exdir":  nothing left */
  505.                 }
  506.                 if (*++pp) {
  507.                     if (extract_flag) {
  508.                         create_dirs = !fflag;
  509.                         if ((error = checkdir(*pp, ROOT)) > 2)
  510.                             RETURN(error);   /* out of memory, or file in way */
  511.                     } else
  512.                         fprintf(stderr,
  513.                           "caution:  not extracting; -d ignored\n");
  514.                 } else {
  515.                     fprintf(stderr, "error:  must specify directory to which to\
  516.  extract with -d option\n");
  517.                     break;   /* no arguments left */
  518.                 }
  519.                 if (pp == argv+1)   /* ... zipfile -d exdir ... */
  520.                     if (pp[1]) {
  521.                         pfnames = pp + 1;  /* argv+2 */
  522.                         filespecs = argc - (pfnames-argv);  /* for now... */
  523.                     } else {
  524.                         process_all_files = TRUE;
  525.                         pfnames = fnames;  /* GRR: necessary? */
  526.                         filespecs = 0;     /* GRR: necessary? */
  527.                         break;
  528.                     }
  529.             } else if (!in_xfiles) {
  530.                 if (strcmp(*pp, "-x") == 0) {
  531.                     in_xfiles = TRUE;
  532.                     if (pp == argv || (pp == argv+2 && dflag)) {
  533.                         pfnames = fnames;  /* defaults */
  534.                         filespecs = 0;
  535.                     } else if (in_files) {
  536.                         *pp = 0;                   /* terminate pfnames */
  537.                         filespecs = pp - pfnames;  /* adjust count */
  538.                         in_files = FALSE;
  539.                     }
  540.                     pxnames = pp + 1;  /* excluded-names ptr starts after -x */
  541.                     xfilespecs = argc - (pxnames-argv);  /* anything left... */
  542.                 } else
  543.                     in_files = TRUE;
  544.             }
  545.         }
  546.     } else
  547.         process_all_files = TRUE;      /* for speed */
  548.  
  549. #endif /* ?OLD_EXDIR */
  550.  
  551. /*---------------------------------------------------------------------------
  552.     Okey dokey, we have everything we need to get started.  Let's roll.
  553.   ---------------------------------------------------------------------------*/
  554.  
  555.     inbuf = (uch *)malloc(INBUFSIZ + 4);    /* 4 extra for hold[] (below) */
  556.     outbuf = (uch *)malloc(OUTBUFSIZ + 1);  /* 1 extra for string termin. */
  557.  
  558.     if ((inbuf == (uch *)NULL) || (outbuf == (uch *)NULL)) {
  559.         fprintf(stderr, "error:  can't allocate unzip buffers\n");
  560.         RETURN(PK_MEM);
  561.     }
  562.     hold = inbuf + INBUFSIZ;     /* to check for boundary-spanning signatures */
  563. #ifdef SMALL_MEM
  564.     outbuf2 = outbuf+RAWBUFSIZ;  /* never changes */
  565. #endif
  566.  
  567.     RETURN(process_zipfiles());  /* keep passing errors back... */
  568.  
  569. } /* end main() */
  570.  
  571.  
  572.  
  573.  
  574.  
  575. /************************/
  576. /*  Function uz_opts()  */
  577. /************************/
  578.  
  579. int uz_opts(pargc, pargv)
  580.     int *pargc;
  581.     char ***pargv;
  582. {
  583.     char **argv, *s;
  584.     int argc, c, error=FALSE, negative=0;
  585.  
  586.  
  587.     argc = *pargc;
  588.     argv = *pargv;
  589.  
  590.     while (--argc > 0 && (*++argv)[0] == '-') {
  591.         s = argv[0] + 1;
  592.         while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
  593.             switch (c) {
  594.                 case ('-'):
  595.                     ++negative;
  596.                     break;
  597.                 case ('a'):
  598.                     if (negative) {
  599.                         aflag = MAX(aflag-negative,0);
  600.                         negative = 0;
  601.                     } else
  602.                         ++aflag;
  603.                     break;
  604.                 case ('b'):
  605.                     if (negative)
  606.                         negative = 0;   /* do nothing:  "-b" is default */
  607.                     else
  608.                         aflag = 0;
  609.                     break;
  610.                 case ('c'):
  611.                     if (negative) {
  612.                         cflag = FALSE, negative = 0;
  613. #ifdef NATIVE
  614.                         aflag = 0;
  615. #endif
  616.                     } else {
  617.                         cflag = TRUE;
  618. #ifdef NATIVE
  619.                         aflag = 2;  /* so you can read it on the screen */
  620. #endif
  621.                     }
  622.                     break;
  623.                 case ('d'):  /* arg after zipfn is stored dir, not extract-to */
  624. #ifdef OLD_EXDIR
  625.                     if (negative)
  626.                         dflag = FALSE, negative = 0;
  627.                     else
  628.                         dflag = TRUE;
  629. #endif
  630.                     break;
  631.                 case ('e'):    /* just ignore -e, -x options (extract) */
  632.                     break;
  633.                 case ('f'):    /* "freshen" (extract only newer files) */
  634.                     if (negative)
  635.                         fflag = uflag = FALSE, negative = 0;
  636.                     else
  637.                         fflag = uflag = TRUE;
  638.                     break;
  639.                 case ('j'):    /* junk pathnames/directory structure */
  640.                     if (negative)
  641.                         jflag = FALSE, negative = 0;
  642.                     else
  643.                         jflag = TRUE;
  644.                     break;
  645.                 case ('l'):
  646.                     if (negative) {
  647.                         vflag = MAX(vflag-negative,0);
  648.                         negative = 0;
  649.                     } else
  650.                         ++vflag;
  651.                     break;
  652.                 case ('n'):    /* don't overwrite any files */
  653.                     if (negative)
  654.                         overwrite_none = FALSE, negative = 0;
  655.                     else
  656.                         overwrite_none = TRUE;
  657.                     break;
  658.                 case ('o'):    /* OK to overwrite files without prompting */
  659.                     if (negative) {
  660.                         overwrite_all = MAX(overwrite_all-negative,0);
  661.                         force_flag = MAX(force_flag-negative,0);
  662.                         negative = 0;
  663.                     } else {
  664.                         ++overwrite_all;
  665.                         ++force_flag;  /* (share -o for now) force to cont. */
  666.                     }
  667.                     break;
  668.                 case ('p'):    /* pipes:  stdout, no translation, no messages */
  669.                     if (negative) {
  670.                         cflag = FALSE;
  671.                         qflag = MAX(qflag-999,0);
  672.                         negative = 0;
  673.                     } else {
  674.                         aflag = 0;
  675.                         cflag = TRUE;
  676.                         qflag += 999;
  677.                     }
  678.                     break;
  679.                 case ('q'):    /* quiet:  fewer comments/messages */
  680.                     if (negative) {
  681.                         qflag = MAX(qflag-negative,0);
  682.                         negative = 0;
  683.                     } else
  684.                         ++qflag;
  685.                     break;
  686. #ifdef DOS_NT_OS2
  687.                 case ('s'):    /* spaces in filenames:  allow by default */
  688.                     if (negative)
  689.                         sflag = FALSE, negative = 0;
  690.                     else
  691.                         sflag = TRUE;
  692.                     break;
  693. #endif
  694.                 case ('t'):
  695.                     if (negative)
  696.                         tflag = FALSE, negative = 0;
  697.                     else
  698.                         tflag = TRUE;
  699.                     break;
  700.                 case ('U'):    /* allow Uppercase (don't make all lowercase) */
  701.                     if (negative)
  702.                         U_flag = FALSE, negative = 0;
  703.                     else
  704.                         U_flag = TRUE;
  705.                     break;
  706.                 case ('u'):    /* update (extract only new and newer files) */
  707.                     if (negative)
  708.                         uflag = FALSE, negative = 0;
  709.                     else
  710.                         uflag = TRUE;
  711.                     break;
  712.                 case ('V'):    /* Version (retain VMS/DEC-20 file versions) */
  713.                     if (negative)
  714.                         V_flag = FALSE, negative = 0;
  715.                     else
  716.                         V_flag = TRUE;
  717.                     break;
  718.                 case ('v'):    /* verbose */
  719.                     if (negative) {
  720.                         vflag = MAX(vflag-negative,0);
  721.                         negative = 0;
  722.                     } else if (vflag)
  723.                         ++vflag;
  724.                     else
  725.                         vflag = 2;
  726.                     break;
  727. #ifdef VMS
  728.                 case ('X'):   /* restore owner/protection info (need privs?) */
  729.                     if (negative)
  730.                         secinf = FALSE, negative = 0;
  731.                     else
  732.                         secinf = TRUE;
  733.                     break;
  734. #endif /* VMS */
  735.                 case ('x'):    /* extract:  default */
  736.                     break;
  737.                 case ('z'):    /* display only the archive comment */
  738.                     if (negative) {
  739.                         zflag -= negative;
  740.                         negative = 0;
  741.                     } else
  742.                         ++zflag;
  743.                     break;
  744. #ifdef DOS_NT_OS2
  745.                 case ('$'):
  746.                     if (negative) {
  747.                         volflag = MAX(volflag-negative,0);
  748.                         negative = 0;
  749.                     } else
  750.                         ++volflag;
  751.                     break;
  752. #endif
  753.                 default:
  754.                     error = TRUE;
  755.                     break;
  756.  
  757.             } /* end switch */
  758.         } /* end while (not end of argument string) */
  759.     } /* end while (not done with switches) */
  760.  
  761. /*---------------------------------------------------------------------------
  762.     Check for nonsensical combinations of options.  [Isn't the -a option use-
  763.     ful when listing the directory (i.e., for reading zipfile comments)?  It
  764.     is only a modifier, so perhaps it should not be included in the test.]
  765.   ---------------------------------------------------------------------------*/
  766.  
  767.     if ((cflag && tflag) || (cflag && uflag) || (cflag && vflag) ||
  768.         (tflag && uflag) || (tflag && vflag) || (uflag && vflag) ||
  769.         (fflag && overwrite_none)) {
  770.         fprintf(stderr, "error:\
  771.   -fn or any combination of -c, -l, -p, -t, -u and -v options invalid\n");
  772.         error = TRUE;
  773.     }
  774.     if (aflag > 2)
  775.         aflag = 2;
  776. #if 0
  777.     if ((aflag && tflag) || (aflag && vflag))   /* -a makes no sense */
  778.         aflag = 0;
  779. #endif
  780.     if (overwrite_all && overwrite_none) {
  781.         fprintf(stderr, "caution:  both -n and -o specified; ignoring -o\n");
  782.         overwrite_all = FALSE;
  783.     }
  784.  
  785. #ifdef SFX
  786.     if (error)
  787. #else
  788.     if ((argc-- == 0) || error)
  789. #endif
  790.     {
  791.         *pargc = argc;
  792.         *pargv = argv;
  793.         return usage(error);
  794.     }
  795.  
  796.     if (cflag || tflag || vflag)
  797.         extract_flag = FALSE;
  798.     else
  799.         extract_flag = TRUE;
  800.  
  801.     *pargc = argc;
  802.     *pargv = argv;
  803.     return 0;
  804.  
  805. } /* end function uz_opts() */
  806.  
  807.  
  808.  
  809.  
  810.  
  811. /**********************/
  812. /*  Function usage()  */
  813. /**********************/
  814.  
  815. #ifdef SFX
  816.  
  817. int usage(error)   /* return PK-type error code */
  818.     int error;
  819. {
  820.     FILE *usagefp;
  821.  
  822.     if (error)
  823.         usagefp = (FILE *)stderr;
  824.     else
  825.         usagefp = (FILE *)stdout;
  826.  
  827.     fprintf(usagefp, "\
  828. UnZipSFX %s, by Info-ZIP (zip-bugs@wkuvx1.wku.edu).\n\n",
  829.       UZ_VERSION);
  830. #ifndef RELEASE
  831.     fprintf(usagefp, "\
  832.     THIS IS STILL A BETA VERSION OF UNZIPSFX -- DO NOT DISTRIBUTE.\n\n");
  833. #endif
  834.  
  835.     if (error)
  836.         return PK_PARAM;
  837.     else
  838.         return PK_COOL;     /* just wanted usage screen: no error */
  839.  
  840. } /* end function usage() */
  841.  
  842.  
  843.  
  844.  
  845.  
  846. #else /* !SFX */
  847.  
  848. int usage(error)   /* return PK-type error code */
  849.     int error;
  850. {
  851. #ifdef VMS
  852. #  define QUOT '\"'
  853. #  define QUOTS "\""
  854. #  define EXAMPLE2 "vms.c"
  855. #  define EXAMPLE1 \
  856. "unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS"
  857. #else
  858. #  define QUOT ' '
  859. #  define QUOTS ""
  860. #  define EXAMPLE2 "ReadMe"
  861. #  define EXAMPLE1 \
  862. "unzip -p foo | more  => send contents of foo.zip via pipe into program more"
  863. #endif
  864.  
  865. #ifdef DOS_NT_OS2
  866.     char *loc_str = " -$  label removables (-$$ => fixed disks)";
  867.     char *loc2str = "\
  868.                                              -s  spaces in filenames => '_'\n";
  869. #else /* !DOS_NT_OS2 */
  870. #ifdef VMS
  871.     char *loc_str = "\"-X\" restore owner/protection info";
  872.     char *loc2str = "\n";
  873. #else
  874.     char *loc_str = "";   /* Unix, Amiga, Mac, etc. */
  875.  /* char *loc_str = " -X  restore UID/GID info";    Unix version, in 5.2 */
  876.     char *loc2str = "";
  877. #endif
  878. #endif /* ?DOS_NT_OS2 */
  879.  
  880.     FILE *usagefp;
  881.  
  882.  
  883. /*---------------------------------------------------------------------------
  884.     If user requested usage, send it to stdout; else send to stderr.
  885.   ---------------------------------------------------------------------------*/
  886.  
  887.     if (error)
  888.         usagefp = (FILE *)stderr;
  889.     else
  890.         usagefp = (FILE *)stdout;
  891.  
  892. /*---------------------------------------------------------------------------
  893.     Print either ZipInfo usage or UnZip usage, depending on incantation.
  894.     (Strings must be no longer than 512 bytes for Turbo C, apparently.)
  895.   ---------------------------------------------------------------------------*/
  896.  
  897.     if (zipinfo_mode) {
  898.  
  899. #ifndef NO_ZIPINFO
  900.  
  901.         fprintf(usagefp, "\
  902. ZipInfo %s, by Newtware and the fine folks at Info-ZIP.\n\
  903. \n\
  904. List name, date/time, attribute, size, compression method, etc., about files\n\
  905. in list (excluding those in xlist) contained in the specified .zip archive(s).\
  906. \n\"file[.zip]\" may be a wildcard name containing *, ?, [] (e.g., \"[a-j]*\
  907. .zip\").\n\n\
  908.    usage:  zipinfo [-12smlvhtz] file[.zip] [list...] [-x xlist...]\n\
  909.       or:  unzip %s-Z%s [-12smlvhtz] file[.zip] [list...] [-x xlist...]\n",
  910.           ZI_VERSION, QUOTS,QUOTS);
  911.         fprintf(usagefp, "\nmain\
  912.  listing-format options:             -s  short Unix \"ls -l\" format (def.)\n\
  913.   -1  filenames ONLY, one per line       -m  medium Unix \"ls -l\" format\n\
  914.   -2  just filenames but allow -h/-t/-z  -l  long Unix \"ls -l\" format\n\
  915.                                          -v  verbose, multi-page format\n\
  916. miscellaneous options:\n  \
  917. -h  print header line      -t  print totals for files listed or for all files\n\
  918.   -z  print zipfile comment  -x  exclude filenames that follow from listing\n");
  919. /* -p  disable automatic \"more\" function (for pipes) [not implemented]\n"); */
  920. #ifdef VMS
  921.         fprintf(usagefp, "\nRemember that non-lowercase filespecs must be\
  922.  quoted in VMS (e.g., \"Makefile\").\n");
  923. #endif
  924.  
  925. #endif /* !NO_ZIPINFO */
  926.  
  927.     } else {   /* UnZip mode */
  928.  
  929.         fprintf(usagefp, "\
  930. UnZip %s, by Info-ZIP.  Portions (c) 1989 by S. H. Smith.\n\
  931. Send bug reports to authors at zip-bugs@wkuvx1.wku.edu; see README for details.\
  932. \n\n", UZ_VERSION);
  933. #ifndef RELEASE
  934.         fprintf(usagefp, "\
  935.         THIS IS STILL A BETA VERSION OF UNZIP -- DO NOT DISTRIBUTE.\n\n");
  936. #endif
  937.         fprintf(usagefp, "\
  938. Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]\n \
  939.  Default action is to extract files in list, except those in xlist, to exdir;\n\
  940.   file[.zip] may be a wildcard.  %s\n\n",
  941. #ifdef NO_ZIPINFO
  942.           "", "(ZipInfo mode is disabled in this version.)");
  943. #else
  944. #ifdef VMS
  945.           "[-Z] ", "\"-Z\" => ZipInfo mode (`unzip \"-Z\"' for usage).");
  946. #else
  947.           "[-Z] ", "-Z => ZipInfo mode (\"unzip -Z\" for usage).");
  948. #endif
  949. #endif /* ?NO_ZIPINFO */
  950.  
  951.         fprintf(usagefp, "\
  952.   -c  extract files to stdout/screen (CRT)   -l  list files (short format)\n\
  953.   -p  extract files to pipe, no messages     -v  list files (verbose format)\n\
  954.   -f  freshen existing files, create none    -t  test compressed archive data\n\
  955.   -u  update files, create if necessary      -z  display archive comment\n\
  956.   -x  exclude files which follow (in xlist)  -d  extract files into exdir\n\n");
  957.  
  958.         fprintf(usagefp, "\
  959. modifiers:                                   -q  quiet mode (-qq => quieter)\n\
  960.   -n  never overwrite existing files         -a  auto-convert any text files\n\
  961.   -o  overwrite files WITHOUT prompting      -aa treat ALL files as text\n\
  962.   -j  junk paths (don't make directories)   %c-U%c don't make names lowercase\n\
  963.  %-42s %c-V%c retain VMS version numbers\n%s",
  964.           QUOT,QUOT, loc_str, QUOT,QUOT, loc2str);
  965.  
  966.         fprintf(usagefp, "\
  967. Examples (see unzip.doc for more info):\n\
  968.   unzip data1 -x joe   => extract all files except joe from zipfile data1.zip\n\
  969.   %s\n\
  970.   unzip -fo foo %-6s => quietly replace existing %s if archive file newer\n",
  971.           EXAMPLE1, EXAMPLE2,EXAMPLE2);
  972.  
  973.     }
  974.  
  975.     if (error)
  976.         return PK_PARAM;
  977.     else
  978.         return PK_COOL;     /* just wanted usage screen: no error */
  979.  
  980. } /* end function usage() */
  981.  
  982. #endif /* ?SFX */
  983. #endif /* ?MSWIN */
  984.  
  985.  
  986.  
  987.  
  988. /*********************************/
  989. /*  Function process_zipfiles()  */
  990. /*********************************/
  991.  
  992. int process_zipfiles()    /* return PK-type error code */
  993. {
  994.     char *lastzipfn = NULL;
  995.     int error=0, error_in_archive=0;
  996.     int num_win_files, num_lose_files, num_warn_files;
  997.     int num_miss_dirs, num_miss_files;
  998.  
  999.  
  1000. /*---------------------------------------------------------------------------
  1001.     Start by constructing the various PK signature strings.
  1002.   ---------------------------------------------------------------------------*/
  1003.  
  1004.     local_hdr_sig[0]  /* = extd_local_sig[0] */  = '\120';   /* ASCII 'P', */
  1005.     central_hdr_sig[0] = end_central_sig[0] = '\120';        /* not EBCDIC */
  1006.  
  1007.     strcpy(local_hdr_sig+1, LOCAL_HDR_SIG);
  1008.     strcpy(central_hdr_sig+1, CENTRAL_HDR_SIG);
  1009.     strcpy(end_central_sig+1, END_CENTRAL_SIG);
  1010. /*  strcpy(extd_local_sig+1, EXTD_LOCAL_SIG);   still to be used in multi? */
  1011.  
  1012. /*---------------------------------------------------------------------------
  1013.     Match (possible) wildcard zipfile specification with existing files and
  1014.     attempt to process each.  If no hits, try again after appending ".zip"
  1015.     suffix.  If still no luck, give up.
  1016.   ---------------------------------------------------------------------------*/
  1017.  
  1018. #ifdef SFX
  1019.     if ((error = do_seekable(0)) != IZ_DIR && error > error_in_archive)
  1020.         error_in_archive = error;
  1021.  
  1022. #else /* !SFX */
  1023.     num_win_files = num_lose_files = num_warn_files = 0;
  1024.     num_miss_dirs = num_miss_files = 0;
  1025.  
  1026.     while ((zipfn = do_wild(wildzipfn)) != NULL) {
  1027.         Trace((stderr, "do_wild( %s ) returns %s\n", wildzipfn, zipfn));
  1028.  
  1029.         lastzipfn = zipfn;
  1030.  
  1031.         if (!qflag  &&  error != PK_NOZIP  &&
  1032.             (num_win_files+num_lose_files+num_warn_files+num_miss_files) > 0)
  1033.             printf("\n");
  1034.         FFLUSH(stdout);
  1035.  
  1036.         if ((error = do_seekable(0)) == PK_WARN)
  1037.             ++num_warn_files;
  1038.         else if (error == IZ_DIR)
  1039.             ++num_miss_dirs;
  1040.         else if (error == PK_NOZIP)
  1041.             ++num_miss_files;
  1042.         else if (error)
  1043.             ++num_lose_files;
  1044.         else
  1045.             ++num_win_files;
  1046.  
  1047.         if (error != IZ_DIR && error > error_in_archive)
  1048.             error_in_archive = error;
  1049.         Trace((stderr, "do_seekable(0) returns %d\n", error));
  1050.  
  1051.     } /* end while-loop (wildcard zipfiles) */
  1052.  
  1053.     if ((num_win_files + num_warn_files + num_lose_files) == 0  &&
  1054.         (num_miss_dirs + num_miss_files) == 1  &&  lastzipfn != NULL)
  1055.     {
  1056.         num_miss_dirs = num_miss_files = 0;
  1057.         if (error_in_archive == PK_NOZIP)
  1058.             error_in_archive = PK_COOL;
  1059.         strcat((zipfn = lastzipfn), ZSUFX);
  1060.  
  1061.         if ((error = do_seekable(1)) == PK_WARN)
  1062.             ++num_warn_files;
  1063.         else if (error == IZ_DIR)
  1064.             ++num_miss_dirs;
  1065.         else if (error == PK_NOZIP)
  1066.             /* if increment again => bug: "1 file had no zipfile directory." */
  1067.             /* ++num_miss_files */ ;
  1068.         else if (error)
  1069.             ++num_lose_files;
  1070.         else
  1071.             ++num_win_files;
  1072.  
  1073.         if (error > error_in_archive)
  1074.             error_in_archive = error;
  1075.         Trace((stderr, "do_seekable(1) returns %d\n", error));
  1076.     }
  1077. #endif /* ?SFX */
  1078.  
  1079.     FFLUSH(stdout);
  1080.     FFLUSH(stderr);
  1081.  
  1082. #ifndef SFX
  1083.     if (num_miss_dirs + num_miss_files + num_lose_files + num_warn_files > 0
  1084.         || num_win_files != 1)
  1085.         fprintf(stderr, "\n");
  1086.     if ((num_win_files > 1) || (num_win_files == 1 &&
  1087.         num_miss_dirs + num_miss_files + num_lose_files + num_warn_files > 0))
  1088.         fprintf(stderr, "%d archive%s successfully processed.\n",
  1089.           num_win_files, (num_win_files == 1)? " was" : "s were");
  1090.     if (num_warn_files > 0)
  1091.         fprintf(stderr, "%d archive%s had warnings but no fatal errors.\n",
  1092.           num_warn_files, (num_warn_files == 1)? "" : "s");
  1093.     if (num_lose_files > 0)
  1094.         fprintf(stderr, "%d archive%s had fatal errors.\n",
  1095.           num_lose_files, (num_lose_files == 1)? "" : "s");
  1096.     if (num_miss_files > 0)
  1097.         fprintf(stderr, "%d file%s had no zipfile directory.\n",
  1098.           num_miss_files, (num_miss_files == 1)? "" : "s");
  1099.     if (num_miss_dirs == 1)
  1100.         fprintf(stderr, "1 \"zipfile\" was a directory.\n");
  1101.     else if (num_miss_dirs > 0)
  1102.         fprintf(stderr, "%d \"zipfiles\" were directories.\n", num_miss_dirs);
  1103.     if (num_win_files + num_lose_files + num_warn_files == 0)
  1104.         fprintf(stderr, "No zipfiles found.\n");
  1105. #endif /* !SFX */
  1106.  
  1107.     /* free allocated memory */
  1108.     inflate_free();
  1109.     checkdir((char *)NULL, END);
  1110. #ifndef SMALL_MEM
  1111.     if (outbuf2)
  1112.         free(outbuf2);   /* malloc'd ONLY if unshrink and -a */
  1113. #endif
  1114.     free(outbuf);
  1115.     free(inbuf);
  1116.  
  1117.     return error_in_archive;
  1118.  
  1119. } /* end function process_zipfiles() */
  1120.  
  1121.  
  1122.  
  1123.  
  1124.  
  1125. /****************************/
  1126. /*  Function do_seekable()  */
  1127. /****************************/
  1128.  
  1129. int do_seekable(lastchance)    /* return PK-type error code */
  1130.     int lastchance;
  1131. {
  1132.     int error=0, error_in_archive, maybe_exe=FALSE;
  1133.     static int no_ecrec = FALSE;
  1134.  
  1135.  
  1136. /*---------------------------------------------------------------------------
  1137.     Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
  1138.     which would corrupt the bit streams.
  1139.   ---------------------------------------------------------------------------*/
  1140.  
  1141.     if (SSTAT(zipfn, &statbuf) || (error = S_ISDIR(statbuf.st_mode)) != 0) {
  1142.         if (lastchance)
  1143.             if (no_ecrec)
  1144.                 fprintf(stderr, "%s:  can't find zipfile directory in %s,\n\
  1145.         %sand can't find %s, period.\n", zipinfo_mode? "zipinfo" : "unzip",
  1146.                   wildzipfn, zipinfo_mode? "  " : "", zipfn);
  1147.             else
  1148.                 fprintf(stderr,
  1149.                   "%s:  can't find either %s or %s, so there.\n",
  1150.                   zipinfo_mode? "zipinfo" : "unzip", wildzipfn, zipfn);
  1151.         return error? IZ_DIR : PK_NOZIP;
  1152.     }
  1153.     ziplen = statbuf.st_size;
  1154.  
  1155. #if defined(UNIX) || defined(DOS_NT_OS2)  /* no extension on Unix exec's: */
  1156.     if (statbuf.st_mode & S_IEXEC)      /* might find zip, not zip.zip; etc. */
  1157.         maybe_exe = TRUE;               /* (for other OS's, some executables */
  1158. #endif                                  /* can be self-extracting archives) */
  1159.  
  1160. #ifdef VMS
  1161.     if (check_format())      /* check for variable-length format */
  1162.         return PK_ERR;
  1163. #endif
  1164.  
  1165.     if (open_input_file())   /* this should never happen, given */
  1166.         return PK_NOZIP;     /*  the stat() test above, but... */
  1167.  
  1168. /*---------------------------------------------------------------------------
  1169.     Find and process the end-of-central-directory header.  UnZip need only
  1170.     check last 65557 bytes of zipfile:  comment may be up to 65535, end-of-
  1171.     central-directory record is 18 bytes, and signature itself is 4 bytes;
  1172.     add some to allow for appended garbage.  Since ZipInfo is often used as
  1173.     a debugging tool, search the whole zipfile if zipinfo_mode is true.
  1174.   ---------------------------------------------------------------------------*/
  1175.  
  1176.     cur_zipfile_bufstart = 0;
  1177.     inptr = inbuf;
  1178.  
  1179.     if (!qflag && !zipinfo_mode)
  1180.         printf("Archive:  %s\n", zipfn);
  1181.  
  1182.     if ((
  1183. #ifndef NO_ZIPINFO
  1184.          zipinfo_mode &&
  1185.           ((error_in_archive = find_end_central_dir(ziplen)) != 0 ||
  1186.           (error_in_archive = zi_end_central()) > PK_WARN))
  1187.         || (!zipinfo_mode &&
  1188. #endif
  1189.           ((error_in_archive = find_end_central_dir(MIN(ziplen,66000L))) != 0 ||
  1190.           (error_in_archive = uz_end_central()) > PK_WARN)))
  1191.     {
  1192.         close(zipfd);
  1193. #ifdef SFX
  1194.         return error_in_archive;
  1195. #else
  1196.         if (maybe_exe)
  1197.             fprintf(stderr, "note:  %s may be an executable, not an archive\n",
  1198.               zipfn);
  1199.         if (lastchance)
  1200.             return error_in_archive;
  1201.         else {
  1202.             no_ecrec = TRUE;    /* assume we found wrong file:  e.g., */
  1203.             return PK_NOZIP;    /*  unzip instead of unzip.zip */
  1204.         }
  1205. #endif /* ?SFX */
  1206.     }
  1207.  
  1208.     if ((zflag > 0) && !zipinfo_mode) {   /* in unzip, zflag = comment ONLY */
  1209.         close(zipfd);
  1210.         return error_in_archive;
  1211.     }
  1212.  
  1213. /*---------------------------------------------------------------------------
  1214.     Test the end-of-central-directory info for incompatibilities (multi-disk
  1215.     archives) or inconsistencies (missing or extra bytes in zipfile).
  1216.   ---------------------------------------------------------------------------*/
  1217.  
  1218.     error = !zipinfo_mode && (ecrec.number_this_disk == 1) &&
  1219.             (ecrec.num_disk_with_start_central_dir == 1);
  1220.  
  1221.     if (zipinfo_mode &&
  1222.         ecrec.number_this_disk != ecrec.num_disk_with_start_central_dir)
  1223.     {
  1224.         fprintf(stderr, "\n\
  1225.      Zipfile is part of a multi-disk archive, and this is not the disk on\n\
  1226.      which the central zipfile directory begins.\n");
  1227.         error_in_archive = PK_FIND;
  1228.  
  1229.     } else if (!zipinfo_mode && !error && ecrec.number_this_disk != 0) {
  1230.  
  1231.         fprintf(stderr, "\nerror [%s]:  zipfile is part of multi-disk archive\n\
  1232.   (sorry, not yet supported).\n", zipfn);
  1233.         error_in_archive = PK_FIND;
  1234.  
  1235.     } else {   /* this is a (relatively) normal zipfile:  process normally */
  1236.  
  1237.         if (error) {
  1238.             fprintf(stderr, "\n\
  1239.      Warning:  zipfile claims to be second disk of a two-part archive;\n\
  1240.      attempting to process anyway.  If no further errors occur, this\n\
  1241.      archive was probably created by PAK v2.51 or earlier.  This bug\n\
  1242.      was reported to NoGate in March 1991 and was supposed to have been\n\
  1243.      fixed by mid-1991; as of mid-1992 it still hadn't been.  (If fur-\n\
  1244.      ther errors do occur, archive was probably created by PKZIP 2.04c\n\
  1245.      or later; UnZip does not yet support multi-part archives.)\n\n");
  1246.             error_in_archive = PK_WARN;
  1247.         }
  1248.         if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < (LONGINT)0) {
  1249.             fprintf(stderr, "error [%s]:  missing %ld bytes in zipfile\n\
  1250.   (attempting to process anyway)\n", zipfn, (long)(-extra_bytes));
  1251.             error_in_archive = PK_ERR;
  1252.         } else if (extra_bytes > 0) {
  1253.             if ((ecrec.offset_start_central_directory == 0) &&
  1254.                 (ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
  1255.             {
  1256.                 fprintf(stderr, "error [%s]:  NULL central directory offset\n\
  1257.   (attempting to process anyway)\n", zipfn);
  1258.                 ecrec.offset_start_central_directory = extra_bytes;
  1259.                 extra_bytes = 0;
  1260.                 error_in_archive = PK_ERR;
  1261.             } else {
  1262. #ifndef SFX
  1263.                 fprintf(stderr, "warning [%s]:  extra %ld bytes at beginning\
  1264.  or within zipfile\n  (attempting to process anyway)\n", zipfn,
  1265.                   (long)extra_bytes);
  1266.                 error_in_archive = PK_WARN;
  1267. #endif
  1268.             }
  1269.         }
  1270.  
  1271.     /*-----------------------------------------------------------------------
  1272.         Check for empty zipfile and exit now if so.
  1273.       -----------------------------------------------------------------------*/
  1274.  
  1275.         if (expect_ecrec_offset == 0L  &&  ecrec.size_central_directory == 0) {
  1276.             if (zipinfo_mode)
  1277.                 printf("%sEmpty zipfile.\n", lflag>9 ? "\n  " : "");
  1278.             else
  1279.                 fprintf(stderr, "warning [%s]:  zipfile is empty\n", zipfn);
  1280.             close(zipfd);
  1281.             return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN;
  1282.         }
  1283.  
  1284.     /*-----------------------------------------------------------------------
  1285.         Compensate for missing or extra bytes, and seek to where the start
  1286.         of central directory should be.  If header not found, uncompensate
  1287.         and try again (necessary for at least some Atari archives created
  1288.         with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
  1289.       -----------------------------------------------------------------------*/
  1290.  
  1291.         LSEEK( ecrec.offset_start_central_directory )
  1292.         if ((error = readbuf(sig, 4)) < 0) {
  1293.             close(zipfd);
  1294.             return PK_ERR;  /* file may be locked, or possibly disk error(?) */
  1295.         }
  1296.         if ((error == 0) || strncmp(sig, central_hdr_sig, 4)) {
  1297.             long tmp = extra_bytes;
  1298.  
  1299.             extra_bytes = 0;
  1300.             LSEEK( ecrec.offset_start_central_directory )
  1301.             if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
  1302.                 fprintf(stderr,
  1303.                   "error [%s]:  start of central directory not found;\n\
  1304.   zipfile corrupt.\n%s", zipfn, ReportMsg);
  1305.                 close(zipfd);
  1306.                 return PK_BADERR;
  1307.             }
  1308.             fprintf(stderr,
  1309.               "error [%s]:  reported length of central directory is\n\
  1310.   %ld bytes too long (Atari STZIP zipfile?  J.H.Holm ZIPSPLIT 1.1\n\
  1311.   zipfile?).  Compensating...\n", zipfn, -tmp);
  1312.             error_in_archive = PK_ERR;
  1313.         }
  1314.  
  1315.     /*-----------------------------------------------------------------------
  1316.         Seek to the start of the central directory one last time, since we
  1317.         have just read the first entry's signature bytes; then list, extract
  1318.         or test member files as instructed, and close the zipfile.
  1319.       -----------------------------------------------------------------------*/
  1320.  
  1321.         Trace((stderr, "about to extract/list files (error = %d)\n",
  1322.           error_in_archive));
  1323.  
  1324.         LSEEK( ecrec.offset_start_central_directory )
  1325.  
  1326. #ifndef NO_ZIPINFO
  1327.         if (zipinfo_mode) {
  1328.             error = zipinfo();                     /* ZIPINFO 'EM */
  1329.             if (lflag > 9)
  1330.                 printf("\n");
  1331.         } else
  1332. #endif
  1333.             if (vflag)
  1334.                 error = list_files();              /* LIST 'EM */
  1335.             else
  1336.                 error = extract_or_test_files();   /* EXTRACT OR TEST 'EM */
  1337.  
  1338.         Trace((stderr, "done with extract/list files (error = %d)\n", error));
  1339.  
  1340.         if (error > error_in_archive)   /* don't overwrite stronger error */
  1341.             error_in_archive = error;   /*  with (for example) a warning */
  1342.     }
  1343.  
  1344.     close(zipfd);
  1345.     return error_in_archive;
  1346.  
  1347. } /* end function do_seekable() */
  1348.  
  1349.  
  1350.  
  1351.  
  1352.  
  1353. /*****************************/
  1354. /* Function uz_end_central() */
  1355. /*****************************/
  1356.  
  1357. int uz_end_central()    /* return PK-type error code */
  1358. {
  1359.     int error = PK_COOL;
  1360.  
  1361.  
  1362. /*---------------------------------------------------------------------------
  1363.     Get the zipfile comment (up to 64KB long), if any, and print it out.
  1364.     Then position the file pointer to the beginning of the central directory
  1365.     and fill buffer.
  1366.   ---------------------------------------------------------------------------*/
  1367.  
  1368. #ifdef MSWIN
  1369.     cchComment = ecrec.zipfile_comment_length; /* save for comment button */
  1370.     if (ecrec.zipfile_comment_length && (zflag > 0))
  1371. #else /* !MSWIN */
  1372.     if (ecrec.zipfile_comment_length && (zflag > 0 || (zflag == 0 && !qflag)))
  1373. #endif /* ?MSWIN */
  1374.     {
  1375. #if 0
  1376. #ifndef MSWIN
  1377.         if (zflag == 0)       (add "&& single_zipfile" perhaps; unnecessary with
  1378.             printf("[%s] comment:\n", zipfn);  multiple zipfiles: "Archive:...")
  1379. #endif /* !MSWIN */
  1380. #endif /* 0 */
  1381.         if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
  1382.             fprintf(stderr, "\ncaution:  zipfile comment truncated\n");
  1383.             error = PK_WARN;
  1384.         }
  1385.     }
  1386.     return error;
  1387.  
  1388. } /* end function uz_end_central() */
  1389.  
  1390.  
  1391.  
  1392.  
  1393.  
  1394. /**************************************/
  1395. /*  Function process_cdir_file_hdr()  */
  1396. /**************************************/
  1397.  
  1398. int process_cdir_file_hdr()    /* return PK-type error code */
  1399. {
  1400.     int error;
  1401.  
  1402.  
  1403. /*---------------------------------------------------------------------------
  1404.     Get central directory info, save host and method numbers, and set flag
  1405.     for lowercase conversion of filename, depending on the OS from which the
  1406.     file is coming.
  1407.   ---------------------------------------------------------------------------*/
  1408.  
  1409.     if ((error = get_cdir_file_hdr()) != 0)
  1410.         return error;
  1411.  
  1412.     pInfo->hostnum = MIN(crec.version_made_by[1], NUM_HOSTS);
  1413. /*  extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
  1414.  
  1415.     pInfo->lcflag = 0;
  1416.     if (!U_flag)   /* as long as user hasn't specified case-preservation */
  1417.         switch (pInfo->hostnum) {
  1418.             case FS_FAT_:     /* PKZIP and zip -k store in uppercase */
  1419.             case ATARI_:      /* MS-DOS filesystem */
  1420.             case CPM_:        /* like MS-DOS, right? */
  1421.             case VM_CMS_:     /* all caps? */
  1422.             case TOPS20_:
  1423.         /*  case Z_SYSTEM_:   ? */
  1424.         /*  case QDOS_:       ? */
  1425.                 pInfo->lcflag = 1;   /* convert filename to lowercase */
  1426.                 break;
  1427.  
  1428.         /*  case VMS_:   Info-ZIP's VMS Zip converts filenames to lowercase */
  1429.             default:     /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, */
  1430.                 break;   /*  (Z_SYSTEM_):  no conversion */
  1431.         }
  1432.  
  1433.     /* do Amigas (AMIGA_) also have volume labels? */
  1434.     if (IS_VOLID(crec.external_file_attributes) &&
  1435.         (pInfo->hostnum == FS_FAT_ || pInfo->hostnum == FS_HPFS_ ||
  1436.          pInfo->hostnum == FS_NTFS_ || pInfo->hostnum == ATARI_))
  1437.     {
  1438.         pInfo->vollabel = TRUE;
  1439.         pInfo->lcflag = 0;        /* preserve case of volume labels */
  1440.     } else
  1441.         pInfo->vollabel = FALSE;
  1442.  
  1443.     return PK_COOL;
  1444.  
  1445. } /* end function process_cdir_file_hdr() */
  1446.  
  1447.  
  1448.  
  1449.  
  1450.  
  1451. /***************************************/
  1452. /*  Function process_local_file_hdr()  */
  1453. /***************************************/
  1454.  
  1455. int process_local_file_hdr()    /* return PK-type error code */
  1456. {
  1457.     local_byte_hdr byterec;
  1458.  
  1459.  
  1460. /*---------------------------------------------------------------------------
  1461.     Read the next local file header and do any necessary machine-type con-
  1462.     versions (byte ordering, structure padding compensation--do so by copy-
  1463.     ing the data from the array into which it was read (byterec) to the
  1464.     usable struct (lrec)).
  1465.   ---------------------------------------------------------------------------*/
  1466.  
  1467.     if (readbuf((char *)byterec, LREC_SIZE) <= 0)
  1468.         return PK_EOF;
  1469.  
  1470.     lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
  1471.     lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
  1472.  
  1473.     lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
  1474.     lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
  1475.     lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
  1476.     lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
  1477.     lrec.crc32 = makelong(&byterec[L_CRC32]);
  1478.     lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]);
  1479.     lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
  1480.     lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
  1481.     lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
  1482.  
  1483.     csize = (long) lrec.csize;
  1484.     ucsize = (long) lrec.ucsize;
  1485.  
  1486.     if ((lrec.general_purpose_bit_flag & 8) != 0) {
  1487.         /* can't trust local header, use central directory: */
  1488.         lrec.crc32 = pInfo->crc;
  1489.         csize = (long)(lrec.csize = pInfo->compr_size);
  1490.     }
  1491.  
  1492.     return PK_COOL;
  1493.  
  1494. } /* end function process_local_file_hdr() */
  1495.