home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip512.zip / unzip.c < prev    next >
C/C++ Source or Header  |  1994-08-23  |  67KB  |  1,907 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.   As of ZipInfo v2.0 and UnZip v5.1, the two programs are combined into one.
  30.   If the executable is named "unzip" (or "unzip.exe", depending), it behaves
  31.   like UnZip by default; if it is named "zipinfo" or "ii", it behaves like
  32.   ZipInfo.  The ZipInfo behavior may also be triggered by use of unzip's -Z
  33.   option; for example, "unzip -Z [zipinfo_options] archive.zip".
  34.  
  35.   Another dandy product from your buddies at Newtware!
  36.  
  37.   Author:  Greg Roelofs, newt@uchicago.edu, 23 August 1990 -> ... 1994
  38.  
  39.   ---------------------------------------------------------------------------
  40.  
  41.   Version:  unzip512.{tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS, Windows,
  42.               Windows NT, Macintosh, Amiga, Atari, Human68K and TOPS-20.  De-
  43.               cryption requires sources in zcrypt23.zip, and Windows (not NT)
  44.               support requires sources in wunz20sr.zip (not up to date).  See
  45.               accompanying file "Where" in the main source distribution for
  46.               ftp, uucp and mail-server sites.
  47.  
  48.   Copyrights:  see accompanying file "COPYING" in UnZip source distribution.
  49.  
  50.   ---------------------------------------------------------------------------*/
  51.  
  52.  
  53.  
  54. #include "unzip.h"        /* includes, typedefs, macros, prototypes, etc. */
  55. #include "crypt.h"
  56. #include "version.h"
  57. #ifdef MSWIN
  58. #  include "wizunzip.h"
  59. #endif
  60.  
  61.  
  62.  
  63. /**********************/
  64. /*  Global Variables  */
  65. /**********************/
  66.  
  67. int zipinfo_mode;     /* behave like ZipInfo or like normal UnZip? */
  68.  
  69. int aflag=0;          /* -a: do ASCII-EBCDIC and/or end-of-line translation */
  70. int cflag=0;          /* -c: output to stdout */
  71. int C_flag=0;         /* -C: match filenames case-insensitively */
  72. int dflag=0;          /* -d: all args are files/dirs to be extracted */
  73. int fflag=0;          /* -f: "freshen" (extract only newer files) */
  74. int hflag=0;          /* -h: header line (zipinfo) */
  75. int jflag=0;          /* -j: junk pathnames (unzip) */
  76. int lflag=(-1);       /* -12slmv: listing format (zipinfo) */
  77. int L_flag=0;         /* -L: convert filenames from some OSes to lowercase */
  78. int overwrite_none=0; /* -n: never overwrite files (no prompting) */
  79. int overwrite_all=0;  /* -o: OK to overwrite files without prompting */
  80. int force_flag=0;     /* (shares -o for now): force to override errors, etc. */
  81. int qflag=0;          /* -q: produce a lot less output */
  82. #ifdef DOS_NT_OS2
  83.    int sflag=0;       /* -s: convert filename spaces (blanks) to underscores */
  84.    int volflag=0;     /* -$: extract volume labels */
  85. #endif
  86. int tflag=0;          /* -t: test (unzip) or totals line (zipinfo) */
  87. int T_flag=0;         /* -T: decimal time format (zipinfo) */
  88. int uflag=0;          /* -u: "update" (extract only newer & brand-new files) */
  89. int vflag=0;          /* -v: (verbosely) list directory */
  90. int V_flag=0;         /* -V: don't strip VMS version numbers */
  91. #ifdef VMS
  92.    int secinf=0;      /* -X: keep owner/protection */
  93. #endif
  94. int zflag=0;          /* -z: display the zipfile comment (only, for unzip) */
  95.  
  96. int filespecs;        /* number of real file specifications to be matched */
  97. int xfilespecs;       /* number of excluded filespecs to be matched */
  98. int process_all_files = 0;
  99. int create_dirs;      /* used by main(), mapname(), checkdir() */
  100. int extract_flag;
  101.  
  102. #if (defined(CRYPT) || !defined(NO_ZIPINFO))
  103.    int newzip;        /* used in extract.c, crypt.c, zipinfo.c */
  104. #endif
  105.  
  106. LONGINT real_ecrec_offset, expect_ecrec_offset;
  107.  
  108. long csize;           /* used by list_files(), ReadByte(): must be signed */
  109. long ucsize;          /* used by list_files(), unReduce(), explode() */
  110. long used_csize;      /* used by extract_or_test_member(), explode() */
  111.  
  112. static char *fnames[2] = {"*", NULL};   /* default filenames vector */
  113. char **pfnames = fnames, **pxnames = &fnames[1];
  114. char near sig[5];
  115. char near answerbuf[10];
  116.  
  117. min_info info[DIR_BLKSIZ], *pInfo=info;
  118.  
  119. /*---------------------------------------------------------------------------
  120.     unreduce/unshrink/explode/inflate working storage and globals:
  121.   ---------------------------------------------------------------------------*/
  122.  
  123. union work area;              /* see unzip.h for the definition of work */
  124. ulg crc32val;
  125.  
  126. ush near mask_bits[] = {
  127.     0x0000,
  128.     0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
  129.     0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
  130. };
  131.  
  132. /*---------------------------------------------------------------------------
  133.     Input file variables:
  134.   ---------------------------------------------------------------------------*/
  135.  
  136. uch *inbuf, *inptr;             /* input buffer (any size is OK) and pointer */
  137. int incnt;
  138.  
  139. ulg bitbuf;
  140. int bits_left;
  141. boolean zipeof;
  142.  
  143. #ifdef SFX
  144.    char *argv0;                 /* used for NT and EXE_EXTENSION */
  145. #else
  146.    char *wildzipfn;
  147. #endif
  148. char *zipfn;    /* GRR:  MSWIN:  must nuke any malloc'd zipfn... */
  149.  
  150. int zipfd;                      /* zipfile file handle */
  151. LONGINT ziplen;
  152.  
  153. uch *hold;
  154. char near local_hdr_sig[5];     /* initialize signatures at runtime so unzip */
  155. char near central_hdr_sig[5];   /*  executable won't look like a zipfile */
  156. char near end_central_sig[5];
  157. /* char extd_local_sig[5];  NOT USED YET */
  158.  
  159. cdir_file_hdr crec;             /* used in unzip.c, extract.c, misc.c */
  160. local_file_hdr lrec;            /* used in unzip.c, extract.c */
  161. ecdir_rec ecrec;                /* used in unzip.c, extract.c */
  162. struct stat statbuf;            /* used by main, mapname, check_for_newer */
  163.  
  164. LONGINT cur_zipfile_bufstart;   /* extract_or_test_files, readbuf, ReadByte */
  165. LONGINT extra_bytes = 0;        /* used in unzip.c, misc.c */
  166.  
  167. uch *extra_field = (uch *)NULL; /* used by VMS, Mac and OS/2 versions */
  168.  
  169. #ifdef MACOS
  170.    short  gnVRefNum;
  171.    long  glDirID;
  172.    OSType  gostCreator;
  173.    OSType  gostType;
  174.    boolean  fMacZipped;
  175.    boolean  macflag;
  176.    CursHandle  rghCursor[4];    /* status cursors */
  177.    short  giCursor = 0;
  178. #endif
  179.  
  180. /*---------------------------------------------------------------------------
  181.     Output stream variables:
  182.   ---------------------------------------------------------------------------*/
  183.  
  184. int mem_mode = 0;
  185. int disk_full;
  186. #ifdef SYMLINKS
  187.    int symlnk;
  188. #endif
  189. FILE *outfile;
  190. uch *outbuf;
  191. uch *outptr;
  192. ulg outcnt;                     /* number of chars stored in outbuf */
  193. #ifdef SMALL_MEM
  194.    uch *outbuf2;                /* initialized in main() (never changes) */
  195. #else
  196.    uch *outbuf2 = (uch *)NULL;  /* malloc'd ONLY if unshrink and -a */
  197. #endif
  198. #ifdef MSWIN
  199.    char *filename;
  200. #else
  201.    char near filename[FILNAMSIZ];  /* also used by NT for temporary SFX path */
  202. #endif
  203.  
  204.  
  205.  
  206.  
  207.  
  208. /********************/
  209. /*  Global strings  */
  210. /********************/
  211.  
  212. char Far UnzipVersion[] = UZ_VERSION;   /* now defined in version.h */
  213. #ifndef NO_ZIPINFO
  214.    char Far ZipinfoVersion[] = ZI_VERSION;
  215. #endif
  216.  
  217. char Far EndSigMsg[] = "\nnote:\
  218.   didn't find end-of-central-dir signature at end of central dir.\n";
  219. char Far CentSigMsg[] =
  220.   "error:  expected central file header signature not found (file #%u).\n";
  221. char Far SeekMsg[] =
  222.   "error [%s]:  attempt to seek before beginning of zipfile\n%s";
  223. char Far FilenameNotMatched[] = "caution: filename not matched:  %s\n";
  224. char Far ExclFilenameNotMatched[] =
  225.   "caution: excluded filename not matched:  %s\n";
  226.  
  227. #ifndef SFX
  228.   char Far CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
  229. #endif
  230.  
  231. #ifdef VMS
  232.   char Far ReportMsg[] = "\
  233.   (please check that you have transferred or created the zipfile in the\n\
  234.   appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n";
  235. #else
  236.   char Far ReportMsg[] = "\
  237.   (please check that you have transferred or created the zipfile in the\n\
  238.   appropriate BINARY mode and that you have compiled unzip properly)\n";
  239. #endif
  240.  
  241. /*******************/
  242. /*  Local strings  */
  243. /*******************/
  244.  
  245. #ifndef SFX
  246.    static char Far EnvUnZip[] = ENV_UNZIP;
  247.    static char Far EnvUnZip2[] = ENV_UNZIP2;
  248.    static char Far EnvZipInfo[] = ENV_ZIPINFO;
  249.    static char Far EnvZipInfo2[] = ENV_ZIPINFO2;
  250. #endif
  251.  
  252. #if (!defined(SFX) || defined(SFX_EXDIR))
  253.    static char Far NotExtracting[] = "caution:  not extracting; -d ignored\n";
  254.    static char Far MustGiveExdir[] =
  255.      "error:  must specify directory to which to extract with -d option\n";
  256. #endif
  257.  
  258. static char Far CentDirTooLong[] =
  259.   "error [%s]:  reported length of central directory is\n\
  260.   %d bytes too long (Atari STZip zipfile?  J.H.Holm ZIPSPLIT 1.1\n\
  261.   zipfile?).  Compensating...\n";
  262. static char Far InvalidOptionsMsg[] = "error:\
  263.   -fn or any combination of -c, -l, -p, -t, -u and -v options invalid\n";
  264. static char Far IgnoreOOptionMsg[] =
  265.   "caution:  both -n and -o specified; ignoring -o\n";
  266. static char Far CantAllocateBuffers[] =
  267.   "error:  can't allocate unzip buffers\n";
  268.  
  269. /* usage() strings */
  270. #ifndef VMSCLI
  271. #ifndef SFX
  272. #ifdef VMS
  273.     static char Far Example2[] = "vms.c";
  274.     static char Far Example1[] = 
  275. "unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS";
  276. #else
  277.     static char Far Example2[] = "ReadMe";
  278.     static char Far Example1[] =
  279. "unzip -p foo | more  => send contents of foo.zip via pipe into program more";
  280. #endif /* ?VMS */
  281.  
  282. #ifdef DOS_NT_OS2
  283.     static char Far loc_str[] = " -$  label removables (-$$ => fixed disks)";
  284.     static char Far loc2str[] = "\
  285.                                              -s  spaces in filenames => '_'\n";
  286. #else /* !DOS_NT_OS2 */
  287. #ifdef VMS
  288.     static char Far loc_str[] = "\"-X\" restore owner/protection info";
  289.     static char Far loc2str[] = "\n";
  290. #else
  291.     static char Far loc_str[] = "";   /* Unix, Amiga, Mac, etc. */
  292.  /* char Far loc_str[] = " -X  restore UID/GID info";    Unix version, in 5.2 */
  293.     static char Far loc2str[] = "";
  294. #endif /* ?VMS */
  295. #endif /* ?DOS_NT_OS2 */
  296. #endif /* !SFX */
  297.  
  298. #ifndef NO_ZIPINFO
  299. #ifdef VMSWILD
  300.    static char Far ZipInfoExample[] = "* or % (e.g., \"*font-%.zip\")";
  301. #else
  302.    static char Far ZipInfoExample[] = "*, ?, [] (e.g., \"[a-j]*.zip\")";
  303. #endif
  304. static char Far ZipInfoUsageLine1[] = "\
  305. ZipInfo %s, by Newtware and the fine folks at Info-ZIP.\n\
  306. \n\
  307. List name, date/time, attribute, size, compression method, etc., about files\n\
  308. in list (excluding those in xlist) contained in the specified .zip archive(s).\
  309. \n\"file[.zip]\" may be a wildcard name containing %s.\n\n\
  310.    usage:  zipinfo [-12smlvhtTz] file[.zip] [list...] [-x xlist...]\n\
  311.       or:  unzip %s-Z%s [-12smlvhtTz] file[.zip] [list...] [-x xlist...]\n";
  312.  
  313. static char Far ZipInfoUsageLine2[] = "\nmain\
  314.  listing-format options:             -s  short Unix \"ls -l\" format (def.)\n\
  315.   -1  filenames ONLY, one per line       -m  medium Unix \"ls -l\" format\n\
  316.   -2  just filenames but allow -h/-t/-z  -l  long Unix \"ls -l\" format\n\
  317.                                          -v  verbose, multi-page format\n";
  318.  
  319. static char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\
  320.   -h  print header line       -t  print totals for listed files or for all\n\
  321.   -z  print zipfile comment  %c-T%c print file times in sortable decimal format\
  322. \n  -x  exclude filenames that follow from listing\n";
  323. /*"  -p  disable automatic \"more\" function (for pipes) [not implemented]\n";*/
  324. #endif /* !NO_ZIPINFO */
  325. #endif /* !VMSCLI */
  326.  
  327. #ifdef BETA
  328.    static char Far BetaVersion[] = "%s\
  329.       THIS IS STILL A BETA VERSION OF UNZIP%s -- DO NOT DISTRIBUTE.\n\n";
  330. #endif
  331.  
  332. #ifdef SFX
  333. # if (defined(SFX_EXDIR) && !defined(VMS))
  334.    static char Far UnzipSFXUsage[] = "\
  335. UnZipSFX %s, by Info-ZIP (zip-bugs@wkuvx1.wku.edu).\n\
  336. Valid options are -tfupcz and -d <exdir>; modifiers are -abjnoqCLV%s.\n";
  337. # else
  338.    static char Far UnzipSFXUsage[] = "\
  339. UnZipSFX %s, by Info-ZIP (zip-bugs@wkuvx1.wku.edu).\n\
  340. Valid options are -tfupcz; modifiers are -abjnoqCLV%s.\n";
  341. # endif
  342.    static char Far CantFindMyself[] =
  343.      "unzipsfx:  can't find myself! [%s]\n";
  344. #else /* !SFX */
  345.    static char Far CompileOptions[] = "UnZip special compilation options:\n";
  346.    static char Far CompileOptFormat[] = "\t%s\n";
  347.    static char Far EnvOptions[] = "\nUnZip and ZipInfo environment options:\n";
  348.    static char Far EnvOptFormat[] = "%16s:  %s\n";
  349.    static char Far None[] = "[none]";
  350. #  ifdef NO_ZIPINFO
  351.      static char Far No_ZipInfo[] = "NO_ZIPINFO";
  352. #  endif
  353. #  ifdef CHECK_EOF
  354.      static char Far Check_EOF[] = "CHECK_EOF";
  355. #  endif
  356. #  ifdef DOSWILD
  357.      static char Far DosWild[] = "DOSWILD";
  358. #  endif
  359. #  ifdef VMSWILD
  360.      static char Far VmsWild[] = "VMSWILD";
  361. #  endif
  362. #  ifdef VMSCLI
  363.      static char Far VmsCLI[] = "VMSCLI";
  364. #  endif
  365. #  ifdef ASM_INFLATECODES
  366.      static char Far AsmInflateCodes[] = "ASM_INFLATECODES";
  367. #  endif
  368. #  ifdef ASM_CRC
  369.      static char Far AsmCRC[] = "ASM_CRC";
  370. #  endif
  371. #  ifdef REGARGS
  372.      static char Far RegArgs[] = "REGARGS";
  373. #  endif
  374. #  ifdef OLD_EXDIR
  375.      static char Far Old_Exdir[] = "OLD_EXDIR";
  376. #  endif
  377. #  ifdef CHECK_VERSIONS
  378.      static char Far Check_Versions[] = "CHECK_VERSIONS";
  379. #  endif
  380. #  ifdef RETURN_CODES
  381.      static char Far Return_Codes[] = "RETURN_CODES";
  382. #  endif
  383. #  ifdef RETURN_SEVERITY
  384.      static char Far Return_Severity[] = "RETURN_SEVERITY";
  385. #  endif
  386. #  ifdef DEBUG
  387.      static char Far Debug[] = "DEBUG";
  388. #  endif
  389. #  ifdef DEBUG_TIME
  390.      static char Far DebugTime[] = "DEBUG_TIME";
  391. #  endif
  392. #  ifdef CRYPT
  393.      static char Far Decryption[] = "[decryption]";
  394. #  endif
  395. #  ifdef __EMX__
  396.      static char Far EnvEMX[] = "EMX";
  397.      static char Far EnvEMXOPT[] = "EMXOPT";
  398. #  endif
  399. #  ifdef __GO32__
  400.      static char Far EnvGO32[] = "GO32";
  401.      static char Far EnvGO32TMP[] = "GO32TMP";
  402. #  endif
  403.  
  404. /* UnzipUsageLine1[] is also used in vms/cmdline.c:  do not make it static */
  405. char Far UnzipUsageLine1[] = "\
  406. UnZip %s, by Info-ZIP.  Portions (c) 1989 by S. H. Smith.\n\
  407. Send bug reports to authors at zip-bugs@wkuvx1.wku.edu; see README for details.\
  408. \n\n";
  409. static char Far UnzipUsageLine2a[] = "\
  410. Latest sources and executables are always in ftp.uu.net:/pub/archiving/zip, at\
  411. \nleast as of date of this release; see \"Where\" for other ftp and non-ftp \
  412. sites.\n\n";
  413.  
  414. #ifndef VMSCLI
  415. static char Far UnzipUsageLine2[] = "\
  416. Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]\n \
  417.  Default action is to extract files in list, except those in xlist, to exdir;\n\
  418.   file[.zip] may be a wildcard.  %s\n\n";
  419.  
  420. #ifdef NO_ZIPINFO
  421. #  define ZIPINFO_MODE_OPTION  ""
  422.    static char Far ZipinfoMode[] =
  423.      "(ZipInfo mode is disabled in this version.)";
  424. #else
  425. #  define ZIPINFO_MODE_OPTION  "[-Z] "
  426. #  ifdef VMS
  427.      static char Far ZipinfoMode[] =
  428.        "\"-Z\" => ZipInfo mode (`unzip \"-Z\"' for usage).";
  429. #  else
  430.      static char Far ZipinfoMode[] =
  431.        "-Z => ZipInfo mode (\"unzip -Z\" for usage).";
  432. #  endif
  433. #endif /* ?NO_ZIPINFO */
  434.  
  435. static char Far UnzipUsageLine3[] = "\
  436.   -p  extract files to pipe, no messages     -l  list files (short format)\n\
  437.   -f  freshen existing files, create none    -t  test compressed archive data\n\
  438.   -u  update files, create if necessary      -z  display archive comment\n\
  439.   -x  exclude files which follow (in xlist)  -d  extract files into exdir\n\n";
  440.  
  441. static char Far UnzipUsageLine4[] = "\
  442. modifiers:                                   -q  quiet mode (-qq => quieter)\n\
  443.   -n  never overwrite existing files         -a  auto-convert any text files\n\
  444.   -o  overwrite files WITHOUT prompting      -aa treat ALL files as text\n \
  445.  -j  junk paths (don't make directories)    -v  be verbose/print version info\n\
  446.  %c-C%c match filenames case-insensitively    %c-L%c make (some) names \
  447. lowercase\n %-42s %c-V%c retain VMS version numbers\n%s";
  448.  
  449. static char Far UnzipUsageLine5[] = "\
  450. Examples (see unzip.doc for more info):\n\
  451.   unzip data1 -x joe   => extract all files except joe from zipfile data1.zip\n\
  452.   %s\n\
  453.   unzip -fo foo %-6s => quietly replace existing %s if archive file newer\n";
  454. #endif /* !VMSCLI */
  455.  
  456. /* process_zipfiles() strings */
  457.    static char Far FilesProcessOK[] = "%d archive%s successfully processed.\n";
  458.    static char Far ArchiveWarning[] =
  459.      "%d archive%s had warnings but no fatal errors.\n";
  460.    static char Far ArchiveFatalError[] = "%d archive%s had fatal errors.\n";
  461.    static char Far FileHadNoZipfileDir[] =
  462.      "%d file%s had no zipfile directory.\n";
  463.    static char Far ZipfileWasDir[] = "1 \"zipfile\" was a directory.\n";
  464.    static char Far ManyZipfilesWereDir[] =
  465.      "%d \"zipfiles\" were directories.\n";
  466.    static char Far NoZipfileFound[] = "No zipfiles found.\n";
  467. #endif /* ?SFX */
  468.  
  469. /* do_seekable() strings */
  470. #ifndef SFX
  471. #ifdef UNIX
  472.    static char Far CantFindZipfileDirMsg[] =
  473.      "%s:  can't find zipfile directory in one of %s or\n\
  474.         %s%s.zip, and can't find %s, period.\n";
  475.    static char Far CantFindEitherZipfile[] =
  476.      "%s:  can't find %s, %s.zip or %s, so there.\n";
  477. #else /* !UNIX */
  478.    static char Far CantFindZipfileDirMsg[] =
  479.      "%s:  can't find zipfile directory in %s,\n\
  480.         %sand can't find %s, period.\n";
  481.    static char Far CantFindEitherZipfile[] =
  482.      "%s:  can't find either %s or %s, so there.\n";
  483. #endif /* ?UNIX */
  484.    static char Far MaybeExe[] =
  485.      "note:  %s may be a plain executable, not an archive\n";
  486.    static char Far CentDirNotInZipMsg[] = "\n\
  487.      Zipfile is part of a multi-disk archive, and this is not the disk on\n\
  488.      which the central zipfile directory begins.\n";
  489. #ifdef NO_MULTIPART
  490.    static char Far NoMultiDiskArcSupport[] =
  491.      "\nerror [%s]:  zipfile is part of multi-disk archive\n\
  492.   (sorry, not yet supported).\n";
  493.    static char Far MaybePakBug[] = "warning [%s]:\
  494.   zipfile claims to be 2nd disk of a 2-part archive;\n\
  495.   attempting to process anyway.  If no further errors occur, this archive\n\
  496.   was probably created by PAK v2.51 or earlier.  This bug was reported to\n\
  497.   NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\
  498.   of mid-1992 it still hadn't been.  (If further errors do occur, archive\n\
  499.   was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\
  500.   multi-part archives.)\n";
  501. #else
  502.    static char Far MaybePakBug[] = "warning [%s]:\
  503.   zipfile claims to be last disk of a multi-part archive;\n\
  504.   attempting to process anyway, assuming all parts have been concatenated\n\
  505.   together in order.  Expect \"errors\" and warnings...true multi-part support\
  506. \n  doesn't exist yet (coming soon).\n";
  507. #endif
  508.    static char Far ExtraBytesAtStart[] =
  509.      "warning [%s]:  extra %ld bytes at beginning or within zipfile\n\
  510.   (attempting to process anyway)\n";
  511. #endif /* !SFX */
  512.  
  513. static char Far MissingBytes[] =
  514.   "error [%s]:  missing %ld bytes in zipfile\n\
  515.   (attempting to process anyway)\n";
  516. static char Far NullCentDirOffset[] =
  517.   "error [%s]:  NULL central directory offset\n\
  518.   (attempting to process anyway)\n";
  519. static char Far ZipfileEmpty[] = "warning [%s]:  zipfile is empty\n";
  520. static char Far CentDirStartNotFound[] =
  521.   "error [%s]:  start of central directory not found;\n\
  522.   zipfile corrupt.\n%s";
  523. static char Far ZipfileCommTrunc1[] = "\ncaution:  zipfile comment truncated\n";
  524.  
  525.  
  526.  
  527.  
  528.  
  529. #ifdef MSWIN
  530. #  include "winsetup.c"   /* duplicates some code in main() */
  531. #else /* !MSWIN */
  532.  
  533.  
  534.  
  535. /******************/
  536. /*  Main program  */
  537. /******************/
  538.  
  539. int MAIN(argc, argv)   /* return PK-type error code (except under VMS) */
  540.     int argc;
  541.     char *argv[];
  542. {
  543. #ifndef NO_ZIPINFO
  544.     char *p;
  545. #endif
  546.     int error=FALSE;
  547. #if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
  548.     extern void DebugMalloc(void);
  549.  
  550.  
  551.     atexit(DebugMalloc);
  552. #endif
  553.  
  554. /*---------------------------------------------------------------------------
  555.     Macintosh initialization code.
  556.   ---------------------------------------------------------------------------*/
  557.  
  558. #ifdef MACOS
  559.     int a;
  560.  
  561.     for (a = 0;  a < 4;  ++a)
  562.         rghCursor[a] = GetCursor(a+128);
  563.     giCursor = 0;
  564.  
  565.     aflag=cflag=dflag=fflag=L_flag=jflag=qflag=tflag=uflag=vflag=zflag = 0;
  566.     local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0';
  567. /*  extd_local_sig[1] = '\0';  */
  568.     error = FALSE;
  569.  
  570.     overwrite_none = overwrite_all = force_flag = 0;
  571. #endif /* MACOS */
  572.  
  573. #ifdef MALLOC_WORK
  574.     area.Slide = (uch *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char));
  575.     area.shrink.Prefix_of = (short *)area.Slide;
  576.     area.shrink.Suffix_of = area.Slide + (sizeof(short)*(HSIZE+1));
  577.     area.shrink.Stack = area.Slide + (sizeof(short) + sizeof(char))*(HSIZE+1);
  578. #endif
  579.  
  580. /*---------------------------------------------------------------------------
  581.     Human68K initialization code.
  582.   ---------------------------------------------------------------------------*/
  583.  
  584. #ifdef __human68k__
  585.     InitTwentyOne();
  586. #endif
  587.  
  588. /*---------------------------------------------------------------------------
  589.     Set signal handler for restoring echo, warn of zipfile corruption, etc.
  590.   ---------------------------------------------------------------------------*/
  591.  
  592.     signal(SIGINT, handler);
  593. #ifdef SIGTERM                 /* some systems really have no SIGTERM */
  594.     signal(SIGTERM, handler);
  595. #endif
  596. #ifdef SIGBUS
  597.     signal(SIGBUS, handler);
  598. #endif
  599. #ifdef SIGSEGV
  600.     signal(SIGSEGV, handler);
  601. #endif
  602.  
  603. /*---------------------------------------------------------------------------
  604.     First figure out if we're running in UnZip mode or ZipInfo mode, and put
  605.     the appropriate environment-variable options into the queue.  Then rip
  606.     through any command-line options lurking about...
  607.   ---------------------------------------------------------------------------*/
  608.  
  609. #ifdef SFX
  610.     argv0 = argv[0];
  611. #if defined(OS2) || defined(NT)
  612.     zipfn = GetLoadPath();   /* non-MSC NT puts path into filename[] */
  613. #else
  614.     zipfn = argv0;
  615. #endif
  616.     zipinfo_mode = FALSE;
  617.     if ((error = uz_opts(&argc, &argv)) != 0)
  618.         RETURN(error);
  619.  
  620. #else /* !SFX */
  621.  
  622. #ifdef MSDOS
  623.     /* extract MKS extended argument list from environment (before envargs!) */
  624.     mksargs(&argc, &argv);
  625. #endif
  626.  
  627. #ifdef VMSCLI
  628.     {
  629.         ulg status = vms_unzip_cmdline(&argc, &argv);
  630.         if (!(status & 1))
  631.             return status;
  632.     }
  633. #endif /* VMSCLI */
  634.  
  635. #ifndef NO_ZIPINFO
  636.     if ((p = strrchr(argv[0], DIR_END)) == (char *)NULL)
  637.         p = argv[0];
  638.     else
  639.         ++p;
  640.  
  641.     if (STRNICMP(p, "zipinfo", 7) == 0 || STRNICMP(p, "ii", 2) == 0 ||
  642.         (argc > 1 && strncmp(argv[1], "-Z", 2) == 0))
  643.     {
  644.         zipinfo_mode = TRUE;
  645.         envargs(&argc, &argv, LoadFarStringSmall(EnvZipInfo),
  646.           LoadFarStringSmall2(EnvZipInfo2));
  647.         error = zi_opts(&argc, &argv);
  648.     } else
  649. #endif /* NO_ZIPINFO */
  650.     {
  651.         zipinfo_mode = FALSE;
  652.         envargs(&argc, &argv, LoadFarStringSmall(EnvUnZip),
  653.           LoadFarStringSmall2(EnvUnZip2));
  654.         error = uz_opts(&argc, &argv);
  655.     }
  656.     if ((argc < 0) || error)
  657.         RETURN(error);
  658.  
  659. #endif /* ?SFX */
  660.  
  661. /*---------------------------------------------------------------------------
  662.     Now get the zipfile name from the command line and then process any re-
  663.     maining options and file specifications.
  664.   ---------------------------------------------------------------------------*/
  665.  
  666. #ifdef DOS_NT_OS2
  667.     /* convert MSDOS-style directory separators to Unix-style ones for
  668.      * user's convenience (include zipfile name itself)
  669.      */
  670.     pfnames = argv;
  671.     while (*pfnames != NULL) {
  672.         char *q;
  673.  
  674.         for (q = *pfnames;  *q;  ++q)
  675.             if (*q == '\\')
  676.                 *q = '/';
  677.         ++pfnames;
  678.     }
  679. #endif /* DOS_NT_OS2 */
  680.  
  681. #ifndef SFX
  682.     wildzipfn = *argv++;
  683. #endif
  684.  
  685. #if (defined(OLD_EXDIR) || (defined(SFX) && !defined(SFX_EXDIR)))
  686.  
  687. #ifndef SFX
  688.     if (argc > 0) {
  689.         /* -d:  "name/" immediately after zipfile name is a stored directory to
  690.          * be extracted--do NOT treat as directory to which to extract files
  691.          */
  692.         if (extract_flag && !dflag) {
  693.             create_dirs = !fflag;
  694.             if ((error = checkdir(*argv, ROOT)) > 2)  /* mem, or file in way */
  695.                 RETURN(error);
  696.             else if (!error) {   /* it IS extract-to dir, so adjust pointers */
  697.                 ++argv;
  698.                 --argc;
  699.             }
  700.         }
  701.     }
  702. #endif /* !SFX */
  703.  
  704.     filespecs = argc;
  705.     xfilespecs = 0;
  706.  
  707.     if (argc > 0) {
  708.         char **pp = argv-1;
  709.  
  710.         pfnames = argv;
  711.         while (*++pp)
  712.             if (strcmp(*pp, "-x") == 0) {
  713.                 if (pp > argv) {
  714.                     *pp = 0;           /* terminate pfnames */
  715.                     filespecs = pp - pfnames;
  716.                 } else {
  717.                     pfnames = fnames;  /* defaults */
  718.                     filespecs = 0;
  719.                 }
  720.                 pxnames = pp + 1;      /* excluded-names ptr starts after -x */
  721.                 xfilespecs = argc - filespecs - 1;
  722.                 break;                 /* skip rest of args */
  723.             }
  724.         process_all_files = FALSE;
  725.     } else
  726.         process_all_files = TRUE;       /* for speed */
  727.  
  728. #else /* !(OLD_EXDIR || (SFX && !SFX_EXDIR)) */
  729.  
  730.     filespecs = argc;
  731.     xfilespecs = 0;
  732.  
  733.     if (argc > 0) {
  734.         int in_files=FALSE, in_xfiles=FALSE;
  735.         char **pp = argv-1;
  736.  
  737.         process_all_files = FALSE;
  738.         pfnames = argv;
  739.         while (*++pp) {
  740.             Trace((stderr, "pp - argv = %d\n", pp-argv));
  741.             if (!dflag && strncmp(*pp, "-d", 2) == 0) {
  742.                 char *q = *pp;
  743.                 int firstarg = (pp == argv);
  744.  
  745.                 dflag = TRUE;
  746.                 if (in_files) {      /* ... zipfile ... -d exdir ... */
  747.                     *pp = 0;                    /* terminate pfnames */
  748.                     filespecs = pp - pfnames;
  749.                     in_files = FALSE;
  750.                 } else if (in_xfiles) {
  751.                     *pp = 0;                    /* terminate pxnames */
  752.                     xfilespecs = pp - pxnames;
  753.                     /* "... -x xlist -d exdir":  nothing left */
  754.                 }
  755.                 /* first check for "-dpath", then for "-d path" */
  756.                 if (q[2])
  757.                     q += 2;
  758.                 else if (*++pp)
  759.                     q = *pp;
  760.                 else {
  761.                     FPRINTF(stderr, LoadFarString(MustGiveExdir));
  762.                     RETURN(PK_PARAM);  /* don't extract here by accident */
  763.                 }
  764.                 if (extract_flag) {
  765.                     create_dirs = !fflag;
  766.                     if ((error = checkdir(q, ROOT)) > 2)
  767.                         RETURN(error);  /* out of memory, or file in way */
  768.                 } else
  769.                     FPRINTF(stderr, LoadFarString(NotExtracting));
  770.                 if (firstarg)   /* ... zipfile -d exdir ... */
  771.                     if (pp[1]) {
  772.                         pfnames = pp + 1;  /* argv+2 */
  773.                         filespecs = argc - (pfnames-argv);  /* for now... */
  774.                     } else {
  775.                         process_all_files = TRUE;
  776.                         pfnames = fnames;  /* GRR: necessary? */
  777.                         filespecs = 0;     /* GRR: necessary? */
  778.                         break;
  779.                     }
  780.             } else if (!in_xfiles) {
  781.                 if (strcmp(*pp, "-x") == 0) {
  782.                     in_xfiles = TRUE;
  783.                     if (pp == argv || (pp == argv+2 && dflag)) {
  784.                         pfnames = fnames;  /* defaults */
  785.                         filespecs = 0;
  786.                     } else if (in_files) {
  787.                         *pp = 0;                   /* terminate pfnames */
  788.                         filespecs = pp - pfnames;  /* adjust count */
  789.                         in_files = FALSE;
  790.                     }
  791.                     pxnames = pp + 1;  /* excluded-names ptr starts after -x */
  792.                     xfilespecs = argc - (pxnames-argv);  /* anything left... */
  793.                 } else
  794.                     in_files = TRUE;
  795.             }
  796.         }
  797.     } else
  798.         process_all_files = TRUE;      /* for speed */
  799.  
  800. #endif /* ?(OLD_EXDIR || (SFX && !SFX_EXDIR)) */
  801.  
  802. /*---------------------------------------------------------------------------
  803.     Okey dokey, we have everything we need to get started.  Let's roll.
  804.   ---------------------------------------------------------------------------*/
  805.  
  806.     inbuf = (uch *)malloc(INBUFSIZ + 4);    /* 4 extra for hold[] (below) */
  807.     outbuf = (uch *)malloc(OUTBUFSIZ + 1);  /* 1 extra for string termin. */
  808.  
  809.     if ((inbuf == (uch *)NULL) || (outbuf == (uch *)NULL)) {
  810.         FPRINTF(stderr, LoadFarString(CantAllocateBuffers));
  811.         RETURN(PK_MEM);
  812.     }
  813.     hold = inbuf + INBUFSIZ;     /* to check for boundary-spanning signatures */
  814. #ifdef SMALL_MEM
  815.     outbuf2 = outbuf+RAWBUFSIZ;  /* never changes */
  816. #endif
  817.  
  818.     RETURN(process_zipfiles());  /* keep passing errors back... */
  819.  
  820. } /* end main() */
  821.  
  822.  
  823.  
  824.  
  825.  
  826. /**********************/
  827. /* Function uz_opts() */
  828. /**********************/
  829.  
  830. int uz_opts(pargc, pargv)
  831.     int *pargc;
  832.     char ***pargv;
  833. {
  834.     char **argv, *s;
  835.     int argc, c, error=FALSE, negative=0;
  836.  
  837.  
  838.     argc = *pargc;
  839.     argv = *pargv;
  840.  
  841.     while (--argc > 0 && (*++argv)[0] == '-') {
  842.         s = argv[0] + 1;
  843.         while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
  844.             switch (c) {
  845.                 case ('-'):
  846.                     ++negative;
  847.                     break;
  848.                 case ('a'):
  849.                     if (negative) {
  850.                         aflag = MAX(aflag-negative,0);
  851.                         negative = 0;
  852.                     } else
  853.                         ++aflag;
  854.                     break;
  855.                 case ('b'):
  856.                     if (negative)
  857.                         negative = 0;   /* do nothing:  "-b" is default */
  858.                     else
  859.                         aflag = 0;
  860.                     break;
  861.                 case ('c'):
  862.                     if (negative) {
  863.                         cflag = FALSE, negative = 0;
  864. #ifdef NATIVE
  865.                         aflag = 0;
  866. #endif
  867.                     } else {
  868.                         cflag = TRUE;
  869. #ifdef NATIVE
  870.                         aflag = 2;  /* so you can read it on the screen */
  871. #endif
  872.                     }
  873.                     break;
  874.                 case ('C'):    /* -C:  match filenames case-insensitively */
  875.                     if (negative)
  876.                         C_flag = FALSE, negative = 0;
  877.                     else
  878.                         C_flag = TRUE;
  879.                     break;
  880.                 case ('d'):  /* arg after zipfn is stored dir, not extract-to */
  881. #ifdef OLD_EXDIR
  882.                     if (negative)
  883.                         dflag = FALSE, negative = 0;
  884.                     else
  885.                         dflag = TRUE;
  886. #endif
  887.                     break;
  888.                 case ('e'):    /* just ignore -e, -x options (extract) */
  889.                     break;
  890.                 case ('f'):    /* "freshen" (extract only newer files) */
  891.                     if (negative)
  892.                         fflag = uflag = FALSE, negative = 0;
  893.                     else
  894.                         fflag = uflag = TRUE;
  895.                     break;
  896.                 case ('j'):    /* junk pathnames/directory structure */
  897.                     if (negative)
  898.                         jflag = FALSE, negative = 0;
  899.                     else
  900.                         jflag = TRUE;
  901.                     break;
  902. #ifndef SFX
  903.                 case ('l'):
  904.                     if (negative) {
  905.                         vflag = MAX(vflag-negative,0);
  906.                         negative = 0;
  907.                     } else
  908.                         ++vflag;
  909.                     break;
  910. #endif /* !SFX */
  911.                 case ('L'):    /* convert (some) filenames to lowercase */
  912.                     if (negative)
  913.                         L_flag = FALSE, negative = 0;
  914.                     else
  915.                         L_flag = TRUE;
  916.                     break;
  917.                 case ('n'):    /* don't overwrite any files */
  918.                     if (negative)
  919.                         overwrite_none = FALSE, negative = 0;
  920.                     else
  921.                         overwrite_none = TRUE;
  922.                     break;
  923.                 case ('o'):    /* OK to overwrite files without prompting */
  924.                     if (negative) {
  925.                         overwrite_all = MAX(overwrite_all-negative,0);
  926.                         force_flag = MAX(force_flag-negative,0);
  927.                         negative = 0;
  928.                     } else {
  929.                         ++overwrite_all;
  930.                         ++force_flag;  /* (share -o for now) force to cont. */
  931.                     }
  932.                     break;
  933.                 case ('p'):    /* pipes:  extract to stdout, no messages */
  934.                     if (negative) {
  935.                         cflag = FALSE;
  936.                         qflag = MAX(qflag-999,0);
  937.                         negative = 0;
  938.                     } else {
  939.                         cflag = TRUE;
  940.                         qflag += 999;
  941.                     }
  942.                     break;
  943.                 case ('q'):    /* quiet:  fewer comments/messages */
  944.                     if (negative) {
  945.                         qflag = MAX(qflag-negative,0);
  946.                         negative = 0;
  947.                     } else
  948.                         ++qflag;
  949.                     break;
  950. #ifdef DOS_NT_OS2
  951.                 case ('s'):    /* spaces in filenames:  allow by default */
  952.                     if (negative)
  953.                         sflag = FALSE, negative = 0;
  954.                     else
  955.                         sflag = TRUE;
  956.                     break;
  957. #endif
  958.                 case ('t'):
  959.                     if (negative)
  960.                         tflag = FALSE, negative = 0;
  961.                     else
  962.                         tflag = TRUE;
  963.                     break;
  964.                 case ('u'):    /* update (extract only new and newer files) */
  965.                     if (negative)
  966.                         uflag = FALSE, negative = 0;
  967.                     else
  968.                         uflag = TRUE;
  969.                     break;
  970.                 case ('U'):    /* obsolete; to be removed in future release */
  971.                     if (negative)
  972.                         L_flag = TRUE, negative = 0;
  973.                     else
  974.                         L_flag = FALSE;
  975.                     break;
  976. #ifndef SFX
  977.                 case ('v'):    /* verbose */
  978.                     if (negative) {
  979.                         vflag = MAX(vflag-negative,0);
  980.                         negative = 0;
  981.                     } else if (vflag)
  982.                         ++vflag;
  983.                     else
  984.                         vflag = 2;
  985.                     break;
  986. #endif /* !SFX */
  987.                 case ('V'):    /* Version (retain VMS/DEC-20 file versions) */
  988.                     if (negative)
  989.                         V_flag = FALSE, negative = 0;
  990.                     else
  991.                         V_flag = TRUE;
  992.                     break;
  993.                 case ('x'):    /* extract:  default */
  994.                     break;
  995. #ifdef VMS
  996.                 case ('X'):   /* restore owner/protection info (need privs?) */
  997.                     if (negative)
  998.                         secinf = FALSE, negative = 0;
  999.                     else
  1000.                         secinf = TRUE;
  1001.                     break;
  1002. #endif /* VMS */
  1003.                 case ('z'):    /* display only the archive comment */
  1004.                     if (negative) {
  1005.                         zflag -= negative;
  1006.                         negative = 0;
  1007.                     } else
  1008.                         ++zflag;
  1009.                     break;
  1010. #ifdef DOS_NT_OS2
  1011.                 case ('$'):
  1012.                     if (negative) {
  1013.                         volflag = MAX(volflag-negative,0);
  1014.                         negative = 0;
  1015.                     } else
  1016.                         ++volflag;
  1017.                     break;
  1018. #endif /* DOS_NT_OS2 */
  1019.                 default:
  1020.                     error = TRUE;
  1021.                     break;
  1022.  
  1023.             } /* end switch */
  1024.         } /* end while (not end of argument string) */
  1025.     } /* end while (not done with switches) */
  1026.  
  1027. /*---------------------------------------------------------------------------
  1028.     Check for nonsensical combinations of options.
  1029.   ---------------------------------------------------------------------------*/
  1030.  
  1031.     if ((cflag && tflag) || (cflag && uflag) || (tflag && uflag) ||
  1032.         (fflag && overwrite_none)) {
  1033.         FPRINTF(stderr, LoadFarString(InvalidOptionsMsg));
  1034.         error = TRUE;
  1035.     }
  1036.     if (aflag > 2)
  1037.         aflag = 2;
  1038.     if (overwrite_all && overwrite_none) {
  1039.         FPRINTF(stderr, LoadFarString(IgnoreOOptionMsg));
  1040.         overwrite_all = FALSE;
  1041.     }
  1042.  
  1043. #ifdef SFX
  1044.     if (error)
  1045. #else
  1046.     if ((argc-- == 0) || error)
  1047. #endif
  1048.     {
  1049.         *pargc = argc;
  1050.         *pargv = argv;
  1051. #ifndef SFX
  1052.         if (vflag >= 2 && argc == -1) {
  1053.             if (qflag > 3)
  1054.                 PRINTF("%d\n", (UZ_MAJORVER*100 + UZ_MINORVER*10 + PATCHLEVEL));
  1055.             else {
  1056.                 char *envptr, *getenv();
  1057.                 int numopts = 0;
  1058.  
  1059.                 PRINTF(LoadFarString(UnzipUsageLine1),
  1060.                   LoadFarStringSmall(UnzipVersion));
  1061.                 PRINTF(LoadFarString(UnzipUsageLine2a));
  1062.                 version();
  1063.                 PRINTF(LoadFarString(CompileOptions));
  1064. #ifdef NO_ZIPINFO
  1065.                 PRINTF(LoadFarString(CompileOptFormat),
  1066.                   LoadFarStringSmall(No_ZipInfo));
  1067.                 ++numopts;
  1068. #endif
  1069. #ifdef CHECK_EOF
  1070.                 PRINTF(LoadFarString(CompileOptFormat),
  1071.                   LoadFarStringSmall(Check_EOF));
  1072.                 ++numopts;
  1073. #endif
  1074. #ifdef DOSWILD
  1075.                 PRINTF(LoadFarString(CompileOptFormat),
  1076.                   LoadFarStringSmall(DosWild));
  1077.                 ++numopts;
  1078. #endif
  1079. #ifdef VMSWILD
  1080.                 PRINTF(LoadFarString(CompileOptFormat),
  1081.                   LoadFarStringSmall(VmsWild));
  1082.                 ++numopts;
  1083. #endif
  1084. #ifdef VMSCLI
  1085.                 PRINTF(LoadFarString(CompileOptFormat),
  1086.                   LoadFarStringSmall(VmsCLI));
  1087.                 ++numopts;
  1088. #endif
  1089. #ifdef ASM_INFLATECODES
  1090.                 PRINTF(LoadFarString(CompileOptFormat),
  1091.                   LoadFarStringSmall(AsmInflateCodes));
  1092.                 ++numopts;
  1093. #endif
  1094. #ifdef ASM_CRC
  1095.                 PRINTF(LoadFarString(CompileOptFormat),
  1096.                   LoadFarStringSmall(AsmCRC));
  1097.                 ++numopts;
  1098. #endif
  1099. #ifdef REGARGS
  1100.                 PRINTF(LoadFarString(CompileOptFormat),
  1101.                   LoadFarStringSmall(RegArgs));
  1102.                 ++numopts;
  1103. #endif
  1104. #ifdef OLD_EXDIR
  1105.                 PRINTF(LoadFarString(CompileOptFormat),
  1106.                   LoadFarStringSmall(Old_Exdir));
  1107.                 ++numopts;
  1108. #endif
  1109. #ifdef CHECK_VERSIONS
  1110.                 PRINTF(LoadFarString(CompileOptFormat),
  1111.                   LoadFarStringSmall(Check_Versions));
  1112.                 ++numopts;
  1113. #endif
  1114. #ifdef RETURN_CODES
  1115.                 PRINTF(LoadFarString(CompileOptFormat),
  1116.                   LoadFarStringSmall(Return_Codes));
  1117.                 ++numopts;
  1118. #endif
  1119. #ifdef RETURN_SEVERITY
  1120.                 PRINTF(LoadFarString(CompileOptFormat),
  1121.                   LoadFarStringSmall(Return_Severity));
  1122.                 ++numopts;
  1123. #endif
  1124. #ifdef DEBUG
  1125.                 PRINTF(LoadFarString(CompileOptFormat),
  1126.                   LoadFarStringSmall(Debug));
  1127.                 ++numopts;
  1128. #endif
  1129. #ifdef DEBUG_TIME
  1130.                 PRINTF(LoadFarString(CompileOptFormat),
  1131.                   LoadFarStringSmall(DebugTime));
  1132.                 ++numopts;
  1133. #endif
  1134. #ifdef CRYPT
  1135.                 PRINTF(LoadFarString(CompileOptFormat),
  1136.                   LoadFarStringSmall(Decryption));
  1137.                 ++numopts;
  1138. #endif
  1139.                 if (numopts == 0)
  1140.                     PRINTF(LoadFarString(CompileOptFormat),
  1141.                       LoadFarStringSmall(None));
  1142.  
  1143.                 PRINTF(LoadFarString(EnvOptions));
  1144.                 envptr = getenv(LoadFarStringSmall(EnvUnZip));
  1145.                 PRINTF(LoadFarString(EnvOptFormat),
  1146.                   LoadFarStringSmall(EnvUnZip),
  1147.                   (envptr == (char *)NULL || *envptr == 0)?
  1148.                   LoadFarStringSmall2(None) : envptr);
  1149.                 envptr = getenv(LoadFarStringSmall(EnvUnZip2));
  1150.                 PRINTF(LoadFarString(EnvOptFormat),
  1151.                   LoadFarStringSmall(EnvUnZip2),
  1152.                   (envptr == (char *)NULL || *envptr == 0)?
  1153.                   LoadFarStringSmall2(None) : envptr);
  1154.                 envptr = getenv(LoadFarStringSmall(EnvZipInfo));
  1155.                 PRINTF(LoadFarString(EnvOptFormat),
  1156.                   LoadFarStringSmall(EnvZipInfo),
  1157.                   (envptr == (char *)NULL || *envptr == 0)?
  1158.                   LoadFarStringSmall2(None) : envptr);
  1159.                 envptr = getenv(LoadFarStringSmall(EnvZipInfo2));
  1160.                 PRINTF(LoadFarString(EnvOptFormat),
  1161.                   LoadFarStringSmall(EnvZipInfo2),
  1162.                   (envptr == (char *)NULL || *envptr == 0)?
  1163.                   LoadFarStringSmall2(None) : envptr);
  1164. #ifdef __EMX__
  1165.                 envptr = getenv(LoadFarStringSmall(EnvEMX));
  1166.                 PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvEMX),
  1167.                   (envptr == (char *)NULL || *envptr == 0)?
  1168.                   LoadFarStringSmall2(None) : envptr);
  1169.                 envptr = getenv(LoadFarStringSmall(EnvEMXOPT));
  1170.                 PRINTF(LoadFarString(EnvOptFormat),
  1171.                   LoadFarStringSmall(EnvEMXOPT),
  1172.                   (envptr == (char *)NULL || *envptr == 0)?
  1173.                   LoadFarStringSmall2(None) : envptr);
  1174. #endif /* __EMX__ */
  1175. #ifdef __GO32__
  1176.                 envptr = getenv(LoadFarStringSmall(EnvGO32));
  1177.                 PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvGO32),
  1178.                   (envptr == (char *)NULL || *envptr == 0)?
  1179.                   LoadFarStringSmall2(None) : envptr);
  1180.                 envptr = getenv(LoadFarStringSmall(EnvGO32TMP));
  1181.                 PRINTF(LoadFarString(EnvOptFormat),
  1182.                   LoadFarStringSmall(EnvGO32TMP),
  1183.                   (envptr == (char *)NULL || *envptr == 0)?
  1184.                   LoadFarStringSmall2(None) : envptr);
  1185. #endif /* __GO32__ */
  1186.             }
  1187.             return 0;
  1188.         } else
  1189. #endif /* !SFX */
  1190.             return usage(error);
  1191.     }
  1192.  
  1193.     if (cflag || tflag || vflag)
  1194.         extract_flag = FALSE;
  1195.     else
  1196.         extract_flag = TRUE;
  1197.  
  1198.     *pargc = argc;
  1199.     *pargv = argv;
  1200.     return 0;
  1201.  
  1202. } /* end function uz_opts() */
  1203.  
  1204.  
  1205.  
  1206.  
  1207.  
  1208. /********************/
  1209. /* Function usage() */
  1210. /********************/
  1211.  
  1212. #ifdef SFX
  1213. #  ifdef VMS
  1214. #    define LOCAL "X.  Quote uppercase options"
  1215. #  else
  1216. #    ifdef DOS_NT_OS2
  1217. #      define LOCAL "s$"
  1218. #    else
  1219. #       ifdef AMIGA
  1220. #         define LOCAL "$"
  1221. #       else
  1222. #         define LOCAL ""
  1223. #       endif
  1224. #    endif /* ?DOS_NT_OS2 */
  1225. #  endif /* ?VMS */
  1226.  
  1227. int usage(error)   /* return PK-type error code */
  1228.     int error;
  1229. {
  1230.     FILE *usagefp;
  1231.  
  1232.     if (error)
  1233.         usagefp = (FILE *)stderr;
  1234.     else
  1235.         usagefp = (FILE *)stdout;
  1236.  
  1237.     FPRINTF(usagefp, LoadFarString(UnzipSFXUsage),
  1238.       LoadFarStringSmall(UnzipVersion), LOCAL);
  1239. #ifdef BETA
  1240.     FPRINTF(usagefp, LoadFarString(BetaVersion), "\n", "SFX");
  1241. #endif
  1242.  
  1243.     if (error)
  1244.         return PK_PARAM;
  1245.     else
  1246.         return PK_COOL;     /* just wanted usage screen: no error */
  1247.  
  1248. } /* end function usage() */
  1249.  
  1250.  
  1251.  
  1252.  
  1253.  
  1254. #else /* !SFX */
  1255. #ifndef VMSCLI
  1256.  
  1257. int usage(error)   /* return PK-type error code */
  1258.     int error;
  1259. {
  1260. #ifdef VMS
  1261. #  define QUOT '\"'
  1262. #  define QUOTS "\""
  1263. #else
  1264. #  define QUOT ' '
  1265. #  define QUOTS ""
  1266. #endif
  1267.  
  1268.     FILE *usagefp;
  1269.  
  1270.  
  1271. /*---------------------------------------------------------------------------
  1272.     If user requested usage, send it to stdout; else send to stderr.
  1273.   ---------------------------------------------------------------------------*/
  1274.  
  1275.     if (error)
  1276.         usagefp = (FILE *)stderr;
  1277.     else
  1278.         usagefp = (FILE *)stdout;
  1279.  
  1280. /*---------------------------------------------------------------------------
  1281.     Print either ZipInfo usage or UnZip usage, depending on incantation.
  1282.     (Strings must be no longer than 512 bytes for Turbo C, apparently.)
  1283.   ---------------------------------------------------------------------------*/
  1284.  
  1285.     if (zipinfo_mode) {
  1286.  
  1287. #ifndef NO_ZIPINFO
  1288.  
  1289.         FPRINTF(usagefp, LoadFarString(ZipInfoUsageLine1),
  1290.           LoadFarStringSmall(ZipinfoVersion),
  1291.           LoadFarStringSmall2(ZipInfoExample), QUOTS,QUOTS);
  1292.         FPRINTF(usagefp, LoadFarString(ZipInfoUsageLine2));
  1293.         FPRINTF(usagefp, LoadFarString(ZipInfoUsageLine3), QUOT,QUOT);
  1294. #ifdef VMS
  1295.         FPRINTF(usagefp, "\nRemember that non-lowercase filespecs must be\
  1296.  quoted in VMS (e.g., \"Makefile\").\n");
  1297. #endif
  1298.  
  1299. #endif /* !NO_ZIPINFO */
  1300.  
  1301.     } else {   /* UnZip mode */
  1302.  
  1303.         FPRINTF(usagefp, LoadFarString(UnzipUsageLine1),
  1304.           LoadFarStringSmall(UnzipVersion));
  1305. #ifdef BETA
  1306.         FPRINTF(usagefp, LoadFarString(BetaVersion), "", "");
  1307. #endif
  1308.         FPRINTF(usagefp, LoadFarString(UnzipUsageLine2), ZIPINFO_MODE_OPTION,
  1309.           LoadFarStringSmall(ZipinfoMode));
  1310.  
  1311.         FPRINTF(usagefp, LoadFarString(UnzipUsageLine3));
  1312.  
  1313.         FPRINTF(usagefp, LoadFarString(UnzipUsageLine4), QUOT,QUOT, QUOT,QUOT,
  1314.                 LoadFarStringSmall(loc_str), QUOT,QUOT,
  1315.                 LoadFarStringSmall2(loc2str));
  1316.  
  1317.         /* This is extra work for SMALL_MEM, but it will work since
  1318.          * LoadFarStringSmall2 uses the same buffer.  Remember, this
  1319.          * is a hack. */
  1320.         FPRINTF(usagefp, LoadFarString(UnzipUsageLine5),
  1321.                 LoadFarStringSmall(Example1),
  1322.                 LoadFarStringSmall2(Example2),
  1323.                 LoadFarStringSmall2(Example2));
  1324.  
  1325.     }
  1326.  
  1327.     if (error)
  1328.         return PK_PARAM;
  1329.     else
  1330.         return PK_COOL;     /* just wanted usage screen: no error */
  1331.  
  1332. } /* end function usage() */
  1333.  
  1334. #endif /* !VMSCLI */
  1335. #endif /* ?SFX */
  1336. #endif /* ?MSWIN */
  1337.  
  1338.  
  1339.  
  1340.  
  1341. /*******************************/
  1342. /* Function process_zipfiles() */
  1343. /*******************************/
  1344.  
  1345. int process_zipfiles()    /* return PK-type error code */
  1346. {
  1347. #ifndef SFX
  1348.     char *lastzipfn = (char *)NULL;
  1349.     int NumWinFiles, NumLoseFiles, NumWarnFiles;
  1350.     int NumMissDirs, NumMissFiles;
  1351. #endif
  1352.     int error=0, error_in_archive=0;
  1353.  
  1354.  
  1355. /*---------------------------------------------------------------------------
  1356.     Start by constructing the various PK signature strings.
  1357.   ---------------------------------------------------------------------------*/
  1358.  
  1359.     local_hdr_sig[0]  /* = extd_local_sig[0] */  = '\120';   /* ASCII 'P', */
  1360.     central_hdr_sig[0] = end_central_sig[0] = '\120';        /* not EBCDIC */
  1361.  
  1362.     strcpy(local_hdr_sig+1, LOCAL_HDR_SIG);
  1363.     strcpy(central_hdr_sig+1, CENTRAL_HDR_SIG);
  1364.     strcpy(end_central_sig+1, END_CENTRAL_SIG);
  1365. /*  strcpy(extd_local_sig+1, EXTD_LOCAL_SIG);   still to be used in multi? */
  1366.  
  1367. /*---------------------------------------------------------------------------
  1368.     Match (possible) wildcard zipfile specification with existing files and
  1369.     attempt to process each.  If no hits, try again after appending ".zip"
  1370.     suffix.  If still no luck, give up.
  1371.   ---------------------------------------------------------------------------*/
  1372.  
  1373. #ifdef SFX
  1374.     if ((error = do_seekable(0)) == PK_NOZIP) {
  1375. #ifdef EXE_EXTENSION
  1376.         int len=strlen(argv0);
  1377.  
  1378.         /* append .exe if appropriate; also .sfx? */
  1379.         if ((zipfn = (char *)malloc(len+5)) != (char *)NULL) {
  1380.             strcpy(zipfn, argv0);
  1381.             strcpy(zipfn+len, EXE_EXTENSION);
  1382.             error = do_seekable(0);
  1383.             free(zipfn);
  1384.             zipfn = argv0;  /* for "can't find myself" message only */
  1385.         }
  1386. #endif /* EXE_EXTENSION */
  1387. #ifdef NT
  1388.         zipfn = argv0;  /* for "can't find myself" message only */
  1389. #endif
  1390.     }
  1391.     if (error) {
  1392.         if (error == IZ_DIR)
  1393.             error_in_archive = PK_NOZIP;
  1394.         else
  1395.             error_in_archive = error;
  1396.         if (error == PK_NOZIP)
  1397.             FPRINTF(stderr, LoadFarString(CantFindMyself), zipfn);
  1398.     }
  1399.  
  1400. #else /* !SFX */
  1401.     NumWinFiles = NumLoseFiles = NumWarnFiles = 0;
  1402.     NumMissDirs = NumMissFiles = 0;
  1403.  
  1404.     while ((zipfn = do_wild(wildzipfn)) != (char *)NULL) {
  1405.         Trace((stderr, "do_wild( %s ) returns %s\n", wildzipfn, zipfn));
  1406.  
  1407.         lastzipfn = zipfn;
  1408.  
  1409.         /* print a blank line between the output of different zipfiles */
  1410.         if (!qflag  &&  error != PK_NOZIP  &&  error != IZ_DIR  &&
  1411.             (NumWinFiles+NumLoseFiles+NumWarnFiles+NumMissFiles) > 0)
  1412.             PRINTF("\n");
  1413.         FFLUSH(stdout);
  1414.  
  1415.         if ((error = do_seekable(0)) == PK_WARN)
  1416.             ++NumWarnFiles;
  1417.         else if (error == IZ_DIR)
  1418.             ++NumMissDirs;
  1419.         else if (error == PK_NOZIP)
  1420.             ++NumMissFiles;
  1421.         else if (error)
  1422.             ++NumLoseFiles;
  1423.         else
  1424.             ++NumWinFiles;
  1425.  
  1426.         if (error != IZ_DIR && error > error_in_archive)
  1427.             error_in_archive = error;
  1428.         Trace((stderr, "do_seekable(0) returns %d\n", error));
  1429.  
  1430.     } /* end while-loop (wildcard zipfiles) */
  1431.  
  1432.     if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0  &&
  1433.         (NumMissDirs + NumMissFiles) == 1  &&  lastzipfn != (char *)NULL)
  1434.     {
  1435.         char *p = lastzipfn + strlen(lastzipfn);
  1436.  
  1437.         NumMissDirs = NumMissFiles = 0;
  1438.         if (error_in_archive == PK_NOZIP)
  1439.             error_in_archive = PK_COOL;
  1440.         zipfn = lastzipfn;
  1441.         strcpy(p, ".zip");
  1442.  
  1443. #ifdef UNIX
  1444.         if ((error = do_seekable(0)) == PK_NOZIP || error == IZ_DIR) {
  1445.             if (error == IZ_DIR)
  1446.                 ++NumMissDirs;
  1447.             strcpy(p, ".ZIP");
  1448.             error = do_seekable(1);
  1449.         }
  1450. #else
  1451.         error = do_seekable(1);
  1452. #endif
  1453.         if (error == PK_WARN)
  1454.             ++NumWarnFiles;
  1455.         else if (error == IZ_DIR)
  1456.             ++NumMissDirs;
  1457.         else if (error == PK_NOZIP)
  1458.             /* if increment again => bug: "1 file had no zipfile directory." */
  1459.             /* ++NumMissFiles */ ;
  1460.         else if (error)
  1461.             ++NumLoseFiles;
  1462.         else
  1463.             ++NumWinFiles;
  1464.  
  1465.         if (error > error_in_archive)
  1466.             error_in_archive = error;
  1467.         Trace((stderr, "do_seekable(1) returns %d\n", error));
  1468.     }
  1469. #endif /* ?SFX */
  1470.  
  1471.     FFLUSH(stdout);
  1472.     FFLUSH(stderr);
  1473.  
  1474. /*---------------------------------------------------------------------------
  1475.     Print summary of all zipfiles, assuming zipfile spec was a wildcard (no
  1476.     need for a summary if just one zipfile).
  1477.   ---------------------------------------------------------------------------*/
  1478.  
  1479. #ifndef SFX
  1480.     if (iswild(wildzipfn)) {
  1481.         if (NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1)
  1482.             FPRINTF(stderr, "\n");
  1483.         if ((NumWinFiles > 1) || (NumWinFiles == 1 &&
  1484.             NumMissDirs + NumMissFiles + NumLoseFiles + NumWarnFiles > 0))
  1485.             FPRINTF(stderr, LoadFarString(FilesProcessOK),
  1486.               NumWinFiles, (NumWinFiles == 1)? " was" : "s were");
  1487.         if (NumWarnFiles > 0)
  1488.             FPRINTF(stderr, LoadFarString(ArchiveWarning),
  1489.               NumWarnFiles, (NumWarnFiles == 1)? "" : "s");
  1490.         if (NumLoseFiles > 0)
  1491.             FPRINTF(stderr, LoadFarString(ArchiveFatalError),
  1492.               NumLoseFiles, (NumLoseFiles == 1)? "" : "s");
  1493.         if (NumMissFiles > 0)
  1494.             FPRINTF(stderr, LoadFarString(FileHadNoZipfileDir),
  1495.               NumMissFiles, (NumMissFiles == 1)? "" : "s");
  1496.         if (NumMissDirs == 1)
  1497.             FPRINTF(stderr, LoadFarString(ZipfileWasDir));
  1498.         else if (NumMissDirs > 0)
  1499.             FPRINTF(stderr, LoadFarString(ManyZipfilesWereDir), NumMissDirs);
  1500.         if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0)
  1501.             FPRINTF(stderr, LoadFarString(NoZipfileFound));
  1502.     }
  1503. #endif /* !SFX */
  1504.  
  1505.     /* free allocated memory */
  1506.     inflate_free();
  1507.     checkdir((char *)NULL, END);
  1508. #ifndef SMALL_MEM
  1509.     if (outbuf2)
  1510.         free(outbuf2);   /* malloc'd ONLY if unshrink and -a */
  1511. #endif
  1512.     free(outbuf);
  1513.     free(inbuf);
  1514.  
  1515.     return error_in_archive;
  1516.  
  1517. } /* end function process_zipfiles() */
  1518.  
  1519.  
  1520.  
  1521.  
  1522.  
  1523. /**************************/
  1524. /* Function do_seekable() */
  1525. /**************************/
  1526.  
  1527. int do_seekable(lastchance)    /* return PK-type error code */
  1528.     int lastchance;
  1529. {
  1530. #ifndef SFX
  1531.     static int no_ecrec = FALSE;
  1532.     int maybe_exe=FALSE;
  1533. #endif
  1534.     int error=0, error_in_archive;
  1535.  
  1536.  
  1537. /*---------------------------------------------------------------------------
  1538.     Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
  1539.     which would corrupt the bit streams.
  1540.   ---------------------------------------------------------------------------*/
  1541.  
  1542.     if (SSTAT(zipfn, &statbuf) || (error = S_ISDIR(statbuf.st_mode)) != 0) {
  1543. #ifndef SFX
  1544.         if (lastchance)
  1545.             if (no_ecrec)
  1546.                 FPRINTF(stderr, LoadFarString(CantFindZipfileDirMsg),
  1547.                   zipinfo_mode? "zipinfo" : "unzip",
  1548.                   wildzipfn, zipinfo_mode? "  " : "",
  1549. #ifdef UNIX
  1550.                                                      wildzipfn,
  1551. #endif
  1552.                                                                zipfn);
  1553.             else
  1554.                 FPRINTF(stderr,
  1555.                   LoadFarString(CantFindEitherZipfile),
  1556.                   zipinfo_mode? "zipinfo" : "unzip", wildzipfn,
  1557. #ifdef UNIX
  1558.                                                                wildzipfn,
  1559. #endif
  1560.                                                                          zipfn);
  1561. #endif /* !SFX */
  1562.         return error? IZ_DIR : PK_NOZIP;
  1563.     }
  1564.     ziplen = statbuf.st_size;
  1565.  
  1566. #ifndef SFX
  1567. #if defined(UNIX) || defined(DOS_NT_OS2)
  1568.     if (statbuf.st_mode & S_IEXEC)   /* no extension on Unix exec's:  might */
  1569.         maybe_exe = TRUE;            /*  find unzip, not unzip.zip; etc. */
  1570. #endif
  1571. #endif /* !SFX */
  1572.  
  1573. #ifdef VMS
  1574.     if (check_format())      /* check for variable-length format */
  1575.         return PK_ERR;
  1576. #endif
  1577.  
  1578.     if (open_input_file())   /* this should never happen, given */
  1579.         return PK_NOZIP;     /*  the stat() test above, but... */
  1580.  
  1581. /*---------------------------------------------------------------------------
  1582.     Find and process the end-of-central-directory header.  UnZip need only
  1583.     check last 65557 bytes of zipfile:  comment may be up to 65535, end-of-
  1584.     central-directory record is 18 bytes, and signature itself is 4 bytes;
  1585.     add some to allow for appended garbage.  Since ZipInfo is often used as
  1586.     a debugging tool, search the whole zipfile if zipinfo_mode is true.
  1587.   ---------------------------------------------------------------------------*/
  1588.  
  1589.     cur_zipfile_bufstart = 0;
  1590.     inptr = inbuf;
  1591.  
  1592.     if (!qflag && !zipinfo_mode)
  1593.         PRINTF("Archive:  %s\n", zipfn);
  1594.  
  1595.     if ((
  1596. #ifndef NO_ZIPINFO
  1597.          zipinfo_mode &&
  1598.           ((error_in_archive = find_ecrec(ziplen)) != 0 ||
  1599.           (error_in_archive = zi_end_central()) > PK_WARN))
  1600.         || (!zipinfo_mode &&
  1601. #endif
  1602.           ((error_in_archive = find_ecrec(MIN(ziplen,66000L))) != 0 ||
  1603.           (error_in_archive = uz_end_central()) > PK_WARN)))
  1604.     {
  1605.         close(zipfd);
  1606. #ifdef SFX
  1607.         ++lastchance;   /* avoid picky compiler warnings */
  1608.         return error_in_archive;
  1609. #else
  1610.         if (maybe_exe)
  1611.             FPRINTF(stderr, LoadFarString(MaybeExe), zipfn);
  1612.         if (lastchance)
  1613.             return error_in_archive;
  1614.         else {
  1615.             no_ecrec = TRUE;    /* assume we found wrong file:  e.g., */
  1616.             return PK_NOZIP;    /*  unzip instead of unzip.zip */
  1617.         }
  1618. #endif /* ?SFX */
  1619.     }
  1620.  
  1621.     if ((zflag > 0) && !zipinfo_mode) {   /* in unzip, zflag = comment ONLY */
  1622.         close(zipfd);
  1623.         return error_in_archive;
  1624.     }
  1625.  
  1626. /*---------------------------------------------------------------------------
  1627.     Test the end-of-central-directory info for incompatibilities (multi-disk
  1628.     archives) or inconsistencies (missing or extra bytes in zipfile).
  1629.   ---------------------------------------------------------------------------*/
  1630.  
  1631. #ifdef NO_MULTIPART
  1632.     error = !zipinfo_mode && (ecrec.number_this_disk == 1) &&
  1633.             (ecrec.num_disk_with_start_central_dir == 1);
  1634. #else
  1635.     error = !zipinfo_mode && (ecrec.number_this_disk != 0);
  1636. #endif
  1637.  
  1638. #ifndef SFX
  1639.     if (zipinfo_mode &&
  1640.         ecrec.number_this_disk != ecrec.num_disk_with_start_central_dir)
  1641.     {
  1642.         FPRINTF(stderr, LoadFarString(CentDirNotInZipMsg));
  1643.         error_in_archive = PK_FIND;
  1644. #ifdef NO_MULTIPART   /* concatenation of multiple parts works in some cases */
  1645.     } else if (!zipinfo_mode && !error && ecrec.number_this_disk != 0) {
  1646.         FPRINTF(stderr, LoadFarString(NoMultiDiskArcSupport), zipfn);
  1647.         error_in_archive = PK_FIND;
  1648. #endif
  1649.     } else {   /* this is a (relatively) normal zipfile:  process normally */
  1650.         if (error) {
  1651.             FPRINTF(stderr, LoadFarString(MaybePakBug), zipfn);
  1652.             error_in_archive = PK_WARN;
  1653.         }
  1654. #endif
  1655.         if ((extra_bytes = real_ecrec_offset-expect_ecrec_offset) < (LONGINT)0)
  1656.         {
  1657.             FPRINTF(stderr, LoadFarString(MissingBytes), zipfn,
  1658.               (long)(-extra_bytes));
  1659.             error_in_archive = PK_ERR;
  1660.         } else if (extra_bytes > 0) {
  1661.             if ((ecrec.offset_start_central_directory == 0) &&
  1662.                 (ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
  1663.             {
  1664.                 FPRINTF(stderr, LoadFarString(NullCentDirOffset), zipfn);
  1665.                 ecrec.offset_start_central_directory = extra_bytes;
  1666.                 extra_bytes = 0;
  1667.                 error_in_archive = PK_ERR;
  1668.             }
  1669. #ifndef SFX
  1670.             else {
  1671.                 FPRINTF(stderr, LoadFarString(ExtraBytesAtStart), zipfn,
  1672.                   (long)extra_bytes);
  1673.                 error_in_archive = PK_WARN;
  1674.             }
  1675. #endif
  1676.         }
  1677.  
  1678.     /*-----------------------------------------------------------------------
  1679.         Check for empty zipfile and exit now if so.
  1680.       -----------------------------------------------------------------------*/
  1681.  
  1682.         if (expect_ecrec_offset == 0L  &&  ecrec.size_central_directory == 0) {
  1683.             if (zipinfo_mode)
  1684.                 PRINTF("%sEmpty zipfile.\n", lflag>9 ? "\n  " : "");
  1685.             else
  1686.                 FPRINTF(stderr, LoadFarString(ZipfileEmpty), zipfn);
  1687.             close(zipfd);
  1688.             return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN;
  1689.         }
  1690.  
  1691.     /*-----------------------------------------------------------------------
  1692.         Compensate for missing or extra bytes, and seek to where the start
  1693.         of central directory should be.  If header not found, uncompensate
  1694.         and try again (necessary for at least some Atari archives created
  1695.         with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
  1696.       -----------------------------------------------------------------------*/
  1697.  
  1698.         LSEEK( ecrec.offset_start_central_directory )
  1699. #ifdef OLD_SEEK_TEST
  1700.         if (readbuf(sig, 4) == 0) {
  1701.             close(zipfd);
  1702.             return PK_ERR;  /* file may be locked, or possibly disk error(?) */
  1703.         }
  1704.         if (strncmp(sig, central_hdr_sig, 4))
  1705. #else
  1706.         if ((readbuf(sig, 4) == 0) || strncmp(sig, central_hdr_sig, 4))
  1707. #endif
  1708.         {
  1709.             long tmp = extra_bytes;
  1710.  
  1711.             extra_bytes = 0;
  1712.             LSEEK( ecrec.offset_start_central_directory )
  1713.             if ((readbuf(sig, 4) == 0) || strncmp(sig, central_hdr_sig, 4)) {
  1714.                 FPRINTF(stderr, LoadFarString(CentDirStartNotFound), zipfn,
  1715.                   LoadFarStringSmall(ReportMsg));
  1716.                 close(zipfd);
  1717.                 return PK_BADERR;
  1718.             }
  1719.             FPRINTF(stderr, LoadFarString(CentDirTooLong), zipfn, -tmp);
  1720.             error_in_archive = PK_ERR;
  1721.         }
  1722.  
  1723.     /*-----------------------------------------------------------------------
  1724.         Seek to the start of the central directory one last time, since we
  1725.         have just read the first entry's signature bytes; then list, extract
  1726.         or test member files as instructed, and close the zipfile.
  1727.       -----------------------------------------------------------------------*/
  1728.  
  1729.         Trace((stderr, "about to extract/list files (error = %d)\n",
  1730.           error_in_archive));
  1731.  
  1732.         LSEEK( ecrec.offset_start_central_directory )
  1733.  
  1734. #ifndef NO_ZIPINFO
  1735.         if (zipinfo_mode) {
  1736.             error = zipinfo();                     /* ZIPINFO 'EM */
  1737.             if (lflag > 9)
  1738.                 PRINTF("\n");
  1739.         } else
  1740. #endif
  1741. #ifndef SFX
  1742.             if (vflag && !tflag && !cflag)
  1743.                 error = list_files();              /* LIST 'EM */
  1744.             else
  1745. #endif
  1746.                 error = extract_or_test_files();   /* EXTRACT OR TEST 'EM */
  1747.  
  1748.         Trace((stderr, "done with extract/list files (error = %d)\n", error));
  1749.  
  1750.         if (error > error_in_archive)   /* don't overwrite stronger error */
  1751.             error_in_archive = error;   /*  with (for example) a warning */
  1752. #ifndef SFX
  1753.     }
  1754. #endif
  1755.  
  1756.     close(zipfd);
  1757.     return error_in_archive;
  1758.  
  1759. } /* end function do_seekable() */
  1760.  
  1761.  
  1762.  
  1763.  
  1764.  
  1765. /*****************************/
  1766. /* Function uz_end_central() */
  1767. /*****************************/
  1768.  
  1769. int uz_end_central()    /* return PK-type error code */
  1770. {
  1771.     int error = PK_COOL;
  1772.  
  1773.  
  1774. /*---------------------------------------------------------------------------
  1775.     Get the zipfile comment (up to 64KB long), if any, and print it out.
  1776.     Then position the file pointer to the beginning of the central directory
  1777.     and fill buffer.
  1778.   ---------------------------------------------------------------------------*/
  1779.  
  1780. #ifdef MSWIN
  1781.     cchComment = ecrec.zipfile_comment_length; /* save for comment button */
  1782.     if (ecrec.zipfile_comment_length && (zflag > 0))
  1783. #else
  1784.     if (ecrec.zipfile_comment_length && (zflag > 0 || (zflag == 0 && !qflag)))
  1785. #endif
  1786.     {
  1787. #if 0
  1788. #ifndef MSWIN
  1789.         if (zflag == 0)       (add "&& single_zipfile" perhaps; unnecessary with
  1790.             PRINTF("[%s] comment:\n", zipfn);  multiple zipfiles: "Archive:...")
  1791. #endif /* !MSWIN */
  1792. #endif /* 0 */
  1793.         if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
  1794.             FPRINTF(stderr, LoadFarString(ZipfileCommTrunc1));
  1795.             error = PK_WARN;
  1796.         }
  1797.     }
  1798.     return error;
  1799.  
  1800. } /* end function uz_end_central() */
  1801.  
  1802.  
  1803.  
  1804.  
  1805.  
  1806. /************************************/
  1807. /* Function process_cdir_file_hdr() */
  1808. /************************************/
  1809.  
  1810. int process_cdir_file_hdr()    /* return PK-type error code */
  1811. {
  1812.     int error;
  1813.  
  1814.  
  1815. /*---------------------------------------------------------------------------
  1816.     Get central directory info, save host and method numbers, and set flag
  1817.     for lowercase conversion of filename, depending on the OS from which the
  1818.     file is coming.
  1819.   ---------------------------------------------------------------------------*/
  1820.  
  1821.     if ((error = get_cdir_ent()) != 0)
  1822.         return error;
  1823.  
  1824.     pInfo->hostnum = MIN(crec.version_made_by[1], NUM_HOSTS);
  1825. /*  extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
  1826.  
  1827.     pInfo->lcflag = 0;
  1828.     if (L_flag)               /* user specified case-conversion */
  1829.         switch (pInfo->hostnum) {
  1830.             case FS_FAT_:     /* PKZIP and zip -k store in uppercase */
  1831.             case ATARI_:      /* MS-DOS filesystem */
  1832.             case CPM_:        /* like MS-DOS, right? */
  1833.             case VM_CMS_:     /* all caps? */
  1834.             case TOPS20_:
  1835.             case VMS_:        /* our Zip uses lowercase, but ASi's doesn't */
  1836.         /*  case Z_SYSTEM_:   ? */
  1837.         /*  case QDOS_:       ? */
  1838.                 pInfo->lcflag = 1;   /* convert filename to lowercase */
  1839.                 break;
  1840.  
  1841.             default:     /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, */
  1842.                 break;   /*  (Z_SYSTEM_):  no conversion */
  1843.         }
  1844.  
  1845.     /* do Amigas (AMIGA_) also have volume labels? */
  1846.     if (IS_VOLID(crec.external_file_attributes) &&
  1847.         (pInfo->hostnum == FS_FAT_ || pInfo->hostnum == FS_HPFS_ ||
  1848.          pInfo->hostnum == FS_NTFS_ || pInfo->hostnum == ATARI_))
  1849.     {
  1850.         pInfo->vollabel = TRUE;
  1851.         pInfo->lcflag = 0;        /* preserve case of volume labels */
  1852.     } else
  1853.         pInfo->vollabel = FALSE;
  1854.  
  1855.     return PK_COOL;
  1856.  
  1857. } /* end function process_cdir_file_hdr() */
  1858.  
  1859.  
  1860.  
  1861.  
  1862.  
  1863. /*************************************/
  1864. /* Function process_local_file_hdr() */
  1865. /*************************************/
  1866.  
  1867. int process_local_file_hdr()    /* return PK-type error code */
  1868. {
  1869.     local_byte_hdr byterec;
  1870.  
  1871.  
  1872. /*---------------------------------------------------------------------------
  1873.     Read the next local file header and do any necessary machine-type con-
  1874.     versions (byte ordering, structure padding compensation--do so by copy-
  1875.     ing the data from the array into which it was read (byterec) to the
  1876.     usable struct (lrec)).
  1877.   ---------------------------------------------------------------------------*/
  1878.  
  1879.     if (readbuf((char *)byterec, LREC_SIZE) == 0)
  1880.         return PK_EOF;
  1881.  
  1882.     lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
  1883.     lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
  1884.  
  1885.     lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
  1886.     lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
  1887.     lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
  1888.     lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
  1889.     lrec.crc32 = makelong(&byterec[L_CRC32]);
  1890.     lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]);
  1891.     lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
  1892.     lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
  1893.     lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
  1894.  
  1895.     csize = (long) lrec.csize;
  1896.     ucsize = (long) lrec.ucsize;
  1897.  
  1898.     if ((lrec.general_purpose_bit_flag & 8) != 0) {
  1899.         /* can't trust local header, use central directory: */
  1900.         lrec.crc32 = pInfo->crc;
  1901.         csize = (long)(lrec.csize = pInfo->compr_size);
  1902.     }
  1903.  
  1904.     return PK_COOL;
  1905.  
  1906. } /* end function process_local_file_hdr() */
  1907.