summaryrefslogtreecommitdiff
path: root/Build/source/libs/unzip/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/unzip/process.c')
-rw-r--r--Build/source/libs/unzip/process.c1378
1 files changed, 1378 insertions, 0 deletions
diff --git a/Build/source/libs/unzip/process.c b/Build/source/libs/unzip/process.c
new file mode 100644
index 00000000000..2d8f179e843
--- /dev/null
+++ b/Build/source/libs/unzip/process.c
@@ -0,0 +1,1378 @@
+/*---------------------------------------------------------------------------
+
+ process.c
+
+ This file contains the top-level routines for processing multiple zipfiles.
+
+ Contains: process_zipfiles()
+ free_G_buffers()
+ do_seekable()
+ find_ecrec()
+ uz_end_central()
+ process_cdir_file_hdr()
+ get_cdir_ent()
+ process_local_file_hdr()
+ ef_scan_for_izux()
+
+ ---------------------------------------------------------------------------*/
+
+
+#define UNZIP_INTERNAL
+#include "unzip.h"
+#ifdef WINDLL
+# ifdef POCKET_UNZIP
+# include "wince/intrface.h"
+# else
+# include "windll/windll.h"
+# endif
+#endif
+
+static int do_seekable OF((__GPRO__ int lastchance));
+static int find_ecrec OF((__GPRO__ long searchlen));
+
+static ZCONST char Far CannotAllocateBuffers[] =
+ "error: cannot allocate unzip buffers\n";
+
+#ifdef SFX
+ static ZCONST char Far CannotFindMyself[] =
+ "unzipsfx: cannot find myself! [%s]\n";
+
+#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
+ 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 %s, %s.zip or %s.\n"; /* ", so there" removed 970918 */
+# else /* !UNIX */
+# ifndef AMIGA
+ static ZCONST char Far CannotFindWildcardMatch[] =
+ "%s: cannot find any matches for wildcard specification \"%s\".\n";
+# endif /* !AMIGA */
+ static ZCONST char Far CannotFindZipfileDirMsg[] =
+ "%s: cannot find zipfile directory in %s,\n\
+ %sand cannot find %s, period.\n";
+ static ZCONST char Far CannotFindEitherZipfile[] =
+ "%s: cannot find either %s or %s.\n"; /* ", so there" removed 970918 */
+# 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
+ 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 %u of a multi-disk archive, and this is not the disk on\n\
+ which the central zipfile directory begins (disk %u).\n";
+ static ZCONST char Far EndCentDirBogus[] =
+ "\nwarning [%s]: end-of-central-directory record claims this\n\
+ is disk %u but that the central directory starts on disk %u; 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]: %ld extra byte%s at beginning or within zipfile\n\
+ (attempting to process anyway)\n";
+#endif /* ?SFX */
+
+static ZCONST char Far MissingBytes[] =
+ "error [%s]: missing %ld 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";
+#ifndef SFX
+ static ZCONST char Far CentDirTooLong[] =
+ "error [%s]: reported length of central directory is\n\
+ %ld bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1\n\
+ zipfile?). Compensating...\n";
+ 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 */
+static ZCONST char Far ZipfileCommTrunc1[] =
+ "\ncaution: zipfile comment truncated\n";
+
+
+
+
+/*******************************/
+/* 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 only later when we know we have a zipfile */
+ CRC_32_TAB = NULL;
+#endif /* 0 */
+
+ /* finish up initialization of magic signature strings */
+ local_hdr_sig[0] /* = extd_local_sig[0] */ = 0x50; /* ASCII 'P', */
+ central_hdr_sig[0] = end_central_sig[0] = 0x50; /* not EBCDIC */
+
+ local_hdr_sig[1] /* = extd_local_sig[1] */ = 0x4B; /* ASCII 'K', */
+ central_hdr_sig[1] = end_central_sig[1] = 0x4B; /* not EBCDIC */
+
+/*---------------------------------------------------------------------------
+ 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 were
+ initially copied from dos_to_unix_time() in fileio.c. probably, they are
+ still too strict; any listed OS that supplies tzset(), regardless of
+ whether the function does anything, should be removed from the ifdefs.
+ ---------------------------------------------------------------------------*/
+
+#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
+
+/*---------------------------------------------------------------------------
+ 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));
+ }
+
+#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)
+ ++NumLoseFiles;
+ else
+ ++NumWinFiles;
+
+ if (error != IZ_DIR && error > error_in_archive)
+ error_in_archive = error;
+ Trace((stderr, "do_seekable(0) returns %d\n", 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)
+ {
+ NumMissDirs = NumMissFiles = 0;
+ if (error_in_archive == PK_NOZIP)
+ error_in_archive = PK_COOL;
+
+#if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */
+ if (iswild(G.wildzipfn))
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(CannotFindWildcardMatch), uO.zipinfo_mode?
+ LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
+ G.wildzipfn));
+ else
+#endif
+ {
+ char *p = lastzipfn + strlen(lastzipfn);
+
+ G.zipfn = lastzipfn;
+ strcpy(p, ZSUFX);
+
+#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
+ if (error == PK_WARN) /* GRR: make this a switch/case stmt ... */
+ ++NumWarnFiles;
+ else if (error == IZ_DIR)
+ ++NumMissDirs;
+ else if (error == PK_NOZIP)
+ /* increment again => bug: "1 file had no zipfile directory." */
+ /* ++NumMissFiles */ ;
+ else if (error)
+ ++NumLoseFiles;
+ else
+ ++NumWinFiles;
+
+ if (error > error_in_archive)
+ error_in_archive = error;
+ Trace((stderr, "do_seekable(1) returns %d\n", 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.qflag && !uO.zipinfo_mode)
+#endif
+ )
+ {
+ if ((NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1)
+#ifdef TIMESTAMP
+ && !(uO.T_flag && !uO.zipinfo_mode)
+#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 error_in_archive;
+
+} /* end function process_zipfiles() */
+
+
+
+
+
+/*****************************/
+/* Function free_G_buffers() */
+/*****************************/
+
+void free_G_buffers(__G) /* releases all memory allocated in global vars */
+ __GDEF
+{
+ 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 (!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 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;
+ unsigned nmember = 0;
+#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) ||
+ (error = S_ISDIR(G.statbuf.st_mode)) != 0)
+ {
+#ifndef SFX
+ if (lastchance) {
+#if defined(UNIX) || defined(QDOS)
+ if (G.no_ecrec)
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(CannotFindZipfileDirMsg), uO.zipinfo_mode?
+ LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
+ G.wildzipfn, uO.zipinfo_mode? " " : "", G.wildzipfn,
+ G.zipfn));
+ else
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(CannotFindEitherZipfile), uO.zipinfo_mode?
+ LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
+ G.wildzipfn, G.wildzipfn, G.zipfn));
+#else /* !UNIX */
+ if (G.no_ecrec)
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(CannotFindZipfileDirMsg), uO.zipinfo_mode?
+ LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
+ G.wildzipfn, uO.zipinfo_mode? " " : "", G.zipfn));
+ else
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(CannotFindEitherZipfile), uO.zipinfo_mode?
+ LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
+ G.wildzipfn, G.zipfn));
+#endif /* ?UNIX */
+ }
+#endif /* !SFX */
+ return error? IZ_DIR : PK_NOZIP;
+ }
+ G.ziplen = G.statbuf.st_size;
+
+#ifndef SFX
+#if defined(UNIX) || defined(DOS_OS2_W32)
+ 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... */
+
+/*---------------------------------------------------------------------------
+ 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.
+ ---------------------------------------------------------------------------*/
+
+ /* initialize the CRC table pointer (once) */
+ if (CRC_32_TAB == NULL) {
+ if ((CRC_32_TAB = get_crc_table()) == NULL)
+ return PK_MEM;
+ }
+
+#if (!defined(SFX) || defined(SFX_EXDIR))
+ /* check out if specified extraction root directory exists */
+ if (uO.exdir != (char *)NULL && G.extract_flag) {
+ G.create_dirs = !uO.fflag;
+ if ((error = checkdir(__G__ uO.exdir, ROOT)) > 2)
+ return error; /* out of memory, or file in way */
+ }
+#endif /* !SFX || SFX_EXDIR */
+
+ G.cur_zipfile_bufstart = 0;
+ G.inptr = G.inbuf;
+
+#if (!defined(WINDLL) && !defined(SFX))
+#ifdef TIMESTAMP
+ if (!uO.zipinfo_mode && !uO.qflag && !uO.T_flag)
+#else
+ if (!uO.zipinfo_mode && !uO.qflag)
+#endif
+#ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */
+ Info(slide, 0, ((char *)slide, "Archive: %s\n", FnFilter1(G.zipfn)));
+#else
+ Info(slide, 0, ((char *)slide, "Archive: %s\n", G.zipfn));
+#endif
+#endif /* !WINDLL && !SFX */
+
+ if ((
+#ifndef NO_ZIPINFO
+ uO.zipinfo_mode &&
+ ((error_in_archive = find_ecrec(__G__ G.ziplen)) != 0 ||
+ (error_in_archive = zi_end_central(__G)) > PK_WARN))
+ || (!uO.zipinfo_mode &&
+#endif
+ ((error_in_archive = find_ecrec(__G__ MIN(G.ziplen,66000L))) != 0 ||
+ (error_in_archive = uz_end_central(__G)) > 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,
+ G.ecrec.number_this_disk, 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,
+ G.ecrec.number_this_disk, 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) <
+ (LONGINT)0)
+ {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(MissingBytes),
+ G.zipfn, (long)(-G.extra_bytes)));
+ 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,
+ (long)G.extra_bytes, (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).
+ -----------------------------------------------------------------------*/
+
+ ZLSEEK( G.ecrec.offset_start_central_directory )
+#ifdef OLD_SEEK_TEST
+ if (readbuf(G.sig, 4) == 0) {
+ CLOSE_INFILE();
+ return PK_ERR; /* file may be locked, or possibly disk error(?) */
+ }
+ if (strncmp(G.sig, central_hdr_sig, 4))
+#else
+ if ((readbuf(__G__ G.sig, 4) == 0) ||
+ strncmp(G.sig, central_hdr_sig, 4))
+#endif
+ {
+#ifndef SFX
+ long tmp = G.extra_bytes;
+#endif
+
+ G.extra_bytes = 0;
+ ZLSEEK( G.ecrec.offset_start_central_directory )
+ if ((readbuf(__G__ G.sig, 4) == 0) ||
+ strncmp(G.sig, central_hdr_sig, 4))
+ {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(CentDirStartNotFound), G.zipfn,
+ LoadFarStringSmall(ReportMsg)));
+ CLOSE_INFILE();
+ return PK_BADERR;
+ }
+#ifndef SFX
+ Info(slide, 0x401, ((char *)slide, LoadFarString(CentDirTooLong),
+ G.zipfn, -tmp));
+#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.
+ -----------------------------------------------------------------------*/
+
+ Trace((stderr, "about to extract/list files (error = %d)\n",
+ error_in_archive));
+
+ ZLSEEK( G.ecrec.offset_start_central_directory )
+
+#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 > 0)) {
+# ifdef WIN32
+ if (stamp_file(__G__ G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */
+# else
+ if (stamp_file(G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */
+# endif
+ Info(slide, 0x201, ((char *)slide,
+ "warning: cannot set time for %s\n", G.zipfn));
+ if (error_in_archive < PK_WARN)
+ error_in_archive = PK_WARN;
+ }
+ }
+#endif
+ return error_in_archive;
+
+} /* end function do_seekable() */
+
+
+
+
+
+/*************************/
+/* Function find_ecrec() */
+/*************************/
+
+static int find_ecrec(__G__ searchlen) /* return PK-class error */
+ __GDEF
+ long searchlen;
+{
+ int i, numblks, found=FALSE;
+ LONGINT tail_len;
+ ec_byte_rec byterec;
+
+
+/*---------------------------------------------------------------------------
+ Treat case of short zipfile separately.
+ ---------------------------------------------------------------------------*/
+
+ if (G.ziplen <= INBUFSIZ) {
+ lseek(G.zipfd, 0L, SEEK_SET);
+ if ((G.incnt = read(G.zipfd,(char *)G.inbuf,(unsigned int)G.ziplen))
+ == (int)G.ziplen)
+
+ /* 'P' must be at least 22 bytes from end of zipfile */
+ for (G.inptr = G.inbuf+(int)G.ziplen-22; G.inptr >= G.inbuf;
+ --G.inptr)
+ if ((native(*G.inptr) == 'P') &&
+ !strncmp((char *)G.inptr, end_central_sig, 4)) {
+ G.incnt -= (int)(G.inptr - G.inbuf);
+ found = TRUE;
+ break;
+ }
+
+/*---------------------------------------------------------------------------
+ Zipfile is longer than INBUFSIZ: may need to loop. Start with short
+ block at end of zipfile (if not TOO short).
+ ---------------------------------------------------------------------------*/
+
+ } else {
+ if ((tail_len = G.ziplen % INBUFSIZ) > ECREC_SIZE) {
+#ifdef USE_STRM_INPUT
+ fseek((FILE *)G.zipfd, G.ziplen-tail_len, SEEK_SET);
+ G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd);
+#else /* !USE_STRM_INPUT */
+ G.cur_zipfile_bufstart = lseek(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)
+ goto fail; /* it's expedient... */
+
+ /* 'P' must be at least 22 bytes from end of zipfile */
+ for (G.inptr = G.inbuf+(int)tail_len-22; G.inptr >= G.inbuf;
+ --G.inptr)
+ if ((native(*G.inptr) == 'P') &&
+ !strncmp((char *)G.inptr, end_central_sig, 4)) {
+ G.incnt -= (int)(G.inptr - G.inbuf);
+ found = TRUE;
+ break;
+ }
+ /* sig may span block boundary: */
+ strncpy((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;
+ lseek(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET);
+ if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ))
+ != INBUFSIZ)
+ break; /* fall through and fail */
+
+ for (G.inptr = G.inbuf+INBUFSIZ-1; G.inptr >= G.inbuf;
+ --G.inptr)
+ if ((native(*G.inptr) == 'P') &&
+ !strncmp((char *)G.inptr, end_central_sig, 4)) {
+ G.incnt -= (int)(G.inptr - G.inbuf);
+ found = TRUE;
+ break;
+ }
+ /* sig may span block boundary: */
+ strncpy((char *)G.hold, (char *)G.inbuf, 3);
+ }
+ } /* end if (ziplen > INBUFSIZ) */
+
+/*---------------------------------------------------------------------------
+ Searched through whole region where signature should be without finding
+ it. Print informational message and die a horrible death.
+ ---------------------------------------------------------------------------*/
+
+fail:
+ 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 %ld (%.8lXh)\n",
+ G.real_ecrec_offset, G.real_ecrec_offset);
+ 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_CENTRAL_DIR]);
+ G.ecrec.num_entries_centrl_dir_ths_disk =
+ makeword(&byterec[NUM_ENTRIES_CENTRL_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]);
+
+ G.expect_ecrec_offset = G.ecrec.offset_start_central_directory +
+ G.ecrec.size_central_directory;
+ return PK_COOL;
+
+} /* end function find_ecrec() */
+
+
+
+
+
+/*****************************/
+/* Function uz_end_central() */
+/*****************************/
+
+int uz_end_central(__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.
+ Then position the file pointer to the beginning of the central directory
+ and fill buffer.
+ ---------------------------------------------------------------------------*/
+
+#ifdef WINDLL
+ /* for comment button: */
+ if ((!G.fValidate) && (G.lpUserFunctions != NULL))
+ G.lpUserFunctions->cchComment = G.ecrec.zipfile_comment_length;
+ if (G.ecrec.zipfile_comment_length && (uO.zflag > 0))
+#else /* !WINDLL */
+ if (G.ecrec.zipfile_comment_length && (uO.zflag > 0 ||
+ (uO.zflag == 0 &&
+#ifdef TIMESTAMP
+ !uO.T_flag &&
+#endif
+ !uO.qflag)))
+#endif /* ?WINDLL */
+ {
+ if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(ZipfileCommTrunc1)));
+ error = PK_WARN;
+ }
+ }
+ return error;
+
+} /* end function uz_end_central() */
+
+
+
+
+
+/************************************/
+/* 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->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) /* user specified case-conversion */
+ 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_, BEOS_ (Z_SYSTEM_): no conversion */
+ }
+
+ /* 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;
+
+ return PK_COOL;
+
+} /* end function process_cdir_file_hdr() */
+
+
+
+
+
+/***************************/
+/* Function get_cdir_ent() */
+/***************************/
+
+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]);
+
+ G.csize = (long) G.lrec.csize;
+ G.ucsize = (long) G.lrec.ucsize;
+
+ if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
+ /* can't trust local header, use central directory: */
+ G.lrec.crc32 = G.pInfo->crc;
+ G.csize = (long)(G.lrec.csize = G.pInfo->compr_size);
+ G.ucsize = (long)(G.lrec.ucsize = G.pInfo->uncompr_size);
+ }
+
+ return PK_COOL;
+
+} /* end function process_local_file_hdr() */
+
+
+#ifdef USE_EF_UT_TIME
+
+/*******************************/
+/* Function ef_scan_for_izux() */
+/*******************************/
+
+unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime,
+ z_utim, z_uidgid)
+ 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 */
+ ush *z_uidgid; /* return storage: uid and gid */
+{
+ unsigned flags = 0;
+ unsigned eb_id;
+ unsigned eb_len;
+ int have_new_type_eb = FALSE;
+ int ut_zip_unzip_compatible = FALSE;
+
+/*---------------------------------------------------------------------------
+ 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 = TRUE;
+ 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) {
+ z_utim->mtime = makelong((EB_HEADSIZE+eb_idx) + ef_buf);
+ eb_idx += 4;
+ TTrace((stderr," UT e.f. modification time = %ld\n",
+ z_utim->mtime));
+
+ if ((ulg)(z_utim->mtime) & (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,
+ " 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;
+ }
+ } 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) {
+ z_utim->atime = makelong((EB_HEADSIZE+eb_idx) + ef_buf);
+ eb_idx += 4;
+ TTrace((stderr," UT e.f. access time = %ld\n",
+ z_utim->atime));
+ if (((ulg)(z_utim->atime) & (ulg)(0x80000000L)) &&
+ !ut_zip_unzip_compatible) {
+ flags &= ~EB_UT_FL_ATIME;
+ TTrace((stderr,
+ " UT access time range error: skip time!\n"));
+ }
+ } else {
+ flags &= ~EB_UT_FL_ATIME;
+ }
+ }
+ if (flags & EB_UT_FL_CTIME) {
+ if ((eb_idx+4) <= eb_len) {
+ z_utim->ctime = makelong((EB_HEADSIZE+eb_idx) + ef_buf);
+ TTrace((stderr," UT e.f. creation time = %ld\n",
+ z_utim->ctime));
+ if (((ulg)(z_utim->ctime) & (ulg)(0x80000000L)) &&
+ !ut_zip_unzip_compatible) {
+ flags &= ~EB_UT_FL_CTIME;
+ TTrace((stderr,
+ " UT creation time range error: skip time!\n"));
+ }
+ } else {
+ flags &= ~EB_UT_FL_CTIME;
+ }
+ }
+ }
+ break;
+
+ case EF_IZUNIX2:
+ if (!have_new_type_eb) {
+ flags &= ~0x0ff; /* ignore any previous IZUNIX field */
+ have_new_type_eb = TRUE;
+ }
+ if (eb_len >= EB_UX2_MINLEN && z_uidgid != NULL) {
+ z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX2_UID) + ef_buf);
+ z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX2_GID) + ef_buf);
+ flags |= EB_UX2_VALID; /* signal success */
+ }
+ 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) {
+ break; /* Ignore IZUNIX extra field block ! */
+ }
+ if (z_utim != NULL) {
+ z_utim->atime = makelong((EB_HEADSIZE+EB_UX_ATIME)+ef_buf);
+ z_utim->mtime = makelong((EB_HEADSIZE+EB_UX_MTIME)+ef_buf);
+ TTrace((stderr," Unix EF actime = %ld\n", z_utim->atime));
+ TTrace((stderr," Unix EF modtime = %ld\n", z_utim->mtime));
+ flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
+ if ((ulg)(z_utim->mtime) & (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;
+ }
+ if ((ulg)(z_utim->atime) & (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"));
+ }
+ }
+ 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;
+ }
+ }
+ 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 */