| 
							- /*
 -   Copyright (c) 1990-2009 Info-ZIP.  All rights reserved.
 - 
 -   See the accompanying file LICENSE, version 2009-Jan-02 or later
 -   (the contents of which are also included in unzip.h) for terms of use.
 -   If, for some reason, all these files are missing, the Info-ZIP license
 -   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
 - */
 - /*---------------------------------------------------------------------------
 - 
 -   process.c
 - 
 -   This file contains the top-level routines for processing multiple zipfiles.
 - 
 -   Contains:  process_zipfiles()
 -              free_G_buffers()
 -              do_seekable()
 -              file_size()
 -              rec_find()
 -              find_ecrec64()
 -              find_ecrec()
 -              process_zip_cmmnt()
 -              process_cdir_file_hdr()
 -              get_cdir_ent()
 -              process_local_file_hdr()
 -              getZip64Data()
 -              ef_scan_for_izux()
 -              getRISCOSexfield()
 - 
 -   ---------------------------------------------------------------------------*/
 - 
 - 
 - #define UNZIP_INTERNAL
 - #include "unzip.h"
 - #ifdef WINDLL
 - #  ifdef POCKET_UNZIP
 - #    include "wince/intrface.h"
 - #  else
 - #    include "windll/windll.h"
 - #  endif
 - #endif
 - #if defined(DYNALLOC_CRCTAB) || defined(UNICODE_SUPPORT)
 - #  include "crc32.h"
 - #endif
 - 
 - #include "unzipfx/appDetails.h"
 - 
 - static int    do_seekable        OF((__GPRO__ int lastchance));
 - #ifdef DO_SAFECHECK_2GB
 - # ifdef USE_STRM_INPUT
 - static zoff_t file_size          OF((FILE *file));
 - # else
 - static zoff_t file_size          OF((int fh));
 - # endif
 - #endif /* DO_SAFECHECK_2GB */
 - static int    rec_find           OF((__GPRO__ zoff_t, char *, int));
 - static int    find_ecrec64       OF((__GPRO__ zoff_t searchlen));
 - static int    find_ecrec         OF((__GPRO__ zoff_t searchlen));
 - static int    process_zip_cmmnt  OF((__GPRO));
 - static int    get_cdir_ent       OF((__GPRO));
 - #ifdef IZ_HAVE_UXUIDGID
 - static int    read_ux3_value     OF((ZCONST uch *dbuf, unsigned uidgid_sz,
 -                                      ulg *p_uidgid));
 - #endif /* IZ_HAVE_UXUIDGID */
 - 
 - 
 - static ZCONST char Far CannotAllocateBuffers[] =
 -   "error:  cannot allocate unzip buffers\n";
 - 
 - #ifdef SFX
 -    static ZCONST char Far CannotFindMyself[] =
 -      "unzipsfx:  cannot find myself! [%s]\n";
 - # ifdef CHEAP_SFX_AUTORUN
 -    static ZCONST char Far AutorunPrompt[] =
 -      "\nAuto-run command: %s\nExecute this command? [y/n] ";
 -    static ZCONST char Far NotAutoRunning[] =
 -      "Not executing auto-run command.";
 - # endif
 - 
 - #else /* !SFX */
 -    /* process_zipfiles() strings */
 - # if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
 -      static ZCONST char Far WarnInvalidTZ[] =
 -        "Warning: TZ environment variable not found, cannot use UTC times!!\n";
 - # endif
 - # if !(defined(UNIX) || defined(AMIGA))
 -    static ZCONST char Far CannotFindWildcardMatch[] =
 -      "%s:  cannot find any matches for wildcard specification \"%s\".\n";
 - # endif /* !(UNIX || AMIGA) */
 -    static ZCONST char Far FilesProcessOK[] =
 -      "%d archive%s successfully processed.\n";
 -    static ZCONST char Far ArchiveWarning[] =
 -      "%d archive%s had warnings but no fatal errors.\n";
 -    static ZCONST char Far ArchiveFatalError[] =
 -      "%d archive%s had fatal errors.\n";
 -    static ZCONST char Far FileHadNoZipfileDir[] =
 -      "%d file%s had no zipfile directory.\n";
 -    static ZCONST char Far ZipfileWasDir[] = "1 \"zipfile\" was a directory.\n";
 -    static ZCONST char Far ManyZipfilesWereDir[] =
 -      "%d \"zipfiles\" were directories.\n";
 -    static ZCONST char Far NoZipfileFound[] = "No zipfiles found.\n";
 - 
 -    /* do_seekable() strings */
 - # ifdef UNIX
 -    static ZCONST char Far CannotFindZipfileDirMsg[] =
 -      "%s:  cannot find zipfile directory in one of %s or\n\
 -         %s%s.zip, and cannot find %s, period.\n";
 -    static ZCONST char Far CannotFindEitherZipfile[] =
 -      "%s:  cannot find or open %s, %s.zip or %s.\n";
 - # else /* !UNIX */
 -    static ZCONST char Far CannotFindZipfileDirMsg[] =
 -      "%s:  cannot find zipfile directory in %s,\n\
 -         %sand cannot find %s, period.\n";
 - # ifdef VMS
 -    static ZCONST char Far CannotFindEitherZipfile[] =
 -      "%s:  cannot find %s (%s).\n";
 - # else /* !VMS */
 -    static ZCONST char Far CannotFindEitherZipfile[] =
 -      "%s:  cannot find either %s or %s.\n";
 - # endif /* ?VMS */
 - # endif /* ?UNIX */
 -    extern ZCONST char Far Zipnfo[];       /* in unzip.c */
 - #ifndef WINDLL
 -    static ZCONST char Far Unzip[] = "unzip";
 - #else
 -    static ZCONST char Far Unzip[] = "UnZip DLL";
 - #endif
 - #ifdef DO_SAFECHECK_2GB
 -    static ZCONST char Far ZipfileTooBig[] =
 -      "Trying to read large file (> 2 GiB) without large file support\n";
 - #endif /* DO_SAFECHECK_2GB */
 -    static ZCONST char Far MaybeExe[] =
 -      "note:  %s may be a plain executable, not an archive\n";
 -    static ZCONST char Far CentDirNotInZipMsg[] = "\n\
 -    [%s]:\n\
 -      Zipfile is disk %lu of a multi-disk archive, and this is not the disk on\n\
 -      which the central zipfile directory begins (disk %lu).\n";
 -    static ZCONST char Far EndCentDirBogus[] =
 -      "\nwarning [%s]:  end-of-central-directory record claims this\n\
 -   is disk %lu but that the central directory starts on disk %lu; this is a\n\
 -   contradiction.  Attempting to process anyway.\n";
 - # ifdef NO_MULTIPART
 -    static ZCONST char Far NoMultiDiskArcSupport[] =
 -      "\nerror [%s]:  zipfile is part of multi-disk archive\n\
 -   (sorry, not yet supported).\n";
 -    static ZCONST char Far MaybePakBug[] = "warning [%s]:\
 -   zipfile claims to be 2nd disk of a 2-part archive;\n\
 -   attempting to process anyway.  If no further errors occur, this archive\n\
 -   was probably created by PAK v2.51 or earlier.  This bug was reported to\n\
 -   NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\
 -   of mid-1992 it still hadn't been.  (If further errors do occur, archive\n\
 -   was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\
 -   multi-part archives.)\n";
 - # else
 -    static ZCONST char Far MaybePakBug[] = "warning [%s]:\
 -   zipfile claims to be last disk of a multi-part archive;\n\
 -   attempting to process anyway, assuming all parts have been concatenated\n\
 -   together in order.  Expect \"errors\" and warnings...true multi-part support\
 - \n  doesn't exist yet (coming soon).\n";
 - # endif
 -    static ZCONST char Far ExtraBytesAtStart[] =
 -      "warning [%s]:  %s extra byte%s at beginning or within zipfile\n\
 -   (attempting to process anyway)\n";
 - #endif /* ?SFX */
 - 
 - #if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO))
 -    static ZCONST char Far LogInitline[] = "Archive:  %s\n";
 - #endif
 - 
 - static ZCONST char Far MissingBytes[] =
 -   "error [%s]:  missing %s bytes in zipfile\n\
 -   (attempting to process anyway)\n";
 - static ZCONST char Far NullCentDirOffset[] =
 -   "error [%s]:  NULL central directory offset\n\
 -   (attempting to process anyway)\n";
 - static ZCONST char Far ZipfileEmpty[] = "warning [%s]:  zipfile is empty\n";
 - static ZCONST char Far CentDirStartNotFound[] =
 -   "error [%s]:  start of central directory not found;\n\
 -   zipfile corrupt.\n%s";
 - static ZCONST char Far Cent64EndSigSearchErr[] =
 -   "fatal error: read failure while seeking for End-of-centdir-64 signature.\n\
 -   This zipfile is corrupt.\n";
 - static ZCONST char Far Cent64EndSigSearchOff[] =
 -   "error: End-of-centdir-64 signature not where expected (prepended bytes?)\n\
 -   (attempting to process anyway)\n";
 - #ifndef SFX
 -    static ZCONST char Far CentDirTooLong[] =
 -      "error [%s]:  reported length of central directory is\n\
 -   %s bytes too long (Atari STZip zipfile?  J.H.Holm ZIPSPLIT 1.1\n\
 -   zipfile?).  Compensating...\n";
 -    static ZCONST char Far CentDirEndSigNotFound[] = "\
 -   End-of-central-directory signature not found.  Either this file is not\n\
 -   a zipfile, or it constitutes one disk of a multi-part archive.  In the\n\
 -   latter case the central directory and zipfile comment will be found on\n\
 -   the last disk(s) of this archive.\n";
 - #else /* SFX */
 -    static ZCONST char Far CentDirEndSigNotFound[] =
 -      "  End-of-central-directory signature not found.\n";
 - #endif /* ?SFX */
 - #ifdef TIMESTAMP
 -    static ZCONST char Far ZipTimeStampFailed[] =
 -      "warning:  cannot set time for %s\n";
 -    static ZCONST char Far ZipTimeStampSuccess[] =
 -      "Updated time stamp for %s.\n";
 - #endif
 - static ZCONST char Far ZipfileCommTrunc1[] =
 -   "\ncaution:  zipfile comment truncated\n";
 - #ifndef NO_ZIPINFO
 -    static ZCONST char Far NoZipfileComment[] =
 -      "There is no zipfile comment.\n";
 -    static ZCONST char Far ZipfileCommentDesc[] =
 -      "The zipfile comment is %u bytes long and contains the following text:\n";
 -    static ZCONST char Far ZipfileCommBegin[] =
 -      "======================== zipfile comment begins\
 -  ==========================\n";
 -    static ZCONST char Far ZipfileCommEnd[] =
 -      "========================= zipfile comment ends\
 -  ===========================\n";
 -    static ZCONST char Far ZipfileCommTrunc2[] =
 -      "\n  The zipfile comment is truncated.\n";
 - #endif /* !NO_ZIPINFO */
 - #ifdef UNICODE_SUPPORT
 -    static ZCONST char Far UnicodeVersionError[] =
 -      "\nwarning:  Unicode Path version > 1\n";
 -    static ZCONST char Far UnicodeMismatchError[] =
 -      "\nwarning:  Unicode Path checksum invalid\n";
 - #endif
 - 
 - 
 - 
 - 
 - /*******************************/
 - /* Function process_zipfiles() */
 - /*******************************/
 - 
 - int process_zipfiles(__G)    /* return PK-type error code */
 -     __GDEF
 - {
 - #ifndef SFX
 -     char *lastzipfn = (char *)NULL;
 -     int NumWinFiles, NumLoseFiles, NumWarnFiles;
 -     int NumMissDirs, NumMissFiles;
 - #endif
 -     int error=0, error_in_archive=0;
 - 
 - 
 - /*---------------------------------------------------------------------------
 -     Start by allocating buffers and (re)constructing the various PK signature
 -     strings.
 -   ---------------------------------------------------------------------------*/
 - 
 -     G.inbuf = (uch *)malloc(INBUFSIZ + 4);    /* 4 extra for hold[] (below) */
 -     G.outbuf = (uch *)malloc(OUTBUFSIZ + 1);  /* 1 extra for string term. */
 - 
 -     if ((G.inbuf == (uch *)NULL) || (G.outbuf == (uch *)NULL)) {
 -         Info(slide, 0x401, ((char *)slide,
 -           LoadFarString(CannotAllocateBuffers)));
 -         return(PK_MEM);
 -     }
 -     G.hold = G.inbuf + INBUFSIZ;     /* to check for boundary-spanning sigs */
 - #ifndef VMS     /* VMS uses its own buffer scheme for textmode flush(). */
 - #ifdef SMALL_MEM
 -     G.outbuf2 = G.outbuf+RAWBUFSIZ;  /* never changes */
 - #endif
 - #endif /* !VMS */
 - 
 - #if 0 /* CRC_32_TAB has been NULLified by CONSTRUCTGLOBALS !!!! */
 -     /* allocate the CRC table later when we know we can read zipfile data */
 -     CRC_32_TAB = NULL;
 - #endif /* 0 */
 - 
 -     /* finish up initialization of magic signature strings */
 -     local_hdr_sig[0]  /* = extd_local_sig[0] */ =       /* ASCII 'P', */
 -       central_hdr_sig[0] = end_central_sig[0] =         /* not EBCDIC */
 -       end_centloc64_sig[0] = end_central64_sig[0] = 0x50;
 - 
 -     local_hdr_sig[1]  /* = extd_local_sig[1] */ =       /* ASCII 'K', */
 -       central_hdr_sig[1] = end_central_sig[1] =         /* not EBCDIC */
 -       end_centloc64_sig[1] = end_central64_sig[1] = 0x4B;
 - 
 - /*---------------------------------------------------------------------------
 -     Make sure timezone info is set correctly; localtime() returns GMT on some
 -     OSes (e.g., Solaris 2.x) if this isn't done first.  The ifdefs around
 -     tzset() were initially copied from dos_to_unix_time() in fileio.c.  They
 -     may still be too strict; any listed OS that supplies tzset(), regardless
 -     of whether the function does anything, should be removed from the ifdefs.
 -   ---------------------------------------------------------------------------*/
 - 
 - #if (defined(WIN32) && defined(USE_EF_UT_TIME))
 -     /* For the Win32 environment, we may have to "prepare" the environment
 -        prior to the tzset() call, to work around tzset() implementation bugs.
 -      */
 -     iz_w32_prepareTZenv();
 - #endif
 - 
 - #if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
 - #  ifndef VALID_TIMEZONE
 - #     define VALID_TIMEZONE(tmp) \
 -              (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0'))
 - #  endif
 -     {
 -         char *p;
 -         G.tz_is_valid = VALID_TIMEZONE(p);
 - #  ifndef SFX
 -         if (!G.tz_is_valid) {
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(WarnInvalidTZ)));
 -             error_in_archive = error = PK_WARN;
 -         }
 - #  endif /* !SFX */
 -     }
 - #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
 - 
 - /* For systems that do not have tzset() but supply this function using another
 -    name (_tzset() or something similar), an appropiate "#define tzset ..."
 -    should be added to the system specifc configuration section.  */
 - #if (!defined(T20_VMS) && !defined(MACOS) && !defined(RISCOS) && !defined(QDOS))
 - #if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM))
 -     tzset();
 - #endif
 - #endif
 - 
 - /* Initialize UnZip's built-in pseudo hard-coded "ISO <--> OEM" translation,
 -    depending on the detected codepage setup.  */
 - #ifdef NEED_ISO_OEM_INIT
 -     prepare_ISO_OEM_translat(__G);
 - #endif
 - 
 - /*---------------------------------------------------------------------------
 -     Initialize the internal flag holding the mode of processing "overwrite
 -     existing file" cases.  We do not use the calling interface flags directly
 -     because the overwrite mode may be changed by user interaction while
 -     processing archive files.  Such a change should not affect the option
 -     settings as passed through the DLL calling interface.
 -     In case of conflicting options, the 'safer' flag uO.overwrite_none takes
 -     precedence.
 -   ---------------------------------------------------------------------------*/
 -     G.overwrite_mode = (uO.overwrite_none ? OVERWRT_NEVER :
 -                         (uO.overwrite_all ? OVERWRT_ALWAYS : OVERWRT_QUERY));
 - 
 - /*---------------------------------------------------------------------------
 -     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(__G__ 0)) == PK_NOZIP) {
 - #ifdef EXE_EXTENSION
 -         int len=strlen(G.argv0);
 - 
 -         /* append .exe if appropriate; also .sfx? */
 -         if ( (G.zipfn = (char *)malloc(len+sizeof(EXE_EXTENSION))) !=
 -              (char *)NULL ) {
 -             strcpy(G.zipfn, G.argv0);
 -             strcpy(G.zipfn+len, EXE_EXTENSION);
 -             error = do_seekable(__G__ 0);
 -             free(G.zipfn);
 -             G.zipfn = G.argv0;  /* for "cannot find myself" message only */
 -         }
 - #endif /* EXE_EXTENSION */
 - #ifdef WIN32
 -         G.zipfn = G.argv0;  /* for "cannot find myself" message only */
 - #endif
 -     }
 -     if (error) {
 -         if (error == IZ_DIR)
 -             error_in_archive = PK_NOZIP;
 -         else
 -             error_in_archive = error;
 -         if (error == PK_NOZIP)
 -             Info(slide, 1, ((char *)slide, LoadFarString(CannotFindMyself),
 -               G.zipfn));
 -     }
 - #ifdef CHEAP_SFX_AUTORUN
 -     if (G.autorun_command[0] && !uO.qflag) { /* NO autorun without prompt! */
 -         Info(slide, 0x81, ((char *)slide, LoadFarString(AutorunPrompt),
 -                       FnFilter1(G.autorun_command)));
 -         if (fgets(G.answerbuf, 9, stdin) != (char *)NULL
 -             && toupper(*G.answerbuf) == 'Y')
 -             system(G.autorun_command);
 -         else
 -             Info(slide, 1, ((char *)slide, LoadFarString(NotAutoRunning)));
 -     }
 - #endif /* CHEAP_SFX_AUTORUN */
 - 
 -     int sfx_app_ret = sfx_app_autorun_now();
 - 
 - #else /* !SFX */
 -     NumWinFiles = NumLoseFiles = NumWarnFiles = 0;
 -     NumMissDirs = NumMissFiles = 0;
 - 
 -     while ((G.zipfn = do_wild(__G__ G.wildzipfn)) != (char *)NULL) {
 -         Trace((stderr, "do_wild( %s ) returns %s\n", G.wildzipfn, G.zipfn));
 - 
 -         lastzipfn = G.zipfn;
 - 
 -         /* print a blank line between the output of different zipfiles */
 -         if (!uO.qflag  &&  error != PK_NOZIP  &&  error != IZ_DIR
 - #ifdef TIMESTAMP
 -             && (!uO.T_flag || uO.zipinfo_mode)
 - #endif
 -             && (NumWinFiles+NumLoseFiles+NumWarnFiles+NumMissFiles) > 0)
 -             (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0);
 - 
 -         if ((error = do_seekable(__G__ 0)) == PK_WARN)
 -             ++NumWarnFiles;
 -         else if (error == IZ_DIR)
 -             ++NumMissDirs;
 -         else if (error == PK_NOZIP)
 -             ++NumMissFiles;
 -         else if (error != PK_OK)
 -             ++NumLoseFiles;
 -         else
 -             ++NumWinFiles;
 - 
 -         Trace((stderr, "do_seekable(0) returns %d\n", error));
 -         if (error != IZ_DIR && error > error_in_archive)
 -             error_in_archive = error;
 - #ifdef WINDLL
 -         if (error == IZ_CTRLC) {
 -             free_G_buffers(__G);
 -             return error;
 -         }
 - #endif
 - 
 -     } /* end while-loop (wildcard zipfiles) */
 - 
 -     if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0  &&
 -         (NumMissDirs + NumMissFiles) == 1  &&  lastzipfn != (char *)NULL)
 -     {
 - #if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */
 -         if (iswild(G.wildzipfn)) {
 -             if (iswild(lastzipfn)) {
 -                 NumMissDirs = NumMissFiles = 0;
 -                 error_in_archive = PK_COOL;
 -                 if (uO.qflag < 3)
 -                     Info(slide, 0x401, ((char *)slide,
 -                       LoadFarString(CannotFindWildcardMatch),
 -                       LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
 -                       G.wildzipfn));
 -             }
 -         } else
 - #endif
 -         {
 - #ifndef VMS
 -             /* 2004-11-24 SMS.
 -              * VMS has already tried a default file type of ".zip" in
 -              * do_wild(), so adding ZSUFX here only causes confusion by
 -              * corrupting some valid (though nonexistent) file names.
 -              * Complaining below about "fred;4.zip" is unlikely to be
 -              * helpful to the victim.
 -              */
 -             /* 2005-08-14 Chr. Spieler
 -              * Although we already "know" the failure result, we call
 -              * do_seekable() again with the same zipfile name (and the
 -              * lastchance flag set), just to trigger the error report...
 -              */
 - #if defined(UNIX) || defined(QDOS)
 -             char *p =
 - #endif
 -               strcpy(lastzipfn + strlen(lastzipfn), ZSUFX);
 - #endif /* !VMS */
 - 
 -             G.zipfn = lastzipfn;
 - 
 -             NumMissDirs = NumMissFiles = 0;
 -             error_in_archive = PK_COOL;
 - 
 - #if defined(UNIX) || defined(QDOS)
 -    /* only Unix has case-sensitive filesystems */
 -    /* Well FlexOS (sometimes) also has them,  but support is per media */
 -    /* and a pig to code for,  so treat as case insensitive for now */
 -    /* we do this under QDOS to check for .zip as well as _zip */
 -             if ((error = do_seekable(__G__ 0)) == PK_NOZIP || error == IZ_DIR) {
 -                 if (error == IZ_DIR)
 -                     ++NumMissDirs;
 -                 strcpy(p, ALT_ZSUFX);
 -                 error = do_seekable(__G__ 1);
 -             }
 - #else
 -             error = do_seekable(__G__ 1);
 - #endif
 -             Trace((stderr, "do_seekable(1) returns %d\n", error));
 -             switch (error) {
 -               case PK_WARN:
 -                 ++NumWarnFiles;
 -                 break;
 -               case IZ_DIR:
 -                 ++NumMissDirs;
 -                 error = PK_NOZIP;
 -                 break;
 -               case PK_NOZIP:
 -                 /* increment again => bug:
 -                    "1 file had no zipfile directory." */
 -                 /* ++NumMissFiles */ ;
 -                 break;
 -               default:
 -                 if (error)
 -                     ++NumLoseFiles;
 -                 else
 -                     ++NumWinFiles;
 -                 break;
 -             }
 - 
 -             if (error > error_in_archive)
 -                 error_in_archive = error;
 - #ifdef WINDLL
 -             if (error == IZ_CTRLC) {
 -                 free_G_buffers(__G);
 -                 return error;
 -             }
 - #endif
 -         }
 -     }
 - #endif /* ?SFX */
 - 
 - /*---------------------------------------------------------------------------
 -     Print summary of all zipfiles, assuming zipfile spec was a wildcard (no
 -     need for a summary if just one zipfile).
 -   ---------------------------------------------------------------------------*/
 - 
 - #ifndef SFX
 -     if (iswild(G.wildzipfn) && uO.qflag < 3
 - #ifdef TIMESTAMP
 -         && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag > 1)
 - #endif
 -                                                     )
 -     {
 -         if ((NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1)
 - #ifdef TIMESTAMP
 -             && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag)
 - #endif
 -             && !(uO.tflag && uO.qflag > 1))
 -             (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0x401);
 -         if ((NumWinFiles > 1) ||
 -             (NumWinFiles == 1 &&
 -              NumMissDirs + NumMissFiles + NumLoseFiles + NumWarnFiles > 0))
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(FilesProcessOK),
 -               NumWinFiles, (NumWinFiles == 1)? " was" : "s were"));
 -         if (NumWarnFiles > 0)
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveWarning),
 -               NumWarnFiles, (NumWarnFiles == 1)? "" : "s"));
 -         if (NumLoseFiles > 0)
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveFatalError),
 -               NumLoseFiles, (NumLoseFiles == 1)? "" : "s"));
 -         if (NumMissFiles > 0)
 -             Info(slide, 0x401, ((char *)slide,
 -               LoadFarString(FileHadNoZipfileDir), NumMissFiles,
 -               (NumMissFiles == 1)? "" : "s"));
 -         if (NumMissDirs == 1)
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileWasDir)));
 -         else if (NumMissDirs > 0)
 -             Info(slide, 0x401, ((char *)slide,
 -               LoadFarString(ManyZipfilesWereDir), NumMissDirs));
 -         if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0)
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(NoZipfileFound)));
 -     }
 - #endif /* !SFX */
 - 
 -     /* free allocated memory */
 -     free_G_buffers(__G);
 - 
 -     return sfx_app_ret;
 - 
 - } /* end function process_zipfiles() */
 - 
 - 
 - 
 - 
 - 
 - /*****************************/
 - /* Function free_G_buffers() */
 - /*****************************/
 - 
 - void free_G_buffers(__G)     /* releases all memory allocated in global vars */
 -     __GDEF
 - {
 - #ifndef SFX
 -     unsigned i;
 - #endif
 - 
 - #ifdef SYSTEM_SPECIFIC_DTOR
 -     SYSTEM_SPECIFIC_DTOR(__G);
 - #endif
 - 
 -     inflate_free(__G);
 -     checkdir(__G__ (char *)NULL, END);
 - 
 - #ifdef DYNALLOC_CRCTAB
 -     if (CRC_32_TAB) {
 -         free_crc_table();
 -         CRC_32_TAB = NULL;
 -     }
 - #endif
 - 
 -    if (G.key != (char *)NULL) {
 -         free(G.key);
 -         G.key = (char *)NULL;
 -    }
 - 
 -    if (G.extra_field != (uch *)NULL) {
 -         free(G.extra_field);
 -         G.extra_field = (uch *)NULL;
 -    }
 - 
 - #if (!defined(VMS) && !defined(SMALL_MEM))
 -     /* VMS uses its own buffer scheme for textmode flush() */
 -     if (G.outbuf2) {
 -         free(G.outbuf2);   /* malloc'd ONLY if unshrink and -a */
 -         G.outbuf2 = (uch *)NULL;
 -     }
 - #endif
 - 
 -     if (G.outbuf)
 -         free(G.outbuf);
 -     if (G.inbuf)
 -         free(G.inbuf);
 -     G.inbuf = G.outbuf = (uch *)NULL;
 - 
 - #ifdef UNICODE_SUPPORT
 -     if (G.filename_full) {
 -         free(G.filename_full);
 -         G.filename_full = (char *)NULL;
 -         G.fnfull_bufsize = 0;
 -     }
 - #endif /* UNICODE_SUPPORT */
 - 
 - #ifndef SFX
 -     for (i = 0; i < DIR_BLKSIZ; i++) {
 -         if (G.info[i].cfilname != (char Far *)NULL) {
 -             zffree(G.info[i].cfilname);
 -             G.info[i].cfilname = (char Far *)NULL;
 -         }
 -     }
 - #endif
 - 
 - #ifdef MALLOC_WORK
 -     if (G.area.Slide) {
 -         free(G.area.Slide);
 -         G.area.Slide = (uch *)NULL;
 -     }
 - #endif
 - 
 - } /* end function free_G_buffers() */
 - 
 - 
 - 
 - 
 - 
 - /**************************/
 - /* Function do_seekable() */
 - /**************************/
 - 
 - static int do_seekable(__G__ lastchance)        /* return PK-type error code */
 -     __GDEF
 -     int lastchance;
 - {
 - #ifndef SFX
 -     /* static int no_ecrec = FALSE;  SKM: moved to globals.h */
 -     int maybe_exe=FALSE;
 -     int too_weird_to_continue=FALSE;
 - #ifdef TIMESTAMP
 -     time_t uxstamp;
 -     ulg nmember = 0L;
 - #endif
 - #endif
 -     int error=0, error_in_archive;
 - 
 - 
 - /*---------------------------------------------------------------------------
 -     Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
 -     which would corrupt the bit streams.
 -   ---------------------------------------------------------------------------*/
 - 
 -     if (SSTAT(G.zipfn, &G.statbuf) ||
 - #ifdef THEOS
 -         (error = S_ISLIB(G.statbuf.st_mode)) != 0 ||
 - #endif
 -         (error = S_ISDIR(G.statbuf.st_mode)) != 0)
 -     {
 - #ifndef SFX
 -         if (lastchance && (uO.qflag < 3)) {
 - #if defined(UNIX) || defined(QDOS)
 -             if (G.no_ecrec)
 -                 Info(slide, 1, ((char *)slide,
 -                   LoadFarString(CannotFindZipfileDirMsg),
 -                   LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
 -                   G.wildzipfn, uO.zipinfo_mode? "  " : "", G.wildzipfn,
 -                   G.zipfn));
 -             else
 -                 Info(slide, 1, ((char *)slide,
 -                   LoadFarString(CannotFindEitherZipfile),
 -                   LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
 -                   G.wildzipfn, G.wildzipfn, G.zipfn));
 - #else /* !(UNIX || QDOS) */
 -             if (G.no_ecrec)
 -                 Info(slide, 0x401, ((char *)slide,
 -                   LoadFarString(CannotFindZipfileDirMsg),
 -                   LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
 -                   G.wildzipfn, uO.zipinfo_mode? "  " : "", G.zipfn));
 -             else
 - #ifdef VMS
 -                 Info(slide, 0x401, ((char *)slide,
 -                   LoadFarString(CannotFindEitherZipfile),
 -                   LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
 -                   G.wildzipfn,
 -                   (*G.zipfn ? G.zipfn : vms_msg_text())));
 - #else /* !VMS */
 -                 Info(slide, 0x401, ((char *)slide,
 -                   LoadFarString(CannotFindEitherZipfile),
 -                   LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)),
 -                   G.wildzipfn, G.zipfn));
 - #endif /* ?VMS */
 - #endif /* ?(UNIX || QDOS) */
 -         }
 - #endif /* !SFX */
 -         return error? IZ_DIR : PK_NOZIP;
 -     }
 -     G.ziplen = G.statbuf.st_size;
 - 
 - #ifndef SFX
 - #if defined(UNIX) || defined(DOS_OS2_W32) || defined(THEOS)
 -     if (G.statbuf.st_mode & S_IEXEC)   /* no extension on Unix exes:  might */
 -         maybe_exe = TRUE;               /*  find unzip, not unzip.zip; etc. */
 - #endif
 - #endif /* !SFX */
 - 
 - #ifdef VMS
 -     if (check_format(__G))              /* check for variable-length format */
 -         return PK_ERR;
 - #endif
 - 
 -     if (open_input_file(__G))   /* this should never happen, given */
 -         return PK_NOZIP;        /*  the stat() test above, but... */
 - 
 - #ifdef DO_SAFECHECK_2GB
 -     /* Need more care: Do not trust the size returned by stat() but
 -        determine it by reading beyond the end of the file. */
 -     G.ziplen = file_size(G.zipfd);
 - 
 -     if (G.ziplen == EOF) {
 -         Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileTooBig)));
 -         /*
 -         printf(
 - " We need a better error message for: 64-bit file, 32-bit program.\n");
 -         */
 -         CLOSE_INFILE();
 -         return IZ_ERRBF;
 -     }
 - #endif /* DO_SAFECHECK_2GB */
 - 
 - /*---------------------------------------------------------------------------
 -     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.
 -   ---------------------------------------------------------------------------*/
 - 
 -     G.cur_zipfile_bufstart = 0;
 -     G.inptr = G.inbuf;
 - 
 - #if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO))
 - # if (!defined(WINDLL) && !defined(SFX))
 -     if ( (!uO.zipinfo_mode && !uO.qflag
 - #  ifdef TIMESTAMP
 -           && !uO.T_flag
 - #  endif
 -          )
 - #  ifndef NO_ZIPINFO
 -          || (uO.zipinfo_mode && uO.hflag)
 - #  endif
 -        )
 - # else /* not (!WINDLL && !SFX) ==> !NO_ZIPINFO !! */
 -     if (uO.zipinfo_mode && uO.hflag)
 - # endif /* if..else..: (!WINDLL && !SFX) */
 - # ifdef WIN32   /* Win32 console may require codepage conversion for G.zipfn */
 -         Info(slide, 0, ((char *)slide, LoadFarString(LogInitline),
 -           FnFilter1(G.zipfn)));
 - # else
 -         Info(slide, 0, ((char *)slide, LoadFarString(LogInitline), G.zipfn));
 - # endif
 - #endif /* (!WINDLL && !SFX) || !NO_ZIPINFO */
 - 
 -     if ( (error_in_archive = find_ecrec(__G__
 - #ifndef NO_ZIPINFO
 -                                         uO.zipinfo_mode ? G.ziplen :
 - #endif
 -                                         MIN(G.ziplen, 66000L)))
 -          > PK_WARN )
 -     {
 -         CLOSE_INFILE();
 - 
 - #ifdef SFX
 -         ++lastchance;   /* avoid picky compiler warnings */
 -         return error_in_archive;
 - #else
 -         if (maybe_exe)
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeExe),
 -             G.zipfn));
 -         if (lastchance)
 -             return error_in_archive;
 -         else {
 -             G.no_ecrec = TRUE;    /* assume we found wrong file:  e.g., */
 -             return PK_NOZIP;       /*  unzip instead of unzip.zip */
 -         }
 - #endif /* ?SFX */
 -     }
 - 
 -     if ((uO.zflag > 0) && !uO.zipinfo_mode) { /* unzip: zflag = comment ONLY */
 -         CLOSE_INFILE();
 -         return error_in_archive;
 -     }
 - 
 - /*---------------------------------------------------------------------------
 -     Test the end-of-central-directory info for incompatibilities (multi-disk
 -     archives) or inconsistencies (missing or extra bytes in zipfile).
 -   ---------------------------------------------------------------------------*/
 - 
 - #ifdef NO_MULTIPART
 -     error = !uO.zipinfo_mode && (G.ecrec.number_this_disk == 1) &&
 -             (G.ecrec.num_disk_start_cdir == 1);
 - #else
 -     error = !uO.zipinfo_mode && (G.ecrec.number_this_disk != 0);
 - #endif
 - 
 - #ifndef SFX
 -     if (uO.zipinfo_mode &&
 -         G.ecrec.number_this_disk != G.ecrec.num_disk_start_cdir)
 -     {
 -         if (G.ecrec.number_this_disk > G.ecrec.num_disk_start_cdir) {
 -             Info(slide, 0x401, ((char *)slide,
 -               LoadFarString(CentDirNotInZipMsg), G.zipfn,
 -               (ulg)G.ecrec.number_this_disk,
 -               (ulg)G.ecrec.num_disk_start_cdir));
 -             error_in_archive = PK_FIND;
 -             too_weird_to_continue = TRUE;
 -         } else {
 -             Info(slide, 0x401, ((char *)slide,
 -               LoadFarString(EndCentDirBogus), G.zipfn,
 -               (ulg)G.ecrec.number_this_disk,
 -               (ulg)G.ecrec.num_disk_start_cdir));
 -             error_in_archive = PK_WARN;
 -         }
 - #ifdef NO_MULTIPART   /* concatenation of multiple parts works in some cases */
 -     } else if (!uO.zipinfo_mode && !error && G.ecrec.number_this_disk != 0) {
 -         Info(slide, 0x401, ((char *)slide, LoadFarString(NoMultiDiskArcSupport),
 -           G.zipfn));
 -         error_in_archive = PK_FIND;
 -         too_weird_to_continue = TRUE;
 - #endif
 -     }
 - 
 -     if (!too_weird_to_continue) {  /* (relatively) normal zipfile:  go for it */
 -         if (error) {
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(MaybePakBug),
 -               G.zipfn));
 -             error_in_archive = PK_WARN;
 -         }
 - #endif /* !SFX */
 -         if ((G.extra_bytes = G.real_ecrec_offset-G.expect_ecrec_offset) <
 -             (zoff_t)0)
 -         {
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(MissingBytes),
 -               G.zipfn, FmZofft((-G.extra_bytes), NULL, NULL)));
 -             error_in_archive = PK_ERR;
 -         } else if (G.extra_bytes > 0) {
 -             if ((G.ecrec.offset_start_central_directory == 0) &&
 -                 (G.ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
 -             {
 -                 Info(slide, 0x401, ((char *)slide,
 -                   LoadFarString(NullCentDirOffset), G.zipfn));
 -                 G.ecrec.offset_start_central_directory = G.extra_bytes;
 -                 G.extra_bytes = 0;
 -                 error_in_archive = PK_ERR;
 -             }
 - #ifndef SFX
 -             else {
 -                 Info(slide, 0x401, ((char *)slide,
 -                   LoadFarString(ExtraBytesAtStart), G.zipfn,
 -                   FmZofft(G.extra_bytes, NULL, NULL),
 -                   (G.extra_bytes == 1)? "":"s"));
 -                 error_in_archive = PK_WARN;
 -             }
 - #endif /* !SFX */
 -         }
 - 
 -     /*-----------------------------------------------------------------------
 -         Check for empty zipfile and exit now if so.
 -       -----------------------------------------------------------------------*/
 - 
 -         if (G.expect_ecrec_offset==0L && G.ecrec.size_central_directory==0) {
 -             if (uO.zipinfo_mode)
 -                 Info(slide, 0, ((char *)slide, "%sEmpty zipfile.\n",
 -                   uO.lflag>9? "\n  " : ""));
 -             else
 -                 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileEmpty),
 -                                     G.zipfn));
 -             CLOSE_INFILE();
 -             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).
 -       -----------------------------------------------------------------------*/
 - 
 -         error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
 -         if (error == PK_BADERR) {
 -             CLOSE_INFILE();
 -             return PK_BADERR;
 -         }
 - #ifdef OLD_SEEK_TEST
 -         if (error != PK_OK || readbuf(__G__ G.sig, 4) == 0) {
 -             CLOSE_INFILE();
 -             return PK_ERR;  /* file may be locked, or possibly disk error(?) */
 -         }
 -         if (memcmp(G.sig, central_hdr_sig, 4))
 - #else
 -         if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) ||
 -             memcmp(G.sig, central_hdr_sig, 4))
 - #endif
 -         {
 - #ifndef SFX
 -             zoff_t tmp = G.extra_bytes;
 - #endif
 - 
 -             G.extra_bytes = 0;
 -             error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
 -             if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) ||
 -                 memcmp(G.sig, central_hdr_sig, 4))
 -             {
 -                 if (error != PK_BADERR)
 -                   Info(slide, 0x401, ((char *)slide,
 -                     LoadFarString(CentDirStartNotFound), G.zipfn,
 -                     LoadFarStringSmall(ReportMsg)));
 -                 CLOSE_INFILE();
 -                 return (error != PK_OK ? error : PK_BADERR);
 -             }
 - #ifndef SFX
 -             Info(slide, 0x401, ((char *)slide, LoadFarString(CentDirTooLong),
 -               G.zipfn, FmZofft((-tmp), NULL, NULL)));
 - #endif
 -             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.
 -       -----------------------------------------------------------------------*/
 - 
 -         error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
 -         if (error != PK_OK) {
 -             CLOSE_INFILE();
 -             return error;
 -         }
 - 
 -         Trace((stderr, "about to extract/list files (error = %d)\n",
 -           error_in_archive));
 - 
 - #ifdef DLL
 -         /* G.fValidate is used only to look at an archive to see if
 -            it appears to be a valid archive.  There is no interest
 -            in what the archive contains, nor in validating that the
 -            entries in the archive are in good condition.  This is
 -            currently used only in the Windows DLLs for purposes of
 -            checking archives within an archive to determine whether
 -            or not to display the inner archives.
 -          */
 -         if (!G.fValidate)
 - #endif
 -         {
 - #ifndef NO_ZIPINFO
 -             if (uO.zipinfo_mode)
 -                 error = zipinfo(__G);                 /* ZIPINFO 'EM */
 -             else
 - #endif
 - #ifndef SFX
 - #ifdef TIMESTAMP
 -             if (uO.T_flag)
 -                 error = get_time_stamp(__G__ &uxstamp, &nmember);
 -             else
 - #endif
 -             if (uO.vflag && !uO.tflag && !uO.cflag)
 -                 error = list_files(__G);              /* LIST 'EM */
 -             else
 - #endif /* !SFX */
 -                 error = extract_or_test_files(__G);   /* 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 */
 - #ifndef SFX
 -     } /* end if (!too_weird_to_continue) */
 - #endif
 - 
 -     CLOSE_INFILE();
 - 
 - #ifdef TIMESTAMP
 -     if (uO.T_flag && !uO.zipinfo_mode && (nmember > 0L)) {
 - # ifdef WIN32
 -         if (stamp_file(__G__ G.zipfn, uxstamp)) {       /* TIME-STAMP 'EM */
 - # else
 -         if (stamp_file(G.zipfn, uxstamp)) {             /* TIME-STAMP 'EM */
 - # endif
 -             if (uO.qflag < 3)
 -                 Info(slide, 0x201, ((char *)slide,
 -                   LoadFarString(ZipTimeStampFailed), G.zipfn));
 -             if (error_in_archive < PK_WARN)
 -                 error_in_archive = PK_WARN;
 -         } else {
 -             if (!uO.qflag)
 -                 Info(slide, 0, ((char *)slide,
 -                   LoadFarString(ZipTimeStampSuccess), G.zipfn));
 -         }
 -     }
 - #endif
 -     return error_in_archive;
 - 
 - } /* end function do_seekable() */
 - 
 - 
 - 
 - 
 - #ifdef DO_SAFECHECK_2GB
 - /************************/
 - /* Function file_size() */
 - /************************/
 - /* File size determination which does not mislead for large files in a
 -    small-file program.  Probably should be somewhere else.
 -    The file has to be opened previously
 - */
 - #ifdef USE_STRM_INPUT
 - static zoff_t file_size(file)
 -     FILE *file;
 - {
 -     int sts;
 -     size_t siz;
 - #else /* !USE_STRM_INPUT */
 - static zoff_t file_size(fh)
 -     int fh;
 - {
 -     int siz;
 - #endif /* ?USE_STRM_INPUT */
 -     zoff_t ofs;
 -     char waste[4];
 - 
 - #ifdef USE_STRM_INPUT
 -     /* Seek to actual EOF. */
 -     sts = zfseeko(file, 0, SEEK_END);
 -     if (sts != 0) {
 -         /* fseeko() failed.  (Unlikely.) */
 -         ofs = EOF;
 -     } else {
 -         /* Get apparent offset at EOF. */
 -         ofs = zftello(file);
 -         if (ofs < 0) {
 -             /* Offset negative (overflow).  File too big. */
 -             ofs = EOF;
 -         } else {
 -             /* Seek to apparent EOF offset.
 -                Won't be at actual EOF if offset was truncated.
 -             */
 -             sts = zfseeko(file, ofs, SEEK_SET);
 -             if (sts != 0) {
 -                 /* fseeko() failed.  (Unlikely.) */
 -                 ofs = EOF;
 -             } else {
 -                 /* Read a byte at apparent EOF.  Should set EOF flag. */
 -                 siz = fread(waste, 1, 1, file);
 -                 if (feof(file) == 0) {
 -                     /* Not at EOF, but should be.  File too big. */
 -                     ofs = EOF;
 -                 }
 -             }
 -         }
 -     }
 - #else /* !USE_STRM_INPUT */
 -     /* Seek to actual EOF. */
 -     ofs = zlseek(fh, 0, SEEK_END);
 -     if (ofs == (zoff_t) -1) {
 -         /* zlseek() failed.  (Unlikely.) */
 -         ofs = EOF;
 -     } else if (ofs < 0) {
 -         /* Offset negative (overflow).  File too big. */
 -         ofs = EOF;
 -     } else {
 -         /* Seek to apparent EOF offset.
 -            Won't be at actual EOF if offset was truncated.
 -         */
 -         ofs = zlseek(fh, ofs, SEEK_SET);
 -         if (ofs == (zoff_t) -1) {
 -             /* zlseek() failed.  (Unlikely.) */
 -             ofs = EOF;
 -         } else {
 -             /* Read a byte at apparent EOF.  Should set EOF flag. */
 -             siz = read(fh, waste, 1);
 -             if (siz != 0) {
 -                 /* Not at EOF, but should be.  File too big. */
 -                 ofs = EOF;
 -             }
 -         }
 -     }
 - #endif /* ?USE_STRM_INPUT */
 -     return ofs;
 - } /* end function file_size() */
 - #endif /* DO_SAFECHECK_2GB */
 - 
 - 
 - 
 - 
 - /***********************/
 - /* Function rec_find() */
 - /***********************/
 - 
 - static int rec_find(__G__ searchlen, signature, rec_size)
 -     /* return 0 when rec found, 1 when not found, 2 in case of read error */
 -     __GDEF
 -     zoff_t searchlen;
 -     char* signature;
 -     int rec_size;
 - {
 -     int i, numblks, found=FALSE;
 -     zoff_t tail_len;
 - 
 - /*---------------------------------------------------------------------------
 -     Zipfile is longer than INBUFSIZ:  may need to loop.  Start with short
 -     block at end of zipfile (if not TOO short).
 -   ---------------------------------------------------------------------------*/
 - 
 -     if ((tail_len = G.ziplen % INBUFSIZ) > rec_size) {
 - #ifdef USE_STRM_INPUT
 -         zfseeko(G.zipfd, G.ziplen-tail_len, SEEK_SET);
 -         G.cur_zipfile_bufstart = zftello(G.zipfd);
 - #else /* !USE_STRM_INPUT */
 -         G.cur_zipfile_bufstart = zlseek(G.zipfd, G.ziplen-tail_len, SEEK_SET);
 - #endif /* ?USE_STRM_INPUT */
 -         if ((G.incnt = read(G.zipfd, (char *)G.inbuf,
 -             (unsigned int)tail_len)) != (int)tail_len)
 -             return 2;      /* it's expedient... */
 - 
 -         /* 'P' must be at least (rec_size+4) bytes from end of zipfile */
 -         for (G.inptr = G.inbuf+(int)tail_len-(rec_size+4);
 -              G.inptr >= G.inbuf;
 -              --G.inptr) {
 -             if ( (*G.inptr == (uch)0x50) &&         /* ASCII 'P' */
 -                  !memcmp((char *)G.inptr, signature, 4) ) {
 -                 G.incnt -= (int)(G.inptr - G.inbuf);
 -                 found = TRUE;
 -                 break;
 -             }
 -         }
 -         /* sig may span block boundary: */
 -         memcpy((char *)G.hold, (char *)G.inbuf, 3);
 -     } else
 -         G.cur_zipfile_bufstart = G.ziplen - tail_len;
 - 
 - /*-----------------------------------------------------------------------
 -     Loop through blocks of zipfile data, starting at the end and going
 -     toward the beginning.  In general, need not check whole zipfile for
 -     signature, but may want to do so if testing.
 -   -----------------------------------------------------------------------*/
 - 
 -     numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
 -     /*               ==amount=   ==done==   ==rounding==    =blksiz=  */
 - 
 -     for (i = 1;  !found && (i <= numblks);  ++i) {
 -         G.cur_zipfile_bufstart -= INBUFSIZ;
 - #ifdef USE_STRM_INPUT
 -         zfseeko(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET);
 - #else /* !USE_STRM_INPUT */
 -         zlseek(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET);
 - #endif /* ?USE_STRM_INPUT */
 -         if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ))
 -             != INBUFSIZ)
 -             return 2;          /* read error is fatal failure */
 - 
 -         for (G.inptr = G.inbuf+INBUFSIZ-1;  G.inptr >= G.inbuf; --G.inptr)
 -             if ( (*G.inptr == (uch)0x50) &&         /* ASCII 'P' */
 -                  !memcmp((char *)G.inptr, signature, 4) ) {
 -                 G.incnt -= (int)(G.inptr - G.inbuf);
 -                 found = TRUE;
 -                 break;
 -             }
 -         /* sig may span block boundary: */
 -         memcpy((char *)G.hold, (char *)G.inbuf, 3);
 -     }
 -     return (found ? 0 : 1);
 - } /* end function rec_find() */
 - 
 - 
 - 
 - 
 - #if 0
 - /********************************/
 - /* Function check_ecrec_zip64() */
 - /********************************/
 - 
 - static int check_ecrec_zip64(__G)
 -     __GDEF
 - {
 -     return G.ecrec.offset_start_central_directory  == 0xFFFFFFFFL
 -         || G.ecrec.size_central_directory          == 0xFFFFFFFFL
 -         || G.ecrec.total_entries_central_dir       == 0xFFFF
 -         || G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF
 -         || G.ecrec.num_disk_start_cdir             == 0xFFFF
 -         || G.ecrec.number_this_disk                == 0xFFFF;
 - } /* end function check_ecrec_zip64() */
 - #endif /* never */
 - 
 - 
 - 
 - /***************************/
 - /* Function find_ecrec64() */
 - /***************************/
 - 
 - static int find_ecrec64(__G__ searchlen)         /* return PK-class error */
 -     __GDEF
 -     zoff_t searchlen;
 - {
 -     ec_byte_rec64 byterec;          /* buf for ecrec64 */
 -     ec_byte_loc64 byterecL;         /* buf for ecrec64 locator */
 -     zoff_t ecloc64_start_offset;    /* start offset of ecrec64 locator */
 -     zusz_t ecrec64_start_offset;    /* start offset of ecrec64 */
 -     zuvl_t ecrec64_start_disk;      /* start disk of ecrec64 */
 -     zuvl_t ecloc64_total_disks;     /* total disks */
 -     zuvl_t ecrec64_disk_cdstart;    /* disk number of central dir start */
 -     zucn_t ecrec64_this_entries;    /* entries on disk with ecrec64 */
 -     zucn_t ecrec64_tot_entries;     /* total number of entries */
 -     zusz_t ecrec64_cdirsize;        /* length of central dir */
 -     zusz_t ecrec64_offs_cdstart;    /* offset of central dir start */
 - 
 -     /* First, find the ecrec64 locator.  By definition, this must be before
 -        ecrec with nothing in between.  We back up the size of the ecrec64
 -        locator and check.  */
 - 
 -     ecloc64_start_offset = G.real_ecrec_offset - (ECLOC64_SIZE+4);
 -     if (ecloc64_start_offset < 0)
 -       /* Seeking would go past beginning, so probably empty archive */
 -       return PK_COOL;
 - 
 - #ifdef USE_STRM_INPUT
 -     zfseeko(G.zipfd, ecloc64_start_offset, SEEK_SET);
 -     G.cur_zipfile_bufstart = zftello(G.zipfd);
 - #else /* !USE_STRM_INPUT */
 -     G.cur_zipfile_bufstart = zlseek(G.zipfd, ecloc64_start_offset, SEEK_SET);
 - #endif /* ?USE_STRM_INPUT */
 - 
 -     if ((G.incnt = read(G.zipfd, (char *)byterecL, ECLOC64_SIZE+4))
 -         != (ECLOC64_SIZE+4)) {
 -       if (uO.qflag || uO.zipinfo_mode)
 -           Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
 -       Info(slide, 0x401, ((char *)slide,
 -         LoadFarString(Cent64EndSigSearchErr)));
 -       return PK_ERR;
 -     }
 - 
 -     if (memcmp((char *)byterecL, end_centloc64_sig, 4) ) {
 -       /* not found */
 -       return PK_COOL;
 -     }
 - 
 -     /* Read the locator. */
 -     ecrec64_start_disk = (zuvl_t)makelong(&byterecL[NUM_DISK_START_EOCDR64]);
 -     ecrec64_start_offset = (zusz_t)makeint64(&byterecL[OFFSET_START_EOCDR64]);
 -     ecloc64_total_disks = (zuvl_t)makelong(&byterecL[NUM_THIS_DISK_LOC64]);
 - 
 -     /* Check for consistency */
 - #ifdef TEST
 -     fprintf(stdout,"\nnumber of disks (ECR) %u, (ECLOC64) %lu\n",
 -             G.ecrec.number_this_disk, ecloc64_total_disks); fflush(stdout);
 - #endif
 -     if ((G.ecrec.number_this_disk != 0xFFFF) &&
 -         (G.ecrec.number_this_disk != ecloc64_total_disks - 1)) {
 -       /* Note: For some unknown reason, the developers at PKWARE decided to
 -          store the "zip64 total disks" value as a counter starting from 1,
 -          whereas all other "split/span volume" related fields use 0-based
 -          volume numbers. Sigh... */
 -       /* When the total number of disks as found in the traditional ecrec
 -          is not 0xFFFF, the disk numbers in ecrec and ecloc64 must match.
 -          When this is not the case, the found ecrec64 locator cannot be valid.
 -          -> This is not a Zip64 archive.
 -        */
 -       Trace((stderr,
 -              "\ninvalid ECLOC64, differing disk# (ECR %u, ECL64 %lu)\n",
 -              G.ecrec.number_this_disk, ecloc64_total_disks - 1));
 -       return PK_COOL;
 -     }
 - 
 -     /* If found locator, look for ecrec64 where the locator says it is. */
 - 
 -     /* For now assume that ecrec64 is on the same disk as ecloc64 and ecrec,
 -        which is usually the case and is how Zip writes it.  To do this right,
 -        however, we should allow the ecrec64 to be on another disk since
 -        the AppNote allows it and the ecrec64 can be large, especially if
 -        Version 2 is used (AppNote uses 8 bytes for the size of this record). */
 - 
 -     /* FIX BELOW IF ADD SUPPORT FOR MULTIPLE DISKS */
 - 
 -     if (ecrec64_start_offset > (zusz_t)ecloc64_start_offset) {
 -       /* ecrec64 has to be before ecrec64 locator */
 -       if (uO.qflag || uO.zipinfo_mode)
 -           Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
 -       Info(slide, 0x401, ((char *)slide,
 -         LoadFarString(Cent64EndSigSearchErr)));
 -       return PK_ERR;
 -     }
 - 
 - #ifdef USE_STRM_INPUT
 -     zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET);
 -     G.cur_zipfile_bufstart = zftello(G.zipfd);
 - #else /* !USE_STRM_INPUT */
 -     G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET);
 - #endif /* ?USE_STRM_INPUT */
 - 
 -     if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4))
 -         != (ECREC64_SIZE+4)) {
 -       if (uO.qflag || uO.zipinfo_mode)
 -           Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
 -       Info(slide, 0x401, ((char *)slide,
 -         LoadFarString(Cent64EndSigSearchErr)));
 -       return PK_ERR;
 -     }
 - 
 -     if (memcmp((char *)byterec, end_central64_sig, 4) ) {
 -       /* Zip64 EOCD Record not found */
 -       /* Since we already have seen the Zip64 EOCD Locator, it's
 -          possible we got here because there are bytes prepended
 -          to the archive, like the sfx prefix. */
 - 
 -       /* Make a guess as to where the Zip64 EOCD Record might be */
 -       ecrec64_start_offset = ecloc64_start_offset - ECREC64_SIZE - 4;
 - 
 - #ifdef USE_STRM_INPUT
 -       zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET);
 -       G.cur_zipfile_bufstart = zftello(G.zipfd);
 - #else /* !USE_STRM_INPUT */
 -       G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET);
 - #endif /* ?USE_STRM_INPUT */
 - 
 -       if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4))
 -           != (ECREC64_SIZE+4)) {
 -         if (uO.qflag || uO.zipinfo_mode)
 -             Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
 -         Info(slide, 0x401, ((char *)slide,
 -           LoadFarString(Cent64EndSigSearchErr)));
 -         return PK_ERR;
 -       }
 - 
 -       if (memcmp((char *)byterec, end_central64_sig, 4) ) {
 -         /* Zip64 EOCD Record not found */
 -         /* Probably something not so easy to handle so exit */
 -         if (uO.qflag || uO.zipinfo_mode)
 -             Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
 -         Info(slide, 0x401, ((char *)slide,
 -           LoadFarString(Cent64EndSigSearchErr)));
 -         return PK_ERR;
 -       }
 - 
 -       if (uO.qflag || uO.zipinfo_mode)
 -           Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
 -       Info(slide, 0x401, ((char *)slide,
 -         LoadFarString(Cent64EndSigSearchOff)));
 -     }
 - 
 -     /* Check consistency of found ecrec64 with ecloc64 (and ecrec): */
 -     if ( (zuvl_t)makelong(&byterec[NUMBER_THIS_DSK_REC64])
 -          != ecrec64_start_disk )
 -         /* found ecrec64 does not match ecloc64 info -> no Zip64 archive */
 -         return PK_COOL;
 -     /* Read all relevant ecrec64 fields and compare them to the corresponding
 -        ecrec fields unless those are set to "all-ones".
 -      */
 -     ecrec64_disk_cdstart =
 -       (zuvl_t)makelong(&byterec[NUM_DISK_START_CEN_DIR64]);
 -     if ( (G.ecrec.num_disk_start_cdir != 0xFFFF) &&
 -          (G.ecrec.num_disk_start_cdir != ecrec64_disk_cdstart) )
 -         return PK_COOL;
 -     ecrec64_this_entries
 -       = makeint64(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK64]);
 -     if ( (G.ecrec.num_entries_centrl_dir_ths_disk != 0xFFFF) &&
 -          (G.ecrec.num_entries_centrl_dir_ths_disk != ecrec64_this_entries) )
 -         return PK_COOL;
 -     ecrec64_tot_entries
 -       = makeint64(&byterec[TOTAL_ENTRIES_CENTRAL_DIR64]);
 -     if ( (G.ecrec.total_entries_central_dir != 0xFFFF) &&
 -          (G.ecrec.total_entries_central_dir != ecrec64_tot_entries) )
 -         return PK_COOL;
 -     ecrec64_cdirsize
 -       = makeint64(&byterec[SIZE_CENTRAL_DIRECTORY64]);
 -     if ( (G.ecrec.size_central_directory != 0xFFFFFFFFL) &&
 -          (G.ecrec.size_central_directory != ecrec64_cdirsize) )
 -         return PK_COOL;
 -     ecrec64_offs_cdstart
 -       = makeint64(&byterec[OFFSET_START_CENTRAL_DIRECT64]);
 -     if ( (G.ecrec.offset_start_central_directory != 0xFFFFFFFFL) &&
 -          (G.ecrec.offset_start_central_directory != ecrec64_offs_cdstart) )
 -         return PK_COOL;
 - 
 -     /* Now, we are (almost) sure that we have a Zip64 archive. */
 -     G.ecrec.have_ecr64 = 1;
 - 
 -     /* Update the "end-of-central-dir offset" for later checks. */
 -     G.real_ecrec_offset = ecrec64_start_offset;
 - 
 -     /* Update all ecdir_rec data that are flagged to be invalid
 -        in Zip64 mode.  Set the ecrec64-mandatory flag when such a
 -        case is found. */
 -     if (G.ecrec.number_this_disk == 0xFFFF) {
 -       G.ecrec.number_this_disk = ecrec64_start_disk;
 -       if (ecrec64_start_disk != 0xFFFF) G.ecrec.is_zip64_archive = TRUE;
 -     }
 -     if (G.ecrec.num_disk_start_cdir == 0xFFFF) {
 -       G.ecrec.num_disk_start_cdir = ecrec64_disk_cdstart;
 -       if (ecrec64_disk_cdstart != 0xFFFF) G.ecrec.is_zip64_archive = TRUE;
 -     }
 -     if (G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF) {
 -       G.ecrec.num_entries_centrl_dir_ths_disk = ecrec64_this_entries;
 -       if (ecrec64_this_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE;
 -     }
 -     if (G.ecrec.total_entries_central_dir == 0xFFFF) {
 -       G.ecrec.total_entries_central_dir = ecrec64_tot_entries;
 -       if (ecrec64_tot_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE;
 -     }
 -     if (G.ecrec.size_central_directory == 0xFFFFFFFFL) {
 -       G.ecrec.size_central_directory = ecrec64_cdirsize;
 -       if (ecrec64_cdirsize != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE;
 -     }
 -     if (G.ecrec.offset_start_central_directory == 0xFFFFFFFFL) {
 -       G.ecrec.offset_start_central_directory = ecrec64_offs_cdstart;
 -       if (ecrec64_offs_cdstart != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE;
 -     }
 - 
 -     return PK_COOL;
 - } /* end function find_ecrec64() */
 - 
 - 
 - 
 - /*************************/
 - /* Function find_ecrec() */
 - /*************************/
 - 
 - static int find_ecrec(__G__ searchlen)          /* return PK-class error */
 -     __GDEF
 -     zoff_t searchlen;
 - {
 -     int found = FALSE;
 -     int error_in_archive;
 -     int result;
 -     ec_byte_rec byterec;
 - 
 - /*---------------------------------------------------------------------------
 -     Treat case of short zipfile separately.
 -   ---------------------------------------------------------------------------*/
 - 
 -     if (G.ziplen <= INBUFSIZ) {
 - #ifdef USE_STRM_INPUT
 -         zfseeko(G.zipfd, 0L, SEEK_SET);
 - #else /* !USE_STRM_INPUT */
 -         zlseek(G.zipfd, 0L, SEEK_SET);
 - #endif /* ?USE_STRM_INPUT */
 -         if ((G.incnt = read(G.zipfd,(char *)G.inbuf,(unsigned int)G.ziplen))
 -             == (int)G.ziplen)
 - 
 -             /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */
 -             for (G.inptr = G.inbuf+(int)G.ziplen-(ECREC_SIZE+4);
 -                  G.inptr >= G.inbuf;
 -                  --G.inptr) {
 -                 if ( (*G.inptr == (uch)0x50) &&         /* ASCII 'P' */
 -                      !memcmp((char *)G.inptr, end_central_sig, 4)) {
 -                     G.incnt -= (int)(G.inptr - G.inbuf);
 -                     found = TRUE;
 -                     break;
 -                 }
 -             }
 - 
 - /*---------------------------------------------------------------------------
 -     Zipfile is longer than INBUFSIZ:
 - 
 -     MB - this next block of code moved to rec_find so that same code can be
 -     used to look for zip64 ec record.  No need to include code above since
 -     a zip64 ec record will only be looked for if it is a BIG file.
 -   ---------------------------------------------------------------------------*/
 - 
 -     } else {
 -         found =
 -           (rec_find(__G__ searchlen, end_central_sig, ECREC_SIZE) == 0
 -            ? TRUE : FALSE);
 -     } /* end if (ziplen > INBUFSIZ) */
 - 
 - /*---------------------------------------------------------------------------
 -     Searched through whole region where signature should be without finding
 -     it.  Print informational message and die a horrible death.
 -   ---------------------------------------------------------------------------*/
 - 
 -     if (!found) {
 -         if (uO.qflag || uO.zipinfo_mode)
 -             Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
 -         Info(slide, 0x401, ((char *)slide,
 -           LoadFarString(CentDirEndSigNotFound)));
 -         return PK_ERR;   /* failed */
 -     }
 - 
 - /*---------------------------------------------------------------------------
 -     Found the signature, so get the end-central data before returning.  Do
 -     any necessary machine-type conversions (byte ordering, structure padding
 -     compensation) by reading data into character array and copying to struct.
 -   ---------------------------------------------------------------------------*/
 - 
 -     G.real_ecrec_offset = G.cur_zipfile_bufstart + (G.inptr-G.inbuf);
 - #ifdef TEST
 -     printf("\n  found end-of-central-dir signature at offset %s (%sh)\n",
 -       FmZofft(G.real_ecrec_offset, NULL, NULL),
 -       FmZofft(G.real_ecrec_offset, FZOFFT_HEX_DOT_WID, "X"));
 -     printf("    from beginning of file; offset %d (%.4Xh) within block\n",
 -       G.inptr-G.inbuf, G.inptr-G.inbuf);
 - #endif
 - 
 -     if (readbuf(__G__ (char *)byterec, ECREC_SIZE+4) == 0)
 -         return PK_EOF;
 - 
 -     G.ecrec.number_this_disk =
 -       makeword(&byterec[NUMBER_THIS_DISK]);
 -     G.ecrec.num_disk_start_cdir =
 -       makeword(&byterec[NUM_DISK_WITH_START_CEN_DIR]);
 -     G.ecrec.num_entries_centrl_dir_ths_disk =
 -       makeword(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK]);
 -     G.ecrec.total_entries_central_dir =
 -       makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
 -     G.ecrec.size_central_directory =
 -       makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
 -     G.ecrec.offset_start_central_directory =
 -       makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
 -     G.ecrec.zipfile_comment_length =
 -       makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
 - 
 -     /* Now, we have to read the archive comment, BEFORE the file pointer
 -        is moved away backwards to seek for a Zip64 ECLOC64 structure.
 -      */
 -     if ( (error_in_archive = process_zip_cmmnt(__G)) > PK_WARN )
 -         return error_in_archive;
 - 
 -     /* Next: Check for existence of Zip64 end-of-cent-dir locator
 -        ECLOC64. This structure must reside on the same volume as the
 -        classic ECREC, at exactly (ECLOC64_SIZE+4) bytes in front
 -        of the ECREC.
 -        The ECLOC64 structure directs to the longer ECREC64 structure
 -        A ECREC64 will ALWAYS exist for a proper Zip64 archive, as
 -        the "Version Needed To Extract" field is required to be set
 -        to 4.5 or higher whenever any Zip64 features are used anywhere
 -        in the archive, so just check for that to see if this is a
 -        Zip64 archive.
 -      */
 -     result = find_ecrec64(__G__ searchlen+76);
 -         /* 76 bytes for zip64ec & zip64 locator */
 -     if (result != PK_COOL) {
 -         if (error_in_archive < result)
 -             error_in_archive = result;
 -         return error_in_archive;
 -     }
 - 
 -     G.expect_ecrec_offset = G.ecrec.offset_start_central_directory +
 -                             G.ecrec.size_central_directory;
 - 
 - #ifndef NO_ZIPINFO
 -     if (uO.zipinfo_mode) {
 -         /* In ZipInfo mode, additional info about the data found in the
 -            end-of-central-directory areas is printed out.
 -          */
 -         zi_end_central(__G);
 -     }
 - #endif
 - 
 -     return error_in_archive;
 - 
 - } /* end function find_ecrec() */
 - 
 - 
 - 
 - 
 - 
 - /********************************/
 - /* Function process_zip_cmmnt() */
 - /********************************/
 - 
 - static int process_zip_cmmnt(__G)       /* return PK-type error code */
 -     __GDEF
 - {
 -     int error = PK_COOL;
 - 
 - 
 - /*---------------------------------------------------------------------------
 -     Get the zipfile comment (up to 64KB long), if any, and print it out.
 -   ---------------------------------------------------------------------------*/
 - 
 - #ifdef WINDLL
 -     /* for comment button: */
 -     if ((!G.fValidate) && (G.lpUserFunctions != NULL))
 -        G.lpUserFunctions->cchComment = G.ecrec.zipfile_comment_length;
 - #endif /* WINDLL */
 - 
 - #ifndef NO_ZIPINFO
 -     /* ZipInfo, verbose format */
 -     if (uO.zipinfo_mode && uO.lflag > 9) {
 -         /*-------------------------------------------------------------------
 -             Get the zipfile comment, if any, and print it out.
 -             (Comment may be up to 64KB long.  May the fleas of a thousand
 -             camels infest the arm-pits of anyone who actually takes advantage
 -             of this fact.)
 -           -------------------------------------------------------------------*/
 - 
 -         if (!G.ecrec.zipfile_comment_length)
 -             Info(slide, 0, ((char *)slide, LoadFarString(NoZipfileComment)));
 -         else {
 -             Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommentDesc),
 -               G.ecrec.zipfile_comment_length));
 -             Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommBegin)));
 -             if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY))
 -                 error = PK_WARN;
 -             Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommEnd)));
 -             if (error)
 -                 Info(slide, 0, ((char *)slide,
 -                   LoadFarString(ZipfileCommTrunc2)));
 -         } /* endif (comment exists) */
 - 
 -     /* ZipInfo, non-verbose mode:  print zipfile comment only if requested */
 -     } else if (G.ecrec.zipfile_comment_length &&
 -                (uO.zflag > 0) && uO.zipinfo_mode) {
 -         if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) {
 -             Info(slide, 0x401, ((char *)slide,
 -               LoadFarString(ZipfileCommTrunc1)));
 -             error = PK_WARN;
 -         }
 -     } else
 - #endif /* !NO_ZIPINFO */
 -     if ( G.ecrec.zipfile_comment_length &&
 -          (uO.zflag > 0
 - #ifndef WINDLL
 -           || (uO.zflag == 0
 - # ifndef NO_ZIPINFO
 -               && !uO.zipinfo_mode
 - # endif
 - # ifdef TIMESTAMP
 -               && !uO.T_flag
 - # endif
 -               && !uO.qflag)
 - #endif /* !WINDLL */
 -          ) )
 -     {
 -         if (do_string(__G__ G.ecrec.zipfile_comment_length,
 - #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
 - # ifndef NO_ZIPINFO
 -                       (oU.zipinfo_mode ? DISPLAY : CHECK_AUTORUN)
 - # else
 -                       CHECK_AUTORUN
 - # endif
 - #else
 -                       DISPLAY
 - #endif
 -                      ))
 -         {
 -             Info(slide, 0x401, ((char *)slide,
 -               LoadFarString(ZipfileCommTrunc1)));
 -             error = PK_WARN;
 -         }
 -     }
 - #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
 -     else if (G.ecrec.zipfile_comment_length) {
 -         if (do_string(__G__ G.ecrec.zipfile_comment_length, CHECK_AUTORUN_Q))
 -         {
 -             Info(slide, 0x401, ((char *)slide,
 -               LoadFarString(ZipfileCommTrunc1)));
 -             error = PK_WARN;
 -         }
 -     }
 - #endif
 -     return error;
 - 
 - } /* end function process_zip_cmmnt() */
 - 
 - 
 - 
 - 
 - 
 - /************************************/
 - /* Function process_cdir_file_hdr() */
 - /************************************/
 - 
 - int process_cdir_file_hdr(__G)    /* return PK-type error code */
 -     __GDEF
 - {
 -     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_ent(__G)) != 0)
 -         return error;
 - 
 -     G.pInfo->hostver = G.crec.version_made_by[0];
 -     G.pInfo->hostnum = MIN(G.crec.version_made_by[1], NUM_HOSTS);
 - /*  extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
 - 
 -     G.pInfo->lcflag = 0;
 -     if (uO.L_flag == 1)       /* name conversion for monocase systems */
 -         switch (G.pInfo->hostnum) {
 -             case FS_FAT_:     /* PKZIP and zip -k store in uppercase */
 -             case CPM_:        /* like MS-DOS, right? */
 -             case VM_CMS_:     /* all caps? */
 -             case MVS_:        /* all caps? */
 -             case TANDEM_:
 -             case TOPS20_:
 -             case VMS_:        /* our Zip uses lowercase, but ASi's doesn't */
 -         /*  case Z_SYSTEM_:   ? */
 -         /*  case QDOS_:       ? */
 -                 G.pInfo->lcflag = 1;   /* convert filename to lowercase */
 -                 break;
 - 
 -             default:     /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */
 -                 break;   /*  FS_VFAT_, ATHEOS_, BEOS_ (Z_SYSTEM_), THEOS_: */
 -                          /*  no conversion */
 -         }
 -     else if (uO.L_flag > 1)   /* let -LL force lower case for all names */
 -         G.pInfo->lcflag = 1;
 - 
 -     /* do Amigas (AMIGA_) also have volume labels? */
 -     if (IS_VOLID(G.crec.external_file_attributes) &&
 -         (G.pInfo->hostnum == FS_FAT_ || G.pInfo->hostnum == FS_HPFS_ ||
 -          G.pInfo->hostnum == FS_NTFS_ || G.pInfo->hostnum == ATARI_))
 -     {
 -         G.pInfo->vollabel = TRUE;
 -         G.pInfo->lcflag = 0;        /* preserve case of volume labels */
 -     } else
 -         G.pInfo->vollabel = FALSE;
 - 
 -     /* this flag is needed to detect archives made by "PKZIP for Unix" when
 -        deciding which kind of codepage conversion has to be applied to
 -        strings (see do_string() function in fileio.c) */
 -     G.pInfo->HasUxAtt = (G.crec.external_file_attributes & 0xffff0000L) != 0L;
 - 
 - #ifdef UNICODE_SUPPORT
 -     /* remember the state of GPB11 (General Purpuse Bit 11) which indicates
 -        that the standard path and comment are UTF-8. */
 -     G.pInfo->GPFIsUTF8
 -         = (G.crec.general_purpose_bit_flag & (1 << 11)) == (1 << 11);
 - #endif
 - 
 -     return PK_COOL;
 - 
 - } /* end function process_cdir_file_hdr() */
 - 
 - 
 - 
 - 
 - 
 - /***************************/
 - /* Function get_cdir_ent() */
 - /***************************/
 - 
 - static int get_cdir_ent(__G)    /* return PK-type error code */
 -     __GDEF
 - {
 -     cdir_byte_hdr byterec;
 - 
 - 
 - /*---------------------------------------------------------------------------
 -     Read the next central directory entry and do any necessary machine-type
 -     conversions (byte ordering, structure padding compensation--do so by
 -     copying the data from the array into which it was read (byterec) to the
 -     usable struct (crec)).
 -   ---------------------------------------------------------------------------*/
 - 
 -     if (readbuf(__G__ (char *)byterec, CREC_SIZE) == 0)
 -         return PK_EOF;
 - 
 -     G.crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
 -     G.crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
 -     G.crec.version_needed_to_extract[0] =
 -       byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
 -     G.crec.version_needed_to_extract[1] =
 -       byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
 - 
 -     G.crec.general_purpose_bit_flag =
 -       makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
 -     G.crec.compression_method =
 -       makeword(&byterec[C_COMPRESSION_METHOD]);
 -     G.crec.last_mod_dos_datetime =
 -       makelong(&byterec[C_LAST_MOD_DOS_DATETIME]);
 -     G.crec.crc32 =
 -       makelong(&byterec[C_CRC32]);
 -     G.crec.csize =
 -       makelong(&byterec[C_COMPRESSED_SIZE]);
 -     G.crec.ucsize =
 -       makelong(&byterec[C_UNCOMPRESSED_SIZE]);
 -     G.crec.filename_length =
 -       makeword(&byterec[C_FILENAME_LENGTH]);
 -     G.crec.extra_field_length =
 -       makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
 -     G.crec.file_comment_length =
 -       makeword(&byterec[C_FILE_COMMENT_LENGTH]);
 -     G.crec.disk_number_start =
 -       makeword(&byterec[C_DISK_NUMBER_START]);
 -     G.crec.internal_file_attributes =
 -       makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
 -     G.crec.external_file_attributes =
 -       makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]);  /* LONG, not word! */
 -     G.crec.relative_offset_local_header =
 -       makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
 - 
 -     return PK_COOL;
 - 
 - } /* end function get_cdir_ent() */
 - 
 - 
 - 
 - 
 - 
 - /*************************************/
 - /* Function process_local_file_hdr() */
 - /*************************************/
 - 
 - int process_local_file_hdr(__G)    /* return PK-type error code */
 -     __GDEF
 - {
 -     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(__G__ (char *)byterec, LREC_SIZE) == 0)
 -         return PK_EOF;
 - 
 -     G.lrec.version_needed_to_extract[0] =
 -       byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
 -     G.lrec.version_needed_to_extract[1] =
 -       byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
 - 
 -     G.lrec.general_purpose_bit_flag =
 -       makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
 -     G.lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
 -     G.lrec.last_mod_dos_datetime = makelong(&byterec[L_LAST_MOD_DOS_DATETIME]);
 -     G.lrec.crc32 = makelong(&byterec[L_CRC32]);
 -     G.lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]);
 -     G.lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
 -     G.lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
 -     G.lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
 - 
 -     if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
 -         /* can't trust local header, use central directory: */
 -         G.lrec.crc32 = G.pInfo->crc;
 -         G.lrec.csize = G.pInfo->compr_size;
 -         G.lrec.ucsize = G.pInfo->uncompr_size;
 -     }
 - 
 -     G.csize = G.lrec.csize;
 - 
 -     return PK_COOL;
 - 
 - } /* end function process_local_file_hdr() */
 - 
 - 
 - /*******************************/
 - /* Function getZip64Data() */
 - /*******************************/
 - 
 - int getZip64Data(__G__ ef_buf, ef_len)
 -     __GDEF
 -     ZCONST uch *ef_buf; /* buffer containing extra field */
 -     unsigned ef_len;    /* total length of extra field */
 - {
 -     unsigned eb_id;
 -     unsigned eb_len;
 - 
 - /*---------------------------------------------------------------------------
 -     This function scans the extra field for zip64 information, ie 8-byte
 -     versions of compressed file size, uncompressed file size, relative offset
 -     and a 4-byte version of disk start number.
 -     Sets both local header and central header fields.  Not terribly clever,
 -     but it means that this procedure is only called in one place.
 -   ---------------------------------------------------------------------------*/
 - 
 -     if (ef_len == 0 || ef_buf == NULL)
 -         return PK_COOL;
 - 
 -     Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n",
 -       ef_len));
 - 
 -     while (ef_len >= EB_HEADSIZE) {
 -         eb_id = makeword(EB_ID + ef_buf);
 -         eb_len = makeword(EB_LEN + ef_buf);
 - 
 -         if (eb_len > (ef_len - EB_HEADSIZE)) {
 -             /* discovered some extra field inconsistency! */
 -             Trace((stderr,
 -               "getZip64Data: block length %u > rest ef_size %u\n", eb_len,
 -               ef_len - EB_HEADSIZE));
 -             break;
 -         }
 -         if (eb_id == EF_PKSZ64) {
 - 
 -           int offset = EB_HEADSIZE;
 - 
 -           if (G.crec.ucsize == 0xffffffff || G.lrec.ucsize == 0xffffffff){
 -             G.lrec.ucsize = G.crec.ucsize = makeint64(offset + ef_buf);
 -             offset += sizeof(G.crec.ucsize);
 -           }
 -           if (G.crec.csize == 0xffffffff || G.lrec.csize == 0xffffffff){
 -             G.csize = G.lrec.csize = G.crec.csize = makeint64(offset + ef_buf);
 -             offset += sizeof(G.crec.csize);
 -           }
 -           if (G.crec.relative_offset_local_header == 0xffffffff){
 -             G.crec.relative_offset_local_header = makeint64(offset + ef_buf);
 -             offset += sizeof(G.crec.relative_offset_local_header);
 -           }
 -           if (G.crec.disk_number_start == 0xffff){
 -             G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf);
 -             offset += sizeof(G.crec.disk_number_start);
 -           }
 -         }
 - 
 -         /* Skip this extra field block */
 -         ef_buf += (eb_len + EB_HEADSIZE);
 -         ef_len -= (eb_len + EB_HEADSIZE);
 -     }
 - 
 -     return PK_COOL;
 - } /* end function getZip64Data() */
 - 
 - 
 - #ifdef UNICODE_SUPPORT
 - 
 - /*******************************/
 - /* Function getUnicodeData() */
 - /*******************************/
 - 
 - int getUnicodeData(__G__ ef_buf, ef_len)
 -     __GDEF
 -     ZCONST uch *ef_buf; /* buffer containing extra field */
 -     unsigned ef_len;    /* total length of extra field */
 - {
 -     unsigned eb_id;
 -     unsigned eb_len;
 - 
 - /*---------------------------------------------------------------------------
 -     This function scans the extra field for Unicode information, ie UTF-8
 -     path extra fields.
 - 
 -     On return, G.unipath_filename =
 -         NULL, if no Unicode path extra field or error
 -         "", if the standard path is UTF-8 (free when done)
 -         null-terminated UTF-8 path (free when done)
 -     Return PK_COOL if no error.
 -   ---------------------------------------------------------------------------*/
 - 
 -     G.unipath_filename = NULL;
 - 
 -     if (ef_len == 0 || ef_buf == NULL)
 -         return PK_COOL;
 - 
 -     Trace((stderr,"\ngetUnicodeData: scanning extra field of length %u\n",
 -       ef_len));
 - 
 -     while (ef_len >= EB_HEADSIZE) {
 -         eb_id = makeword(EB_ID + ef_buf);
 -         eb_len = makeword(EB_LEN + ef_buf);
 - 
 -         if (eb_len > (ef_len - EB_HEADSIZE)) {
 -             /* discovered some extra field inconsistency! */
 -             Trace((stderr,
 -               "getUnicodeData: block length %u > rest ef_size %u\n", eb_len,
 -               ef_len - EB_HEADSIZE));
 -             break;
 -         }
 -         if (eb_id == EF_UNIPATH) {
 - 
 -           int offset = EB_HEADSIZE;
 -           ush ULen = eb_len - 5;
 -           ulg chksum = CRCVAL_INITIAL;
 - 
 -           /* version */
 -           G.unipath_version = (uch) *(offset + ef_buf);
 -           offset += 1;
 -           if (G.unipath_version > 1) {
 -             /* can do only version 1 */
 -             Info(slide, 0x401, ((char *)slide,
 -               LoadFarString(UnicodeVersionError)));
 -             return PK_ERR;
 -           }
 - 
 -           /* filename CRC */
 -           G.unipath_checksum = makelong(offset + ef_buf);
 -           offset += 4;
 - 
 -           /*
 -            * Compute 32-bit crc
 -            */
 - 
 -           chksum = crc32(chksum, (uch *)(G.filename_full),
 -                          strlen(G.filename_full));
 - 
 -           /* If the checksums's don't match then likely filename has been
 -            * modified and the Unicode Path is no longer valid.
 -            */
 -           if (chksum != G.unipath_checksum) {
 -             Info(slide, 0x401, ((char *)slide,
 -               LoadFarString(UnicodeMismatchError)));
 -             if (G.unicode_mismatch == 1) {
 -               /* warn and continue */
 -             } else if (G.unicode_mismatch == 2) {
 -               /* ignore and continue */
 -             } else if (G.unicode_mismatch == 0) {
 -             }
 -             return PK_ERR;
 -           }
 - 
 -           /* UTF-8 Path */
 -           if ((G.unipath_filename = malloc(ULen + 1)) == NULL) {
 -             return PK_ERR;
 -           }
 -           if (ULen == 0) {
 -             /* standard path is UTF-8 so use that */
 -             G.unipath_filename[0] = '\0';
 -           } else {
 -             /* UTF-8 path */
 -             strncpy(G.unipath_filename,
 -                     (ZCONST char *)(offset + ef_buf), ULen);
 -             G.unipath_filename[ULen] = '\0';
 -           }
 -         }
 - 
 -         /* Skip this extra field block */
 -         ef_buf += (eb_len + EB_HEADSIZE);
 -         ef_len -= (eb_len + EB_HEADSIZE);
 -     }
 - 
 -     return PK_COOL;
 - } /* end function getUnicodeData() */
 - 
 - 
 - 
 - 
 - #ifdef UNICODE_WCHAR
 -   /*---------------------------------------------
 -  * Unicode conversion functions
 -  *
 -  * Based on functions provided by Paul Kienitz
 -  *
 -  *---------------------------------------------
 -  */
 - 
 - /*
 -    NOTES APPLICABLE TO ALL STRING FUNCTIONS:
 - 
 -    All of the x_to_y functions take parameters for an output buffer and
 -    its available length, and return an int.  The value returned is the
 -    length of the string that the input produces, which may be larger than
 -    the provided buffer length.  If the returned value is less than the
 -    buffer length, then the contents of the buffer will be null-terminated;
 -    otherwise, it will not be terminated and may be invalid, possibly
 -    stopping in the middle of a multibyte sequence.
 - 
 -    In all cases you may pass NULL as the buffer and/or 0 as the length, if
 -    you just want to learn how much space the string is going to require.
 - 
 -    The functions will return -1 if the input is invalid UTF-8 or cannot be
 -    encoded as UTF-8.
 - */
 - 
 - static int utf8_char_bytes OF((ZCONST char *utf8));
 - static ulg ucs4_char_from_utf8 OF((ZCONST char **utf8));
 - static int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *ucs4buf,
 -                                    int buflen));
 - 
 - /* utility functions for managing UTF-8 and UCS-4 strings */
 - 
 - 
 - /* utf8_char_bytes
 -  *
 -  * Returns the number of bytes used by the first character in a UTF-8
 -  * string, or -1 if the UTF-8 is invalid or null.
 -  */
 - static int utf8_char_bytes(utf8)
 -   ZCONST char *utf8;
 - {
 -   int      t, r;
 -   unsigned lead;
 - 
 -   if (!utf8)
 -     return -1;          /* no input */
 -   lead = (unsigned char) *utf8;
 -   if (lead < 0x80)
 -     r = 1;              /* an ascii-7 character */
 -   else if (lead < 0xC0)
 -     return -1;          /* error: trailing byte without lead byte */
 -   else if (lead < 0xE0)
 -     r = 2;              /* an 11 bit character */
 -   else if (lead < 0xF0)
 -     r = 3;              /* a 16 bit character */
 -   else if (lead < 0xF8)
 -     r = 4;              /* a 21 bit character (the most currently used) */
 -   else if (lead < 0xFC)
 -     r = 5;              /* a 26 bit character (shouldn't happen) */
 -   else if (lead < 0xFE)
 -     r = 6;              /* a 31 bit character (shouldn't happen) */
 -   else
 -     return -1;          /* error: invalid lead byte */
 -   for (t = 1; t < r; t++)
 -     if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0)
 -       return -1;        /* error: not enough valid trailing bytes */
 -   return r;
 - }
 - 
 - 
 - /* ucs4_char_from_utf8
 -  *
 -  * Given a reference to a pointer into a UTF-8 string, returns the next
 -  * UCS-4 character and advances the pointer to the next character sequence.
 -  * Returns ~0 (= -1 in twos-complement notation) and does not advance the
 -  * pointer when input is ill-formed.
 -  */
 - static ulg ucs4_char_from_utf8(utf8)
 -   ZCONST char **utf8;
 - {
 -   ulg  ret;
 -   int  t, bytes;
 - 
 -   if (!utf8)
 -     return ~0L;                         /* no input */
 -   bytes = utf8_char_bytes(*utf8);
 -   if (bytes <= 0)
 -     return ~0L;                         /* invalid input */
 -   if (bytes == 1)
 -     ret = **utf8;                       /* ascii-7 */
 -   else
 -     ret = **utf8 & (0x7F >> bytes);     /* lead byte of a multibyte sequence */
 -   (*utf8)++;
 -   for (t = 1; t < bytes; t++)           /* consume trailing bytes */
 -     ret = (ret << 6) | (*((*utf8)++) & 0x3F);
 -   return (zwchar) ret;
 - }
 - 
 - 
 - #if 0 /* currently unused */
 - /* utf8_from_ucs4_char - Convert UCS char to UTF-8
 -  *
 -  * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6,
 -  * or -1 if ch is too large to represent.  utf8buf must have room for 6 bytes.
 -  */
 - static int utf8_from_ucs4_char(utf8buf, ch)
 -   char *utf8buf;
 -   ulg ch;
 - {
 -   int trailing = 0;
 -   int leadmask = 0x80;
 -   int leadbits = 0x3F;
 -   int tch = ch;
 -   int ret;
 - 
 -   if (ch > 0x7FFFFFFFL)
 -     return -1;                /* UTF-8 can represent 31 bits */
 -   if (ch < 0x7F)
 -   {
 -     *utf8buf++ = (char) ch;   /* ascii-7 */
 -     return 1;
 -   }
 -   do {
 -     trailing++;
 -     leadmask = (leadmask >> 1) | 0x80;
 -     leadbits >>= 1;
 -     tch >>= 6;
 -   } while (tch & ~leadbits);
 -   ret = trailing + 1;
 -   /* produce lead byte */
 -   *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing)));
 -   while (--trailing >= 0)
 -     /* produce trailing bytes */
 -     *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F));
 -   return ret;
 - }
 - #endif /* unused */
 - 
 - 
 - /*===================================================================*/
 - 
 - /* utf8_to_ucs4_string - convert UTF-8 string to UCS string
 -  *
 -  * Return UCS count.  Now returns int so can return -1.
 -  */
 - static int utf8_to_ucs4_string(utf8, ucs4buf, buflen)
 -   ZCONST char *utf8;
 -   ulg *ucs4buf;
 -   int buflen;
 - {
 -   int count = 0;
 - 
 -   for (;;)
 -   {
 -     ulg ch = ucs4_char_from_utf8(&utf8);
 -     if (ch == ~0L)
 -       return -1;
 -     else
 -     {
 -       if (ucs4buf && count < buflen)
 -         ucs4buf[count] = ch;
 -       if (ch == 0)
 -         return count;
 -       count++;
 -     }
 -   }
 - }
 - 
 - 
 - #if 0 /* currently unused */
 - /* ucs4_string_to_utf8
 -  *
 -  *
 -  */
 - static int ucs4_string_to_utf8(ucs4, utf8buf, buflen)
 -   ZCONST ulg *ucs4;
 -   char *utf8buf;
 -   int buflen;
 - {
 -   char mb[6];
 -   int  count = 0;
 - 
 -   if (!ucs4)
 -     return -1;
 -   for (;;)
 -   {
 -     int mbl = utf8_from_ucs4_char(mb, *ucs4++);
 -     int c;
 -     if (mbl <= 0)
 -       return -1;
 -     /* We could optimize this a bit by passing utf8buf + count */
 -     /* directly to utf8_from_ucs4_char when buflen >= count + 6... */
 -     c = buflen - count;
 -     if (mbl < c)
 -       c = mbl;
 -     if (utf8buf && count < buflen)
 -       strncpy(utf8buf + count, mb, c);
 -     if (mbl == 1 && !mb[0])
 -       return count;           /* terminating nul */
 -     count += mbl;
 -   }
 - }
 - 
 - 
 - /* utf8_chars
 -  *
 -  * Wrapper: counts the actual unicode characters in a UTF-8 string.
 -  */
 - static int utf8_chars(utf8)
 -   ZCONST char *utf8;
 - {
 -   return utf8_to_ucs4_string(utf8, NULL, 0);
 - }
 - #endif /* unused */
 - 
 - /* --------------------------------------------------- */
 - /* Unicode Support
 -  *
 -  * These functions common for all Unicode ports.
 -  *
 -  * These functions should allocate and return strings that can be
 -  * freed with free().
 -  *
 -  * 8/27/05 EG
 -  *
 -  * Use zwchar for wide char which is unsigned long
 -  * in zip.h and 32 bits.  This avoids problems with
 -  * different sizes of wchar_t.
 -  */
 - 
 - #if 0 /* currently unused */
 - /* is_ascii_string
 -  * Checks if a string is all ascii
 -  */
 - int is_ascii_string(mbstring)
 -   ZCONST char *mbstring;
 - {
 -   char *p;
 -   uch c;
 - 
 -   for (p = mbstring; c = (uch)*p; p++) {
 -     if (c > 0x7F) {
 -       return 0;
 -     }
 -   }
 -   return 1;
 - }
 - 
 - /* local to UTF-8 */
 - char *local_to_utf8_string(local_string)
 -   ZCONST char *local_string;
 - {
 -   return wide_to_utf8_string(local_to_wide_string(local_string));
 - }
 - # endif /* unused */
 - 
 - /* wide_to_escape_string
 -    provides a string that represents a wide char not in local char set
 - 
 -    An initial try at an algorithm.  Suggestions welcome.
 - 
 -    According to the standard, Unicode character points are restricted to
 -    the number range from 0 to 0x10FFFF, respective 21 bits.
 -    For a hexadecimal notation, 2 octets are sufficient for the mostly
 -    used characters from the "Basic Multilingual Plane", all other
 -    Unicode characters can be represented by 3 octets (= 6 hex digits).
 -    The Unicode standard suggests to write Unicode character points
 -    as 4 resp. 6 hex digits, preprended by "U+".
 -    (e.g.: U+10FFFF for the highest character point, or U+0030 for the ASCII
 -    digit "0")
 - 
 -    However, for the purpose of escaping non-ASCII chars in an ASCII character
 -    stream, the "U" is not a very good escape initializer. Therefore, we
 -    use the following convention within our Info-ZIP code:
 - 
 -    If not an ASCII char probably need 2 bytes at least.  So if
 -    a 2-byte wide encode it as 4 hex digits with a leading #U.  If
 -    needs 3 bytes then prefix the string with #L.  So
 -    #U1234
 -    is a 2-byte wide character with bytes 0x12 and 0x34 while
 -    #L123456
 -    is a 3-byte wide character with bytes 0x12, 0x34, 0x56.
 -    On Windows, wide that need two wide characters need to be converted
 -    to a single number.
 -   */
 - 
 -  /* set this to the max bytes an escape can be */
 - #define MAX_ESCAPE_BYTES 8
 - 
 - char *wide_to_escape_string(wide_char)
 -   zwchar wide_char;
 - {
 -   int i;
 -   zwchar w = wide_char;
 -   uch b[sizeof(zwchar)];
 -   char d[3];
 -   char e[11];
 -   int len;
 -   char *r;
 - 
 -   /* fill byte array with zeros */
 -   memzero(b, sizeof(zwchar));
 -   /* get bytes in right to left order */
 -   for (len = 0; w; len++) {
 -     b[len] = (char)(w % 0x100);
 -     w /= 0x100;
 -   }
 -   strcpy(e, "#");
 -   /* either 2 bytes or 3 bytes */
 -   if (len <= 2) {
 -     len = 2;
 -     strcat(e, "U");
 -   } else {
 -     strcat(e, "L");
 -   }
 -   for (i = len - 1; i >= 0; i--) {
 -     sprintf(d, "%02x", b[i]);
 -     strcat(e, d);
 -   }
 -   if ((r = malloc(strlen(e) + 1)) == NULL) {
 -     return NULL;
 -   }
 -   strcpy(r, e);
 -   return r;
 - }
 - 
 - #if 0 /* currently unused */
 - /* returns the wide character represented by the escape string */
 - zwchar escape_string_to_wide(escape_string)
 -   ZCONST char *escape_string;
 - {
 -   int i;
 -   zwchar w;
 -   char c;
 -   int len;
 -   ZCONST char *e = escape_string;
 - 
 -   if (e == NULL) {
 -     return 0;
 -   }
 -   if (e[0] != '#') {
 -     /* no leading # */
 -     return 0;
 -   }
 -   len = strlen(e);
 -   /* either #U1234 or #L123456 format */
 -   if (len != 6 && len != 8) {
 -     return 0;
 -   }
 -   w = 0;
 -   if (e[1] == 'L') {
 -     if (len != 8) {
 -       return 0;
 -     }
 -     /* 3 bytes */
 -     for (i = 2; i < 8; i++) {
 -       c = e[i];
 -       if (c < '0' || c > '9') {
 -         return 0;
 -       }
 -       w = w * 0x10 + (zwchar)(c - '0');
 -     }
 -   } else if (e[1] == 'U') {
 -     /* 2 bytes */
 -     for (i = 2; i < 6; i++) {
 -       c = e[i];
 -       if (c < '0' || c > '9') {
 -         return 0;
 -       }
 -       w = w * 0x10 + (zwchar)(c - '0');
 -     }
 -   }
 -   return w;
 - }
 - #endif /* unused */
 - 
 - #ifndef WIN32  /* WIN32 supplies a special variant of this function */
 - /* convert wide character string to multi-byte character string */
 - char *wide_to_local_string(wide_string, escape_all)
 -   ZCONST zwchar *wide_string;
 -   int escape_all;
 - {
 -   int i;
 -   wchar_t wc;
 -   int b;
 -   int state_dependent;
 -   int wsize = 0;
 -   int max_bytes = MB_CUR_MAX;
 -   char buf[9];
 -   char *buffer = NULL;
 -   char *local_string = NULL;
 - 
 -   for (wsize = 0; wide_string[wsize]; wsize++) ;
 - 
 -   if (max_bytes < MAX_ESCAPE_BYTES)
 -     max_bytes = MAX_ESCAPE_BYTES;
 - 
 -   if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
 -     return NULL;
 -   }
 - 
 -   /* convert it */
 -   buffer[0] = '\0';
 -   /* set initial state if state-dependent encoding */
 -   wc = (wchar_t)'a';
 -   b = wctomb(NULL, wc);
 -   if (b == 0)
 -     state_dependent = 0;
 -   else
 -     state_dependent = 1;
 -   for (i = 0; i < wsize; i++) {
 -     if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
 -       /* wchar_t probably 2 bytes */
 -       /* could do surrogates if state_dependent and wctomb can do */
 -       wc = zwchar_to_wchar_t_default_char;
 -     } else {
 -       wc = (wchar_t)wide_string[i];
 -     }
 -     b = wctomb(buf, wc);
 -     if (escape_all) {
 -       if (b == 1 && (uch)buf[0] <= 0x7f) {
 -         /* ASCII */
 -         strncat(buffer, buf, b);
 -       } else {
 -         /* use escape for wide character */
 -         char *escape_string = wide_to_escape_string(wide_string[i]);
 -         strcat(buffer, escape_string);
 -         free(escape_string);
 -       }
 -     } else if (b > 0) {
 -       /* multi-byte char */
 -       strncat(buffer, buf, b);
 -     } else {
 -       /* no MB for this wide */
 -         /* use escape for wide character */
 -         char *escape_string = wide_to_escape_string(wide_string[i]);
 -         strcat(buffer, escape_string);
 -         free(escape_string);
 -     }
 -   }
 -   if ((local_string = (char *)malloc(strlen(buffer) + 1)) != NULL) {
 -     strcpy(local_string, buffer);
 -   }
 -   free(buffer);
 - 
 -   return local_string;
 - }
 - #endif /* !WIN32 */
 - 
 - #if 0 /* currently unused */
 - /* convert local string to display character set string */
 - char *local_to_display_string(local_string)
 -   ZCONST char *local_string;
 - {
 -   char *display_string;
 - 
 -   /* For Windows, OEM string should never be bigger than ANSI string, says
 -      CharToOem description.
 -      For all other ports, just make a copy of local_string.
 -   */
 -   if ((display_string = (char *)malloc(strlen(local_string) + 1)) == NULL) {
 -     return NULL;
 -   }
 - 
 -   strcpy(display_string, local_string);
 - 
 - #ifdef EBCDIC
 -   {
 -     char *ebc;
 - 
 -     if ((ebc = malloc(strlen(display_string) + 1)) ==  NULL) {
 -       return NULL;
 -     }
 -     strtoebc(ebc, display_string);
 -     free(display_string);
 -     display_string = ebc;
 -   }
 - #endif
 - 
 -   return display_string;
 - }
 - #endif /* unused */
 - 
 - /* UTF-8 to local */
 - char *utf8_to_local_string(utf8_string, escape_all)
 -   ZCONST char *utf8_string;
 -   int escape_all;
 - {
 -   zwchar *wide = utf8_to_wide_string(utf8_string);
 -   char *loc = wide_to_local_string(wide, escape_all);
 -   free(wide);
 -   return loc;
 - }
 - 
 - #if 0 /* currently unused */
 - /* convert multi-byte character string to wide character string */
 - zwchar *local_to_wide_string(local_string)
 -   ZCONST char *local_string;
 - {
 -   int wsize;
 -   wchar_t *wc_string;
 -   zwchar *wide_string;
 - 
 -   /* for now try to convert as string - fails if a bad char in string */
 -   wsize = mbstowcs(NULL, local_string, strlen(local_string) + 1);
 -   if (wsize == (size_t)-1) {
 -     /* could not convert */
 -     return NULL;
 -   }
 - 
 -   /* convert it */
 -   if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) {
 -     return NULL;
 -   }
 -   wsize = mbstowcs(wc_string, local_string, strlen(local_string) + 1);
 -   wc_string[wsize] = (wchar_t) 0;
 - 
 -   /* in case wchar_t is not zwchar */
 -   if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) {
 -     return NULL;
 -   }
 -   for (wsize = 0; wide_string[wsize] = (zwchar)wc_string[wsize]; wsize++) ;
 -   wide_string[wsize] = (zwchar) 0;
 -   free(wc_string);
 - 
 -   return wide_string;
 - }
 - 
 - 
 - /* convert wide string to UTF-8 */
 - char *wide_to_utf8_string(wide_string)
 -   ZCONST zwchar *wide_string;
 - {
 -   int mbcount;
 -   char *utf8_string;
 - 
 -   /* get size of utf8 string */
 -   mbcount = ucs4_string_to_utf8(wide_string, NULL, 0);
 -   if (mbcount == -1)
 -     return NULL;
 -   if ((utf8_string = (char *) malloc(mbcount + 1)) == NULL) {
 -     return NULL;
 -   }
 -   mbcount = ucs4_string_to_utf8(wide_string, utf8_string, mbcount + 1);
 -   if (mbcount == -1)
 -     return NULL;
 - 
 -   return utf8_string;
 - }
 - #endif /* unused */
 - 
 - /* convert UTF-8 string to wide string */
 - zwchar *utf8_to_wide_string(utf8_string)
 -   ZCONST char *utf8_string;
 - {
 -   int wcount;
 -   zwchar *wide_string;
 - 
 -   wcount = utf8_to_ucs4_string(utf8_string, NULL, 0);
 -   if (wcount == -1)
 -     return NULL;
 -   if ((wide_string = (zwchar *) malloc((wcount + 1) * sizeof(zwchar)))
 -       == NULL) {
 -     return NULL;
 -   }
 -   wcount = utf8_to_ucs4_string(utf8_string, wide_string, wcount + 1);
 - 
 -   return wide_string;
 - }
 - 
 - #endif /* UNICODE_WCHAR */
 - #endif /* UNICODE_SUPPORT */
 - 
 - 
 - 
 - 
 - 
 - #ifdef USE_EF_UT_TIME
 - 
 - #ifdef IZ_HAVE_UXUIDGID
 - static int read_ux3_value(dbuf, uidgid_sz, p_uidgid)
 -     ZCONST uch *dbuf;   /* buffer a uid or gid value */
 -     unsigned uidgid_sz; /* size of uid/gid value */
 -     ulg *p_uidgid;      /* return storage: uid or gid value */
 - {
 -     zusz_t uidgid64;
 - 
 -     switch (uidgid_sz) {
 -       case 2:
 -         *p_uidgid = (ulg)makeword(dbuf);
 -         break;
 -       case 4:
 -         *p_uidgid = (ulg)makelong(dbuf);
 -         break;
 -       case 8:
 -         uidgid64 = makeint64(dbuf);
 - #ifndef LARGE_FILE_SUPPORT
 -         if (uidgid64 == (zusz_t)0xffffffffL)
 -             return FALSE;
 - #endif
 -         *p_uidgid = (ulg)uidgid64;
 -         if ((zusz_t)(*p_uidgid) != uidgid64)
 -             return FALSE;
 -         break;
 -     }
 -     return TRUE;
 - }
 - #endif /* IZ_HAVE_UXUIDGID */
 - 
 - 
 - /*******************************/
 - /* Function ef_scan_for_izux() */
 - /*******************************/
 - 
 - unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime,
 -                           z_utim, z_uidgid)
 -     ZCONST uch *ef_buf; /* buffer containing extra field */
 -     unsigned ef_len;    /* total length of extra field */
 -     int ef_is_c;        /* flag indicating "is central extra field" */
 -     ulg dos_mdatetime;  /* last_mod_file_date_time in DOS format */
 -     iztimes *z_utim;    /* return storage: atime, mtime, ctime */
 -     ulg *z_uidgid;      /* return storage: uid and gid */
 - {
 -     unsigned flags = 0;
 -     unsigned eb_id;
 -     unsigned eb_len;
 -     int have_new_type_eb = 0;
 -     long i_time;        /* buffer for Unix style 32-bit integer time value */
 - #ifdef TIME_T_TYPE_DOUBLE
 -     int ut_in_archive_sgn = 0;
 - #else
 -     int ut_zip_unzip_compatible = FALSE;
 - #endif
 - 
 - /*---------------------------------------------------------------------------
 -     This function scans the extra field for EF_TIME, EF_IZUNIX2, EF_IZUNIX, or
 -     EF_PKUNIX blocks containing Unix-style time_t (GMT) values for the entry's
 -     access, creation, and modification time.
 -     If a valid block is found, the time stamps are copied to the iztimes
 -     structure (provided the z_utim pointer is not NULL).
 -     If a IZUNIX2 block is found or the IZUNIX block contains UID/GID fields,
 -     and the z_uidgid array pointer is valid (!= NULL), the owner info is
 -     transfered as well.
 -     The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring all
 -     data from probably present obsolete EF_IZUNIX blocks.
 -     If multiple blocks of the same type are found, only the information from
 -     the last block is used.
 -     The return value is a combination of the EF_TIME Flags field with an
 -     additional flag bit indicating the presence of valid UID/GID info,
 -     or 0 in case of failure.
 -   ---------------------------------------------------------------------------*/
 - 
 -     if (ef_len == 0 || ef_buf == NULL || (z_utim == 0 && z_uidgid == NULL))
 -         return 0;
 - 
 -     TTrace((stderr,"\nef_scan_for_izux: scanning extra field of length %u\n",
 -       ef_len));
 - 
 -     while (ef_len >= EB_HEADSIZE) {
 -         eb_id = makeword(EB_ID + ef_buf);
 -         eb_len = makeword(EB_LEN + ef_buf);
 - 
 -         if (eb_len > (ef_len - EB_HEADSIZE)) {
 -             /* discovered some extra field inconsistency! */
 -             TTrace((stderr,
 -               "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len,
 -               ef_len - EB_HEADSIZE));
 -             break;
 -         }
 - 
 -         switch (eb_id) {
 -           case EF_TIME:
 -             flags &= ~0x0ff;    /* ignore previous IZUNIX or EF_TIME fields */
 -             have_new_type_eb = 1;
 -             if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) {
 -                 unsigned eb_idx = EB_UT_TIME1;
 -                 TTrace((stderr,"ef_scan_for_izux: found TIME extra field\n"));
 -                 flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x0ff);
 -                 if ((flags & EB_UT_FL_MTIME)) {
 -                     if ((eb_idx+4) <= eb_len) {
 -                         i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf);
 -                         eb_idx += 4;
 -                         TTrace((stderr,"  UT e.f. modification time = %ld\n",
 -                                 i_time));
 - 
 - #ifdef TIME_T_TYPE_DOUBLE
 -                         if ((ulg)(i_time) & (ulg)(0x80000000L)) {
 -                             if (dos_mdatetime == DOSTIME_MINIMUM) {
 -                               ut_in_archive_sgn = -1;
 -                               z_utim->mtime =
 -                                 (time_t)((long)i_time | (~(long)0x7fffffffL));
 -                             } else if (dos_mdatetime >= DOSTIME_2038_01_18) {
 -                               ut_in_archive_sgn = 1;
 -                               z_utim->mtime =
 -                                 (time_t)((ulg)i_time & (ulg)0xffffffffL);
 -                             } else {
 -                               ut_in_archive_sgn = 0;
 -                               /* cannot determine sign of mtime;
 -                                  without modtime: ignore complete UT field */
 -                               flags &= ~0x0ff;  /* no time_t times available */
 -                               TTrace((stderr,
 -                                 "  UT modtime range error; ignore e.f.!\n"));
 -                               break;            /* stop scanning this field */
 -                             }
 -                         } else {
 -                             /* cannot determine, safe assumption is FALSE */
 -                             ut_in_archive_sgn = 0;
 -                             z_utim->mtime = (time_t)i_time;
 -                         }
 - #else /* !TIME_T_TYPE_DOUBLE */
 -                         if ((ulg)(i_time) & (ulg)(0x80000000L)) {
 -                             ut_zip_unzip_compatible =
 -                               ((time_t)0x80000000L < (time_t)0L)
 -                               ? (dos_mdatetime == DOSTIME_MINIMUM)
 -                               : (dos_mdatetime >= DOSTIME_2038_01_18);
 -                             if (!ut_zip_unzip_compatible) {
 -                               /* UnZip interprets mtime differently than Zip;
 -                                  without modtime: ignore complete UT field */
 -                               flags &= ~0x0ff;  /* no time_t times available */
 -                               TTrace((stderr,
 -                                 "  UT modtime range error; ignore e.f.!\n"));
 -                               break;            /* stop scanning this field */
 -                             }
 -                         } else {
 -                             /* cannot determine, safe assumption is FALSE */
 -                             ut_zip_unzip_compatible = FALSE;
 -                         }
 -                         z_utim->mtime = (time_t)i_time;
 - #endif /* ?TIME_T_TYPE_DOUBLE */
 -                     } else {
 -                         flags &= ~EB_UT_FL_MTIME;
 -                         TTrace((stderr,"  UT e.f. truncated; no modtime\n"));
 -                     }
 -                 }
 -                 if (ef_is_c) {
 -                     break;      /* central version of TIME field ends here */
 -                 }
 - 
 -                 if (flags & EB_UT_FL_ATIME) {
 -                     if ((eb_idx+4) <= eb_len) {
 -                         i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf);
 -                         eb_idx += 4;
 -                         TTrace((stderr,"  UT e.f. access time = %ld\n",
 -                                 i_time));
 - #ifdef TIME_T_TYPE_DOUBLE
 -                         if ((ulg)(i_time) & (ulg)(0x80000000L)) {
 -                             if (ut_in_archive_sgn == -1)
 -                               z_utim->atime =
 -                                 (time_t)((long)i_time | (~(long)0x7fffffffL));
 -                             } else if (ut_in_archive_sgn == 1) {
 -                               z_utim->atime =
 -                                 (time_t)((ulg)i_time & (ulg)0xffffffffL);
 -                             } else {
 -                               /* sign of 32-bit time is unknown -> ignore it */
 -                               flags &= ~EB_UT_FL_ATIME;
 -                               TTrace((stderr,
 -                                 "  UT access time range error: skip time!\n"));
 -                             }
 -                         } else {
 -                             z_utim->atime = (time_t)i_time;
 -                         }
 - #else /* !TIME_T_TYPE_DOUBLE */
 -                         if (((ulg)(i_time) & (ulg)(0x80000000L)) &&
 -                             !ut_zip_unzip_compatible) {
 -                             flags &= ~EB_UT_FL_ATIME;
 -                             TTrace((stderr,
 -                               "  UT access time range error: skip time!\n"));
 -                         } else {
 -                             z_utim->atime = (time_t)i_time;
 -                         }
 - #endif /* ?TIME_T_TYPE_DOUBLE */
 -                     } else {
 -                         flags &= ~EB_UT_FL_ATIME;
 -                     }
 -                 }
 -                 if (flags & EB_UT_FL_CTIME) {
 -                     if ((eb_idx+4) <= eb_len) {
 -                         i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf);
 -                         TTrace((stderr,"  UT e.f. creation time = %ld\n",
 -                                 i_time));
 - #ifdef TIME_T_TYPE_DOUBLE
 -                         if ((ulg)(i_time) & (ulg)(0x80000000L)) {
 -                             if (ut_in_archive_sgn == -1)
 -                               z_utim->ctime =
 -                                 (time_t)((long)i_time | (~(long)0x7fffffffL));
 -                             } else if (ut_in_archive_sgn == 1) {
 -                               z_utim->ctime =
 -                                 (time_t)((ulg)i_time & (ulg)0xffffffffL);
 -                             } else {
 -                               /* sign of 32-bit time is unknown -> ignore it */
 -                               flags &= ~EB_UT_FL_CTIME;
 -                               TTrace((stderr,
 -                               "  UT creation time range error: skip time!\n"));
 -                             }
 -                         } else {
 -                             z_utim->ctime = (time_t)i_time;
 -                         }
 - #else /* !TIME_T_TYPE_DOUBLE */
 -                         if (((ulg)(i_time) & (ulg)(0x80000000L)) &&
 -                             !ut_zip_unzip_compatible) {
 -                             flags &= ~EB_UT_FL_CTIME;
 -                             TTrace((stderr,
 -                               "  UT creation time range error: skip time!\n"));
 -                         } else {
 -                             z_utim->ctime = (time_t)i_time;
 -                         }
 - #endif /* ?TIME_T_TYPE_DOUBLE */
 -                     } else {
 -                         flags &= ~EB_UT_FL_CTIME;
 -                     }
 -                 }
 -             }
 -             break;
 - 
 -           case EF_IZUNIX2:
 -             if (have_new_type_eb == 0) {
 -                 flags &= ~0x0ff;        /* ignore any previous IZUNIX field */
 -                 have_new_type_eb = 1;
 -             }
 - #ifdef IZ_HAVE_UXUIDGID
 -             if (have_new_type_eb > 1)
 -                 break;          /* IZUNIX3 overrides IZUNIX2 e.f. block ! */
 -             if (eb_len == EB_UX2_MINLEN && z_uidgid != NULL) {
 -                 z_uidgid[0] = (ulg)makeword((EB_HEADSIZE+EB_UX2_UID) + ef_buf);
 -                 z_uidgid[1] = (ulg)makeword((EB_HEADSIZE+EB_UX2_GID) + ef_buf);
 -                 flags |= EB_UX2_VALID;   /* signal success */
 -             }
 - #endif
 -             break;
 - 
 -           case EF_IZUNIX3:
 -             /* new 3rd generation Unix ef */
 -             have_new_type_eb = 2;
 - 
 -         /*
 -           Version       1 byte      version of this extra field, currently 1
 -           UIDSize       1 byte      Size of UID field
 -           UID           Variable    UID for this entry
 -           GIDSize       1 byte      Size of GID field
 -           GID           Variable    GID for this entry
 -         */
 - 
 - #ifdef IZ_HAVE_UXUIDGID
 -             if (eb_len >= EB_UX3_MINLEN
 -                 && z_uidgid != NULL
 -                 && (*((EB_HEADSIZE + 0) + ef_buf) == 1)
 -                     /* only know about version 1 */
 -             {
 -                 uch uid_size;
 -                 uch gid_size;
 - 
 -                 uid_size = *((EB_HEADSIZE + 1) + ef_buf);
 -                 gid_size = *((EB_HEADSIZE + uid_size + 2) + ef_buf);
 - 
 -                 flags &= ~0x0ff;      /* ignore any previous UNIX field */
 - 
 -                 if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf,
 -                                     uid_size, z_uidgid[0])
 -                     &&
 -                      read_ux3_value((EB_HEADSIZE + uid_size + 3) + ef_buf,
 -                                     gid_size, z_uidgid[1]) )
 -                 {
 -                     flags |= EB_UX2_VALID;   /* signal success */
 -                 }
 -             }
 - #endif /* IZ_HAVE_UXUIDGID */
 -             break;
 - 
 -           case EF_IZUNIX:
 -           case EF_PKUNIX:       /* PKUNIX e.f. layout is identical to IZUNIX */
 -             if (eb_len >= EB_UX_MINLEN) {
 -                 TTrace((stderr,"ef_scan_for_izux: found %s extra field\n",
 -                         (eb_id == EF_IZUNIX ? "IZUNIX" : "PKUNIX")));
 -                 if (have_new_type_eb > 0) {
 -                     break;      /* Ignore IZUNIX extra field block ! */
 -                 }
 -                 if (z_utim != NULL) {
 -                     flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
 -                     i_time = (long)makelong((EB_HEADSIZE+EB_UX_MTIME)+ef_buf);
 -                     TTrace((stderr,"  Unix EF modtime = %ld\n", i_time));
 - #ifdef TIME_T_TYPE_DOUBLE
 -                     if ((ulg)(i_time) & (ulg)(0x80000000L)) {
 -                         if (dos_mdatetime == DOSTIME_MINIMUM) {
 -                             ut_in_archive_sgn = -1;
 -                             z_utim->mtime =
 -                               (time_t)((long)i_time | (~(long)0x7fffffffL));
 -                         } else if (dos_mdatetime >= DOSTIME_2038_01_18) {
 -                             ut_in_archive_sgn = 1;
 -                             z_utim->mtime =
 -                               (time_t)((ulg)i_time & (ulg)0xffffffffL);
 -                         } else {
 -                             ut_in_archive_sgn = 0;
 -                             /* cannot determine sign of mtime;
 -                                without modtime: ignore complete UT field */
 -                             flags &= ~0x0ff;    /* no time_t times available */
 -                             TTrace((stderr,
 -                                   "  UX modtime range error: ignore e.f.!\n"));
 -                         }
 -                     } else {
 -                         /* cannot determine, safe assumption is FALSE */
 -                         ut_in_archive_sgn = 0;
 -                         z_utim->mtime = (time_t)i_time;
 -                     }
 - #else /* !TIME_T_TYPE_DOUBLE */
 -                     if ((ulg)(i_time) & (ulg)(0x80000000L)) {
 -                         ut_zip_unzip_compatible =
 -                           ((time_t)0x80000000L < (time_t)0L)
 -                           ? (dos_mdatetime == DOSTIME_MINIMUM)
 -                           : (dos_mdatetime >= DOSTIME_2038_01_18);
 -                         if (!ut_zip_unzip_compatible) {
 -                             /* UnZip interpretes mtime differently than Zip;
 -                                without modtime: ignore complete UT field */
 -                             flags &= ~0x0ff;    /* no time_t times available */
 -                             TTrace((stderr,
 -                                   "  UX modtime range error: ignore e.f.!\n"));
 -                         }
 -                     } else {
 -                         /* cannot determine, safe assumption is FALSE */
 -                         ut_zip_unzip_compatible = FALSE;
 -                     }
 -                     z_utim->mtime = (time_t)i_time;
 - #endif /* ?TIME_T_TYPE_DOUBLE */
 -                     i_time = (long)makelong((EB_HEADSIZE+EB_UX_ATIME)+ef_buf);
 -                     TTrace((stderr,"  Unix EF actime = %ld\n", i_time));
 - #ifdef TIME_T_TYPE_DOUBLE
 -                     if ((ulg)(i_time) & (ulg)(0x80000000L)) {
 -                         if (ut_in_archive_sgn == -1)
 -                             z_utim->atime =
 -                               (time_t)((long)i_time | (~(long)0x7fffffffL));
 -                         } else if (ut_in_archive_sgn == 1) {
 -                             z_utim->atime =
 -                               (time_t)((ulg)i_time & (ulg)0xffffffffL);
 -                         } else if (flags & 0x0ff) {
 -                             /* sign of 32-bit time is unknown -> ignore it */
 -                             flags &= ~EB_UT_FL_ATIME;
 -                             TTrace((stderr,
 -                                 "  UX access time range error: skip time!\n"));
 -                         }
 -                     } else {
 -                         z_utim->atime = (time_t)i_time;
 -                     }
 - #else /* !TIME_T_TYPE_DOUBLE */
 -                     if (((ulg)(i_time) & (ulg)(0x80000000L)) &&
 -                         !ut_zip_unzip_compatible && (flags & 0x0ff)) {
 -                         /* atime not in range of UnZip's time_t */
 -                         flags &= ~EB_UT_FL_ATIME;
 -                         TTrace((stderr,
 -                                 "  UX access time range error: skip time!\n"));
 -                     } else {
 -                         z_utim->atime = (time_t)i_time;
 -                     }
 - #endif /* ?TIME_T_TYPE_DOUBLE */
 -                 }
 - #ifdef IZ_HAVE_UXUIDGID
 -                 if (eb_len >= EB_UX_FULLSIZE && z_uidgid != NULL) {
 -                     z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX_UID) + ef_buf);
 -                     z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX_GID) + ef_buf);
 -                     flags |= EB_UX2_VALID;
 -                 }
 - #endif /* IZ_HAVE_UXUIDGID */
 -             }
 -             break;
 - 
 -           default:
 -             break;
 -         }
 - 
 -         /* Skip this extra field block */
 -         ef_buf += (eb_len + EB_HEADSIZE);
 -         ef_len -= (eb_len + EB_HEADSIZE);
 -     }
 - 
 -     return flags;
 - }
 - 
 - #endif /* USE_EF_UT_TIME */
 - 
 - 
 - #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
 - 
 - #define SPARKID_2 0x30435241    /* = "ARC0" */
 - 
 - /*******************************/
 - /* Function getRISCOSexfield() */
 - /*******************************/
 - 
 - zvoid *getRISCOSexfield(ef_buf, ef_len)
 -     ZCONST uch *ef_buf; /* buffer containing extra field */
 -     unsigned ef_len;    /* total length of extra field */
 - {
 -     unsigned eb_id;
 -     unsigned eb_len;
 - 
 - /*---------------------------------------------------------------------------
 -     This function scans the extra field for a Acorn SPARK filetype ef-block.
 -     If a valid block is found, the function returns a pointer to the start
 -     of the SPARK_EF block in the extra field buffer.  Otherwise, a NULL
 -     pointer is returned.
 -   ---------------------------------------------------------------------------*/
 - 
 -     if (ef_len == 0 || ef_buf == NULL)
 -         return NULL;
 - 
 -     Trace((stderr,"\ngetRISCOSexfield: scanning extra field of length %u\n",
 -       ef_len));
 - 
 -     while (ef_len >= EB_HEADSIZE) {
 -         eb_id = makeword(EB_ID + ef_buf);
 -         eb_len = makeword(EB_LEN + ef_buf);
 - 
 -         if (eb_len > (ef_len - EB_HEADSIZE)) {
 -             /* discovered some extra field inconsistency! */
 -             Trace((stderr,
 -               "getRISCOSexfield: block length %u > rest ef_size %u\n", eb_len,
 -               ef_len - EB_HEADSIZE));
 -             break;
 -         }
 - 
 -         if (eb_id == EF_SPARK && (eb_len == 24 || eb_len == 20)) {
 -             if (makelong(EB_HEADSIZE + ef_buf) == SPARKID_2) {
 -                 /* Return a pointer to the valid SPARK filetype ef block */
 -                 return (zvoid *)ef_buf;
 -             }
 -         }
 - 
 -         /* Skip this extra field block */
 -         ef_buf += (eb_len + EB_HEADSIZE);
 -         ef_len -= (eb_len + EB_HEADSIZE);
 -     }
 - 
 -     return NULL;
 - }
 - 
 - #endif /* (RISCOS || ACORN_FTYPE_NFS) */
 
 
  |