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