ftp.nice.ch/NiCE/Opener/unzip.tar.gz#/unzip/unzip.c

This is unzip.c in view mode; [Download] [Up]

/*---------------------------------------------------------------------------

  unzip.c

  UnZip - a zipfile extraction utility.  See below for make instructions, or
  read the comments in Makefile and the various Contents files for more de-
  tailed explanations.  To report a bug, send a *complete* description to
  zip-bugs@wkuvx1.wku.edu; include machine type, operating system and ver-
  sion, compiler and version, and reasonably detailed error messages or prob-
  lem report.  To join Info-ZIP, see the instructions in README.

  UnZip 5.x is a greatly expanded and partially rewritten successor to 4.x,
  which in turn was almost a complete rewrite of version 3.x.  For a detailed
  revision history, see UnzpHist.zip at quest.jpl.nasa.gov.  For a list of
  the many (near infinite) contributors, see "CONTRIBS" in the UnZip source
  distribution.

  ---------------------------------------------------------------------------

  [from original zipinfo.c]

  This program reads great gobs of totally nifty information, including the
  central directory stuff, from ZIP archives ("zipfiles" for short).  It
  started as just a testbed for fooling with zipfiles, but at this point it
  is actually a useful utility.  It also became the basis for the rewrite of
  UnZip (3.16 -> 4.0), using the central directory for processing rather than
  the individual (local) file headers.

  The author finds it convenient to define an alias "ii" (under Unix and VMS)
  or to rename the executable to "ii.exe" (OS/2 and DOS).  This nicely comple-
  ments the common Unix "ll" long-listing alias (ls -lF), since zipinfo's de-
  fault action is to produce a Unix-like listing of the archive's contents.
  "ii zipfile" is easier to type than "zipinfo zipfile"...

  As of ZipInfo v2.0 and UnZip v5.1, the two programs are combined into one.
  If the executable is named "unzip" (or "unzip.exe", depending), it behaves
  like UnZip by default; if it is named "zipinfo" or "ii", it behaves like
  ZipInfo.  The ZipInfo behavior may also be triggered by use of unzip's -Z
  option; for example, "unzip -Z [zipinfo_options] archive.zip".

  Another dandy product from your buddies at Newtware!

  Author:  Greg Roelofs, newt@uchicago.edu, 23 August 1990 -> ...
           SizeOfEAs() by Kai Uwe Rommel.

  ---------------------------------------------------------------------------

  Quick compile instructions (see INSTALL file):  copy and/or rename appro-
  priate makefile to main unzip directory, then:

     under Unix (cc):  make <system name>
       (type "make list" for a list of valid names, or read Makefile for 
        details.  "make unzip" works for most systems.  If you have a NEW
        system, not covered by any of the existing targets, send FULL in-
        formation--hardware, OS, versions, etc.--to zip-bugs)

     under VMS (VAX or Alpha C, or GNU C):  @make_vaxc  or  @make_gcc
       (can also use MMS or MAKE/VMS; see [.vms]README.)

     under OS/2:  nmake -f makefile.os2 <compiler>
       (type "nmake -f makefile.os2" for list of targets; Watcom, Borland,
        IBM, Microsoft, emx+gcc compilers and nmake and dmake supported)

     under MS-DOS (MS or Quick C, Turbo or Borland C[++]):  make
       (project files no longer supported; for Microsoft, use nmake; for
        djgpp or cross-compiling, use appropriate targets in unix/Makefile)

     under MS Windows 3.1:  get wunz20sr.{zip | zoo | whatever} and use
       the included makefile

     under Windows NT (MS Visual C++):  nmake

     under Macintosh OS (Think C):  un-BinHex the Think C project file and
       UnZip resource file, then click on something or other :-) )

     under AmigaDOS (SAS/Lattice C or Aztec C):
       with SAS C 6.x:  lmk -f amiga/SMakeFile all
       with Aztec C:    make -f amiga/Makefile.AZT all

     under Atari TOS (MiNT libraries and gcc 2.4.5):  make
       (see atari/README and atari/Makefile for info about other compilers)

     under TOPS-20:  use make.mic and "do make" [no longer fully ported]

  ---------------------------------------------------------------------------

  Version:  unzip51.{tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS, Windows,
              Windows NT, Macintosh, Amiga, Atari and TOPS-20.  Decryption
              requires sources in zcrypt20.zip, and Windows (not NT) support
              requires sources in wunz20sr.zip.  See accompanying file "Where"
              in the main source distribution for ftp, uucp and mail-server
              sites.
  Copyrights:  see accompanying file "COPYING" in UnZip source distribution.

  ---------------------------------------------------------------------------*/



#include "unzip.h"               /* includes, typedefs, macros, etc. */
#ifdef MSWIN
#  include "wizunzip.h"
#endif


#define RELEASE
#ifdef RELEASE
#  define UZ_VERSION  "5.1 of 7 February 1994"   /* official release version */
#  define ZI_VERSION  "2.0 of 7 February 1994"
#else
#  define UZ_VERSION  "5.1p BETA of 6 Feb 94"   /* internal beta level */
#  define ZI_VERSION  "1.99 BETA of 6 Feb 94"
#endif



/**********************/
/*  Global Variables  */
/**********************/

#ifdef MACOS
   extern char *unzip_version = UZ_VERSION;
   extern char *zipinfo_version = ZI_VERSION;
#endif

int zipinfo_mode;     /* behave like ZipInfo or like normal UnZip? */

int aflag=0;          /* -a: do ASCII-EBCDIC and/or end-of-line translation */
int cflag=0;          /* -c: output to stdout */
int dflag=0;          /* -d: all args are files/dirs to be extracted */
int fflag=0;          /* -f: "freshen" (extract only newer files) */
int hflag=0;          /* -h: header line (zipinfo) */
int jflag=0;          /* -j: junk pathnames (unzip) */
int lflag=(-1);       /* -12slmv: listing format (zipinfo) */
int overwrite_none=0; /* -n: never overwrite files (no prompting) */
int overwrite_all=0;  /* -o: OK to overwrite files without prompting */
int force_flag=0;     /* (shares -o for now): force to override errors, etc. */
int qflag=0;          /* -q: produce a lot less output */
#ifdef DOS_NT_OS2
   int sflag=0;       /* -s: convert filename spaces (blanks) to underscores */
   int volflag=0;     /* -$: extract volume labels */
#endif
int tflag=0;          /* -t: test (unzip) or totals line (zipinfo) */
int uflag=0;          /* -u: "update" (extract only newer & brand-new files) */
int U_flag=0;         /* -U: preserve uppercase characters in filenames */
int vflag=0;          /* -v: (verbosely) list directory */
int V_flag=0;         /* -V: don't strip VMS version numbers */
#ifdef VMS
   int secinf=0;      /* -X: keep owner/protection */
#endif
int zflag=0;          /* -z: display the zipfile comment (only, for unzip) */

int filespecs;        /* number of real file specifications to be matched */
int xfilespecs;       /* number of excluded filespecs to be matched */
int process_all_files = 0;
int create_dirs;      /* used by main(), mapname(), checkdir() */
int extract_flag;

LONGINT real_ecrec_offset, expect_ecrec_offset;

long csize;           /* used by list_files(), ReadByte(): must be signed */
long ucsize;          /* used by list_files(), unReduce(), explode() */
long used_csize;      /* used by extract_or_test_member(), explode() */

static char *fnames[2] = {"*", NULL};   /* default filenames vector */
char **pfnames = fnames, **pxnames = &fnames[1];
char near sig[5];
char near answerbuf[10];

min_info info[DIR_BLKSIZ], *pInfo=info;

/*---------------------------------------------------------------------------
    unreduce/unshrink/explode/inflate working storage and globals:
  ---------------------------------------------------------------------------*/

union work area;              /* see unzip.h for the definition of work */
ulg crc32val;

ush near mask_bits[] = {
    0x0000,
    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
};

/*---------------------------------------------------------------------------
    Input file variables:
  ---------------------------------------------------------------------------*/

uch *inbuf, *inptr;             /* input buffer (any size is OK) and pointer */
int incnt;

ulg bitbuf;
int bits_left;
boolean zipeof;

char *wildzipfn, *zipfn;    /* GRR:  MSWIN:  must nuke any malloc'd zipfn... */

int zipfd;                      /* zipfile file handle */
LONGINT ziplen;

uch *hold;
char near local_hdr_sig[5];     /* initialize signatures at runtime so unzip */
char near central_hdr_sig[5];   /*  executable won't look like a zipfile */
char near end_central_sig[5];
/* char extd_local_sig[5];  NOT USED YET */

cdir_file_hdr crec;             /* used in unzip.c, extract.c, misc.c */
local_file_hdr lrec;            /* used in unzip.c, extract.c */
ecdir_rec ecrec;                /* used in unzip.c, extract.c */
struct stat statbuf;            /* used by main, mapname, check_for_newer */

LONGINT cur_zipfile_bufstart;   /* extract_or_test_files, readbuf, ReadByte */
LONGINT extra_bytes = 0;        /* used in unzip.c, misc.c */

uch *extra_field = (uch *)NULL; /* used by VMS, Mac and OS/2 versions */

#ifdef MACOS
   short  gnVRefNum;
   long  glDirID;
   OSType  gostCreator;
   OSType  gostType;
   boolean  fMacZipped;
   boolean  macflag;
   CursHandle  rghCursor[4];    /* status cursors */
   short  giCursor = 0;
#endif

/*---------------------------------------------------------------------------
    Output stream variables:
  ---------------------------------------------------------------------------*/

int mem_mode = 0;
int disk_full;
#ifdef SYMLINKS
   int symlnk;
#endif
FILE *outfile;
uch *outbuf;
uch *outptr;
ulg outcnt;                     /* number of chars stored in outbuf */
#ifdef SMALL_MEM
   uch *outbuf2;                /* initialized in main() (never changes) */
#else
   uch *outbuf2 = NULL;         /* malloc'd ONLY if unshrink and -a */
#endif
#ifdef MSWIN
   char *filename;
#else
   char near filename[FILNAMSIZ];
#endif

/*---------------------------------------------------------------------------
    unzip.c repeated error messages (we use all of these at least twice)
  ---------------------------------------------------------------------------*/

char *EndSigMsg = "\nnote:\
  didn't find end-of-central-dir signature at end of central dir.\n";
char *CentSigMsg =
  "error:  expected central file header signature not found (file #%u).\n";
char *SeekMsg =
  "error [%s]:  attempt to seek before beginning of zipfile\n%s";

#ifdef VMS
  char *ReportMsg = "\
  (please check that you have transferred or created the zipfile in the\n\
  appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n";
#else
  char *ReportMsg = "\
  (please check that you have transferred or created the zipfile in the\n\
  appropriate BINARY mode and that you have compiled unzip properly)\n";
#endif





#ifdef MSWIN
#  include "winsetup.c"   /* duplicates some code in main() */
#else /* !MSWIN */

/******************/
/*  Main program  */
/******************/

#ifdef THINK_C
 int unzip(argc, argv)
#else
 int main(argc, argv)   /* return PK-type error code (except under VMS) */
#endif
    int argc;
    char *argv[];
{
    char *p;
    int error=FALSE;
#if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
    extern void DebugMalloc(void);


    atexit(DebugMalloc);
#endif

/*---------------------------------------------------------------------------
    Macintosh initialization code.
  ---------------------------------------------------------------------------*/

#ifdef MACOS
    int a;

    for (a = 0;  a < 4;  ++a)
        rghCursor[a] = GetCursor(a+128);
    giCursor = 0;

    aflag=cflag=dflag=fflag=jflag=qflag=tflag=U_flag=uflag=vflag=zflag = 0;
    local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0';
/*  extd_local_sig[1] = '\0';  */
    error = FALSE;

    overwrite_none = overwrite_all = force_flag = 0;
#endif /* MACOS */

#ifdef MALLOC_WORK
    area.Slide = (uch *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char));
    area.shrink.Prefix_of = (short *)area.Slide;
    area.shrink.Suffix_of = area.Slide + (sizeof(short)*(HSIZE+1));
    area.shrink.Stack = area.Slide + (sizeof(short) + sizeof(char))*(HSIZE+1);
#endif

/*---------------------------------------------------------------------------
    Human68K initialization code.
  ---------------------------------------------------------------------------*/

#ifdef __human68k__
    InitTwentyOne();
#endif

/*---------------------------------------------------------------------------
    Set signal handler for restoring echo, warn of zipfile corruption, etc.
  ---------------------------------------------------------------------------*/

    signal(SIGINT, handler);
#ifdef SIGTERM                 /* some systems really have no SIGTERM */
    signal(SIGTERM, handler);
#endif
#ifdef SIGBUS
    signal(SIGBUS, handler);
#endif
#ifdef SIGSEGV
    signal(SIGSEGV, handler);
#endif

/*---------------------------------------------------------------------------
    Debugging info for checking on structure padding:
  ---------------------------------------------------------------------------*/

#ifdef DEBUG_STRUC
    printf("local_file_hdr size: %X\n",
           sizeof(local_file_hdr));
    printf("local_byte_hdr size: %X\n",
           sizeof(local_byte_hdr));
    printf("actual size of local headers: %X\n", LREC_SIZE);

    printf("central directory header size: %X\n",
           sizeof(cdir_file_hdr));
    printf("central directory byte header size: %X\n",
           sizeof(cdir_byte_hdr));
    printf("actual size of central dir headers: %X\n", CREC_SIZE);

    printf("end central dir record size: %X\n",
           sizeof(ecdir_rec));
    printf("end central dir byte record size: %X\n",
           sizeof(ec_byte_rec));
    printf("actual size of end-central-dir record: %X\n", ECREC_SIZE);
#endif /* DEBUG_STRUC */

/*---------------------------------------------------------------------------
    First figure out if we're running in UnZip mode or ZipInfo mode, and put
    the appropriate environment-variable options into the queue.  Then rip
    through any command-line options lurking about...
  ---------------------------------------------------------------------------*/

#ifdef SFX
    zipfn = argv[0];
#endif

#ifndef NO_ZIPINFO
    if ((p = strrchr(argv[0], DIR_END)) == NULL)
        p = argv[0];
    else
        ++p;

    if (STRNICMP(p, "zipinfo", 7) == 0 || STRNICMP(p, "ii", 2) == 0 ||
        (argc > 1 && strncmp(argv[1], "-Z", 2) == 0))
    {
        zipinfo_mode = TRUE;
        envargs(&argc, &argv, ENV_ZIPINFO);
        error = zi_opts(&argc, &argv);
    } else
#endif
    {
        zipinfo_mode = FALSE;
        envargs(&argc, &argv, ENV_UNZIP);
        error = uz_opts(&argc, &argv);
    }

#ifdef MSDOS
    /* extract MKS extended argument list from environment */
    mksargs(&argc, &argv);
#endif

#ifdef SFX
    if (error)
#else
    if ((argc < 0) || error)
#endif
        RETURN(error);

/*---------------------------------------------------------------------------
    Now get the zipfile name from the command line and see if it exists as a
    regular (non-directory) file.  If not, append the ".zip" suffix.  We don't
    immediately check to see if this results in a good name, but we will do so
    later.  In the meantime, see if there are any member filespecs on the com-
    mand line, and if so, set the filename pointer to point at them.
  ---------------------------------------------------------------------------*/

#ifdef DOS_NT_OS2
    /* convert MSDOS-style directory separators to Unix-style ones for
     * user's convenience (include zipfile name itself)
     */
    pfnames = argv;
    while (*pfnames != NULL) {
        char *q;

        for (q = *pfnames;  *q;  ++q)
            if (*q == '\\')
                *q = '/';
        ++pfnames;
    }
#endif

    wildzipfn = *argv++;

#ifdef OLD_EXDIR

    if (argc > 0) {
        /* -d:  "name/" immediately after zipfile name is a stored directory to
         * be extracted--do NOT treat as directory to which to extract files
         */
        if (extract_flag && !dflag) {
            create_dirs = !fflag;
            if ((error = checkdir(*argv, ROOT)) > 2)  /* mem, or file in way */
                RETURN(error);
            else if (!error) {   /* it IS extract-to dir, so adjust pointers */
                ++argv;
                --argc;
            }
        }
    }

    filespecs = argc;
    xfilespecs = 0;

    if (argc > 0) {
        char **pp = argv-1;

        pfnames = argv;
        while (*++pp)
            if (strcmp(*pp, "-x") == 0) {
                if (pp > argv) {
                    *pp = 0;           /* terminate pfnames */
                    filespecs = pp - pfnames;
                } else {
                    pfnames = fnames;  /* defaults */
                    filespecs = 0;
                }
                pxnames = pp + 1;      /* excluded-names ptr starts after -x */
                xfilespecs = argc - filespecs - 1;
                break;                 /* skip rest of args */
            }
        process_all_files = FALSE;
    } else
        process_all_files = TRUE;       /* for speed */

#else /* !OLD_EXDIR */

    filespecs = argc;
    xfilespecs = 0;

    if (argc > 0) {
        int in_files=FALSE, in_xfiles=FALSE;
        char **pp = argv-1;

        process_all_files = FALSE;
        pfnames = argv;
        while (*++pp) {
            Trace((stderr, "pp - argv = %d\n", pp-argv));
            if (!dflag && strcmp(*pp, "-d") == 0) {
                dflag = TRUE;
                if (in_files) {      /* ... zipfile ... -d exdir ... */
                    *pp = 0;                    /* terminate pfnames */
                    filespecs = pp - pfnames;
                    in_files = FALSE;
                } else if (in_xfiles) {
                    *pp = 0;                    /* terminate pxnames */
                    xfilespecs = pp - pxnames;
                    /* "... -x xlist -d exdir":  nothing left */
                }
                if (*++pp) {
                    if (extract_flag) {
                        create_dirs = !fflag;
                        if ((error = checkdir(*pp, ROOT)) > 2)
                            RETURN(error);   /* out of memory, or file in way */
                    } else
                        fprintf(stderr,
                          "caution:  not extracting; -d ignored\n");
                } else {
                    fprintf(stderr, "error:  must specify directory to which to\
 extract with -d option\n");
                    break;   /* no arguments left */
                }
                if (pp == argv+1)   /* ... zipfile -d exdir ... */
                    if (pp[1]) {
                        pfnames = pp + 1;  /* argv+2 */
                        filespecs = argc - (pfnames-argv);  /* for now... */
                    } else {
                        process_all_files = TRUE;
                        pfnames = fnames;  /* GRR: necessary? */
                        filespecs = 0;     /* GRR: necessary? */
                        break;
                    }
            } else if (!in_xfiles) {
                if (strcmp(*pp, "-x") == 0) {
                    in_xfiles = TRUE;
                    if (pp == argv || (pp == argv+2 && dflag)) {
                        pfnames = fnames;  /* defaults */
                        filespecs = 0;
                    } else if (in_files) {
                        *pp = 0;                   /* terminate pfnames */
                        filespecs = pp - pfnames;  /* adjust count */
                        in_files = FALSE;
                    }
                    pxnames = pp + 1;  /* excluded-names ptr starts after -x */
                    xfilespecs = argc - (pxnames-argv);  /* anything left... */
                } else
                    in_files = TRUE;
            }
        }
    } else
        process_all_files = TRUE;      /* for speed */

#endif /* ?OLD_EXDIR */

/*---------------------------------------------------------------------------
    Okey dokey, we have everything we need to get started.  Let's roll.
  ---------------------------------------------------------------------------*/

    inbuf = (uch *)malloc(INBUFSIZ + 4);    /* 4 extra for hold[] (below) */
    outbuf = (uch *)malloc(OUTBUFSIZ + 1);  /* 1 extra for string termin. */

    if ((inbuf == (uch *)NULL) || (outbuf == (uch *)NULL)) {
        fprintf(stderr, "error:  can't allocate unzip buffers\n");
        RETURN(PK_MEM);
    }
    hold = inbuf + INBUFSIZ;     /* to check for boundary-spanning signatures */
#ifdef SMALL_MEM
    outbuf2 = outbuf+RAWBUFSIZ;  /* never changes */
#endif

    RETURN(process_zipfiles());  /* keep passing errors back... */

} /* end main() */





/************************/
/*  Function uz_opts()  */
/************************/

int uz_opts(pargc, pargv)
    int *pargc;
    char ***pargv;
{
    char **argv, *s;
    int argc, c, error=FALSE, negative=0;


    argc = *pargc;
    argv = *pargv;

    while (--argc > 0 && (*++argv)[0] == '-') {
        s = argv[0] + 1;
        while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
            switch (c) {
                case ('-'):
                    ++negative;
                    break;
                case ('a'):
                    if (negative) {
                        aflag = MAX(aflag-negative,0);
                        negative = 0;
                    } else
                        ++aflag;
                    break;
                case ('b'):
                    if (negative)
                        negative = 0;   /* do nothing:  "-b" is default */
                    else
                        aflag = 0;
                    break;
                case ('c'):
                    if (negative) {
                        cflag = FALSE, negative = 0;
#ifdef NATIVE
                        aflag = 0;
#endif
                    } else {
                        cflag = TRUE;
#ifdef NATIVE
                        aflag = 2;  /* so you can read it on the screen */
#endif
                    }
                    break;
                case ('d'):  /* arg after zipfn is stored dir, not extract-to */
#ifdef OLD_EXDIR
                    if (negative)
                        dflag = FALSE, negative = 0;
                    else
                        dflag = TRUE;
#endif
                    break;
                case ('e'):    /* just ignore -e, -x options (extract) */
                    break;
                case ('f'):    /* "freshen" (extract only newer files) */
                    if (negative)
                        fflag = uflag = FALSE, negative = 0;
                    else
                        fflag = uflag = TRUE;
                    break;
                case ('j'):    /* junk pathnames/directory structure */
                    if (negative)
                        jflag = FALSE, negative = 0;
                    else
                        jflag = TRUE;
                    break;
                case ('l'):
                    if (negative) {
                        vflag = MAX(vflag-negative,0);
                        negative = 0;
                    } else
                        ++vflag;
                    break;
                case ('n'):    /* don't overwrite any files */
                    if (negative)
                        overwrite_none = FALSE, negative = 0;
                    else
                        overwrite_none = TRUE;
                    break;
                case ('o'):    /* OK to overwrite files without prompting */
                    if (negative) {
                        overwrite_all = MAX(overwrite_all-negative,0);
                        force_flag = MAX(force_flag-negative,0);
                        negative = 0;
                    } else {
                        ++overwrite_all;
                        ++force_flag;  /* (share -o for now) force to cont. */
                    }
                    break;
                case ('p'):    /* pipes:  stdout, no translation, no messages */
                    if (negative) {
                        cflag = FALSE;
                        qflag = MAX(qflag-999,0);
                        negative = 0;
                    } else {
                        aflag = 0;
                        cflag = TRUE;
                        qflag += 999;
                    }
                    break;
                case ('q'):    /* quiet:  fewer comments/messages */
                    if (negative) {
                        qflag = MAX(qflag-negative,0);
                        negative = 0;
                    } else
                        ++qflag;
                    break;
#ifdef DOS_NT_OS2
                case ('s'):    /* spaces in filenames:  allow by default */
                    if (negative)
                        sflag = FALSE, negative = 0;
                    else
                        sflag = TRUE;
                    break;
#endif
                case ('t'):
                    if (negative)
                        tflag = FALSE, negative = 0;
                    else
                        tflag = TRUE;
                    break;
                case ('U'):    /* allow Uppercase (don't make all lowercase) */
                    if (negative)
                        U_flag = FALSE, negative = 0;
                    else
                        U_flag = TRUE;
                    break;
                case ('u'):    /* update (extract only new and newer files) */
                    if (negative)
                        uflag = FALSE, negative = 0;
                    else
                        uflag = TRUE;
                    break;
                case ('V'):    /* Version (retain VMS/DEC-20 file versions) */
                    if (negative)
                        V_flag = FALSE, negative = 0;
                    else
                        V_flag = TRUE;
                    break;
                case ('v'):    /* verbose */
                    if (negative) {
                        vflag = MAX(vflag-negative,0);
                        negative = 0;
                    } else if (vflag)
                        ++vflag;
                    else
                        vflag = 2;
                    break;
#ifdef VMS
                case ('X'):   /* restore owner/protection info (need privs?) */
                    if (negative)
                        secinf = FALSE, negative = 0;
                    else
                        secinf = TRUE;
                    break;
#endif /* VMS */
                case ('x'):    /* extract:  default */
                    break;
                case ('z'):    /* display only the archive comment */
                    if (negative) {
                        zflag -= negative;
                        negative = 0;
                    } else
                        ++zflag;
                    break;
#ifdef DOS_NT_OS2
                case ('$'):
                    if (negative) {
                        volflag = MAX(volflag-negative,0);
                        negative = 0;
                    } else
                        ++volflag;
                    break;
#endif
                default:
                    error = TRUE;
                    break;

            } /* end switch */
        } /* end while (not end of argument string) */
    } /* end while (not done with switches) */

/*---------------------------------------------------------------------------
    Check for nonsensical combinations of options.  [Isn't the -a option use-
    ful when listing the directory (i.e., for reading zipfile comments)?  It
    is only a modifier, so perhaps it should not be included in the test.]
  ---------------------------------------------------------------------------*/

    if ((cflag && tflag) || (cflag && uflag) || (cflag && vflag) ||
        (tflag && uflag) || (tflag && vflag) || (uflag && vflag) ||
        (fflag && overwrite_none)) {
        fprintf(stderr, "error:\
  -fn or any combination of -c, -l, -p, -t, -u and -v options invalid\n");
        error = TRUE;
    }
    if (aflag > 2)
        aflag = 2;
#if 0
    if ((aflag && tflag) || (aflag && vflag))   /* -a makes no sense */
        aflag = 0;
#endif
    if (overwrite_all && overwrite_none) {
        fprintf(stderr, "caution:  both -n and -o specified; ignoring -o\n");
        overwrite_all = FALSE;
    }

#ifdef SFX
    if (error)
#else
    if ((argc-- == 0) || error)
#endif
    {
        *pargc = argc;
        *pargv = argv;
        return usage(error);
    }

    if (cflag || tflag || vflag)
        extract_flag = FALSE;
    else
        extract_flag = TRUE;

    *pargc = argc;
    *pargv = argv;
    return 0;

} /* end function uz_opts() */





/**********************/
/*  Function usage()  */
/**********************/

#ifdef SFX

int usage(error)   /* return PK-type error code */
    int error;
{
    FILE *usagefp;

    if (error)
        usagefp = (FILE *)stderr;
    else
        usagefp = (FILE *)stdout;

    fprintf(usagefp, "\
UnZipSFX %s, by Info-ZIP (zip-bugs@wkuvx1.wku.edu).\n\n",
      UZ_VERSION);
#ifndef RELEASE
    fprintf(usagefp, "\
    THIS IS STILL A BETA VERSION OF UNZIPSFX -- DO NOT DISTRIBUTE.\n\n");
#endif

    if (error)
        return PK_PARAM;
    else
        return PK_COOL;     /* just wanted usage screen: no error */

} /* end function usage() */





#else /* !SFX */

int usage(error)   /* return PK-type error code */
    int error;
{
#ifdef VMS
#  define QUOT '\"'
#  define QUOTS "\""
#  define EXAMPLE2 "vms.c"
#  define EXAMPLE1 \
"unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS"
#else
#  define QUOT ' '
#  define QUOTS ""
#  define EXAMPLE2 "ReadMe"
#  define EXAMPLE1 \
"unzip -p foo | more  => send contents of foo.zip via pipe into program more"
#endif

#ifdef DOS_NT_OS2
    char *loc_str = " -$  label removables (-$$ => fixed disks)";
    char *loc2str = "\
                                             -s  spaces in filenames => '_'\n";
#else /* !DOS_NT_OS2 */
#ifdef VMS
    char *loc_str = "\"-X\" restore owner/protection info";
    char *loc2str = "\n";
#else
    char *loc_str = "";   /* Unix, Amiga, Mac, etc. */
 /* char *loc_str = " -X  restore UID/GID info";    Unix version, in 5.2 */
    char *loc2str = "";
#endif
#endif /* ?DOS_NT_OS2 */

    FILE *usagefp;


/*---------------------------------------------------------------------------
    If user requested usage, send it to stdout; else send to stderr.
  ---------------------------------------------------------------------------*/

    if (error)
        usagefp = (FILE *)stderr;
    else
        usagefp = (FILE *)stdout;

/*---------------------------------------------------------------------------
    Print either ZipInfo usage or UnZip usage, depending on incantation.
    (Strings must be no longer than 512 bytes for Turbo C, apparently.)
  ---------------------------------------------------------------------------*/

    if (zipinfo_mode) {

#ifndef NO_ZIPINFO

        fprintf(usagefp, "\
ZipInfo %s, by Newtware and the fine folks at Info-ZIP.\n\
\n\
List name, date/time, attribute, size, compression method, etc., about files\n\
in list (excluding those in xlist) contained in the specified .zip archive(s).\
\n\"file[.zip]\" may be a wildcard name containing *, ?, [] (e.g., \"[a-j]*\
.zip\").\n\n\
   usage:  zipinfo [-12smlvhtz] file[.zip] [list...] [-x xlist...]\n\
      or:  unzip %s-Z%s [-12smlvhtz] file[.zip] [list...] [-x xlist...]\n",
          ZI_VERSION, QUOTS,QUOTS);
        fprintf(usagefp, "\nmain\
 listing-format options:             -s  short Unix \"ls -l\" format (def.)\n\
  -1  filenames ONLY, one per line       -m  medium Unix \"ls -l\" format\n\
  -2  just filenames but allow -h/-t/-z  -l  long Unix \"ls -l\" format\n\
                                         -v  verbose, multi-page format\n\
miscellaneous options:\n  \
-h  print header line      -t  print totals for files listed or for all files\n\
  -z  print zipfile comment  -x  exclude filenames that follow from listing\n");
/* -p  disable automatic \"more\" function (for pipes) [not implemented]\n"); */
#ifdef VMS
        fprintf(usagefp, "\nRemember that non-lowercase filespecs must be\
 quoted in VMS (e.g., \"Makefile\").\n");
#endif

#endif /* !NO_ZIPINFO */

    } else {   /* UnZip mode */

        fprintf(usagefp, "\
UnZip %s, by Info-ZIP.  Portions (c) 1989 by S. H. Smith.\n\
Send bug reports to authors at zip-bugs@wkuvx1.wku.edu; see README for details.\
\n\n", UZ_VERSION);
#ifndef RELEASE
        fprintf(usagefp, "\
        THIS IS STILL A BETA VERSION OF UNZIP -- DO NOT DISTRIBUTE.\n\n");
#endif
        fprintf(usagefp, "\
Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]\n \
 Default action is to extract files in list, except those in xlist, to exdir;\n\
  file[.zip] may be a wildcard.  %s\n\n",
#ifdef NO_ZIPINFO
          "", "(ZipInfo mode is disabled in this version.)");
#else
#ifdef VMS
          "[-Z] ", "\"-Z\" => ZipInfo mode (`unzip \"-Z\"' for usage).");
#else
          "[-Z] ", "-Z => ZipInfo mode (\"unzip -Z\" for usage).");
#endif
#endif /* ?NO_ZIPINFO */

        fprintf(usagefp, "\
  -c  extract files to stdout/screen (CRT)   -l  list files (short format)\n\
  -p  extract files to pipe, no messages     -v  list files (verbose format)\n\
  -f  freshen existing files, create none    -t  test compressed archive data\n\
  -u  update files, create if necessary      -z  display archive comment\n\
  -x  exclude files which follow (in xlist)  -d  extract files into exdir\n\n");

        fprintf(usagefp, "\
modifiers:                                   -q  quiet mode (-qq => quieter)\n\
  -n  never overwrite existing files         -a  auto-convert any text files\n\
  -o  overwrite files WITHOUT prompting      -aa treat ALL files as text\n\
  -j  junk paths (don't make directories)   %c-U%c don't make names lowercase\n\
 %-42s %c-V%c retain VMS version numbers\n%s",
          QUOT,QUOT, loc_str, QUOT,QUOT, loc2str);

        fprintf(usagefp, "\
Examples (see unzip.doc for more info):\n\
  unzip data1 -x joe   => extract all files except joe from zipfile data1.zip\n\
  %s\n\
  unzip -fo foo %-6s => quietly replace existing %s if archive file newer\n",
          EXAMPLE1, EXAMPLE2,EXAMPLE2);

    }

    if (error)
        return PK_PARAM;
    else
        return PK_COOL;     /* just wanted usage screen: no error */

} /* end function usage() */

#endif /* ?SFX */
#endif /* ?MSWIN */




/*********************************/
/*  Function process_zipfiles()  */
/*********************************/

int process_zipfiles()    /* return PK-type error code */
{
    char *lastzipfn = NULL;
    int error=0, error_in_archive=0;
    int num_win_files, num_lose_files, num_warn_files;
    int num_miss_dirs, num_miss_files;


/*---------------------------------------------------------------------------
    Start by constructing the various PK signature strings.
  ---------------------------------------------------------------------------*/

    local_hdr_sig[0]  /* = extd_local_sig[0] */  = '\120';   /* ASCII 'P', */
    central_hdr_sig[0] = end_central_sig[0] = '\120';        /* not EBCDIC */

    strcpy(local_hdr_sig+1, LOCAL_HDR_SIG);
    strcpy(central_hdr_sig+1, CENTRAL_HDR_SIG);
    strcpy(end_central_sig+1, END_CENTRAL_SIG);
/*  strcpy(extd_local_sig+1, EXTD_LOCAL_SIG);   still to be used in multi? */

/*---------------------------------------------------------------------------
    Match (possible) wildcard zipfile specification with existing files and
    attempt to process each.  If no hits, try again after appending ".zip"
    suffix.  If still no luck, give up.
  ---------------------------------------------------------------------------*/

#ifdef SFX
    if ((error = do_seekable(0)) != IZ_DIR && error > error_in_archive)
        error_in_archive = error;

#else /* !SFX */
    num_win_files = num_lose_files = num_warn_files = 0;
    num_miss_dirs = num_miss_files = 0;

    while ((zipfn = do_wild(wildzipfn)) != NULL) {
        Trace((stderr, "do_wild( %s ) returns %s\n", wildzipfn, zipfn));

        lastzipfn = zipfn;

        if (!qflag  &&  error != PK_NOZIP  &&
            (num_win_files+num_lose_files+num_warn_files+num_miss_files) > 0)
            printf("\n");
        FFLUSH(stdout);

        if ((error = do_seekable(0)) == PK_WARN)
            ++num_warn_files;
        else if (error == IZ_DIR)
            ++num_miss_dirs;
        else if (error == PK_NOZIP)
            ++num_miss_files;
        else if (error)
            ++num_lose_files;
        else
            ++num_win_files;

        if (error != IZ_DIR && error > error_in_archive)
            error_in_archive = error;
        Trace((stderr, "do_seekable(0) returns %d\n", error));

    } /* end while-loop (wildcard zipfiles) */

    if ((num_win_files + num_warn_files + num_lose_files) == 0  &&
        (num_miss_dirs + num_miss_files) == 1  &&  lastzipfn != NULL)
    {
        num_miss_dirs = num_miss_files = 0;
        if (error_in_archive == PK_NOZIP)
            error_in_archive = PK_COOL;
        strcat((zipfn = lastzipfn), ZSUFX);

        if ((error = do_seekable(1)) == PK_WARN)
            ++num_warn_files;
        else if (error == IZ_DIR)
            ++num_miss_dirs;
        else if (error == PK_NOZIP)
            /* if increment again => bug: "1 file had no zipfile directory." */
            /* ++num_miss_files */ ;
        else if (error)
            ++num_lose_files;
        else
            ++num_win_files;

        if (error > error_in_archive)
            error_in_archive = error;
        Trace((stderr, "do_seekable(1) returns %d\n", error));
    }
#endif /* ?SFX */

    FFLUSH(stdout);
    FFLUSH(stderr);

#ifndef SFX
    if (num_miss_dirs + num_miss_files + num_lose_files + num_warn_files > 0
        || num_win_files != 1)
        fprintf(stderr, "\n");
    if ((num_win_files > 1) || (num_win_files == 1 &&
        num_miss_dirs + num_miss_files + num_lose_files + num_warn_files > 0))
        fprintf(stderr, "%d archive%s successfully processed.\n",
          num_win_files, (num_win_files == 1)? " was" : "s were");
    if (num_warn_files > 0)
        fprintf(stderr, "%d archive%s had warnings but no fatal errors.\n",
          num_warn_files, (num_warn_files == 1)? "" : "s");
    if (num_lose_files > 0)
        fprintf(stderr, "%d archive%s had fatal errors.\n",
          num_lose_files, (num_lose_files == 1)? "" : "s");
    if (num_miss_files > 0)
        fprintf(stderr, "%d file%s had no zipfile directory.\n",
          num_miss_files, (num_miss_files == 1)? "" : "s");
    if (num_miss_dirs == 1)
        fprintf(stderr, "1 \"zipfile\" was a directory.\n");
    else if (num_miss_dirs > 0)
        fprintf(stderr, "%d \"zipfiles\" were directories.\n", num_miss_dirs);
    if (num_win_files + num_lose_files + num_warn_files == 0)
        fprintf(stderr, "No zipfiles found.\n");
#endif /* !SFX */

    /* free allocated memory */
    inflate_free();
    checkdir((char *)NULL, END);
#ifndef SMALL_MEM
    if (outbuf2)
        free(outbuf2);   /* malloc'd ONLY if unshrink and -a */
#endif
    free(outbuf);
    free(inbuf);

    return error_in_archive;

} /* end function process_zipfiles() */





/****************************/
/*  Function do_seekable()  */
/****************************/

int do_seekable(lastchance)    /* return PK-type error code */
    int lastchance;
{
    int error=0, error_in_archive, maybe_exe=FALSE;
    static int no_ecrec = FALSE;


/*---------------------------------------------------------------------------
    Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
    which would corrupt the bit streams.
  ---------------------------------------------------------------------------*/

    if (SSTAT(zipfn, &statbuf) || (error = S_ISDIR(statbuf.st_mode)) != 0) {
        if (lastchance)
            if (no_ecrec)
                fprintf(stderr, "%s:  can't find zipfile directory in %s,\n\
        %sand can't find %s, period.\n", zipinfo_mode? "zipinfo" : "unzip",
                  wildzipfn, zipinfo_mode? "  " : "", zipfn);
            else
                fprintf(stderr,
                  "%s:  can't find either %s or %s, so there.\n",
                  zipinfo_mode? "zipinfo" : "unzip", wildzipfn, zipfn);
        return error? IZ_DIR : PK_NOZIP;
    }
    ziplen = statbuf.st_size;

#if defined(UNIX) || defined(DOS_NT_OS2)  /* no extension on Unix exec's: */
    if (statbuf.st_mode & S_IEXEC)      /* might find zip, not zip.zip; etc. */
        maybe_exe = TRUE;               /* (for other OS's, some executables */
#endif                                  /* can be self-extracting archives) */

#ifdef VMS
    if (check_format())      /* check for variable-length format */
        return PK_ERR;
#endif

    if (open_input_file())   /* this should never happen, given */
        return PK_NOZIP;     /*  the stat() test above, but... */

/*---------------------------------------------------------------------------
    Find and process the end-of-central-directory header.  UnZip need only
    check last 65557 bytes of zipfile:  comment may be up to 65535, end-of-
    central-directory record is 18 bytes, and signature itself is 4 bytes;
    add some to allow for appended garbage.  Since ZipInfo is often used as
    a debugging tool, search the whole zipfile if zipinfo_mode is true.
  ---------------------------------------------------------------------------*/

    cur_zipfile_bufstart = 0;
    inptr = inbuf;

    if (!qflag && !zipinfo_mode)
        printf("Archive:  %s\n", zipfn);

    if ((
#ifndef NO_ZIPINFO
         zipinfo_mode &&
          ((error_in_archive = find_end_central_dir(ziplen)) != 0 ||
          (error_in_archive = zi_end_central()) > PK_WARN))
        || (!zipinfo_mode &&
#endif
          ((error_in_archive = find_end_central_dir(MIN(ziplen,66000L))) != 0 ||
          (error_in_archive = uz_end_central()) > PK_WARN)))
    {
        close(zipfd);
#ifdef SFX
        return error_in_archive;
#else
        if (maybe_exe)
            fprintf(stderr, "note:  %s may be an executable, not an archive\n",
              zipfn);
        if (lastchance)
            return error_in_archive;
        else {
            no_ecrec = TRUE;    /* assume we found wrong file:  e.g., */
            return PK_NOZIP;    /*  unzip instead of unzip.zip */
        }
#endif /* ?SFX */
    }

    if ((zflag > 0) && !zipinfo_mode) {   /* in unzip, zflag = comment ONLY */
        close(zipfd);
        return error_in_archive;
    }

/*---------------------------------------------------------------------------
    Test the end-of-central-directory info for incompatibilities (multi-disk
    archives) or inconsistencies (missing or extra bytes in zipfile).
  ---------------------------------------------------------------------------*/

    error = !zipinfo_mode && (ecrec.number_this_disk == 1) &&
            (ecrec.num_disk_with_start_central_dir == 1);

    if (zipinfo_mode &&
        ecrec.number_this_disk != ecrec.num_disk_with_start_central_dir)
    {
        fprintf(stderr, "\n\
     Zipfile is part of a multi-disk archive, and this is not the disk on\n\
     which the central zipfile directory begins.\n");
        error_in_archive = PK_FIND;

    } else if (!zipinfo_mode && !error && ecrec.number_this_disk != 0) {

        fprintf(stderr, "\nerror [%s]:  zipfile is part of multi-disk archive\n\
  (sorry, not yet supported).\n", zipfn);
        error_in_archive = PK_FIND;

    } else {   /* this is a (relatively) normal zipfile:  process normally */

        if (error) {
            fprintf(stderr, "\n\
     Warning:  zipfile claims to be second disk of a two-part archive;\n\
     attempting to process anyway.  If no further errors occur, this\n\
     archive was probably created by PAK v2.51 or earlier.  This bug\n\
     was reported to NoGate in March 1991 and was supposed to have been\n\
     fixed by mid-1991; as of mid-1992 it still hadn't been.  (If fur-\n\
     ther errors do occur, archive was probably created by PKZIP 2.04c\n\
     or later; UnZip does not yet support multi-part archives.)\n\n");
            error_in_archive = PK_WARN;
        }
        if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < (LONGINT)0) {
            fprintf(stderr, "error [%s]:  missing %ld bytes in zipfile\n\
  (attempting to process anyway)\n", zipfn, (long)(-extra_bytes));
            error_in_archive = PK_ERR;
        } else if (extra_bytes > 0) {
            if ((ecrec.offset_start_central_directory == 0) &&
                (ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
            {
                fprintf(stderr, "error [%s]:  NULL central directory offset\n\
  (attempting to process anyway)\n", zipfn);
                ecrec.offset_start_central_directory = extra_bytes;
                extra_bytes = 0;
                error_in_archive = PK_ERR;
            } else {
#ifndef SFX
                fprintf(stderr, "warning [%s]:  extra %ld bytes at beginning\
 or within zipfile\n  (attempting to process anyway)\n", zipfn,
                  (long)extra_bytes);
                error_in_archive = PK_WARN;
#endif
            }
        }

    /*-----------------------------------------------------------------------
        Check for empty zipfile and exit now if so.
      -----------------------------------------------------------------------*/

        if (expect_ecrec_offset == 0L  &&  ecrec.size_central_directory == 0) {
            if (zipinfo_mode)
                printf("%sEmpty zipfile.\n", lflag>9 ? "\n  " : "");
            else
                fprintf(stderr, "warning [%s]:  zipfile is empty\n", zipfn);
            close(zipfd);
            return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN;
        }

    /*-----------------------------------------------------------------------
        Compensate for missing or extra bytes, and seek to where the start
        of central directory should be.  If header not found, uncompensate
        and try again (necessary for at least some Atari archives created
        with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
      -----------------------------------------------------------------------*/

        LSEEK( ecrec.offset_start_central_directory )
        if ((error = readbuf(sig, 4)) < 0) {
            close(zipfd);
            return PK_ERR;  /* file may be locked, or possibly disk error(?) */
        }
        if ((error == 0) || strncmp(sig, central_hdr_sig, 4)) {
            long tmp = extra_bytes;

            extra_bytes = 0;
            LSEEK( ecrec.offset_start_central_directory )
            if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
                fprintf(stderr,
                  "error [%s]:  start of central directory not found;\n\
  zipfile corrupt.\n%s", zipfn, ReportMsg);
                close(zipfd);
                return PK_BADERR;
            }
            fprintf(stderr,
              "error [%s]:  reported length of central directory is\n\
  %ld bytes too long (Atari STZIP zipfile?  J.H.Holm ZIPSPLIT 1.1\n\
  zipfile?).  Compensating...\n", zipfn, -tmp);
            error_in_archive = PK_ERR;
        }

    /*-----------------------------------------------------------------------
        Seek to the start of the central directory one last time, since we
        have just read the first entry's signature bytes; then list, extract
        or test member files as instructed, and close the zipfile.
      -----------------------------------------------------------------------*/

        Trace((stderr, "about to extract/list files (error = %d)\n",
          error_in_archive));

        LSEEK( ecrec.offset_start_central_directory )

#ifndef NO_ZIPINFO
        if (zipinfo_mode) {
            error = zipinfo();                     /* ZIPINFO 'EM */
            if (lflag > 9)
                printf("\n");
        } else
#endif
            if (vflag)
                error = list_files();              /* LIST 'EM */
            else
                error = extract_or_test_files();   /* EXTRACT OR TEST 'EM */

        Trace((stderr, "done with extract/list files (error = %d)\n", error));

        if (error > error_in_archive)   /* don't overwrite stronger error */
            error_in_archive = error;   /*  with (for example) a warning */
    }

    close(zipfd);
    return error_in_archive;

} /* end function do_seekable() */





/*****************************/
/* Function uz_end_central() */
/*****************************/

int uz_end_central()    /* return PK-type error code */
{
    int error = PK_COOL;


/*---------------------------------------------------------------------------
    Get the zipfile comment (up to 64KB long), if any, and print it out.
    Then position the file pointer to the beginning of the central directory
    and fill buffer.
  ---------------------------------------------------------------------------*/

#ifdef MSWIN
    cchComment = ecrec.zipfile_comment_length; /* save for comment button */
    if (ecrec.zipfile_comment_length && (zflag > 0))
#else /* !MSWIN */
    if (ecrec.zipfile_comment_length && (zflag > 0 || (zflag == 0 && !qflag)))
#endif /* ?MSWIN */
    {
#if 0
#ifndef MSWIN
        if (zflag == 0)       (add "&& single_zipfile" perhaps; unnecessary with
            printf("[%s] comment:\n", zipfn);  multiple zipfiles: "Archive:...")
#endif /* !MSWIN */
#endif /* 0 */
        if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
            fprintf(stderr, "\ncaution:  zipfile comment truncated\n");
            error = PK_WARN;
        }
    }
    return error;

} /* end function uz_end_central() */





/**************************************/
/*  Function process_cdir_file_hdr()  */
/**************************************/

int process_cdir_file_hdr()    /* return PK-type error code */
{
    int error;


/*---------------------------------------------------------------------------
    Get central directory info, save host and method numbers, and set flag
    for lowercase conversion of filename, depending on the OS from which the
    file is coming.
  ---------------------------------------------------------------------------*/

    if ((error = get_cdir_file_hdr()) != 0)
        return error;

    pInfo->hostnum = MIN(crec.version_made_by[1], NUM_HOSTS);
/*  extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */

    pInfo->lcflag = 0;
    if (!U_flag)   /* as long as user hasn't specified case-preservation */
        switch (pInfo->hostnum) {
            case FS_FAT_:     /* PKZIP and zip -k store in uppercase */
            case ATARI_:      /* MS-DOS filesystem */
            case CPM_:        /* like MS-DOS, right? */
            case VM_CMS_:     /* all caps? */
            case TOPS20_:
        /*  case Z_SYSTEM_:   ? */
        /*  case QDOS_:       ? */
                pInfo->lcflag = 1;   /* convert filename to lowercase */
                break;

        /*  case VMS_:   Info-ZIP's VMS Zip converts filenames to lowercase */
            default:     /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, */
                break;   /*  (Z_SYSTEM_):  no conversion */
        }

    /* do Amigas (AMIGA_) also have volume labels? */
    if (IS_VOLID(crec.external_file_attributes) &&
        (pInfo->hostnum == FS_FAT_ || pInfo->hostnum == FS_HPFS_ ||
         pInfo->hostnum == FS_NTFS_ || pInfo->hostnum == ATARI_))
    {
        pInfo->vollabel = TRUE;
        pInfo->lcflag = 0;        /* preserve case of volume labels */
    } else
        pInfo->vollabel = FALSE;

    return PK_COOL;

} /* end function process_cdir_file_hdr() */





/***************************************/
/*  Function process_local_file_hdr()  */
/***************************************/

int process_local_file_hdr()    /* return PK-type error code */
{
    local_byte_hdr byterec;


/*---------------------------------------------------------------------------
    Read the next local file header and do any necessary machine-type con-
    versions (byte ordering, structure padding compensation--do so by copy-
    ing the data from the array into which it was read (byterec) to the
    usable struct (lrec)).
  ---------------------------------------------------------------------------*/

    if (readbuf((char *)byterec, LREC_SIZE) <= 0)
        return PK_EOF;

    lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
    lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];

    lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
    lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
    lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
    lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
    lrec.crc32 = makelong(&byterec[L_CRC32]);
    lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]);
    lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
    lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
    lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);

    csize = (long) lrec.csize;
    ucsize = (long) lrec.ucsize;

    if ((lrec.general_purpose_bit_flag & 8) != 0) {
        /* can't trust local header, use central directory: */
        lrec.crc32 = pInfo->crc;
        csize = (long)(lrec.csize = pInfo->compr_size);
    }

    return PK_COOL;

} /* end function process_local_file_hdr() */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.