alfs/SRC_ARCHIVE/unzip-6.0-consolidated_fixes-1.patch
2023-11-14 18:47:30 -05:00

16714 lines
597 KiB
Diff

Submitted By: Ken Moffat <ken at linuxfromscratch dot org>
Date: 2019-12-03
Initial Package Version: 6.0
Upstream Status: Some from upstream, but that now appears to be defunct.
Origin: Found at fedora (omitting their manpage and symlinks patches)
Description:
1. Allow it to use system libbz2.so, this allows unzip and zipinfo to
deal with archives which contain bz2 compressed members.
2. Locale fixes to handle non-latin non-unicode filenames,
originally from Arch but updated by Canonical to fix buffer overflow
and to print them (apparently from fedora or redhat) - not tested!
3. A large number of security fixes, including for CVE-2014-81{39..41},
CVE-2016-9844, CVE-2018-18384, CVE-2018-1000035 as well as several
similar overflow fixes not labelled with CVE numbers and a few general
fixes.
diff -Naur a/crc_i386.S b/crc_i386.S
--- a/crc_i386.S 2007-01-07 05:02:58.000000000 +0000
+++ b/crc_i386.S 2019-12-01 23:48:05.278335299 +0000
@@ -302,3 +302,6 @@
#endif /* i386 || _i386 || _I386 || __i386 */
#endif /* !USE_ZLIB && !CRC_TABLE_ONLY */
+
+.section .note.GNU-stack, "", @progbits
+.previous
diff -Naur a/crypt.c b/crypt.c
--- a/crypt.c 2007-01-05 15:47:36.000000000 +0000
+++ b/crypt.c 2019-12-02 00:37:13.921788251 +0000
@@ -465,7 +465,17 @@
GLOBAL(pInfo->encrypted) = FALSE;
defer_leftover_input(__G);
for (n = 0; n < RAND_HEAD_LEN; n++) {
- b = NEXTBYTE;
+ /* 2012-11-23 SMS. (OUSPG report.)
+ * Quit early if compressed size < HEAD_LEN. The resulting
+ * error message ("unable to get password") could be improved,
+ * but it's better than trying to read nonexistent data, and
+ * then continuing with a negative G.csize. (See
+ * fileio.c:readbyte()).
+ */
+ if ((b = NEXTBYTE) == (ush)EOF)
+ {
+ return PK_ERR;
+ }
h[n] = (uch)b;
Trace((stdout, " (%02x)", h[n]));
}
diff -Naur a/extract.c b/extract.c
--- a/extract.c 2009-03-14 01:32:52.000000000 +0000
+++ b/extract.c 2019-12-02 01:05:52.857702371 +0000
@@ -1,5 +1,5 @@
/*
- Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
+ Copyright (c) 1990-2014 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.
@@ -298,6 +298,8 @@
#ifndef SFX
static ZCONST char Far InconsistEFlength[] = "bad extra-field entry:\n \
EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n";
+ static ZCONST char Far TooSmallEBlength[] = "bad extra-field entry:\n \
+ EF block length (%u bytes) invalid (< %d)\n";
static ZCONST char Far InvalidComprDataEAs[] =
" invalid compressed data for EAs\n";
# if (defined(WIN32) && defined(NTSD_EAS))
@@ -472,8 +474,8 @@
*/
Info(slide, 0x401, ((char *)slide,
LoadFarString(CentSigMsg), j + blknum*DIR_BLKSIZ + 1));
- Info(slide, 0x401, ((char *)slide,
- LoadFarString(ReportMsg)));
+ Info(slide, 0x401,
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
error_in_archive = PK_BADERR;
}
reached_end = TRUE; /* ...so no more left to do */
@@ -752,8 +754,8 @@
#ifndef SFX
if (no_endsig_found) { /* just to make sure */
- Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
- Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg)));
+ Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg)));
+ Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(ReportMsg)));
if (!error_in_archive) /* don't overwrite stronger error */
error_in_archive = PK_WARN;
}
@@ -1255,8 +1257,17 @@
if (G.lrec.compression_method == STORED) {
zusz_t csiz_decrypted = G.lrec.csize;
- if (G.pInfo->encrypted)
+ if (G.pInfo->encrypted) {
+ if (csiz_decrypted < 12) {
+ /* handle the error now to prevent unsigned overflow */
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipNoFile),
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(Inflate)));
+ return PK_ERR;
+ }
csiz_decrypted -= 12;
+ }
if (G.lrec.ucsize != csiz_decrypted) {
Info(slide, 0x401, ((char *)slide,
LoadFarStringSmall2(WrnStorUCSizCSizDiff),
@@ -1924,24 +1935,21 @@
#ifdef VMS /* VMS: required even for stdout! (final flush) */
if (!uO.tflag) /* don't close NULL file */
- close_outfile(__G);
+ error = close_outfile(__G);
#else
#ifdef DLL
if (!uO.tflag && (!uO.cflag || G.redirect_data)) {
if (G.redirect_data)
FINISH_REDIRECT();
else
- close_outfile(__G);
+ error = close_outfile(__G);
}
#else
if (!uO.tflag && !uO.cflag) /* don't close NULL file or stdout */
- close_outfile(__G);
+ error = close_outfile(__G);
#endif
#endif /* VMS */
- /* GRR: CONVERT close_outfile() TO NON-VOID: CHECK FOR ERRORS! */
-
-
if (G.disk_full) { /* set by flush() */
if (G.disk_full > 1) {
#if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK))
@@ -2023,7 +2031,8 @@
ebID = makeword(ef);
ebLen = (unsigned)makeword(ef+EB_LEN);
- if (ebLen > (ef_len - EB_HEADSIZE)) {
+ if (ebLen > (ef_len - EB_HEADSIZE))
+ {
/* Discovered some extra field inconsistency! */
if (uO.qflag)
Info(slide, 1, ((char *)slide, "%-22s ",
@@ -2158,11 +2167,29 @@
}
break;
case EF_PKVMS:
- if (makelong(ef+EB_HEADSIZE) !=
- crc32(CRCVAL_INITIAL, ef+(EB_HEADSIZE+4),
- (extent)(ebLen-4)))
- Info(slide, 1, ((char *)slide,
- LoadFarString(BadCRC_EAs)));
+ /* 2015-01-30 SMS. Added sufficient-bytes test/message
+ * here. (Removed defective ebLen test above.)
+ *
+ * If sufficient bytes (EB_PKVMS_MINLEN) are available,
+ * then compare the stored CRC value with the calculated
+ * CRC for the remainder of the data (and complain about
+ * a mismatch).
+ */
+ if (ebLen < EB_PKVMS_MINLEN)
+ {
+ /* Insufficient bytes available. */
+ Info( slide, 1,
+ ((char *)slide, LoadFarString( TooSmallEBlength),
+ ebLen, EB_PKVMS_MINLEN));
+ }
+ else if (makelong(ef+ EB_HEADSIZE) !=
+ crc32(CRCVAL_INITIAL,
+ (ef+ EB_HEADSIZE+ EB_PKVMS_MINLEN),
+ (extent)(ebLen- EB_PKVMS_MINLEN)))
+ {
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(BadCRC_EAs)));
+ }
break;
case EF_PKW32:
case EF_PKUNIX:
@@ -2217,14 +2244,28 @@
ulg eb_ucsize;
uch *eb_ucptr;
int r;
+ ush method;
if (compr_offset < 4) /* field is not compressed: */
return PK_OK; /* do nothing and signal OK */
+ /* Return no/bad-data error status if any problem is found:
+ * 1. eb_size is too small to hold the uncompressed size
+ * (eb_ucsize). (Else extract eb_ucsize.)
+ * 2. eb_ucsize is zero (invalid). 2014-12-04 SMS.
+ * 3. eb_ucsize is positive, but eb_size is too small to hold
+ * the compressed data header.
+ */
if ((eb_size < (EB_UCSIZE_P + 4)) ||
- ((eb_ucsize = makelong(eb+(EB_HEADSIZE+EB_UCSIZE_P))) > 0L &&
- eb_size <= (compr_offset + EB_CMPRHEADLEN)))
- return IZ_EF_TRUNC; /* no compressed data! */
+ ((eb_ucsize = makelong( eb+ (EB_HEADSIZE+ EB_UCSIZE_P))) == 0L) ||
+ ((eb_ucsize > 0L) && (eb_size <= (compr_offset + EB_CMPRHEADLEN))))
+ return IZ_EF_TRUNC; /* no/bad compressed data! */
+
+ method = makeword(eb + (EB_HEADSIZE + compr_offset));
+ if ((method == STORED) && (eb_size != compr_offset + EB_CMPRHEADLEN + eb_ucsize))
+ return PK_ERR; /* compressed & uncompressed
+ * should match in STORED
+ * method */
if (
#ifdef INT_16BIT
@@ -2542,8 +2583,21 @@
} /* end function set_deferred_symlink() */
#endif /* SYMLINKS */
+/*
+ * If Unicode is supported, assume we have what we need to do this
+ * check using wide characters, avoiding MBCS issues.
+ */
-
+#ifndef UZ_FNFILTER_REPLACECHAR
+ /* A convenient choice for the replacement of unprintable char codes is
+ * the "single char wildcard", as this character is quite unlikely to
+ * appear in filenames by itself. The following default definition
+ * sets the replacement char to a question mark as the most common
+ * "single char wildcard"; this setting should be overridden in the
+ * appropiate system-specific configuration header when needed.
+ */
+# define UZ_FNFILTER_REPLACECHAR '?'
+#endif
/*************************/
/* Function fnfilter() */ /* here instead of in list.c for SFX */
@@ -2555,48 +2609,168 @@
extent size;
{
#ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */
- ZCONST uch *r=(ZCONST uch *)raw;
+ ZCONST uch *r; // =(ZCONST uch *)raw;
uch *s=space;
uch *slim=NULL;
uch *se=NULL;
int have_overflow = FALSE;
- if (size > 0) {
- slim = space + size
-#ifdef _MBCS
- - (MB_CUR_MAX - 1)
-#endif
- - 4;
+# if defined( UNICODE_SUPPORT) && defined( _MBCS)
+/* If Unicode support is enabled, and we have multi-byte characters,
+ * then do the isprint() checks by first converting to wide characters
+ * and checking those. This avoids our having to parse multi-byte
+ * characters for ourselves. After the wide-char replacements have been
+ * made, the wide string is converted back to the local character set.
+ */
+ wchar_t *wstring; /* wchar_t version of raw */
+ size_t wslen; /* length of wstring */
+ wchar_t *wostring; /* wchar_t version of output string */
+ size_t woslen; /* length of wostring */
+ char *newraw; /* new raw */
+
+ /* 2012-11-06 SMS.
+ * Changed to check the value returned by mbstowcs(), and bypass the
+ * Unicode processing if it fails. This seems to fix a problem
+ * reported in the SourceForge forum, but it's not clear that we
+ * should be doing any Unicode processing without some evidence that
+ * the name actually is Unicode. (Check bit 11 in the flags before
+ * coming here?)
+ * http://sourceforge.net/p/infozip/bugs/40/
+ */
+
+ if (MB_CUR_MAX <= 1)
+ {
+ /* There's no point to converting multi-byte chars if there are
+ * no multi-byte chars.
+ */
+ wslen = (size_t)-1;
}
- while (*r) {
- if (size > 0 && s >= slim && se == NULL) {
- se = s;
- }
-#ifdef QDOS
- if (qlflag & 2) {
- if (*r == '/' || *r == '.') {
+ else
+ {
+ /* Get Unicode wide character count (for storage allocation). */
+ wslen = mbstowcs( NULL, raw, 0);
+ }
+
+ if (wslen != (size_t)-1)
+ {
+ /* Apparently valid Unicode. Allocate wide-char storage. */
+ wstring = (wchar_t *)malloc((wslen + 1) * sizeof(wchar_t));
+ if (wstring == NULL) {
+ strcpy( (char *)space, raw);
+ return (char *)space;
+ }
+ wostring = (wchar_t *)malloc(2 * (wslen + 1) * sizeof(wchar_t));
+ if (wostring == NULL) {
+ free(wstring);
+ strcpy( (char *)space, raw);
+ return (char *)space;
+ }
+
+ /* Convert the multi-byte Unicode to wide chars. */
+ wslen = mbstowcs(wstring, raw, wslen + 1);
+
+ /* Filter the wide-character string. */
+ fnfilterw( wstring, wostring, (2 * (wslen + 1) * sizeof(wchar_t)));
+
+ /* Convert filtered wide chars back to multi-byte. */
+ woslen = wcstombs( NULL, wostring, 0);
+ if ((newraw = malloc(woslen + 1)) == NULL) {
+ free(wstring);
+ free(wostring);
+ strcpy( (char *)space, raw);
+ return (char *)space;
+ }
+ woslen = wcstombs( newraw, wostring, (woslen * MB_CUR_MAX) + 1);
+
+ if (size > 0) {
+ slim = space + size - 4;
+ }
+ r = (ZCONST uch *)newraw;
+ while (*r) {
+ if (size > 0 && s >= slim && se == NULL) {
+ se = s;
+ }
+# ifdef QDOS
+ if (qlflag & 2) {
+ if (*r == '/' || *r == '.') {
+ if (se != NULL && (s > (space + (size-3)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ ++r;
+ *s++ = '_';
+ continue;
+ }
+ } else
+# endif
+ {
if (se != NULL && (s > (space + (size-3)))) {
have_overflow = TRUE;
break;
}
- ++r;
- *s++ = '_';
- continue;
+ *s++ = *r++;
}
- } else
+ }
+ if (have_overflow) {
+ strcpy((char *)se, "...");
+ } else {
+ *s = '\0';
+ }
+
+ free(wstring);
+ free(wostring);
+ free(newraw);
+ }
+ else
+# endif /* defined( UNICODE_SUPPORT) && defined( _MBCS) */
+ {
+ /* No Unicode support, or apparently invalid Unicode. */
+ r = (ZCONST uch *)raw;
+
+ if (size > 0) {
+ slim = space + size
+#ifdef _MBCS
+ - (MB_CUR_MAX - 1)
+#endif
+ - 4;
+ }
+ while (*r) {
+ if (size > 0 && s >= slim && se == NULL) {
+ se = s;
+ }
+#ifdef QDOS
+ if (qlflag & 2) {
+ if (*r == '/' || *r == '.') {
+ if (se != NULL && (s > (space + (size-3)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ ++r;
+ *s++ = '_';
+ continue;
+ }
+ } else
#endif
#ifdef HAVE_WORKING_ISPRINT
-# ifndef UZ_FNFILTER_REPLACECHAR
- /* A convenient choice for the replacement of unprintable char codes is
- * the "single char wildcard", as this character is quite unlikely to
- * appear in filenames by itself. The following default definition
- * sets the replacement char to a question mark as the most common
- * "single char wildcard"; this setting should be overridden in the
- * appropiate system-specific configuration header when needed.
- */
-# define UZ_FNFILTER_REPLACECHAR '?'
-# endif
- if (!isprint(*r)) {
+ if (!isprint(*r)) {
+ if (*r < 32) {
+ /* ASCII control codes are escaped as "^{letter}". */
+ if (se != NULL && (s > (space + (size-4)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ *s++ = '^', *s++ = (uch)(64 + *r++);
+ } else {
+ /* Other unprintable codes are replaced by the
+ * placeholder character. */
+ if (se != NULL && (s > (space + (size-3)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ *s++ = UZ_FNFILTER_REPLACECHAR;
+ INCSTR(r);
+ }
+#else /* !HAVE_WORKING_ISPRINT */
if (*r < 32) {
/* ASCII control codes are escaped as "^{letter}". */
if (se != NULL && (s > (space + (size-4)))) {
@@ -2604,47 +2778,30 @@
break;
}
*s++ = '^', *s++ = (uch)(64 + *r++);
+#endif /* ?HAVE_WORKING_ISPRINT */
} else {
- /* Other unprintable codes are replaced by the
- * placeholder character. */
+#ifdef _MBCS
+ unsigned i = CLEN(r);
+ if (se != NULL && (s > (space + (size-i-2)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ for (; i > 0; i--)
+ *s++ = *r++;
+#else
if (se != NULL && (s > (space + (size-3)))) {
have_overflow = TRUE;
break;
}
- *s++ = UZ_FNFILTER_REPLACECHAR;
- INCSTR(r);
- }
-#else /* !HAVE_WORKING_ISPRINT */
- if (*r < 32) {
- /* ASCII control codes are escaped as "^{letter}". */
- if (se != NULL && (s > (space + (size-4)))) {
- have_overflow = TRUE;
- break;
- }
- *s++ = '^', *s++ = (uch)(64 + *r++);
-#endif /* ?HAVE_WORKING_ISPRINT */
- } else {
-#ifdef _MBCS
- unsigned i = CLEN(r);
- if (se != NULL && (s > (space + (size-i-2)))) {
- have_overflow = TRUE;
- break;
- }
- for (; i > 0; i--)
*s++ = *r++;
-#else
- if (se != NULL && (s > (space + (size-3)))) {
- have_overflow = TRUE;
- break;
- }
- *s++ = *r++;
#endif
- }
- }
- if (have_overflow) {
- strcpy((char *)se, "...");
- } else {
- *s = '\0';
+ }
+ }
+ if (have_overflow) {
+ strcpy((char *)se, "...");
+ } else {
+ *s = '\0';
+ }
}
#ifdef WINDLL
@@ -2666,6 +2823,53 @@
} /* end function fnfilter() */
+#if defined( UNICODE_SUPPORT) && defined( _MBCS)
+
+/****************************/
+/* Function fnfilter[w]() */ /* (Here instead of in list.c for SFX.) */
+/****************************/
+
+/* fnfilterw() - Convert wide name to safely printable form. */
+
+/* fnfilterw() - Convert wide-character name to safely printable form. */
+
+wchar_t *fnfilterw( src, dst, siz)
+ ZCONST wchar_t *src; /* Pointer to source char (string). */
+ wchar_t *dst; /* Pointer to destination char (string). */
+ extent siz; /* Not used (!). */
+{
+ wchar_t *dsx = dst;
+
+ /* Filter the wide chars. */
+ while (*src)
+ {
+ if (iswprint( *src))
+ {
+ /* Printable code. Copy it. */
+ *dst++ = *src;
+ }
+ else
+ {
+ /* Unprintable code. Substitute something printable for it. */
+ if (*src < 32)
+ {
+ /* Replace ASCII control code with "^{letter}". */
+ *dst++ = (wchar_t)'^';
+ *dst++ = (wchar_t)(64 + *src);
+ }
+ else
+ {
+ /* Replace other unprintable code with the placeholder. */
+ *dst++ = (wchar_t)UZ_FNFILTER_REPLACECHAR;
+ }
+ }
+ src++;
+ }
+ *dst = (wchar_t)0; /* NUL-terminate the destination string. */
+ return dsx;
+} /* fnfilterw(). */
+
+#endif /* defined( UNICODE_SUPPORT) && defined( _MBCS) */
#ifdef SET_DIR_ATTRIB
@@ -2701,6 +2905,12 @@
int repeated_buf_err;
bz_stream bstrm;
+ if (G.incnt <= 0 && G.csize <= 0L) {
+ /* avoid an infinite loop */
+ Trace((stderr, "UZbunzip2() got empty input\n"));
+ return 2;
+ }
+
#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
if (G.redirect_slide)
wsize = G.redirect_size, redirSlide = G.redirect_buffer;
diff -Naur a/extract.c.orig b/extract.c.orig
--- a/extract.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/extract.c.orig 2019-12-02 00:37:13.921788251 +0000
@@ -0,0 +1,2867 @@
+/*
+ Copyright (c) 1990-2014 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
+*/
+/*---------------------------------------------------------------------------
+
+ extract.c
+
+ This file contains the high-level routines ("driver routines") for extrac-
+ ting and testing zipfile members. It calls the low-level routines in files
+ explode.c, inflate.c, unreduce.c and unshrink.c.
+
+ Contains: extract_or_test_files()
+ store_info()
+ find_compr_idx()
+ extract_or_test_entrylist()
+ extract_or_test_member()
+ TestExtraField()
+ test_compr_eb()
+ memextract()
+ memflush()
+ extract_izvms_block() (VMS or VMS_TEXT_CONV)
+ set_deferred_symlink() (SYMLINKS only)
+ fnfilter()
+ dircomp() (SET_DIR_ATTRIB only)
+ UZbunzip2() (USE_BZIP2 only)
+
+ ---------------------------------------------------------------------------*/
+
+
+#define __EXTRACT_C /* identifies this source module */
+#define UNZIP_INTERNAL
+#include "unzip.h"
+#ifdef WINDLL
+# ifdef POCKET_UNZIP
+# include "wince/intrface.h"
+# else
+# include "windll/windll.h"
+# endif
+#endif
+#include "crc32.h"
+#include "crypt.h"
+
+#define GRRDUMP(buf,len) { \
+ int i, j; \
+ \
+ for (j = 0; j < (len)/16; ++j) { \
+ printf(" "); \
+ for (i = 0; i < 16; ++i) \
+ printf("%02x ", (uch)(buf)[i+(j<<4)]); \
+ printf("\n "); \
+ for (i = 0; i < 16; ++i) { \
+ char c = (char)(buf)[i+(j<<4)]; \
+ \
+ if (c == '\n') \
+ printf("\\n "); \
+ else if (c == '\r') \
+ printf("\\r "); \
+ else \
+ printf(" %c ", c); \
+ } \
+ printf("\n"); \
+ } \
+ if ((len) % 16) { \
+ printf(" "); \
+ for (i = j<<4; i < (len); ++i) \
+ printf("%02x ", (uch)(buf)[i]); \
+ printf("\n "); \
+ for (i = j<<4; i < (len); ++i) { \
+ char c = (char)(buf)[i]; \
+ \
+ if (c == '\n') \
+ printf("\\n "); \
+ else if (c == '\r') \
+ printf("\\r "); \
+ else \
+ printf(" %c ", c); \
+ } \
+ printf("\n"); \
+ } \
+}
+
+static int store_info OF((__GPRO));
+#ifdef SET_DIR_ATTRIB
+static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
+ ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes,
+ unsigned *pnum_dirs, direntry **pdirlist,
+ int error_in_archive));
+#else
+static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
+ ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes,
+ int error_in_archive));
+#endif
+static int extract_or_test_member OF((__GPRO));
+#ifndef SFX
+ static int TestExtraField OF((__GPRO__ uch *ef, unsigned ef_len));
+ static int test_compr_eb OF((__GPRO__ uch *eb, unsigned eb_size,
+ unsigned compr_offset,
+ int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size,
+ uch *eb_ucptr, ulg eb_ucsize)));
+#endif
+#if (defined(VMS) || defined(VMS_TEXT_CONV))
+ static void decompress_bits OF((uch *outptr, unsigned needlen,
+ ZCONST uch *bitptr));
+#endif
+#ifdef SYMLINKS
+ static void set_deferred_symlink OF((__GPRO__ slinkentry *slnk_entry));
+#endif
+#ifdef SET_DIR_ATTRIB
+ static int Cdecl dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b));
+#endif
+
+
+
+/*******************************/
+/* Strings used in extract.c */
+/*******************************/
+
+static ZCONST char Far VersionMsg[] =
+ " skipping: %-22s need %s compat. v%u.%u (can do v%u.%u)\n";
+static ZCONST char Far ComprMsgNum[] =
+ " skipping: %-22s unsupported compression method %u\n";
+#ifndef SFX
+ static ZCONST char Far ComprMsgName[] =
+ " skipping: %-22s `%s' method not supported\n";
+ static ZCONST char Far CmprNone[] = "store";
+ static ZCONST char Far CmprShrink[] = "shrink";
+ static ZCONST char Far CmprReduce[] = "reduce";
+ static ZCONST char Far CmprImplode[] = "implode";
+ static ZCONST char Far CmprTokenize[] = "tokenize";
+ static ZCONST char Far CmprDeflate[] = "deflate";
+ static ZCONST char Far CmprDeflat64[] = "deflate64";
+ static ZCONST char Far CmprDCLImplode[] = "DCL implode";
+ static ZCONST char Far CmprBzip[] = "bzip2";
+ static ZCONST char Far CmprLZMA[] = "LZMA";
+ static ZCONST char Far CmprIBMTerse[] = "IBM/Terse";
+ static ZCONST char Far CmprIBMLZ77[] = "IBM LZ77";
+ static ZCONST char Far CmprWavPack[] = "WavPack";
+ static ZCONST char Far CmprPPMd[] = "PPMd";
+ static ZCONST char Far *ComprNames[NUM_METHODS] = {
+ CmprNone, CmprShrink, CmprReduce, CmprReduce, CmprReduce, CmprReduce,
+ CmprImplode, CmprTokenize, CmprDeflate, CmprDeflat64, CmprDCLImplode,
+ CmprBzip, CmprLZMA, CmprIBMTerse, CmprIBMLZ77, CmprWavPack, CmprPPMd
+ };
+ static ZCONST unsigned ComprIDs[NUM_METHODS] = {
+ STORED, SHRUNK, REDUCED1, REDUCED2, REDUCED3, REDUCED4,
+ IMPLODED, TOKENIZED, DEFLATED, ENHDEFLATED, DCLIMPLODED,
+ BZIPPED, LZMAED, IBMTERSED, IBMLZ77ED, WAVPACKED, PPMDED
+ };
+#endif /* !SFX */
+static ZCONST char Far FilNamMsg[] =
+ "%s: bad filename length (%s)\n";
+#ifndef SFX
+ static ZCONST char Far WarnNoMemCFName[] =
+ "%s: warning, no memory for comparison with local header\n";
+ static ZCONST char Far LvsCFNamMsg[] =
+ "%s: mismatching \"local\" filename (%s),\n\
+ continuing with \"central\" filename version\n";
+#endif /* !SFX */
+#if (!defined(SFX) && defined(UNICODE_SUPPORT))
+ static ZCONST char Far GP11FlagsDiffer[] =
+ "file #%lu (%s):\n\
+ mismatch between local and central GPF bit 11 (\"UTF-8\"),\n\
+ continuing with central flag (IsUTF8 = %d)\n";
+#endif /* !SFX && UNICODE_SUPPORT */
+static ZCONST char Far WrnStorUCSizCSizDiff[] =
+ "%s: ucsize %s <> csize %s for STORED entry\n\
+ continuing with \"compressed\" size value\n";
+static ZCONST char Far ExtFieldMsg[] =
+ "%s: bad extra field length (%s)\n";
+static ZCONST char Far OffsetMsg[] =
+ "file #%lu: bad zipfile offset (%s): %ld\n";
+static ZCONST char Far ExtractMsg[] =
+ "%8sing: %-22s %s%s";
+#ifndef SFX
+ static ZCONST char Far LengthMsg[] =
+ "%s %s: %s bytes required to uncompress to %s bytes;\n %s\
+ supposed to require %s bytes%s%s%s\n";
+#endif
+
+static ZCONST char Far BadFileCommLength[] = "%s: bad file comment length\n";
+static ZCONST char Far LocalHdrSig[] = "local header sig";
+static ZCONST char Far BadLocalHdr[] = "file #%lu: bad local header\n";
+static ZCONST char Far AttemptRecompensate[] =
+ " (attempting to re-compensate)\n";
+#ifndef SFX
+ static ZCONST char Far BackslashPathSep[] =
+ "warning: %s appears to use backslashes as path separators\n";
+#endif
+static ZCONST char Far AbsolutePathWarning[] =
+ "warning: stripped absolute path spec from %s\n";
+static ZCONST char Far SkipVolumeLabel[] =
+ " skipping: %-22s %svolume label\n";
+
+#ifdef SET_DIR_ATTRIB /* messages of code for setting directory attributes */
+ static ZCONST char Far DirlistEntryNoMem[] =
+ "warning: cannot alloc memory for dir times/permissions/UID/GID\n";
+ static ZCONST char Far DirlistSortNoMem[] =
+ "warning: cannot alloc memory to sort dir times/perms/etc.\n";
+ static ZCONST char Far DirlistSetAttrFailed[] =
+ "warning: set times/attribs failed for %s\n";
+ static ZCONST char Far DirlistFailAttrSum[] =
+ " failed setting times/attribs for %lu dir entries";
+#endif
+
+#ifdef SYMLINKS /* messages of the deferred symlinks handler */
+ static ZCONST char Far SymLnkWarnNoMem[] =
+ "warning: deferred symlink (%s) failed:\n\
+ out of memory\n";
+ static ZCONST char Far SymLnkWarnInvalid[] =
+ "warning: deferred symlink (%s) failed:\n\
+ invalid placeholder file\n";
+ static ZCONST char Far SymLnkDeferred[] =
+ "finishing deferred symbolic links:\n";
+ static ZCONST char Far SymLnkFinish[] =
+ " %-22s -> %s\n";
+#endif
+
+#ifndef WINDLL
+ static ZCONST char Far ReplaceQuery[] =
+# ifdef VMS
+ "new version of %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ";
+# else
+ "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ";
+# endif
+ static ZCONST char Far AssumeNone[] =
+ " NULL\n(EOF or read error, treating as \"[N]one\" ...)\n";
+ static ZCONST char Far NewNameQuery[] = "new name: ";
+ static ZCONST char Far InvalidResponse[] =
+ "error: invalid response [%s]\n";
+#endif /* !WINDLL */
+
+static ZCONST char Far ErrorInArchive[] =
+ "At least one %serror was detected in %s.\n";
+static ZCONST char Far ZeroFilesTested[] =
+ "Caution: zero files tested in %s.\n";
+
+#ifndef VMS
+ static ZCONST char Far VMSFormatQuery[] =
+ "\n%s: stored in VMS format. Extract anyway? (y/n) ";
+#endif
+
+#if CRYPT
+ static ZCONST char Far SkipCannotGetPasswd[] =
+ " skipping: %-22s unable to get password\n";
+ static ZCONST char Far SkipIncorrectPasswd[] =
+ " skipping: %-22s incorrect password\n";
+ static ZCONST char Far FilesSkipBadPasswd[] =
+ "%lu file%s skipped because of incorrect password.\n";
+ static ZCONST char Far MaybeBadPasswd[] =
+ " (may instead be incorrect password)\n";
+#else
+ static ZCONST char Far SkipEncrypted[] =
+ " skipping: %-22s encrypted (not supported)\n";
+#endif
+
+static ZCONST char Far NoErrInCompData[] =
+ "No errors detected in compressed data of %s.\n";
+static ZCONST char Far NoErrInTestedFiles[] =
+ "No errors detected in %s for the %lu file%s tested.\n";
+static ZCONST char Far FilesSkipped[] =
+ "%lu file%s skipped because of unsupported compression or encoding.\n";
+
+static ZCONST char Far ErrUnzipFile[] = " error: %s%s %s\n";
+static ZCONST char Far ErrUnzipNoFile[] = "\n error: %s%s\n";
+static ZCONST char Far NotEnoughMem[] = "not enough memory to ";
+static ZCONST char Far InvalidComprData[] = "invalid compressed data to ";
+static ZCONST char Far Inflate[] = "inflate";
+#ifdef USE_BZIP2
+ static ZCONST char Far BUnzip[] = "bunzip";
+#endif
+
+#ifndef SFX
+ static ZCONST char Far Explode[] = "explode";
+#ifndef LZW_CLEAN
+ static ZCONST char Far Unshrink[] = "unshrink";
+#endif
+#endif
+
+#if (!defined(DELETE_IF_FULL) || !defined(HAVE_UNLINK))
+ static ZCONST char Far FileTruncated[] =
+ "warning: %s is probably truncated\n";
+#endif
+
+static ZCONST char Far FileUnknownCompMethod[] =
+ "%s: unknown compression method\n";
+static ZCONST char Far BadCRC[] = " bad CRC %08lx (should be %08lx)\n";
+
+ /* TruncEAs[] also used in OS/2 mapname(), close_outfile() */
+char ZCONST Far TruncEAs[] = " compressed EA data missing (%d bytes)%s";
+char ZCONST Far TruncNTSD[] =
+ " compressed WinNT security data missing (%d bytes)%s";
+
+#ifndef SFX
+ static ZCONST char Far InconsistEFlength[] = "bad extra-field entry:\n \
+ EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n";
+ static ZCONST char Far TooSmallEBlength[] = "bad extra-field entry:\n \
+ EF block length (%u bytes) invalid (< %d)\n";
+ static ZCONST char Far InvalidComprDataEAs[] =
+ " invalid compressed data for EAs\n";
+# if (defined(WIN32) && defined(NTSD_EAS))
+ static ZCONST char Far InvalidSecurityEAs[] =
+ " EAs fail security check\n";
+# endif
+ static ZCONST char Far UnsuppNTSDVersEAs[] =
+ " unsupported NTSD EAs version %d\n";
+ static ZCONST char Far BadCRC_EAs[] = " bad CRC for extended attributes\n";
+ static ZCONST char Far UnknComprMethodEAs[] =
+ " unknown compression method for EAs (%u)\n";
+ static ZCONST char Far NotEnoughMemEAs[] =
+ " out of memory while inflating EAs\n";
+ static ZCONST char Far UnknErrorEAs[] =
+ " unknown error on extended attributes\n";
+#endif /* !SFX */
+
+static ZCONST char Far UnsupportedExtraField[] =
+ "\nerror: unsupported extra-field compression type (%u)--skipping\n";
+static ZCONST char Far BadExtraFieldCRC[] =
+ "error [%s]: bad extra-field CRC %08lx (should be %08lx)\n";
+
+
+
+
+
+/**************************************/
+/* Function extract_or_test_files() */
+/**************************************/
+
+int extract_or_test_files(__G) /* return PK-type error code */
+ __GDEF
+{
+ unsigned i, j;
+ zoff_t cd_bufstart;
+ uch *cd_inptr;
+ int cd_incnt;
+ ulg filnum=0L, blknum=0L;
+ int reached_end;
+#ifndef SFX
+ int no_endsig_found;
+#endif
+ int error, error_in_archive=PK_COOL;
+ int *fn_matched=NULL, *xn_matched=NULL;
+ zucn_t members_processed;
+ ulg num_skipped=0L, num_bad_pwd=0L;
+ zoff_t old_extra_bytes = 0L;
+#ifdef SET_DIR_ATTRIB
+ unsigned num_dirs=0;
+ direntry *dirlist=(direntry *)NULL, **sorted_dirlist=(direntry **)NULL;
+#endif
+
+ /*
+ * First, two general initializations are applied. These have been moved
+ * here from process_zipfiles() because they are only needed for accessing
+ * and/or extracting the data content of the zip archive.
+ */
+
+ /* a) 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))
+ /* b) 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)) > MPN_INF_SKIP) {
+ /* out of memory, or file in way */
+ return (error == MPN_NOMEM ? PK_MEM : PK_ERR);
+ }
+ }
+#endif /* !SFX || SFX_EXDIR */
+
+/*---------------------------------------------------------------------------
+ The basic idea of this function is as follows. Since the central di-
+ rectory lies at the end of the zipfile and the member files lie at the
+ beginning or middle or wherever, it is not very desirable to simply
+ read a central directory entry, jump to the member and extract it, and
+ then jump back to the central directory. In the case of a large zipfile
+ this would lead to a whole lot of disk-grinding, especially if each mem-
+ ber file is small. Instead, we read from the central directory the per-
+ tinent information for a block of files, then go extract/test the whole
+ block. Thus this routine contains two small(er) loops within a very
+ large outer loop: the first of the small ones reads a block of files
+ from the central directory; the second extracts or tests each file; and
+ the outer one loops over blocks. There's some file-pointer positioning
+ stuff in between, but that's about it. Btw, it's because of this jump-
+ ing around that we can afford to be lenient if an error occurs in one of
+ the member files: we should still be able to go find the other members,
+ since we know the offset of each from the beginning of the zipfile.
+ ---------------------------------------------------------------------------*/
+
+ G.pInfo = G.info;
+
+#if CRYPT
+ G.newzip = TRUE;
+#endif
+#ifndef SFX
+ G.reported_backslash = FALSE;
+#endif
+
+ /* malloc space for check on unmatched filespecs (OK if one or both NULL) */
+ if (G.filespecs > 0 &&
+ (fn_matched=(int *)malloc(G.filespecs*sizeof(int))) != (int *)NULL)
+ for (i = 0; i < G.filespecs; ++i)
+ fn_matched[i] = FALSE;
+ if (G.xfilespecs > 0 &&
+ (xn_matched=(int *)malloc(G.xfilespecs*sizeof(int))) != (int *)NULL)
+ for (i = 0; i < G.xfilespecs; ++i)
+ xn_matched[i] = FALSE;
+
+/*---------------------------------------------------------------------------
+ Begin main loop over blocks of member files. We know the entire central
+ directory is on this disk: we would not have any of this information un-
+ less the end-of-central-directory record was on this disk, and we would
+ not have gotten to this routine unless this is also the disk on which
+ the central directory starts. In practice, this had better be the ONLY
+ disk in the archive, but we'll add multi-disk support soon.
+ ---------------------------------------------------------------------------*/
+
+ members_processed = 0;
+#ifndef SFX
+ no_endsig_found = FALSE;
+#endif
+ reached_end = FALSE;
+ while (!reached_end) {
+ j = 0;
+#ifdef AMIGA
+ memzero(G.filenotes, DIR_BLKSIZ * sizeof(char *));
+#endif
+
+ /*
+ * Loop through files in central directory, storing offsets, file
+ * attributes, case-conversion and text-conversion flags until block
+ * size is reached.
+ */
+
+ while ((j < DIR_BLKSIZ)) {
+ G.pInfo = &G.info[j];
+
+ if (readbuf(__G__ G.sig, 4) == 0) {
+ error_in_archive = PK_EOF;
+ reached_end = TRUE; /* ...so no more left to do */
+ break;
+ }
+ if (memcmp(G.sig, central_hdr_sig, 4)) { /* is it a new entry? */
+ /* no new central directory entry
+ * -> is the number of processed entries compatible with the
+ * number of entries as stored in the end_central record?
+ */
+ if ((members_processed
+ & (G.ecrec.have_ecr64 ? MASK_ZUCN64 : MASK_ZUCN16))
+ == G.ecrec.total_entries_central_dir) {
+#ifndef SFX
+ /* yes, so look if we ARE back at the end_central record
+ */
+ no_endsig_found =
+ ( (memcmp(G.sig,
+ (G.ecrec.have_ecr64 ?
+ end_central64_sig : end_central_sig),
+ 4) != 0)
+ && (!G.ecrec.is_zip64_archive)
+ && (memcmp(G.sig, end_central_sig, 4) != 0)
+ );
+#endif /* !SFX */
+ } else {
+ /* no; we have found an error in the central directory
+ * -> report it and stop searching for more Zip entries
+ */
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(CentSigMsg), j + blknum*DIR_BLKSIZ + 1));
+ Info(slide, 0x401,
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
+ error_in_archive = PK_BADERR;
+ }
+ reached_end = TRUE; /* ...so no more left to do */
+ break;
+ }
+ /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */
+ if ((error = process_cdir_file_hdr(__G)) != PK_COOL) {
+ error_in_archive = error; /* only PK_EOF defined */
+ reached_end = TRUE; /* ...so no more left to do */
+ break;
+ }
+ if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) !=
+ PK_COOL)
+ {
+ if (error > error_in_archive)
+ error_in_archive = error;
+ if (error > PK_WARN) { /* fatal: no more left to do */
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(FilNamMsg),
+ FnFilter1(G.filename), "central"));
+ reached_end = TRUE;
+ break;
+ }
+ }
+ if ((error = do_string(__G__ G.crec.extra_field_length,
+ EXTRA_FIELD)) != 0)
+ {
+ if (error > error_in_archive)
+ error_in_archive = error;
+ if (error > PK_WARN) { /* fatal */
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(ExtFieldMsg),
+ FnFilter1(G.filename), "central"));
+ reached_end = TRUE;
+ break;
+ }
+ }
+#ifdef AMIGA
+ G.filenote_slot = j;
+ if ((error = do_string(__G__ G.crec.file_comment_length,
+ uO.N_flag ? FILENOTE : SKIP)) != PK_COOL)
+#else
+ if ((error = do_string(__G__ G.crec.file_comment_length, SKIP))
+ != PK_COOL)
+#endif
+ {
+ if (error > error_in_archive)
+ error_in_archive = error;
+ if (error > PK_WARN) { /* fatal */
+ Info(slide, 0x421, ((char *)slide,
+ LoadFarString(BadFileCommLength),
+ FnFilter1(G.filename)));
+ reached_end = TRUE;
+ break;
+ }
+ }
+ if (G.process_all_files) {
+ if (store_info(__G))
+ ++j; /* file is OK; info[] stored; continue with next */
+ else
+ ++num_skipped;
+ } else {
+ int do_this_file;
+
+ if (G.filespecs == 0)
+ do_this_file = TRUE;
+ else { /* check if this entry matches an `include' argument */
+ do_this_file = FALSE;
+ for (i = 0; i < G.filespecs; i++)
+ if (match(G.filename, G.pfnames[i], uO.C_flag WISEP)) {
+ do_this_file = TRUE; /* ^-- ignore case or not? */
+ if (fn_matched)
+ fn_matched[i] = TRUE;
+ break; /* found match, so stop looping */
+ }
+ }
+ if (do_this_file) { /* check if this is an excluded file */
+ for (i = 0; i < G.xfilespecs; i++)
+ if (match(G.filename, G.pxnames[i], uO.C_flag WISEP)) {
+ do_this_file = FALSE; /* ^-- ignore case or not? */
+ if (xn_matched)
+ xn_matched[i] = TRUE;
+ break;
+ }
+ }
+ if (do_this_file) {
+ if (store_info(__G))
+ ++j; /* file is OK */
+ else
+ ++num_skipped; /* unsupp. compression or encryption */
+ }
+ } /* end if (process_all_files) */
+
+ members_processed++;
+
+ } /* end while-loop (adding files to current block) */
+
+ /* save position in central directory so can come back later */
+ cd_bufstart = G.cur_zipfile_bufstart;
+ cd_inptr = G.inptr;
+ cd_incnt = G.incnt;
+
+ /*-----------------------------------------------------------------------
+ Second loop: process files in current block, extracting or testing
+ each one.
+ -----------------------------------------------------------------------*/
+
+ error = extract_or_test_entrylist(__G__ j,
+ &filnum, &num_bad_pwd, &old_extra_bytes,
+#ifdef SET_DIR_ATTRIB
+ &num_dirs, &dirlist,
+#endif
+ error_in_archive);
+ if (error != PK_COOL) {
+ if (error > error_in_archive)
+ error_in_archive = error;
+ /* ...and keep going (unless disk full or user break) */
+ if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
+ /* clear reached_end to signal premature stop ... */
+ reached_end = FALSE;
+ /* ... and cancel scanning the central directory */
+ break;
+ }
+ }
+
+
+ /*
+ * Jump back to where we were in the central directory, then go and do
+ * the next batch of files.
+ */
+
+#ifdef USE_STRM_INPUT
+ zfseeko(G.zipfd, cd_bufstart, SEEK_SET);
+ G.cur_zipfile_bufstart = zftello(G.zipfd);
+#else /* !USE_STRM_INPUT */
+ G.cur_zipfile_bufstart =
+ zlseek(G.zipfd, cd_bufstart, SEEK_SET);
+#endif /* ?USE_STRM_INPUT */
+ read(G.zipfd, (char *)G.inbuf, INBUFSIZ); /* been here before... */
+ G.inptr = cd_inptr;
+ G.incnt = cd_incnt;
+ ++blknum;
+
+#ifdef TEST
+ printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart);
+ printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart,
+ cur_zipfile_bufstart);
+ printf("inptr-inbuf = %d\n", G.inptr-G.inbuf);
+ printf("incnt = %d\n\n", G.incnt);
+#endif
+
+ } /* end while-loop (blocks of files in central directory) */
+
+/*---------------------------------------------------------------------------
+ Process the list of deferred symlink extractions and finish up
+ the symbolic links.
+ ---------------------------------------------------------------------------*/
+
+#ifdef SYMLINKS
+ if (G.slink_last != NULL) {
+ if (QCOND2)
+ Info(slide, 0, ((char *)slide, LoadFarString(SymLnkDeferred)));
+ while (G.slink_head != NULL) {
+ set_deferred_symlink(__G__ G.slink_head);
+ /* remove the processed entry from the chain and free its memory */
+ G.slink_last = G.slink_head;
+ G.slink_head = G.slink_last->next;
+ free(G.slink_last);
+ }
+ G.slink_last = NULL;
+ }
+#endif /* SYMLINKS */
+
+/*---------------------------------------------------------------------------
+ Go back through saved list of directories, sort and set times/perms/UIDs
+ and GIDs from the deepest level on up.
+ ---------------------------------------------------------------------------*/
+
+#ifdef SET_DIR_ATTRIB
+ if (num_dirs > 0) {
+ sorted_dirlist = (direntry **)malloc(num_dirs*sizeof(direntry *));
+ if (sorted_dirlist == (direntry **)NULL) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(DirlistSortNoMem)));
+ while (dirlist != (direntry *)NULL) {
+ direntry *d = dirlist;
+
+ dirlist = dirlist->next;
+ free(d);
+ }
+ } else {
+ ulg ndirs_fail = 0;
+
+ if (num_dirs == 1)
+ sorted_dirlist[0] = dirlist;
+ else {
+ for (i = 0; i < num_dirs; ++i) {
+ sorted_dirlist[i] = dirlist;
+ dirlist = dirlist->next;
+ }
+ qsort((char *)sorted_dirlist, num_dirs, sizeof(direntry *),
+ dircomp);
+ }
+
+ Trace((stderr, "setting directory times/perms/attributes\n"));
+ for (i = 0; i < num_dirs; ++i) {
+ direntry *d = sorted_dirlist[i];
+
+ Trace((stderr, "dir = %s\n", d->fn));
+ if ((error = set_direc_attribs(__G__ d)) != PK_OK) {
+ ndirs_fail++;
+ Info(slide, 0x201, ((char *)slide,
+ LoadFarString(DirlistSetAttrFailed), d->fn));
+ if (!error_in_archive)
+ error_in_archive = error;
+ }
+ free(d);
+ }
+ free(sorted_dirlist);
+ if (!uO.tflag && QCOND2) {
+ if (ndirs_fail > 0)
+ Info(slide, 0, ((char *)slide,
+ LoadFarString(DirlistFailAttrSum), ndirs_fail));
+ }
+ }
+ }
+#endif /* SET_DIR_ATTRIB */
+
+/*---------------------------------------------------------------------------
+ Check for unmatched filespecs on command line and print warning if any
+ found. Free allocated memory. (But suppress check when central dir
+ scan was interrupted prematurely.)
+ ---------------------------------------------------------------------------*/
+
+ if (fn_matched) {
+ if (reached_end) for (i = 0; i < G.filespecs; ++i)
+ if (!fn_matched[i]) {
+#ifdef DLL
+ if (!G.redirect_data && !G.redirect_text)
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(FilenameNotMatched), G.pfnames[i]));
+ else
+ setFileNotFound(__G);
+#else
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(FilenameNotMatched), G.pfnames[i]));
+#endif
+ if (error_in_archive <= PK_WARN)
+ error_in_archive = PK_FIND; /* some files not found */
+ }
+ free((zvoid *)fn_matched);
+ }
+ if (xn_matched) {
+ if (reached_end) for (i = 0; i < G.xfilespecs; ++i)
+ if (!xn_matched[i])
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(ExclFilenameNotMatched), G.pxnames[i]));
+ free((zvoid *)xn_matched);
+ }
+
+/*---------------------------------------------------------------------------
+ Now, all locally allocated memory has been released. When the central
+ directory processing has been interrupted prematurely, it is safe to
+ return immediately. All completeness checks and summary messages are
+ skipped in this case.
+ ---------------------------------------------------------------------------*/
+ if (!reached_end)
+ return error_in_archive;
+
+/*---------------------------------------------------------------------------
+ Double-check that we're back at the end-of-central-directory record, and
+ print quick summary of results, if we were just testing the archive. We
+ send the summary to stdout so that people doing the testing in the back-
+ ground and redirecting to a file can just do a "tail" on the output file.
+ ---------------------------------------------------------------------------*/
+
+#ifndef SFX
+ if (no_endsig_found) { /* just to make sure */
+ Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg)));
+ Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(ReportMsg)));
+ if (!error_in_archive) /* don't overwrite stronger error */
+ error_in_archive = PK_WARN;
+ }
+#endif /* !SFX */
+ if (uO.tflag) {
+ ulg num = filnum - num_bad_pwd;
+
+ if (uO.qflag < 2) { /* GRR 930710: was (uO.qflag == 1) */
+ if (error_in_archive)
+ Info(slide, 0, ((char *)slide, LoadFarString(ErrorInArchive),
+ (error_in_archive == PK_WARN)? "warning-" : "", G.zipfn));
+ else if (num == 0L)
+ Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested),
+ G.zipfn));
+ else if (G.process_all_files && (num_skipped+num_bad_pwd == 0L))
+ Info(slide, 0, ((char *)slide, LoadFarString(NoErrInCompData),
+ G.zipfn));
+ else
+ Info(slide, 0, ((char *)slide, LoadFarString(NoErrInTestedFiles)
+ , G.zipfn, num, (num==1L)? "":"s"));
+ if (num_skipped > 0L)
+ Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipped),
+ num_skipped, (num_skipped==1L)? "":"s"));
+#if CRYPT
+ if (num_bad_pwd > 0L)
+ Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipBadPasswd)
+ , num_bad_pwd, (num_bad_pwd==1L)? "":"s"));
+#endif /* CRYPT */
+ }
+ }
+
+ /* give warning if files not tested or extracted (first condition can still
+ * happen if zipfile is empty and no files specified on command line) */
+
+ if ((filnum == 0) && error_in_archive <= PK_WARN) {
+ if (num_skipped > 0L)
+ error_in_archive = IZ_UNSUP; /* unsupport. compression/encryption */
+ else
+ error_in_archive = PK_FIND; /* no files found at all */
+ }
+#if CRYPT
+ else if ((filnum == num_bad_pwd) && error_in_archive <= PK_WARN)
+ error_in_archive = IZ_BADPWD; /* bad passwd => all files skipped */
+#endif
+ else if ((num_skipped > 0L) && error_in_archive <= PK_WARN)
+ error_in_archive = IZ_UNSUP; /* was PK_WARN; Jean-loup complained */
+#if CRYPT
+ else if ((num_bad_pwd > 0L) && !error_in_archive)
+ error_in_archive = PK_WARN;
+#endif
+
+ return error_in_archive;
+
+} /* end function extract_or_test_files() */
+
+
+
+
+
+/***************************/
+/* Function store_info() */
+/***************************/
+
+static int store_info(__G) /* return 0 if skipping, 1 if OK */
+ __GDEF
+{
+#ifdef USE_BZIP2
+# define UNKN_BZ2 (G.crec.compression_method!=BZIPPED)
+#else
+# define UNKN_BZ2 TRUE /* bzip2 unknown */
+#endif
+
+#ifdef USE_LZMA
+# define UNKN_LZMA (G.crec.compression_method!=LZMAED)
+#else
+# define UNKN_LZMA TRUE /* LZMA unknown */
+#endif
+
+#ifdef USE_WAVP
+# define UNKN_WAVP (G.crec.compression_method!=WAVPACKED)
+#else
+# define UNKN_WAVP TRUE /* WavPack unknown */
+#endif
+
+#ifdef USE_PPMD
+# define UNKN_PPMD (G.crec.compression_method!=PPMDED)
+#else
+# define UNKN_PPMD TRUE /* PPMd unknown */
+#endif
+
+#ifdef SFX
+# ifdef USE_DEFLATE64
+# define UNKN_COMPR \
+ (G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \
+ && G.crec.compression_method>ENHDEFLATED \
+ && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
+# else
+# define UNKN_COMPR \
+ (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED\
+ && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
+# endif
+#else
+# ifdef COPYRIGHT_CLEAN /* no reduced files */
+# define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
+ G.crec.compression_method <= REDUCED4)
+# else
+# define UNKN_RED FALSE /* reducing not unknown */
+# endif
+# ifdef LZW_CLEAN /* no shrunk files */
+# define UNKN_SHR (G.crec.compression_method == SHRUNK)
+# else
+# define UNKN_SHR FALSE /* unshrinking not unknown */
+# endif
+# ifdef USE_DEFLATE64
+# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
+ G.crec.compression_method==TOKENIZED || \
+ (G.crec.compression_method>ENHDEFLATED && UNKN_BZ2 && UNKN_LZMA \
+ && UNKN_WAVP && UNKN_PPMD))
+# else
+# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
+ G.crec.compression_method==TOKENIZED || \
+ (G.crec.compression_method>DEFLATED && UNKN_BZ2 && UNKN_LZMA \
+ && UNKN_WAVP && UNKN_PPMD))
+# endif
+#endif
+
+#if (defined(USE_BZIP2) && (UNZIP_VERSION < UNZIP_BZ2VERS))
+ int unzvers_support = (UNKN_BZ2 ? UNZIP_VERSION : UNZIP_BZ2VERS);
+# define UNZVERS_SUPPORT unzvers_support
+#else
+# define UNZVERS_SUPPORT UNZIP_VERSION
+#endif
+
+/*---------------------------------------------------------------------------
+ Check central directory info for version/compatibility requirements.
+ ---------------------------------------------------------------------------*/
+
+ G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1; /* bit field */
+ G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8; /* bit */
+ G.pInfo->textfile = G.crec.internal_file_attributes & 1; /* bit field */
+ G.pInfo->crc = G.crec.crc32;
+ G.pInfo->compr_size = G.crec.csize;
+ G.pInfo->uncompr_size = G.crec.ucsize;
+
+ switch (uO.aflag) {
+ case 0:
+ G.pInfo->textmode = FALSE; /* bit field */
+ break;
+ case 1:
+ G.pInfo->textmode = G.pInfo->textfile; /* auto-convert mode */
+ break;
+ default: /* case 2: */
+ G.pInfo->textmode = TRUE;
+ break;
+ }
+
+ if (G.crec.version_needed_to_extract[1] == VMS_) {
+ if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
+ Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
+ FnFilter1(G.filename), "VMS",
+ G.crec.version_needed_to_extract[0] / 10,
+ G.crec.version_needed_to_extract[0] % 10,
+ VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10));
+ return 0;
+ }
+#ifndef VMS /* won't be able to use extra field, but still have data */
+ else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */
+ Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery),
+ FnFilter1(G.filename)));
+ fgets(G.answerbuf, sizeof(G.answerbuf), stdin);
+ if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y'))
+ return 0;
+ }
+#endif /* !VMS */
+ /* usual file type: don't need VMS to extract */
+ } else if (G.crec.version_needed_to_extract[0] > UNZVERS_SUPPORT) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
+ Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
+ FnFilter1(G.filename), "PK",
+ G.crec.version_needed_to_extract[0] / 10,
+ G.crec.version_needed_to_extract[0] % 10,
+ UNZVERS_SUPPORT / 10, UNZVERS_SUPPORT % 10));
+ return 0;
+ }
+
+ if (UNKN_COMPR) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) {
+#ifndef SFX
+ unsigned cmpridx;
+
+ if ((cmpridx = find_compr_idx(G.crec.compression_method))
+ < NUM_METHODS)
+ Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName),
+ FnFilter1(G.filename),
+ LoadFarStringSmall(ComprNames[cmpridx])));
+ else
+#endif
+ Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum),
+ FnFilter1(G.filename),
+ G.crec.compression_method));
+ }
+ return 0;
+ }
+#if (!CRYPT)
+ if (G.pInfo->encrypted) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
+ Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted),
+ FnFilter1(G.filename)));
+ return 0;
+ }
+#endif /* !CRYPT */
+
+#ifndef SFX
+ /* store a copy of the central header filename for later comparison */
+ if ((G.pInfo->cfilname = zfmalloc(strlen(G.filename) + 1)) == NULL) {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(WarnNoMemCFName),
+ FnFilter1(G.filename)));
+ } else
+ zfstrcpy(G.pInfo->cfilname, G.filename);
+#endif /* !SFX */
+
+ /* map whatever file attributes we have into the local format */
+ mapattr(__G); /* GRR: worry about return value later */
+
+ G.pInfo->diskstart = G.crec.disk_number_start;
+ G.pInfo->offset = (zoff_t)G.crec.relative_offset_local_header;
+ return 1;
+
+} /* end function store_info() */
+
+
+
+
+
+#ifndef SFX
+/*******************************/
+/* Function find_compr_idx() */
+/*******************************/
+
+unsigned find_compr_idx(compr_methodnum)
+ unsigned compr_methodnum;
+{
+ unsigned i;
+
+ for (i = 0; i < NUM_METHODS; i++) {
+ if (ComprIDs[i] == compr_methodnum) break;
+ }
+ return i;
+}
+#endif /* !SFX */
+
+
+
+
+
+/******************************************/
+/* Function extract_or_test_entrylist() */
+/******************************************/
+
+static int extract_or_test_entrylist(__G__ numchunk,
+ pfilnum, pnum_bad_pwd, pold_extra_bytes,
+#ifdef SET_DIR_ATTRIB
+ pnum_dirs, pdirlist,
+#endif
+ error_in_archive) /* return PK-type error code */
+ __GDEF
+ unsigned numchunk;
+ ulg *pfilnum;
+ ulg *pnum_bad_pwd;
+ zoff_t *pold_extra_bytes;
+#ifdef SET_DIR_ATTRIB
+ unsigned *pnum_dirs;
+ direntry **pdirlist;
+#endif
+ int error_in_archive;
+{
+ unsigned i;
+ int renamed, query;
+ int skip_entry;
+ zoff_t bufstart, inbuf_offset, request;
+ int error, errcode;
+
+/* possible values for local skip_entry flag: */
+#define SKIP_NO 0 /* do not skip this entry */
+#define SKIP_Y_EXISTING 1 /* skip this entry, do not overwrite file */
+#define SKIP_Y_NONEXIST 2 /* skip this entry, do not create new file */
+
+ /*-----------------------------------------------------------------------
+ Second loop: process files in current block, extracting or testing
+ each one.
+ -----------------------------------------------------------------------*/
+
+ for (i = 0; i < numchunk; ++i) {
+ (*pfilnum)++; /* *pfilnum = i + blknum*DIR_BLKSIZ + 1; */
+ G.pInfo = &G.info[i];
+#ifdef NOVELL_BUG_FAILSAFE
+ G.dne = FALSE; /* assume file exists until stat() says otherwise */
+#endif
+
+ /* if the target position is not within the current input buffer
+ * (either haven't yet read far enough, or (maybe) skipping back-
+ * ward), skip to the target position and reset readbuf(). */
+
+ /* seek_zipf(__G__ pInfo->offset); */
+ request = G.pInfo->offset + G.extra_bytes;
+ inbuf_offset = request % INBUFSIZ;
+ bufstart = request - inbuf_offset;
+
+ Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n",
+ (long)request, (long)inbuf_offset));
+ Trace((stderr,
+ "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
+ (long)bufstart, (long)G.cur_zipfile_bufstart));
+ if (request < 0) {
+ Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg),
+ G.zipfn, LoadFarString(ReportMsg)));
+ error_in_archive = PK_ERR;
+ if (*pfilnum == 1 && G.extra_bytes != 0L) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(AttemptRecompensate)));
+ *pold_extra_bytes = G.extra_bytes;
+ G.extra_bytes = 0L;
+ request = G.pInfo->offset; /* could also check if != 0 */
+ inbuf_offset = request % INBUFSIZ;
+ bufstart = request - inbuf_offset;
+ Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n",
+ (long)request, (long)inbuf_offset));
+ Trace((stderr,
+ "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
+ (long)bufstart, (long)G.cur_zipfile_bufstart));
+ /* try again */
+ if (request < 0) {
+ Trace((stderr,
+ "debug: recompensated request still < 0\n"));
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(SeekMsg),
+ G.zipfn, LoadFarString(ReportMsg)));
+ error_in_archive = PK_BADERR;
+ continue;
+ }
+ } else {
+ error_in_archive = PK_BADERR;
+ continue; /* this one hosed; try next */
+ }
+ }
+
+ if (bufstart != G.cur_zipfile_bufstart) {
+ Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n"));
+#ifdef USE_STRM_INPUT
+ zfseeko(G.zipfd, bufstart, SEEK_SET);
+ G.cur_zipfile_bufstart = zftello(G.zipfd);
+#else /* !USE_STRM_INPUT */
+ G.cur_zipfile_bufstart =
+ zlseek(G.zipfd, bufstart, SEEK_SET);
+#endif /* ?USE_STRM_INPUT */
+ if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0)
+ {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
+ *pfilnum, "lseek", (long)bufstart));
+ error_in_archive = PK_BADERR;
+ continue; /* can still do next file */
+ }
+ G.inptr = G.inbuf + (int)inbuf_offset;
+ G.incnt -= (int)inbuf_offset;
+ } else {
+ G.incnt += (int)(G.inptr-G.inbuf) - (int)inbuf_offset;
+ G.inptr = G.inbuf + (int)inbuf_offset;
+ }
+
+ /* should be in proper position now, so check for sig */
+ if (readbuf(__G__ G.sig, 4) == 0) { /* bad offset */
+ Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
+ *pfilnum, "EOF", (long)request));
+ error_in_archive = PK_BADERR;
+ continue; /* but can still try next one */
+ }
+ if (memcmp(G.sig, local_hdr_sig, 4)) {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
+ *pfilnum, LoadFarStringSmall(LocalHdrSig), (long)request));
+ /*
+ GRRDUMP(G.sig, 4)
+ GRRDUMP(local_hdr_sig, 4)
+ */
+ error_in_archive = PK_ERR;
+ if ((*pfilnum == 1 && G.extra_bytes != 0L) ||
+ (G.extra_bytes == 0L && *pold_extra_bytes != 0L)) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(AttemptRecompensate)));
+ if (G.extra_bytes) {
+ *pold_extra_bytes = G.extra_bytes;
+ G.extra_bytes = 0L;
+ } else
+ G.extra_bytes = *pold_extra_bytes; /* third attempt */
+ if (((error = seek_zipf(__G__ G.pInfo->offset)) != PK_OK) ||
+ (readbuf(__G__ G.sig, 4) == 0)) { /* bad offset */
+ if (error != PK_BADERR)
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(OffsetMsg), *pfilnum, "EOF",
+ (long)request));
+ error_in_archive = PK_BADERR;
+ continue; /* but can still try next one */
+ }
+ if (memcmp(G.sig, local_hdr_sig, 4)) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(OffsetMsg), *pfilnum,
+ LoadFarStringSmall(LocalHdrSig), (long)request));
+ error_in_archive = PK_BADERR;
+ continue;
+ }
+ } else
+ continue; /* this one hosed; try next */
+ }
+ if ((error = process_local_file_hdr(__G)) != PK_COOL) {
+ Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr),
+ *pfilnum));
+ error_in_archive = error; /* only PK_EOF defined */
+ continue; /* can still try next one */
+ }
+#if (!defined(SFX) && defined(UNICODE_SUPPORT))
+ if (((G.lrec.general_purpose_bit_flag & (1 << 11)) == (1 << 11))
+ != (G.pInfo->GPFIsUTF8 != 0)) {
+ if (QCOND2) {
+# ifdef SMALL_MEM
+ char *temp_cfilnam = slide + (7 * (WSIZE>>3));
+
+ zfstrcpy((char Far *)temp_cfilnam, G.pInfo->cfilname);
+# define cFile_PrintBuf temp_cfilnam
+# else
+# define cFile_PrintBuf G.pInfo->cfilname
+# endif
+ Info(slide, 0x421, ((char *)slide,
+ LoadFarStringSmall2(GP11FlagsDiffer),
+ *pfilnum, FnFilter1(cFile_PrintBuf), G.pInfo->GPFIsUTF8));
+# undef cFile_PrintBuf
+ }
+ if (error_in_archive < PK_WARN)
+ error_in_archive = PK_WARN;
+ }
+#endif /* !SFX && UNICODE_SUPPORT */
+ if ((error = do_string(__G__ G.lrec.filename_length, DS_FN_L)) !=
+ PK_COOL)
+ {
+ if (error > error_in_archive)
+ error_in_archive = error;
+ if (error > PK_WARN) {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg),
+ FnFilter1(G.filename), "local"));
+ continue; /* go on to next one */
+ }
+ }
+ if (G.extra_field != (uch *)NULL) {
+ free(G.extra_field);
+ G.extra_field = (uch *)NULL;
+ }
+ if ((error =
+ do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0)
+ {
+ if (error > error_in_archive)
+ error_in_archive = error;
+ if (error > PK_WARN) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(ExtFieldMsg),
+ FnFilter1(G.filename), "local"));
+ continue; /* go on */
+ }
+ }
+#ifndef SFX
+ /* Filename consistency checks must come after reading in the local
+ * extra field, so that a UTF-8 entry name e.f. block has already
+ * been processed.
+ */
+ if (G.pInfo->cfilname != (char Far *)NULL) {
+ if (zfstrcmp(G.pInfo->cfilname, G.filename) != 0) {
+# ifdef SMALL_MEM
+ char *temp_cfilnam = slide + (7 * (WSIZE>>3));
+
+ zfstrcpy((char Far *)temp_cfilnam, G.pInfo->cfilname);
+# define cFile_PrintBuf temp_cfilnam
+# else
+# define cFile_PrintBuf G.pInfo->cfilname
+# endif
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall2(LvsCFNamMsg),
+ FnFilter2(cFile_PrintBuf), FnFilter1(G.filename)));
+# undef cFile_PrintBuf
+ zfstrcpy(G.filename, G.pInfo->cfilname);
+ if (error_in_archive < PK_WARN)
+ error_in_archive = PK_WARN;
+ }
+ zffree(G.pInfo->cfilname);
+ G.pInfo->cfilname = (char Far *)NULL;
+ }
+#endif /* !SFX */
+ /* Size consistency checks must come after reading in the local extra
+ * field, so that any Zip64 extension local e.f. block has already
+ * been processed.
+ */
+ if (G.lrec.compression_method == STORED) {
+ zusz_t csiz_decrypted = G.lrec.csize;
+
+ if (G.pInfo->encrypted) {
+ if (csiz_decrypted < 12) {
+ /* handle the error now to prevent unsigned overflow */
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipNoFile),
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(Inflate)));
+ return PK_ERR;
+ }
+ csiz_decrypted -= 12;
+ }
+ if (G.lrec.ucsize != csiz_decrypted) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall2(WrnStorUCSizCSizDiff),
+ FnFilter1(G.filename),
+ FmZofft(G.lrec.ucsize, NULL, "u"),
+ FmZofft(csiz_decrypted, NULL, "u")));
+ G.lrec.ucsize = csiz_decrypted;
+ if (error_in_archive < PK_WARN)
+ error_in_archive = PK_WARN;
+ }
+ }
+
+#if CRYPT
+ if (G.pInfo->encrypted &&
+ (error = decrypt(__G__ uO.pwdarg)) != PK_COOL) {
+ if (error == PK_WARN) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(SkipIncorrectPasswd),
+ FnFilter1(G.filename)));
+ ++(*pnum_bad_pwd);
+ } else { /* (error > PK_WARN) */
+ if (error > error_in_archive)
+ error_in_archive = error;
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(SkipCannotGetPasswd),
+ FnFilter1(G.filename)));
+ }
+ continue; /* go on to next file */
+ }
+#endif /* CRYPT */
+
+ /*
+ * just about to extract file: if extracting to disk, check if
+ * already exists, and if so, take appropriate action according to
+ * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
+ * loop because we don't store the possibly renamed filename[] in
+ * info[])
+ */
+#ifdef DLL
+ if (!uO.tflag && !uO.cflag && !G.redirect_data)
+#else
+ if (!uO.tflag && !uO.cflag)
+#endif
+ {
+ renamed = FALSE; /* user hasn't renamed output file yet */
+
+startover:
+ query = FALSE;
+ skip_entry = SKIP_NO;
+ /* for files from DOS FAT, check for use of backslash instead
+ * of slash as directory separator (bug in some zipper(s); so
+ * far, not a problem in HPFS, NTFS or VFAT systems)
+ */
+#ifndef SFX
+ if (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/')) {
+ char *p=G.filename;
+
+ if (*p) do {
+ if (*p == '\\') {
+ if (!G.reported_backslash) {
+ Info(slide, 0x21, ((char *)slide,
+ LoadFarString(BackslashPathSep), G.zipfn));
+ G.reported_backslash = TRUE;
+ if (!error_in_archive)
+ error_in_archive = PK_WARN;
+ }
+ *p = '/';
+ }
+ } while (*PREINCSTR(p));
+ }
+#endif /* !SFX */
+
+ if (!renamed) {
+ /* remove absolute path specs */
+ if (G.filename[0] == '/') {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(AbsolutePathWarning),
+ FnFilter1(G.filename)));
+ if (!error_in_archive)
+ error_in_archive = PK_WARN;
+ do {
+ char *p = G.filename + 1;
+ do {
+ *(p-1) = *p;
+ } while (*p++ != '\0');
+ } while (G.filename[0] == '/');
+ }
+ }
+
+ /* mapname can create dirs if not freshening or if renamed */
+ error = mapname(__G__ renamed);
+ if ((errcode = error & ~MPN_MASK) != PK_OK &&
+ error_in_archive < errcode)
+ error_in_archive = errcode;
+ if ((errcode = error & MPN_MASK) > MPN_INF_TRUNC) {
+ if (errcode == MPN_CREATED_DIR) {
+#ifdef SET_DIR_ATTRIB
+ direntry *d_entry;
+
+ error = defer_dir_attribs(__G__ &d_entry);
+ if (d_entry == (direntry *)NULL) {
+ /* There may be no dir_attribs info available, or
+ * we have encountered a mem allocation error.
+ * In case of an error, report it and set program
+ * error state to warning level.
+ */
+ if (error) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(DirlistEntryNoMem)));
+ if (!error_in_archive)
+ error_in_archive = PK_WARN;
+ }
+ } else {
+ d_entry->next = (*pdirlist);
+ (*pdirlist) = d_entry;
+ ++(*pnum_dirs);
+ }
+#endif /* SET_DIR_ATTRIB */
+ } else if (errcode == MPN_VOL_LABEL) {
+#ifdef DOS_OS2_W32
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(SkipVolumeLabel),
+ FnFilter1(G.filename),
+ uO.volflag? "hard disk " : ""));
+#else
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(SkipVolumeLabel),
+ FnFilter1(G.filename), ""));
+#endif
+ } else if (errcode > MPN_INF_SKIP &&
+ error_in_archive < PK_ERR)
+ error_in_archive = PK_ERR;
+ Trace((stderr, "mapname(%s) returns error code = %d\n",
+ FnFilter1(G.filename), error));
+ continue; /* go on to next file */
+ }
+
+#ifdef QDOS
+ QFilename(__G__ G.filename);
+#endif
+ switch (check_for_newer(__G__ G.filename)) {
+ case DOES_NOT_EXIST:
+#ifdef NOVELL_BUG_FAILSAFE
+ G.dne = TRUE; /* stat() says file DOES NOT EXIST */
+#endif
+ /* freshen (no new files): skip unless just renamed */
+ if (uO.fflag && !renamed)
+ skip_entry = SKIP_Y_NONEXIST;
+ break;
+ case EXISTS_AND_OLDER:
+#ifdef UNIXBACKUP
+ if (!uO.B_flag)
+#endif
+ {
+ if (IS_OVERWRT_NONE)
+ /* never overwrite: skip file */
+ skip_entry = SKIP_Y_EXISTING;
+ else if (!IS_OVERWRT_ALL)
+ query = TRUE;
+ }
+ break;
+ case EXISTS_AND_NEWER: /* (or equal) */
+#ifdef UNIXBACKUP
+ if ((!uO.B_flag && IS_OVERWRT_NONE) ||
+#else
+ if (IS_OVERWRT_NONE ||
+#endif
+ (uO.uflag && !renamed)) {
+ /* skip if update/freshen & orig name */
+ skip_entry = SKIP_Y_EXISTING;
+ } else {
+#ifdef UNIXBACKUP
+ if (!IS_OVERWRT_ALL && !uO.B_flag)
+#else
+ if (!IS_OVERWRT_ALL)
+#endif
+ query = TRUE;
+ }
+ break;
+ }
+#ifdef VMS
+ /* 2008-07-24 SMS.
+ * On VMS, if the file name includes a version number,
+ * and "-V" ("retain VMS version numbers", V_flag) is in
+ * effect, then the VMS-specific code will handle any
+ * conflicts with an existing file, making this query
+ * redundant. (Implicit "y" response here.)
+ */
+ if (query && uO.V_flag) {
+ /* Not discarding file versions. Look for one. */
+ int cndx = strlen(G.filename) - 1;
+
+ while ((cndx > 0) && (isdigit(G.filename[cndx])))
+ cndx--;
+ if (G.filename[cndx] == ';')
+ /* File version found; skip the generic query,
+ * proceeding with its default response "y".
+ */
+ query = FALSE;
+ }
+#endif /* VMS */
+ if (query) {
+#ifdef WINDLL
+ switch (G.lpUserFunctions->replace != NULL ?
+ (*G.lpUserFunctions->replace)(G.filename, FILNAMSIZ) :
+ IDM_REPLACE_NONE) {
+ case IDM_REPLACE_RENAME:
+ _ISO_INTERN(G.filename);
+ renamed = TRUE;
+ goto startover;
+ case IDM_REPLACE_ALL:
+ G.overwrite_mode = OVERWRT_ALWAYS;
+ /* FALL THROUGH, extract */
+ case IDM_REPLACE_YES:
+ break;
+ case IDM_REPLACE_NONE:
+ G.overwrite_mode = OVERWRT_NEVER;
+ /* FALL THROUGH, skip */
+ case IDM_REPLACE_NO:
+ skip_entry = SKIP_Y_EXISTING;
+ break;
+ }
+#else /* !WINDLL */
+ extent fnlen;
+reprompt:
+ Info(slide, 0x81, ((char *)slide,
+ LoadFarString(ReplaceQuery),
+ FnFilter1(G.filename)));
+ if (fgets(G.answerbuf, sizeof(G.answerbuf), stdin)
+ == (char *)NULL) {
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(AssumeNone)));
+ *G.answerbuf = 'N';
+ if (!error_in_archive)
+ error_in_archive = 1; /* not extracted: warning */
+ }
+ switch (*G.answerbuf) {
+ case 'r':
+ case 'R':
+ do {
+ Info(slide, 0x81, ((char *)slide,
+ LoadFarString(NewNameQuery)));
+ fgets(G.filename, FILNAMSIZ, stdin);
+ /* usually get \n here: better check for it */
+ fnlen = strlen(G.filename);
+ if (lastchar(G.filename, fnlen) == '\n')
+ G.filename[--fnlen] = '\0';
+ } while (fnlen == 0);
+#ifdef WIN32 /* WIN32 fgets( ... , stdin) returns OEM coded strings */
+ _OEM_INTERN(G.filename);
+#endif
+ renamed = TRUE;
+ goto startover; /* sorry for a goto */
+ case 'A': /* dangerous option: force caps */
+ G.overwrite_mode = OVERWRT_ALWAYS;
+ /* FALL THROUGH, extract */
+ case 'y':
+ case 'Y':
+ break;
+ case 'N':
+ G.overwrite_mode = OVERWRT_NEVER;
+ /* FALL THROUGH, skip */
+ case 'n':
+ /* skip file */
+ skip_entry = SKIP_Y_EXISTING;
+ break;
+ case '\n':
+ case '\r':
+ /* Improve echo of '\n' and/or '\r'
+ (sizeof(G.answerbuf) == 10 (see globals.h), so
+ there is enough space for the provided text...) */
+ strcpy(G.answerbuf, "{ENTER}");
+ /* fall through ... */
+ default:
+ /* usually get \n here: remove it for nice display
+ (fnlen can be re-used here, we are outside the
+ "enter new filename" loop) */
+ fnlen = strlen(G.answerbuf);
+ if (lastchar(G.answerbuf, fnlen) == '\n')
+ G.answerbuf[--fnlen] = '\0';
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(InvalidResponse), G.answerbuf));
+ goto reprompt; /* yet another goto? */
+ } /* end switch (*answerbuf) */
+#endif /* ?WINDLL */
+ } /* end if (query) */
+ if (skip_entry != SKIP_NO) {
+#ifdef WINDLL
+ if (skip_entry == SKIP_Y_EXISTING) {
+ /* report skipping of an existing entry */
+ Info(slide, 0, ((char *)slide,
+ ((IS_OVERWRT_NONE || !uO.uflag || renamed) ?
+ "Target file exists. Skipping %s\n" :
+ "Target file newer. Skipping %s\n"),
+ FnFilter1(G.filename)));
+ }
+#endif /* WINDLL */
+ continue;
+ }
+ } /* end if (extracting to disk) */
+
+#ifdef DLL
+ if ((G.statreportcb != NULL) &&
+ (*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn,
+ G.filename, NULL)) {
+ return IZ_CTRLC; /* cancel operation by user request */
+ }
+#endif
+#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
+ UserStop();
+#endif
+#ifdef AMIGA
+ G.filenote_slot = i;
+#endif
+ G.disk_full = 0;
+ if ((error = extract_or_test_member(__G)) != PK_COOL) {
+ if (error > error_in_archive)
+ error_in_archive = error; /* ...and keep going */
+#ifdef DLL
+ if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
+#else
+ if (G.disk_full > 1) {
+#endif
+ return error_in_archive; /* (unless disk full) */
+ }
+ }
+#ifdef DLL
+ if ((G.statreportcb != NULL) &&
+ (*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn,
+ G.filename, (zvoid *)&G.lrec.ucsize)) {
+ return IZ_CTRLC; /* cancel operation by user request */
+ }
+#endif
+#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
+ UserStop();
+#endif
+ } /* end for-loop (i: files in current block) */
+
+ return error_in_archive;
+
+} /* end function extract_or_test_entrylist() */
+
+
+
+
+
+/* wsize is used in extract_or_test_member() and UZbunzip2() */
+#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
+# define wsize G._wsize /* wsize is a variable */
+#else
+# define wsize WSIZE /* wsize is a constant */
+#endif
+
+/***************************************/
+/* Function extract_or_test_member() */
+/***************************************/
+
+static int extract_or_test_member(__G) /* return PK-type error code */
+ __GDEF
+{
+ char *nul="[empty] ", *txt="[text] ", *bin="[binary]";
+#ifdef CMS_MVS
+ char *ebc="[ebcdic]";
+#endif
+ register int b;
+ int r, error=PK_COOL;
+
+
+/*---------------------------------------------------------------------------
+ Initialize variables, buffers, etc.
+ ---------------------------------------------------------------------------*/
+
+ G.bits_left = 0;
+ G.bitbuf = 0L; /* unreduce and unshrink only */
+ G.zipeof = 0;
+ G.newfile = TRUE;
+ G.crc32val = CRCVAL_INITIAL;
+
+#ifdef SYMLINKS
+ /* If file is a (POSIX-compatible) symbolic link and we are extracting
+ * to disk, prepare to restore the link. */
+ G.symlnk = (G.pInfo->symlink &&
+ !uO.tflag && !uO.cflag && (G.lrec.ucsize > 0));
+#endif /* SYMLINKS */
+
+ if (uO.tflag) {
+ if (!uO.qflag)
+ Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), "test",
+ FnFilter1(G.filename), "", ""));
+ } else {
+#ifdef DLL
+ if (uO.cflag && !G.redirect_data)
+#else
+ if (uO.cflag)
+#endif
+ {
+#if (defined(OS2) && defined(__IBMC__) && (__IBMC__ >= 200))
+ G.outfile = freopen("", "wb", stdout); /* VAC++ ignores setmode */
+#else
+ G.outfile = stdout;
+#endif
+#ifdef DOS_FLX_NLM_OS2_W32
+#if (defined(__HIGHC__) && !defined(FLEXOS))
+ setmode(G.outfile, _BINARY);
+#else /* !(defined(__HIGHC__) && !defined(FLEXOS)) */
+ setmode(fileno(G.outfile), O_BINARY);
+#endif /* ?(defined(__HIGHC__) && !defined(FLEXOS)) */
+# define NEWLINE "\r\n"
+#else /* !DOS_FLX_NLM_OS2_W32 */
+# define NEWLINE "\n"
+#endif /* ?DOS_FLX_NLM_OS2_W32 */
+#ifdef VMS
+ /* VMS: required even for stdout! */
+ if ((r = open_outfile(__G)) != 0)
+ switch (r) {
+ case OPENOUT_SKIPOK:
+ return PK_OK;
+ case OPENOUT_SKIPWARN:
+ return PK_WARN;
+ default:
+ return PK_DISK;
+ }
+ } else if ((r = open_outfile(__G)) != 0)
+ switch (r) {
+ case OPENOUT_SKIPOK:
+ return PK_OK;
+ case OPENOUT_SKIPWARN:
+ return PK_WARN;
+ default:
+ return PK_DISK;
+ }
+#else /* !VMS */
+ } else if (open_outfile(__G))
+ return PK_DISK;
+#endif /* ?VMS */
+ }
+
+/*---------------------------------------------------------------------------
+ Unpack the file.
+ ---------------------------------------------------------------------------*/
+
+ defer_leftover_input(__G); /* so NEXTBYTE bounds check will work */
+ switch (G.lrec.compression_method) {
+ case STORED:
+ if (!uO.tflag && QCOND2) {
+#ifdef SYMLINKS
+ if (G.symlnk) /* can also be deflated, but rarer... */
+ Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
+ "link", FnFilter1(G.filename), "", ""));
+ else
+#endif /* SYMLINKS */
+ Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
+ "extract", FnFilter1(G.filename),
+ (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
+ "" : (G.lrec.ucsize == 0L? nul : (G.pInfo->textfile? txt :
+ bin)), uO.cflag? NEWLINE : ""));
+ }
+#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
+ if (G.redirect_slide) {
+ wsize = G.redirect_size; redirSlide = G.redirect_buffer;
+ } else {
+ wsize = WSIZE; redirSlide = slide;
+ }
+#endif
+ G.outptr = redirSlide;
+ G.outcnt = 0L;
+ while ((b = NEXTBYTE) != EOF) {
+ *G.outptr++ = (uch)b;
+ if (++G.outcnt == wsize) {
+ error = flush(__G__ redirSlide, G.outcnt, 0);
+ G.outptr = redirSlide;
+ G.outcnt = 0L;
+ if (error != PK_COOL || G.disk_full) break;
+ }
+ }
+ if (G.outcnt) { /* flush final (partial) buffer */
+ r = flush(__G__ redirSlide, G.outcnt, 0);
+ if (error < r) error = r;
+ }
+ break;
+
+#ifndef SFX
+#ifndef LZW_CLEAN
+ case SHRUNK:
+ if (!uO.tflag && QCOND2) {
+ Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
+ LoadFarStringSmall(Unshrink), FnFilter1(G.filename),
+ (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
+ "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
+ }
+ if ((r = unshrink(__G)) != PK_COOL) {
+ if (r < PK_DISK) {
+ if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipFile), r == PK_MEM3 ?
+ LoadFarString(NotEnoughMem) :
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(Unshrink),
+ FnFilter1(G.filename)));
+ else
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipNoFile), r == PK_MEM3 ?
+ LoadFarString(NotEnoughMem) :
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(Unshrink)));
+ }
+ error = r;
+ }
+ break;
+#endif /* !LZW_CLEAN */
+
+#ifndef COPYRIGHT_CLEAN
+ case REDUCED1:
+ case REDUCED2:
+ case REDUCED3:
+ case REDUCED4:
+ if (!uO.tflag && QCOND2) {
+ Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
+ "unreduc", FnFilter1(G.filename),
+ (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
+ "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
+ }
+ if ((r = unreduce(__G)) != PK_COOL) {
+ /* unreduce() returns only PK_COOL, PK_DISK, or IZ_CTRLC */
+ error = r;
+ }
+ break;
+#endif /* !COPYRIGHT_CLEAN */
+
+ case IMPLODED:
+ if (!uO.tflag && QCOND2) {
+ Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
+ "explod", FnFilter1(G.filename),
+ (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
+ "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
+ }
+ if ((r = explode(__G)) != 0) {
+ if (r == 5) { /* treat 5 specially */
+ int warning = ((zusz_t)G.used_csize <= G.lrec.csize);
+
+ if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(LengthMsg),
+ "", warning ? "warning" : "error",
+ FmZofft(G.used_csize, NULL, NULL),
+ FmZofft(G.lrec.ucsize, NULL, "u"),
+ warning ? " " : "",
+ FmZofft(G.lrec.csize, NULL, "u"),
+ " [", FnFilter1(G.filename), "]"));
+ else
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(LengthMsg),
+ "\n", warning ? "warning" : "error",
+ FmZofft(G.used_csize, NULL, NULL),
+ FmZofft(G.lrec.ucsize, NULL, "u"),
+ warning ? " " : "",
+ FmZofft(G.lrec.csize, NULL, "u"),
+ "", "", "."));
+ error = warning ? PK_WARN : PK_ERR;
+ } else if (r < PK_DISK) {
+ if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipFile), r == 3?
+ LoadFarString(NotEnoughMem) :
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(Explode),
+ FnFilter1(G.filename)));
+ else
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipNoFile), r == 3?
+ LoadFarString(NotEnoughMem) :
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(Explode)));
+ error = ((r == 3) ? PK_MEM3 : PK_ERR);
+ } else {
+ error = r;
+ }
+ }
+ break;
+#endif /* !SFX */
+
+ case DEFLATED:
+#ifdef USE_DEFLATE64
+ case ENHDEFLATED:
+#endif
+ if (!uO.tflag && QCOND2) {
+ Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
+ "inflat", FnFilter1(G.filename),
+ (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
+ "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
+ }
+#ifndef USE_ZLIB /* zlib's function is called inflate(), too */
+# define UZinflate inflate
+#endif
+ if ((r = UZinflate(__G__
+ (G.lrec.compression_method == ENHDEFLATED)))
+ != 0) {
+ if (r < PK_DISK) {
+ if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipFile), r == 3?
+ LoadFarString(NotEnoughMem) :
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(Inflate),
+ FnFilter1(G.filename)));
+ else
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipNoFile), r == 3?
+ LoadFarString(NotEnoughMem) :
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(Inflate)));
+ error = ((r == 3) ? PK_MEM3 : PK_ERR);
+ } else {
+ error = r;
+ }
+ }
+ break;
+
+#ifdef USE_BZIP2
+ case BZIPPED:
+ if (!uO.tflag && QCOND2) {
+ Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
+ "bunzipp", FnFilter1(G.filename),
+ (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
+ "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
+ }
+ if ((r = UZbunzip2(__G)) != 0) {
+ if (r < PK_DISK) {
+ if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipFile), r == 3?
+ LoadFarString(NotEnoughMem) :
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(BUnzip),
+ FnFilter1(G.filename)));
+ else
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipNoFile), r == 3?
+ LoadFarString(NotEnoughMem) :
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(BUnzip)));
+ error = ((r == 3) ? PK_MEM3 : PK_ERR);
+ } else {
+ error = r;
+ }
+ }
+ break;
+#endif /* USE_BZIP2 */
+
+ default: /* should never get to this point */
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(FileUnknownCompMethod), FnFilter1(G.filename)));
+ /* close and delete file before return? */
+ undefer_input(__G);
+ return PK_WARN;
+
+ } /* end switch (compression method) */
+
+/*---------------------------------------------------------------------------
+ Close the file and set its date and time (not necessarily in that order),
+ and make sure the CRC checked out OK. Logical-AND the CRC for 64-bit
+ machines (redundant on 32-bit machines).
+ ---------------------------------------------------------------------------*/
+
+#ifdef VMS /* VMS: required even for stdout! (final flush) */
+ if (!uO.tflag) /* don't close NULL file */
+ error = close_outfile(__G);
+#else
+#ifdef DLL
+ if (!uO.tflag && (!uO.cflag || G.redirect_data)) {
+ if (G.redirect_data)
+ FINISH_REDIRECT();
+ else
+ error = close_outfile(__G);
+ }
+#else
+ if (!uO.tflag && !uO.cflag) /* don't close NULL file or stdout */
+ error = close_outfile(__G);
+#endif
+#endif /* VMS */
+
+ if (G.disk_full) { /* set by flush() */
+ if (G.disk_full > 1) {
+#if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK))
+ /* delete the incomplete file if we can */
+ if (unlink(G.filename) != 0)
+ Trace((stderr, "extract.c: could not delete %s\n",
+ FnFilter1(G.filename)));
+#else
+ /* warn user about the incomplete file */
+ Info(slide, 0x421, ((char *)slide, LoadFarString(FileTruncated),
+ FnFilter1(G.filename)));
+#endif
+ error = PK_DISK;
+ } else {
+ error = PK_WARN;
+ }
+ }
+
+ if (error > PK_WARN) {/* don't print redundant CRC error if error already */
+ undefer_input(__G);
+ return error;
+ }
+ if (G.crc32val != G.lrec.crc32) {
+ /* if quiet enough, we haven't output the filename yet: do it */
+ if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
+ Info(slide, 0x401, ((char *)slide, "%-22s ",
+ FnFilter1(G.filename)));
+ Info(slide, 0x401, ((char *)slide, LoadFarString(BadCRC), G.crc32val,
+ G.lrec.crc32));
+#if CRYPT
+ if (G.pInfo->encrypted)
+ Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeBadPasswd)));
+#endif
+ error = PK_ERR;
+ } else if (uO.tflag) {
+#ifndef SFX
+ if (G.extra_field) {
+ if ((r = TestExtraField(__G__ G.extra_field,
+ G.lrec.extra_field_length)) > error)
+ error = r;
+ } else
+#endif /* !SFX */
+ if (!uO.qflag)
+ Info(slide, 0, ((char *)slide, " OK\n"));
+ } else {
+ if (QCOND2 && !error) /* GRR: is stdout reset to text mode yet? */
+ Info(slide, 0, ((char *)slide, "\n"));
+ }
+
+ undefer_input(__G);
+ return error;
+
+} /* end function extract_or_test_member() */
+
+
+
+
+
+#ifndef SFX
+
+/*******************************/
+/* Function TestExtraField() */
+/*******************************/
+
+static int TestExtraField(__G__ ef, ef_len)
+ __GDEF
+ uch *ef;
+ unsigned ef_len;
+{
+ ush ebID;
+ unsigned ebLen;
+ unsigned eb_cmpr_offs = 0;
+ int r;
+
+ /* we know the regular compressed file data tested out OK, or else we
+ * wouldn't be here ==> print filename if any extra-field errors found
+ */
+ while (ef_len >= EB_HEADSIZE) {
+ ebID = makeword(ef);
+ ebLen = (unsigned)makeword(ef+EB_LEN);
+
+ if (ebLen > (ef_len - EB_HEADSIZE))
+ {
+ /* Discovered some extra field inconsistency! */
+ if (uO.qflag)
+ Info(slide, 1, ((char *)slide, "%-22s ",
+ FnFilter1(G.filename)));
+ Info(slide, 1, ((char *)slide, LoadFarString(InconsistEFlength),
+ ebLen, (ef_len - EB_HEADSIZE)));
+ return PK_ERR;
+ }
+
+ switch (ebID) {
+ case EF_OS2:
+ case EF_ACL:
+ case EF_MAC3:
+ case EF_BEOS:
+ case EF_ATHEOS:
+ switch (ebID) {
+ case EF_OS2:
+ case EF_ACL:
+ eb_cmpr_offs = EB_OS2_HLEN;
+ break;
+ case EF_MAC3:
+ if (ebLen >= EB_MAC3_HLEN &&
+ (makeword(ef+(EB_HEADSIZE+EB_FLGS_OFFS))
+ & EB_M3_FL_UNCMPR) &&
+ (makelong(ef+EB_HEADSIZE) == ebLen - EB_MAC3_HLEN))
+ eb_cmpr_offs = 0;
+ else
+ eb_cmpr_offs = EB_MAC3_HLEN;
+ break;
+ case EF_BEOS:
+ case EF_ATHEOS:
+ if (ebLen >= EB_BEOS_HLEN &&
+ (*(ef+(EB_HEADSIZE+EB_FLGS_OFFS)) & EB_BE_FL_UNCMPR) &&
+ (makelong(ef+EB_HEADSIZE) == ebLen - EB_BEOS_HLEN))
+ eb_cmpr_offs = 0;
+ else
+ eb_cmpr_offs = EB_BEOS_HLEN;
+ break;
+ }
+ if ((r = test_compr_eb(__G__ ef, ebLen, eb_cmpr_offs, NULL))
+ != PK_OK) {
+ if (uO.qflag)
+ Info(slide, 1, ((char *)slide, "%-22s ",
+ FnFilter1(G.filename)));
+ switch (r) {
+ case IZ_EF_TRUNC:
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(TruncEAs),
+ ebLen-(eb_cmpr_offs+EB_CMPRHEADLEN), "\n"));
+ break;
+ case PK_ERR:
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(InvalidComprDataEAs)));
+ break;
+ case PK_MEM3:
+ case PK_MEM4:
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(NotEnoughMemEAs)));
+ break;
+ default:
+ if ((r & 0xff) != PK_ERR)
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(UnknErrorEAs)));
+ else {
+ ush m = (ush)(r >> 8);
+ if (m == DEFLATED) /* GRR KLUDGE! */
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(BadCRC_EAs)));
+ else
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(UnknComprMethodEAs), m));
+ }
+ break;
+ }
+ return r;
+ }
+ break;
+
+ case EF_NTSD:
+ Trace((stderr, "ebID: %i / ebLen: %u\n", ebID, ebLen));
+ r = ebLen < EB_NTSD_L_LEN ? IZ_EF_TRUNC :
+ ((ef[EB_HEADSIZE+EB_NTSD_VERSION] > EB_NTSD_MAX_VER) ?
+ (PK_WARN | 0x4000) :
+ test_compr_eb(__G__ ef, ebLen, EB_NTSD_L_LEN, TEST_NTSD));
+ if (r != PK_OK) {
+ if (uO.qflag)
+ Info(slide, 1, ((char *)slide, "%-22s ",
+ FnFilter1(G.filename)));
+ switch (r) {
+ case IZ_EF_TRUNC:
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(TruncNTSD),
+ ebLen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n"));
+ break;
+#if (defined(WIN32) && defined(NTSD_EAS))
+ case PK_WARN:
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(InvalidSecurityEAs)));
+ break;
+#endif
+ case PK_ERR:
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(InvalidComprDataEAs)));
+ break;
+ case PK_MEM3:
+ case PK_MEM4:
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(NotEnoughMemEAs)));
+ break;
+ case (PK_WARN | 0x4000):
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(UnsuppNTSDVersEAs),
+ (int)ef[EB_HEADSIZE+EB_NTSD_VERSION]));
+ r = PK_WARN;
+ break;
+ default:
+ if ((r & 0xff) != PK_ERR)
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(UnknErrorEAs)));
+ else {
+ ush m = (ush)(r >> 8);
+ if (m == DEFLATED) /* GRR KLUDGE! */
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(BadCRC_EAs)));
+ else
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(UnknComprMethodEAs), m));
+ }
+ break;
+ }
+ return r;
+ }
+ break;
+ case EF_PKVMS:
+ /* 2015-01-30 SMS. Added sufficient-bytes test/message
+ * here. (Removed defective ebLen test above.)
+ *
+ * If sufficient bytes (EB_PKVMS_MINLEN) are available,
+ * then compare the stored CRC value with the calculated
+ * CRC for the remainder of the data (and complain about
+ * a mismatch).
+ */
+ if (ebLen < EB_PKVMS_MINLEN)
+ {
+ /* Insufficient bytes available. */
+ Info( slide, 1,
+ ((char *)slide, LoadFarString( TooSmallEBlength),
+ ebLen, EB_PKVMS_MINLEN));
+ }
+ else if (makelong(ef+ EB_HEADSIZE) !=
+ crc32(CRCVAL_INITIAL,
+ (ef+ EB_HEADSIZE+ EB_PKVMS_MINLEN),
+ (extent)(ebLen- EB_PKVMS_MINLEN)))
+ {
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(BadCRC_EAs)));
+ }
+ break;
+ case EF_PKW32:
+ case EF_PKUNIX:
+ case EF_ASIUNIX:
+ case EF_IZVMS:
+ case EF_IZUNIX:
+ case EF_VMCMS:
+ case EF_MVS:
+ case EF_SPARK:
+ case EF_TANDEM:
+ case EF_THEOS:
+ case EF_AV:
+ default:
+ break;
+ }
+ ef_len -= (ebLen + EB_HEADSIZE);
+ ef += (ebLen + EB_HEADSIZE);
+ }
+
+ if (!uO.qflag)
+ Info(slide, 0, ((char *)slide, " OK\n"));
+
+ return PK_COOL;
+
+} /* end function TestExtraField() */
+
+
+
+
+
+/******************************/
+/* Function test_compr_eb() */
+/******************************/
+
+#ifdef PROTO
+static int test_compr_eb(
+ __GPRO__
+ uch *eb,
+ unsigned eb_size,
+ unsigned compr_offset,
+ int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size,
+ uch *eb_ucptr, ulg eb_ucsize))
+#else /* !PROTO */
+static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
+ __GDEF
+ uch *eb;
+ unsigned eb_size;
+ unsigned compr_offset;
+ int (*test_uc_ebdata)();
+#endif /* ?PROTO */
+{
+ ulg eb_ucsize;
+ uch *eb_ucptr;
+ int r;
+ ush method;
+
+ if (compr_offset < 4) /* field is not compressed: */
+ return PK_OK; /* do nothing and signal OK */
+
+ /* Return no/bad-data error status if any problem is found:
+ * 1. eb_size is too small to hold the uncompressed size
+ * (eb_ucsize). (Else extract eb_ucsize.)
+ * 2. eb_ucsize is zero (invalid). 2014-12-04 SMS.
+ * 3. eb_ucsize is positive, but eb_size is too small to hold
+ * the compressed data header.
+ */
+ if ((eb_size < (EB_UCSIZE_P + 4)) ||
+ ((eb_ucsize = makelong( eb+ (EB_HEADSIZE+ EB_UCSIZE_P))) == 0L) ||
+ ((eb_ucsize > 0L) && (eb_size <= (compr_offset + EB_CMPRHEADLEN))))
+ return IZ_EF_TRUNC; /* no/bad compressed data! */
+
+ method = makeword(eb + (EB_HEADSIZE + compr_offset));
+ if ((method == STORED) && (eb_size != compr_offset + EB_CMPRHEADLEN + eb_ucsize))
+ return PK_ERR; /* compressed & uncompressed
+ * should match in STORED
+ * method */
+
+ if (
+#ifdef INT_16BIT
+ (((ulg)(extent)eb_ucsize) != eb_ucsize) ||
+#endif
+ (eb_ucptr = (uch *)malloc((extent)eb_ucsize)) == (uch *)NULL)
+ return PK_MEM4;
+
+ r = memextract(__G__ eb_ucptr, eb_ucsize,
+ eb + (EB_HEADSIZE + compr_offset),
+ (ulg)(eb_size - compr_offset));
+
+ if (r == PK_OK && test_uc_ebdata != NULL)
+ r = (*test_uc_ebdata)(__G__ eb, eb_size, eb_ucptr, eb_ucsize);
+
+ free(eb_ucptr);
+ return r;
+
+} /* end function test_compr_eb() */
+
+#endif /* !SFX */
+
+
+
+
+
+/***************************/
+/* Function memextract() */
+/***************************/
+
+int memextract(__G__ tgt, tgtsize, src, srcsize) /* extract compressed */
+ __GDEF /* extra field block; */
+ uch *tgt; /* return PK-type error */
+ ulg tgtsize; /* level */
+ ZCONST uch *src;
+ ulg srcsize;
+{
+ zoff_t old_csize=G.csize;
+ uch *old_inptr=G.inptr;
+ int old_incnt=G.incnt;
+ int r, error=PK_OK;
+ ush method;
+ ulg extra_field_crc;
+
+
+ method = makeword(src);
+ extra_field_crc = makelong(src+2);
+
+ /* compressed extra field exists completely in memory at this location: */
+ G.inptr = (uch *)src + (2 + 4); /* method and extra_field_crc */
+ G.incnt = (int)(G.csize = (long)(srcsize - (2 + 4)));
+ G.mem_mode = TRUE;
+ G.outbufptr = tgt;
+ G.outsize = tgtsize;
+
+ switch (method) {
+ case STORED:
+ memcpy((char *)tgt, (char *)G.inptr, (extent)G.incnt);
+ G.outcnt = (ulg)G.csize; /* for CRC calculation */
+ break;
+ case DEFLATED:
+#ifdef USE_DEFLATE64
+ case ENHDEFLATED:
+#endif
+ G.outcnt = 0L;
+ if ((r = UZinflate(__G__ (method == ENHDEFLATED))) != 0) {
+ if (!uO.tflag)
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(ErrUnzipNoFile), r == 3?
+ LoadFarString(NotEnoughMem) :
+ LoadFarString(InvalidComprData),
+ LoadFarStringSmall2(Inflate)));
+ error = (r == 3)? PK_MEM3 : PK_ERR;
+ }
+ if (G.outcnt == 0L) /* inflate's final FLUSH sets outcnt */
+ break;
+ break;
+ default:
+ if (uO.tflag)
+ error = PK_ERR | ((int)method << 8);
+ else {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(UnsupportedExtraField), method));
+ error = PK_ERR; /* GRR: should be passed on up via SetEAs() */
+ }
+ break;
+ }
+
+ G.inptr = old_inptr;
+ G.incnt = old_incnt;
+ G.csize = old_csize;
+ G.mem_mode = FALSE;
+
+ if (!error) {
+ register ulg crcval = crc32(CRCVAL_INITIAL, tgt, (extent)G.outcnt);
+
+ if (crcval != extra_field_crc) {
+ if (uO.tflag)
+ error = PK_ERR | (DEFLATED << 8); /* kludge for now */
+ else {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(BadExtraFieldCRC), G.zipfn, crcval,
+ extra_field_crc));
+ error = PK_ERR;
+ }
+ }
+ }
+ return error;
+
+} /* end function memextract() */
+
+
+
+
+
+/*************************/
+/* Function memflush() */
+/*************************/
+
+int memflush(__G__ rawbuf, size)
+ __GDEF
+ ZCONST uch *rawbuf;
+ ulg size;
+{
+ if (size > G.outsize)
+ /* Here, PK_DISK is a bit off-topic, but in the sense of marking
+ "overflow of output space", its use may be tolerated. */
+ return PK_DISK; /* more data than output buffer can hold */
+
+
+
+ memcpy((char *)G.outbufptr, (char *)rawbuf, (extent)size);
+ G.outbufptr += (unsigned int)size;
+ G.outsize -= size;
+ G.outcnt += size;
+
+ return 0;
+
+} /* end function memflush() */
+
+
+
+
+
+#if (defined(VMS) || defined(VMS_TEXT_CONV))
+
+/************************************/
+/* Function extract_izvms_block() */
+/************************************/
+
+/*
+ * Extracts block from p. If resulting length is less than needed, fill
+ * extra space with corresponding bytes from 'init'.
+ * Currently understands 3 formats of block compression:
+ * - Simple storing
+ * - Compression of zero bytes to zero bits
+ * - Deflation (see memextract())
+ * The IZVMS block data is returned in malloc'd space.
+ */
+uch *extract_izvms_block(__G__ ebdata, size, retlen, init, needlen)
+ __GDEF
+ ZCONST uch *ebdata;
+ unsigned size;
+ unsigned *retlen;
+ ZCONST uch *init;
+ unsigned needlen;
+{
+ uch *ucdata; /* Pointer to block allocated */
+ int cmptype;
+ unsigned usiz, csiz;
+
+ cmptype = (makeword(ebdata+EB_IZVMS_FLGS) & EB_IZVMS_BCMASK);
+ csiz = size - EB_IZVMS_HLEN;
+ usiz = (cmptype == EB_IZVMS_BCSTOR ?
+ csiz : makeword(ebdata+EB_IZVMS_UCSIZ));
+
+ if (retlen)
+ *retlen = usiz;
+
+ if ((ucdata = (uch *)malloc(MAX(needlen, usiz))) == NULL)
+ return NULL;
+
+ if (init && (usiz < needlen))
+ memcpy((char *)ucdata, (ZCONST char *)init, needlen);
+
+ switch (cmptype)
+ {
+ case EB_IZVMS_BCSTOR: /* The simplest case */
+ memcpy(ucdata, ebdata+EB_IZVMS_HLEN, usiz);
+ break;
+ case EB_IZVMS_BC00:
+ decompress_bits(ucdata, usiz, ebdata+EB_IZVMS_HLEN);
+ break;
+ case EB_IZVMS_BCDEFL:
+ memextract(__G__ ucdata, (ulg)usiz,
+ ebdata+EB_IZVMS_HLEN, (ulg)csiz);
+ break;
+ default:
+ free(ucdata);
+ ucdata = NULL;
+ }
+ return ucdata;
+
+} /* end of extract_izvms_block */
+
+
+
+
+
+/********************************/
+/* Function decompress_bits() */
+/********************************/
+/*
+ * Simple uncompression routine. The compression uses bit stream.
+ * Compression scheme:
+ *
+ * if (byte!=0)
+ * putbit(1),putbyte(byte)
+ * else
+ * putbit(0)
+ */
+static void decompress_bits(outptr, needlen, bitptr)
+ uch *outptr; /* Pointer into output block */
+ unsigned needlen; /* Size of uncompressed block */
+ ZCONST uch *bitptr; /* Pointer into compressed data */
+{
+ ulg bitbuf = 0;
+ int bitcnt = 0;
+
+#define _FILL { bitbuf |= (*bitptr++) << bitcnt;\
+ bitcnt += 8; \
+ }
+
+ while (needlen--)
+ {
+ if (bitcnt <= 0)
+ _FILL;
+
+ if (bitbuf & 1)
+ {
+ bitbuf >>= 1;
+ if ((bitcnt -= 1) < 8)
+ _FILL;
+ *outptr++ = (uch)bitbuf;
+ bitcnt -= 8;
+ bitbuf >>= 8;
+ }
+ else
+ {
+ *outptr++ = '\0';
+ bitcnt -= 1;
+ bitbuf >>= 1;
+ }
+ }
+} /* end function decompress_bits() */
+
+#endif /* VMS || VMS_TEXT_CONV */
+
+
+
+
+
+#ifdef SYMLINKS
+/***********************************/
+/* Function set_deferred_symlink() */
+/***********************************/
+
+static void set_deferred_symlink(__G__ slnk_entry)
+ __GDEF
+ slinkentry *slnk_entry;
+{
+ extent ucsize = slnk_entry->targetlen;
+ char *linkfname = slnk_entry->fname;
+ char *linktarget = (char *)malloc(ucsize+1);
+
+ if (!linktarget) {
+ Info(slide, 0x201, ((char *)slide,
+ LoadFarString(SymLnkWarnNoMem), FnFilter1(linkfname)));
+ return;
+ }
+ linktarget[ucsize] = '\0';
+ G.outfile = zfopen(linkfname, FOPR); /* open link placeholder for reading */
+ /* Check that the following conditions are all fulfilled:
+ * a) the placeholder file exists,
+ * b) the placeholder file contains exactly "ucsize" bytes
+ * (read the expected placeholder content length + 1 extra byte, this
+ * should return the expected content length),
+ * c) the placeholder content matches the link target specification as
+ * stored in the symlink control structure.
+ */
+ if (!G.outfile ||
+ fread(linktarget, 1, ucsize+1, G.outfile) != ucsize ||
+ strcmp(slnk_entry->target, linktarget))
+ {
+ Info(slide, 0x201, ((char *)slide,
+ LoadFarString(SymLnkWarnInvalid), FnFilter1(linkfname)));
+ free(linktarget);
+ if (G.outfile)
+ fclose(G.outfile);
+ return;
+ }
+ fclose(G.outfile); /* close "data" file for good... */
+ unlink(linkfname); /* ...and delete it */
+ if (QCOND2)
+ Info(slide, 0, ((char *)slide, LoadFarString(SymLnkFinish),
+ FnFilter1(linkfname), FnFilter2(linktarget)));
+ if (symlink(linktarget, linkfname)) /* create the real link */
+ perror("symlink error");
+ free(linktarget);
+#ifdef SET_SYMLINK_ATTRIBS
+ set_symlnk_attribs(__G__ slnk_entry);
+#endif
+ return; /* can't set time on symlinks */
+
+} /* end function set_deferred_symlink() */
+#endif /* SYMLINKS */
+
+
+
+
+/*************************/
+/* Function fnfilter() */ /* here instead of in list.c for SFX */
+/*************************/
+
+char *fnfilter(raw, space, size) /* convert name to safely printable form */
+ ZCONST char *raw;
+ uch *space;
+ extent size;
+{
+#ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */
+ ZCONST uch *r=(ZCONST uch *)raw;
+ uch *s=space;
+ uch *slim=NULL;
+ uch *se=NULL;
+ int have_overflow = FALSE;
+
+ if (size > 0) {
+ slim = space + size
+#ifdef _MBCS
+ - (MB_CUR_MAX - 1)
+#endif
+ - 4;
+ }
+ while (*r) {
+ if (size > 0 && s >= slim && se == NULL) {
+ se = s;
+ }
+#ifdef QDOS
+ if (qlflag & 2) {
+ if (*r == '/' || *r == '.') {
+ if (se != NULL && (s > (space + (size-3)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ ++r;
+ *s++ = '_';
+ continue;
+ }
+ } else
+#endif
+#ifdef HAVE_WORKING_ISPRINT
+# ifndef UZ_FNFILTER_REPLACECHAR
+ /* A convenient choice for the replacement of unprintable char codes is
+ * the "single char wildcard", as this character is quite unlikely to
+ * appear in filenames by itself. The following default definition
+ * sets the replacement char to a question mark as the most common
+ * "single char wildcard"; this setting should be overridden in the
+ * appropiate system-specific configuration header when needed.
+ */
+# define UZ_FNFILTER_REPLACECHAR '?'
+# endif
+ if (!isprint(*r)) {
+ if (*r < 32) {
+ /* ASCII control codes are escaped as "^{letter}". */
+ if (se != NULL && (s > (space + (size-4)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ *s++ = '^', *s++ = (uch)(64 + *r++);
+ } else {
+ /* Other unprintable codes are replaced by the
+ * placeholder character. */
+ if (se != NULL && (s > (space + (size-3)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ *s++ = UZ_FNFILTER_REPLACECHAR;
+ INCSTR(r);
+ }
+#else /* !HAVE_WORKING_ISPRINT */
+ if (*r < 32) {
+ /* ASCII control codes are escaped as "^{letter}". */
+ if (se != NULL && (s > (space + (size-4)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ *s++ = '^', *s++ = (uch)(64 + *r++);
+#endif /* ?HAVE_WORKING_ISPRINT */
+ } else {
+#ifdef _MBCS
+ unsigned i = CLEN(r);
+ if (se != NULL && (s > (space + (size-i-2)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ for (; i > 0; i--)
+ *s++ = *r++;
+#else
+ if (se != NULL && (s > (space + (size-3)))) {
+ have_overflow = TRUE;
+ break;
+ }
+ *s++ = *r++;
+#endif
+ }
+ }
+ if (have_overflow) {
+ strcpy((char *)se, "...");
+ } else {
+ *s = '\0';
+ }
+
+#ifdef WINDLL
+ INTERN_TO_ISO((char *)space, (char *)space); /* translate to ANSI */
+#else
+#if (defined(WIN32) && !defined(_WIN32_WCE))
+ /* Win9x console always uses OEM character coding, and
+ WinNT console is set to OEM charset by default, too */
+ INTERN_TO_OEM((char *)space, (char *)space);
+#endif /* (WIN32 && !_WIN32_WCE) */
+#endif /* ?WINDLL */
+
+ return (char *)space;
+
+#else /* NATIVE: EBCDIC or whatever */
+ return (char *)raw;
+#endif
+
+} /* end function fnfilter() */
+
+
+
+
+#ifdef SET_DIR_ATTRIB
+/* must sort saved directories so can set perms from bottom up */
+
+/************************/
+/* Function dircomp() */
+/************************/
+
+static int Cdecl dircomp(a, b) /* used by qsort(); swiped from Zip */
+ ZCONST zvoid *a, *b;
+{
+ /* order is significant: this sorts in reverse order (deepest first) */
+ return strcmp((*(direntry **)b)->fn, (*(direntry **)a)->fn);
+ /* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */
+}
+
+#endif /* SET_DIR_ATTRIB */
+
+
+#ifdef USE_BZIP2
+
+/**************************/
+/* Function UZbunzip2() */
+/**************************/
+
+int UZbunzip2(__G)
+__GDEF
+/* decompress a bzipped entry using the libbz2 routines */
+{
+ int retval = 0; /* return code: 0 = "no error" */
+ int err=BZ_OK;
+ int repeated_buf_err;
+ bz_stream bstrm;
+
+ if (G.incnt <= 0 && G.csize <= 0L) {
+ /* avoid an infinite loop */
+ Trace((stderr, "UZbunzip2() got empty input\n"));
+ return 2;
+ }
+
+#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
+ if (G.redirect_slide)
+ wsize = G.redirect_size, redirSlide = G.redirect_buffer;
+ else
+ wsize = WSIZE, redirSlide = slide;
+#endif
+
+ bstrm.next_out = (char *)redirSlide;
+ bstrm.avail_out = wsize;
+
+ bstrm.next_in = (char *)G.inptr;
+ bstrm.avail_in = G.incnt;
+
+ {
+ /* local buffer for efficiency */
+ /* $TODO Check for BZIP LIB version? */
+
+ bstrm.bzalloc = NULL;
+ bstrm.bzfree = NULL;
+ bstrm.opaque = NULL;
+
+ Trace((stderr, "initializing bzlib()\n"));
+ err = BZ2_bzDecompressInit(&bstrm, 0, 0);
+
+ if (err == BZ_MEM_ERROR)
+ return 3;
+ else if (err != BZ_OK)
+ Trace((stderr, "oops! (BZ2_bzDecompressInit() err = %d)\n", err));
+ }
+
+#ifdef FUNZIP
+ while (err != BZ_STREAM_END) {
+#else /* !FUNZIP */
+ while (G.csize > 0) {
+ Trace((stderr, "first loop: G.csize = %ld\n", G.csize));
+#endif /* ?FUNZIP */
+ while (bstrm.avail_out > 0) {
+ err = BZ2_bzDecompress(&bstrm);
+
+ if (err == BZ_DATA_ERROR) {
+ retval = 2; goto uzbunzip_cleanup_exit;
+ } else if (err == BZ_MEM_ERROR) {
+ retval = 3; goto uzbunzip_cleanup_exit;
+ } else if (err != BZ_OK && err != BZ_STREAM_END)
+ Trace((stderr, "oops! (bzip(first loop) err = %d)\n", err));
+
+#ifdef FUNZIP
+ if (err == BZ_STREAM_END) /* "END-of-entry-condition" ? */
+#else /* !FUNZIP */
+ if (G.csize <= 0L) /* "END-of-entry-condition" ? */
+#endif /* ?FUNZIP */
+ break;
+
+ if (bstrm.avail_in == 0) {
+ if (fillinbuf(__G) == 0) {
+ /* no "END-condition" yet, but no more data */
+ retval = 2; goto uzbunzip_cleanup_exit;
+ }
+
+ bstrm.next_in = (char *)G.inptr;
+ bstrm.avail_in = G.incnt;
+ }
+ Trace((stderr, " avail_in = %u\n", bstrm.avail_in));
+ }
+ /* flush slide[] */
+ if ((retval = FLUSH(wsize - bstrm.avail_out)) != 0)
+ goto uzbunzip_cleanup_exit;
+ Trace((stderr, "inside loop: flushing %ld bytes (ptr diff = %ld)\n",
+ (long)(wsize - bstrm.avail_out),
+ (long)(bstrm.next_out-(char *)redirSlide)));
+ bstrm.next_out = (char *)redirSlide;
+ bstrm.avail_out = wsize;
+ }
+
+ /* no more input, so loop until we have all output */
+ Trace((stderr, "beginning final loop: err = %d\n", err));
+ repeated_buf_err = FALSE;
+ while (err != BZ_STREAM_END) {
+ err = BZ2_bzDecompress(&bstrm);
+ if (err == BZ_DATA_ERROR) {
+ retval = 2; goto uzbunzip_cleanup_exit;
+ } else if (err == BZ_MEM_ERROR) {
+ retval = 3; goto uzbunzip_cleanup_exit;
+ } else if (err != BZ_OK && err != BZ_STREAM_END) {
+ Trace((stderr, "oops! (bzip(final loop) err = %d)\n", err));
+ DESTROYGLOBALS();
+ EXIT(PK_MEM3);
+ }
+ /* final flush of slide[] */
+ if ((retval = FLUSH(wsize - bstrm.avail_out)) != 0)
+ goto uzbunzip_cleanup_exit;
+ Trace((stderr, "final loop: flushing %ld bytes (ptr diff = %ld)\n",
+ (long)(wsize - bstrm.avail_out),
+ (long)(bstrm.next_out-(char *)redirSlide)));
+ bstrm.next_out = (char *)redirSlide;
+ bstrm.avail_out = wsize;
+ }
+#ifdef LARGE_FILE_SUPPORT
+ Trace((stderr, "total in = %llu, total out = %llu\n",
+ (zusz_t)(bstrm.total_in_lo32) + ((zusz_t)(bstrm.total_in_hi32))<<32,
+ (zusz_t)(bstrm.total_out_lo32) + ((zusz_t)(bstrm.total_out_hi32))<<32));
+#else
+ Trace((stderr, "total in = %lu, total out = %lu\n", bstrm.total_in_lo32,
+ bstrm.total_out_lo32));
+#endif
+
+ G.inptr = (uch *)bstrm.next_in;
+ G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */
+
+uzbunzip_cleanup_exit:
+ err = BZ2_bzDecompressEnd(&bstrm);
+ if (err != BZ_OK)
+ Trace((stderr, "oops! (BZ2_bzDecompressEnd() err = %d)\n", err));
+
+ return retval;
+} /* end function UZbunzip2() */
+#endif /* USE_BZIP2 */
diff -Naur a/fileio.c b/fileio.c
--- a/fileio.c 2009-04-20 01:03:44.000000000 +0100
+++ b/fileio.c 2019-12-02 01:45:40.913845391 +0000
@@ -1,5 +1,5 @@
/*
- Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
+ Copyright (c) 1990-2017 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.
@@ -176,6 +176,8 @@
#endif
static ZCONST char Far ExtraFieldTooLong[] =
"warning: extra field too long (%d). Ignoring...\n";
+static ZCONST char Far ExtraFieldCorrupt[] =
+ "warning: extra field (type: 0x%04x) corrupt. Continuing...\n";
#ifdef WINDLL
static ZCONST char Far DiskFullQuery[] =
@@ -1580,6 +1582,8 @@
int r = IZ_PW_ENTERED;
char *m;
char *prompt;
+ char *ep;
+ char *zp;
#ifndef REENTRANT
/* tell picky compilers to shut up about "unused variable" warnings */
@@ -1588,9 +1592,12 @@
if (*rcnt == 0) { /* First call for current entry */
*rcnt = 2;
- if ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL) {
- sprintf(prompt, LoadFarString(PasswPrompt),
- FnFilter1(zfn), FnFilter2(efn));
+ zp = FnFilter1( zfn);
+ ep = FnFilter2( efn);
+ prompt = (char *)malloc( /* Slightly too long (2* "%s"). */
+ sizeof( PasswPrompt)+ strlen( zp)+ strlen( ep));
+ if (prompt != (char *)NULL) {
+ sprintf(prompt, LoadFarString(PasswPrompt), zp, ep);
m = prompt;
} else
m = (char *)LoadFarString(PasswPrompt2);
@@ -2006,6 +2013,7 @@
unsigned comment_bytes_left;
unsigned int block_len;
int error=PK_OK;
+ unsigned int length2;
#ifdef AMIGA
char tmp_fnote[2 * AMIGA_FILENOTELEN]; /* extra room for squozen chars */
#endif
@@ -2292,10 +2300,20 @@
seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes +
(G.inptr-G.inbuf) + length);
} else {
- if (readbuf(__G__ (char *)G.extra_field, length) == 0)
+ if ((length2 = readbuf(__G__ (char *)G.extra_field, length)) == 0)
return PK_EOF;
+ if(length2 < length) {
+ memset (__G__ (char *)G.extra_field+length2, 0 , length-length2);
+ length = length2;
+ }
/* Looks like here is where extra fields are read */
- getZip64Data(__G__ G.extra_field, length);
+ if (getZip64Data(__G__ G.extra_field, length) != PK_COOL)
+ {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString( ExtraFieldCorrupt), EF_PKSZ64));
+ error = PK_WARN;
+ }
+
#ifdef UNICODE_SUPPORT
G.unipath_filename = NULL;
if (G.UzO.U_flag < 2) {
diff -Naur a/list.c b/list.c
--- a/list.c 2009-02-08 17:11:34.000000000 +0000
+++ b/list.c 2019-12-02 01:48:07.035331859 +0000
@@ -97,7 +97,7 @@
{
int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
#ifndef WINDLL
- char sgn, cfactorstr[10];
+ char sgn, cfactorstr[1+10+1+1]; /* <sgn><int>%NUL */
int longhdr=(uO.vflag>1);
#endif
int date_format;
@@ -181,7 +181,7 @@
Info(slide, 0x401,
((char *)slide, LoadFarString(CentSigMsg), j));
Info(slide, 0x401,
- ((char *)slide, LoadFarString(ReportMsg)));
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
return PK_BADERR; /* sig not found */
}
}
@@ -339,7 +339,19 @@
G.crec.compression_method == ENHDEFLATED) {
methbuf[5] = dtype[(G.crec.general_purpose_bit_flag>>1) & 3];
} else if (methnum >= NUM_METHODS) {
- sprintf(&methbuf[4], "%03u", G.crec.compression_method);
+ /* 2013-02-26 SMS.
+ * http://sourceforge.net/tracker/?func=detail
+ * &aid=2861648&group_id=118012&atid=679786
+ * Unexpectedly large compression methods overflow
+ * &methbuf[]. Use the old, three-digit decimal format
+ * for values which fit. Otherwise, sacrifice the
+ * colon, and use four-digit hexadecimal.
+ */
+ if (G.crec.compression_method <= 999) {
+ sprintf( &methbuf[ 4], "%03u", G.crec.compression_method);
+ } else {
+ sprintf( &methbuf[ 3], "%04X", G.crec.compression_method);
+ }
}
#if 0 /* GRR/Euro: add this? */
@@ -378,9 +390,9 @@
}
#else /* !WINDLL */
if (cfactor == 100)
- sprintf(cfactorstr, LoadFarString(CompFactor100));
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100));
else
- sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor);
if (longhdr)
Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats),
FmZofft(G.crec.ucsize, "8", "u"), methbuf,
@@ -460,9 +472,9 @@
#else /* !WINDLL */
if (cfactor == 100)
- sprintf(cfactorstr, LoadFarString(CompFactor100));
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100));
else
- sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor);
if (longhdr) {
Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer),
FmZofft(tot_ucsize, "8", "u"), FmZofft(tot_csize, "8", "u"),
@@ -507,7 +519,8 @@
&& (!G.ecrec.is_zip64_archive)
&& (memcmp(G.sig, end_central_sig, 4) != 0)
) { /* just to make sure again */
- Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
+ Info(slide, 0x401,
+ ((char *)slide,"%s", LoadFarString(EndSigMsg)));
error_in_archive = PK_WARN; /* didn't find sig */
}
@@ -591,7 +604,7 @@
Info(slide, 0x401,
((char *)slide, LoadFarString(CentSigMsg), j));
Info(slide, 0x401,
- ((char *)slide, LoadFarString(ReportMsg)));
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
return PK_BADERR; /* sig not found */
}
}
@@ -674,7 +687,7 @@
---------------------------------------------------------------------------*/
if (memcmp(G.sig, end_central_sig, 4)) { /* just to make sure again */
- Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
+ Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg)));
error_in_archive = PK_WARN;
}
if (*nmember == 0L && error_in_archive <= PK_WARN)
diff -Naur a/list.c.orig b/list.c.orig
--- a/list.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/list.c.orig 2019-12-02 00:34:56.656315493 +0000
@@ -0,0 +1,746 @@
+/*
+ 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
+*/
+/*---------------------------------------------------------------------------
+
+ list.c
+
+ This file contains the non-ZipInfo-specific listing routines for UnZip.
+
+ Contains: list_files()
+ get_time_stamp() [optional feature]
+ ratio()
+ fnprint()
+
+ ---------------------------------------------------------------------------*/
+
+
+#define UNZIP_INTERNAL
+#include "unzip.h"
+#ifdef WINDLL
+# ifdef POCKET_UNZIP
+# include "wince/intrface.h"
+# else
+# include "windll/windll.h"
+# endif
+#endif
+
+
+#ifdef TIMESTAMP
+ static int fn_is_dir OF((__GPRO));
+#endif
+
+#ifndef WINDLL
+ static ZCONST char Far CompFactorStr[] = "%c%d%%";
+ static ZCONST char Far CompFactor100[] = "100%%";
+
+#ifdef OS2_EAS
+ static ZCONST char Far HeadersS[] =
+ " Length EAs ACLs Date Time Name";
+ static ZCONST char Far HeadersS1[] =
+ "--------- --- ---- ---------- ----- ----";
+#else
+ static ZCONST char Far HeadersS[] =
+ " Length Date Time Name";
+ static ZCONST char Far HeadersS1[] =
+ "--------- ---------- ----- ----";
+#endif
+
+ static ZCONST char Far HeadersL[] =
+ " Length Method Size Cmpr Date Time CRC-32 Name";
+ static ZCONST char Far HeadersL1[] =
+ "-------- ------ ------- ---- ---------- ----- -------- ----";
+ static ZCONST char Far *Headers[][2] =
+ { {HeadersS, HeadersS1}, {HeadersL, HeadersL1} };
+
+ static ZCONST char Far CaseConversion[] =
+ "%s (\"^\" ==> case\n%s conversion)\n";
+ static ZCONST char Far LongHdrStats[] =
+ "%s %-7s%s %4s %02u%c%02u%c%02u %02u:%02u %08lx %c";
+ static ZCONST char Far LongFileTrailer[] =
+ "-------- ------- --- \
+ -------\n%s %s %4s %lu file%s\n";
+#ifdef OS2_EAS
+ static ZCONST char Far ShortHdrStats[] =
+ "%s %6lu %6lu %02u%c%02u%c%02u %02u:%02u %c";
+ static ZCONST char Far ShortFileTrailer[] =
+ "--------- ----- ----- \
+ -------\n%s %6lu %6lu %lu file%s\n";
+ static ZCONST char Far OS2ExtAttrTrailer[] =
+ "%lu file%s %lu bytes of OS/2 extended attributes attached.\n";
+ static ZCONST char Far OS2ACLTrailer[] =
+ "%lu file%s %lu bytes of access control lists attached.\n";
+#else
+ static ZCONST char Far ShortHdrStats[] =
+ "%s %02u%c%02u%c%02u %02u:%02u %c";
+ static ZCONST char Far ShortFileTrailer[] =
+ "--------- -------\n%s\
+ %lu file%s\n";
+#endif /* ?OS2_EAS */
+#endif /* !WINDLL */
+
+
+
+
+
+/*************************/
+/* Function list_files() */
+/*************************/
+
+int list_files(__G) /* return PK-type error code */
+ __GDEF
+{
+ int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
+#ifndef WINDLL
+ char sgn, cfactorstr[13];
+ int longhdr=(uO.vflag>1);
+#endif
+ int date_format;
+ char dt_sepchar;
+ ulg members=0L;
+ zusz_t j;
+ unsigned methnum;
+#ifdef USE_EF_UT_TIME
+ iztimes z_utime;
+ struct tm *t;
+#endif
+ unsigned yr, mo, dy, hh, mm;
+ zusz_t csiz, tot_csize=0L, tot_ucsize=0L;
+#ifdef OS2_EAS
+ ulg ea_size, tot_easize=0L, tot_eafiles=0L;
+ ulg acl_size, tot_aclsize=0L, tot_aclfiles=0L;
+#endif
+ min_info info;
+ char methbuf[8];
+ static ZCONST char dtype[]="NXFS"; /* see zi_short() */
+ static ZCONST char Far method[NUM_METHODS+1][8] =
+ {"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4",
+ "Implode", "Token", "Defl:#", "Def64#", "ImplDCL", "BZip2",
+ "LZMA", "Terse", "IBMLZ77", "WavPack", "PPMd", "Unk:###"};
+
+
+
+/*---------------------------------------------------------------------------
+ Unlike extract_or_test_files(), this routine confines itself to the cen-
+ tral directory. Thus its structure is somewhat simpler, since we can do
+ just a single loop through the entire directory, listing files as we go.
+
+ So to start off, print the heading line and then begin main loop through
+ the central directory. The results will look vaguely like the following:
+
+ Length Method Size Ratio Date Time CRC-32 Name ("^" ==> case
+-------- ------ ------- ----- ---- ---- ------ ---- conversion)
+ 44004 Implode 13041 71% 11-02-89 19:34 8b4207f7 Makefile.UNIX
+ 3438 Shrunk 2209 36% 09-15-90 14:07 a2394fd8 ^dos-file.ext
+ 16717 Defl:X 5252 69% 11-03-97 06:40 1ce0f189 WHERE
+-------- ------- --- -------
+ 64159 20502 68% 3 files
+ ---------------------------------------------------------------------------*/
+
+ G.pInfo = &info;
+ date_format = DATE_FORMAT;
+ dt_sepchar = DATE_SEPCHAR;
+
+#ifndef WINDLL
+ if (uO.qflag < 2) {
+ if (uO.L_flag)
+ Info(slide, 0, ((char *)slide, LoadFarString(CaseConversion),
+ LoadFarStringSmall(Headers[longhdr][0]),
+ LoadFarStringSmall2(Headers[longhdr][1])));
+ else
+ Info(slide, 0, ((char *)slide, "%s\n%s\n",
+ LoadFarString(Headers[longhdr][0]),
+ LoadFarStringSmall(Headers[longhdr][1])));
+ }
+#endif /* !WINDLL */
+
+ for (j = 1L;;j++) {
+
+ if (readbuf(__G__ G.sig, 4) == 0)
+ return PK_EOF;
+ if (memcmp(G.sig, central_hdr_sig, 4)) { /* is it a CentDir entry? */
+ /* no new central directory entry
+ * -> is the number of processed entries compatible with the
+ * number of entries as stored in the end_central record?
+ */
+ if (((j - 1) &
+ (ulg)(G.ecrec.have_ecr64 ? MASK_ZUCN64 : MASK_ZUCN16))
+ == (ulg)G.ecrec.total_entries_central_dir)
+ {
+ /* "j modulus 4T/64k" matches the reported 64/16-bit-unsigned
+ * number of directory entries -> probably, the regular
+ * end of the central directory has been reached
+ */
+ break;
+ } else {
+ Info(slide, 0x401,
+ ((char *)slide, LoadFarString(CentSigMsg), j));
+ Info(slide, 0x401,
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
+ return PK_BADERR; /* sig not found */
+ }
+ }
+ /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag, ...: */
+ if ((error = process_cdir_file_hdr(__G)) != PK_COOL)
+ return error; /* only PK_EOF defined */
+
+ /*
+ * We could DISPLAY the filename instead of storing (and possibly trun-
+ * cating, in the case of a very long name) and printing it, but that
+ * has the disadvantage of not allowing case conversion--and it's nice
+ * to be able to see in the listing precisely how you have to type each
+ * filename in order for unzip to consider it a match. Speaking of
+ * which, if member names were specified on the command line, check in
+ * with match() to see if the current file is one of them, and make a
+ * note of it if it is.
+ */
+
+ if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) !=
+ PK_COOL) /* ^--(uses pInfo->lcflag) */
+ {
+ error_in_archive = error;
+ if (error > PK_WARN) /* fatal: can't continue */
+ return error;
+ }
+ if (G.extra_field != (uch *)NULL) {
+ free(G.extra_field);
+ G.extra_field = (uch *)NULL;
+ }
+ if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD))
+ != 0)
+ {
+ error_in_archive = error;
+ if (error > PK_WARN) /* fatal */
+ return error;
+ }
+ if (!G.process_all_files) { /* check if specified on command line */
+ unsigned i;
+
+ if (G.filespecs == 0)
+ do_this_file = TRUE;
+ else { /* check if this entry matches an `include' argument */
+ do_this_file = FALSE;
+ for (i = 0; i < G.filespecs; i++)
+ if (match(G.filename, G.pfnames[i], uO.C_flag WISEP)) {
+ do_this_file = TRUE;
+ break; /* found match, so stop looping */
+ }
+ }
+ if (do_this_file) { /* check if this is an excluded file */
+ for (i = 0; i < G.xfilespecs; i++)
+ if (match(G.filename, G.pxnames[i], uO.C_flag WISEP)) {
+ do_this_file = FALSE; /* ^-- ignore case in match */
+ break;
+ }
+ }
+ }
+ /*
+ * If current file was specified on command line, or if no names were
+ * specified, do the listing for this file. Otherwise, get rid of the
+ * file comment and go back for the next file.
+ */
+
+ if (G.process_all_files || do_this_file) {
+
+#ifdef OS2DLL
+ /* this is used by UzpFileTree() to allow easy processing of lists
+ * of zip directory contents */
+ if (G.processExternally) {
+ if ((G.processExternally)(G.filename, &G.crec))
+ break;
+ ++members;
+ } else {
+#endif
+#ifdef OS2_EAS
+ {
+ uch *ef_ptr = G.extra_field;
+ int ef_size, ef_len = G.crec.extra_field_length;
+ ea_size = acl_size = 0;
+
+ while (ef_len >= EB_HEADSIZE) {
+ ef_size = makeword(&ef_ptr[EB_LEN]);
+ switch (makeword(&ef_ptr[EB_ID])) {
+ case EF_OS2:
+ ea_size = makelong(&ef_ptr[EB_HEADSIZE]);
+ break;
+ case EF_ACL:
+ acl_size = makelong(&ef_ptr[EB_HEADSIZE]);
+ break;
+ }
+ ef_ptr += (ef_size + EB_HEADSIZE);
+ ef_len -= (ef_size + EB_HEADSIZE);
+ }
+ }
+#endif
+#ifdef USE_EF_UT_TIME
+ if (G.extra_field &&
+#ifdef IZ_CHECK_TZ
+ G.tz_is_valid &&
+#endif
+ (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1,
+ G.crec.last_mod_dos_datetime, &z_utime, NULL)
+ & EB_UT_FL_MTIME))
+ {
+ TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7.0, Mac */
+ t = localtime(&(z_utime.mtime));
+ } else
+ t = (struct tm *)NULL;
+ if (t != (struct tm *)NULL) {
+ mo = (unsigned)(t->tm_mon + 1);
+ dy = (unsigned)(t->tm_mday);
+ yr = (unsigned)(t->tm_year + 1900);
+ hh = (unsigned)(t->tm_hour);
+ mm = (unsigned)(t->tm_min);
+ } else
+#endif /* USE_EF_UT_TIME */
+ {
+ yr = ((((unsigned)(G.crec.last_mod_dos_datetime >> 25) & 0x7f)
+ + 1980));
+ mo = ((unsigned)(G.crec.last_mod_dos_datetime >> 21) & 0x0f);
+ dy = ((unsigned)(G.crec.last_mod_dos_datetime >> 16) & 0x1f);
+ hh = (((unsigned)G.crec.last_mod_dos_datetime >> 11) & 0x1f);
+ mm = (((unsigned)G.crec.last_mod_dos_datetime >> 5) & 0x3f);
+ }
+ /* permute date so it displays according to nat'l convention
+ * ('methnum' is not yet set, it is used as temporary buffer) */
+ switch (date_format) {
+ case DF_YMD:
+ methnum = mo;
+ mo = yr; yr = dy; dy = methnum;
+ break;
+ case DF_DMY:
+ methnum = mo;
+ mo = dy; dy = methnum;
+ }
+
+ csiz = G.crec.csize;
+ if (G.crec.general_purpose_bit_flag & 1)
+ csiz -= 12; /* if encrypted, don't count encryption header */
+ if ((cfactor = ratio(G.crec.ucsize, csiz)) < 0) {
+#ifndef WINDLL
+ sgn = '-';
+#endif
+ cfactor = (-cfactor + 5) / 10;
+ } else {
+#ifndef WINDLL
+ sgn = ' ';
+#endif
+ cfactor = (cfactor + 5) / 10;
+ }
+
+ methnum = find_compr_idx(G.crec.compression_method);
+ zfstrcpy(methbuf, method[methnum]);
+ if (G.crec.compression_method == DEFLATED ||
+ G.crec.compression_method == ENHDEFLATED) {
+ methbuf[5] = dtype[(G.crec.general_purpose_bit_flag>>1) & 3];
+ } else if (methnum >= NUM_METHODS) {
+ /* 2013-02-26 SMS.
+ * http://sourceforge.net/tracker/?func=detail
+ * &aid=2861648&group_id=118012&atid=679786
+ * Unexpectedly large compression methods overflow
+ * &methbuf[]. Use the old, three-digit decimal format
+ * for values which fit. Otherwise, sacrifice the
+ * colon, and use four-digit hexadecimal.
+ */
+ if (G.crec.compression_method <= 999) {
+ sprintf( &methbuf[ 4], "%03u", G.crec.compression_method);
+ } else {
+ sprintf( &methbuf[ 3], "%04X", G.crec.compression_method);
+ }
+ }
+
+#if 0 /* GRR/Euro: add this? */
+#if defined(DOS_FLX_NLM_OS2_W32) || defined(THEOS) || defined(UNIX)
+ for (p = G.filename; *p; ++p)
+ if (!isprint(*p))
+ *p = '?'; /* change non-printable chars to '?' */
+#endif /* DOS_FLX_NLM_OS2_W32 || THEOS || UNIX */
+#endif /* 0 */
+
+#ifdef WINDLL
+ /* send data to application for formatting and printing */
+ if (G.lpUserFunctions->SendApplicationMessage != NULL)
+ (*G.lpUserFunctions->SendApplicationMessage)(G.crec.ucsize,
+ csiz, (unsigned)cfactor, mo, dy, yr, hh, mm,
+ (char)(G.pInfo->lcflag ? '^' : ' '),
+ (LPCSTR)fnfilter(G.filename, slide, (WSIZE>>1)),
+ (LPCSTR)methbuf, G.crec.crc32,
+ (char)((G.crec.general_purpose_bit_flag & 1) ? 'E' : ' '));
+ else if (G.lpUserFunctions->SendApplicationMessage_i32 != NULL) {
+ unsigned long ucsize_lo, csiz_lo;
+ unsigned long ucsize_hi=0L, csiz_hi=0L;
+ ucsize_lo = (unsigned long)(G.crec.ucsize);
+ csiz_lo = (unsigned long)(csiz);
+#ifdef ZIP64_SUPPORT
+ ucsize_hi = (unsigned long)(G.crec.ucsize >> 32);
+ csiz_hi = (unsigned long)(csiz >> 32);
+#endif /* ZIP64_SUPPORT */
+ (*G.lpUserFunctions->SendApplicationMessage_i32)(ucsize_lo,
+ ucsize_hi, csiz_lo, csiz_hi, (unsigned)cfactor,
+ mo, dy, yr, hh, mm,
+ (char)(G.pInfo->lcflag ? '^' : ' '),
+ (LPCSTR)fnfilter(G.filename, slide, (WSIZE>>1)),
+ (LPCSTR)methbuf, G.crec.crc32,
+ (char)((G.crec.general_purpose_bit_flag & 1) ? 'E' : ' '));
+ }
+#else /* !WINDLL */
+ if (cfactor == 100)
+ sprintf(cfactorstr, LoadFarString(CompFactor100));
+ else
+ sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
+ if (longhdr)
+ Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats),
+ FmZofft(G.crec.ucsize, "8", "u"), methbuf,
+ FmZofft(csiz, "8", "u"), cfactorstr,
+ mo, dt_sepchar, dy, dt_sepchar, yr, hh, mm,
+ G.crec.crc32, (G.pInfo->lcflag? '^':' ')));
+ else
+#ifdef OS2_EAS
+ Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats),
+ FmZofft(G.crec.ucsize, "9", "u"), ea_size, acl_size,
+ mo, dt_sepchar, dy, dt_sepchar, yr, hh, mm,
+ (G.pInfo->lcflag? '^':' ')));
+#else
+ Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats),
+ FmZofft(G.crec.ucsize, "9", "u"),
+ mo, dt_sepchar, dy, dt_sepchar, yr, hh, mm,
+ (G.pInfo->lcflag? '^':' ')));
+#endif
+ fnprint(__G);
+#endif /* ?WINDLL */
+
+ if ((error = do_string(__G__ G.crec.file_comment_length,
+ QCOND? DISPL_8 : SKIP)) != 0)
+ {
+ error_in_archive = error; /* might be just warning */
+ if (error > PK_WARN) /* fatal */
+ return error;
+ }
+ tot_ucsize += G.crec.ucsize;
+ tot_csize += csiz;
+ ++members;
+#ifdef OS2_EAS
+ if (ea_size) {
+ tot_easize += ea_size;
+ ++tot_eafiles;
+ }
+ if (acl_size) {
+ tot_aclsize += acl_size;
+ ++tot_aclfiles;
+ }
+#endif
+#ifdef OS2DLL
+ } /* end of "if (G.processExternally) {...} else {..." */
+#endif
+ } else { /* not listing this file */
+ SKIP_(G.crec.file_comment_length)
+ }
+ } /* end for-loop (j: files in central directory) */
+
+/*---------------------------------------------------------------------------
+ Print footer line and totals (compressed size, uncompressed size, number
+ of members in zipfile).
+ ---------------------------------------------------------------------------*/
+
+ if (uO.qflag < 2
+#ifdef OS2DLL
+ && !G.processExternally
+#endif
+ ) {
+ if ((cfactor = ratio(tot_ucsize, tot_csize)) < 0) {
+#ifndef WINDLL
+ sgn = '-';
+#endif
+ cfactor = (-cfactor + 5) / 10;
+ } else {
+#ifndef WINDLL
+ sgn = ' ';
+#endif
+ cfactor = (cfactor + 5) / 10;
+ }
+#ifdef WINDLL
+ /* pass the totals back to the calling application */
+ G.lpUserFunctions->TotalSizeComp = tot_csize;
+ G.lpUserFunctions->TotalSize = tot_ucsize;
+ G.lpUserFunctions->CompFactor = (ulg)cfactor;
+ G.lpUserFunctions->NumMembers = members;
+
+#else /* !WINDLL */
+ if (cfactor == 100)
+ sprintf(cfactorstr, LoadFarString(CompFactor100));
+ else
+ sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
+ if (longhdr) {
+ Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer),
+ FmZofft(tot_ucsize, "8", "u"), FmZofft(tot_csize, "8", "u"),
+ cfactorstr, members, members==1? "":"s"));
+#ifdef OS2_EAS
+ if (tot_easize || tot_aclsize)
+ Info(slide, 0, ((char *)slide, "\n"));
+ if (tot_eafiles && tot_easize)
+ Info(slide, 0, ((char *)slide, LoadFarString(OS2ExtAttrTrailer),
+ tot_eafiles, tot_eafiles == 1? " has" : "s have a total of",
+ tot_easize));
+ if (tot_aclfiles && tot_aclsize)
+ Info(slide, 0, ((char *)slide, LoadFarString(OS2ACLTrailer),
+ tot_aclfiles,
+ tot_aclfiles == 1 ? " has" : "s have a total of",
+ tot_aclsize));
+#endif /* OS2_EAS */
+ } else
+#ifdef OS2_EAS
+ Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer),
+ FmZofft(tot_ucsize, "9", "u"), tot_easize, tot_aclsize,
+ members, members == 1 ? "" : "s"));
+#else
+ Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer),
+ FmZofft(tot_ucsize, "9", "u"),
+ members, members == 1 ? "" : "s"));
+#endif /* OS2_EAS */
+#endif /* ?WINDLL */
+ }
+
+ /* Skip the following checks in case of a premature listing break. */
+ if (error_in_archive <= PK_WARN) {
+
+/*---------------------------------------------------------------------------
+ Double check that we're back at the end-of-central-directory record.
+ ---------------------------------------------------------------------------*/
+
+ if ( (memcmp(G.sig,
+ (G.ecrec.have_ecr64 ?
+ end_central64_sig : end_central_sig),
+ 4) != 0)
+ && (!G.ecrec.is_zip64_archive)
+ && (memcmp(G.sig, end_central_sig, 4) != 0)
+ ) { /* just to make sure again */
+ Info(slide, 0x401,
+ ((char *)slide,"%s", LoadFarString(EndSigMsg)));
+ error_in_archive = PK_WARN; /* didn't find sig */
+ }
+
+ /* Set specific return code when no files have been found. */
+ if (members == 0L && error_in_archive <= PK_WARN)
+ error_in_archive = PK_FIND;
+
+ }
+
+ return error_in_archive;
+
+} /* end function list_files() */
+
+
+
+
+
+#ifdef TIMESTAMP
+
+/************************/
+/* Function fn_is_dir() */
+/************************/
+
+static int fn_is_dir(__G) /* returns TRUE if G.filename is directory */
+ __GDEF
+{
+ extent fn_len = strlen(G.filename);
+ register char endc;
+
+ return fn_len > 0 &&
+ ((endc = lastchar(G.filename, fn_len)) == '/' ||
+ (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/') &&
+ endc == '\\'));
+}
+
+
+
+
+
+/*****************************/
+/* Function get_time_stamp() */
+/*****************************/
+
+int get_time_stamp(__G__ last_modtime, nmember) /* return PK-type error code */
+ __GDEF
+ time_t *last_modtime;
+ ulg *nmember;
+{
+ int do_this_file=FALSE, error, error_in_archive=PK_COOL;
+ ulg j;
+#ifdef USE_EF_UT_TIME
+ iztimes z_utime;
+#endif
+ min_info info;
+
+
+/*---------------------------------------------------------------------------
+ Unlike extract_or_test_files() but like list_files(), this function works
+ on information in the central directory alone. Thus we have a single,
+ large loop through the entire directory, searching for the latest time
+ stamp.
+ ---------------------------------------------------------------------------*/
+
+ *last_modtime = 0L; /* assuming no zipfile data older than 1970 */
+ *nmember = 0L;
+ G.pInfo = &info;
+
+ for (j = 1L;; j++) {
+
+ if (readbuf(__G__ G.sig, 4) == 0)
+ return PK_EOF;
+ if (memcmp(G.sig, central_hdr_sig, 4)) { /* is it a CentDir entry? */
+ if (((unsigned)(j - 1) & (unsigned)0xFFFF) ==
+ (unsigned)G.ecrec.total_entries_central_dir) {
+ /* "j modulus 64k" matches the reported 16-bit-unsigned
+ * number of directory entries -> probably, the regular
+ * end of the central directory has been reached
+ */
+ break;
+ } else {
+ Info(slide, 0x401,
+ ((char *)slide, LoadFarString(CentSigMsg), j));
+ Info(slide, 0x401,
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
+ return PK_BADERR; /* sig not found */
+ }
+ }
+ /* process_cdir_file_hdr() sets pInfo->lcflag: */
+ if ((error = process_cdir_file_hdr(__G)) != PK_COOL)
+ return error; /* only PK_EOF defined */
+ if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) != PK_OK)
+ { /* ^-- (uses pInfo->lcflag) */
+ error_in_archive = error;
+ if (error > PK_WARN) /* fatal: can't continue */
+ return error;
+ }
+ if (G.extra_field != (uch *)NULL) {
+ free(G.extra_field);
+ G.extra_field = (uch *)NULL;
+ }
+ if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD))
+ != 0)
+ {
+ error_in_archive = error;
+ if (error > PK_WARN) /* fatal */
+ return error;
+ }
+ if (!G.process_all_files) { /* check if specified on command line */
+ unsigned i;
+
+ if (G.filespecs == 0)
+ do_this_file = TRUE;
+ else { /* check if this entry matches an `include' argument */
+ do_this_file = FALSE;
+ for (i = 0; i < G.filespecs; i++)
+ if (match(G.filename, G.pfnames[i], uO.C_flag WISEP)) {
+ do_this_file = TRUE;
+ break; /* found match, so stop looping */
+ }
+ }
+ if (do_this_file) { /* check if this is an excluded file */
+ for (i = 0; i < G.xfilespecs; i++)
+ if (match(G.filename, G.pxnames[i], uO.C_flag WISEP)) {
+ do_this_file = FALSE; /* ^-- ignore case in match */
+ break;
+ }
+ }
+ }
+
+ /* If current file was specified on command line, or if no names were
+ * specified, check the time for this file. Either way, get rid of the
+ * file comment and go back for the next file.
+ * Directory entries are always ignored, to stay compatible with both
+ * Zip and PKZIP.
+ */
+ if ((G.process_all_files || do_this_file) && !fn_is_dir(__G)) {
+#ifdef USE_EF_UT_TIME
+ if (G.extra_field &&
+#ifdef IZ_CHECK_TZ
+ G.tz_is_valid &&
+#endif
+ (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1,
+ G.crec.last_mod_dos_datetime, &z_utime, NULL)
+ & EB_UT_FL_MTIME))
+ {
+ if (*last_modtime < z_utime.mtime)
+ *last_modtime = z_utime.mtime;
+ } else
+#endif /* USE_EF_UT_TIME */
+ {
+ time_t modtime = dos_to_unix_time(G.crec.last_mod_dos_datetime);
+
+ if (*last_modtime < modtime)
+ *last_modtime = modtime;
+ }
+ ++*nmember;
+ }
+ SKIP_(G.crec.file_comment_length)
+
+ } /* end for-loop (j: files in central directory) */
+
+/*---------------------------------------------------------------------------
+ Double check that we're back at the end-of-central-directory record.
+ ---------------------------------------------------------------------------*/
+
+ if (memcmp(G.sig, end_central_sig, 4)) { /* just to make sure again */
+ Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg)));
+ error_in_archive = PK_WARN;
+ }
+ if (*nmember == 0L && error_in_archive <= PK_WARN)
+ error_in_archive = PK_FIND;
+
+ return error_in_archive;
+
+} /* end function get_time_stamp() */
+
+#endif /* TIMESTAMP */
+
+
+
+
+
+/********************/
+/* Function ratio() */ /* also used by ZipInfo routines */
+/********************/
+
+int ratio(uc, c)
+ zusz_t uc, c;
+{
+ zusz_t denom;
+
+ if (uc == 0)
+ return 0;
+ if (uc > 2000000L) { /* risk signed overflow if multiply numerator */
+ denom = uc / 1000L;
+ return ((uc >= c) ?
+ (int) ((uc-c + (denom>>1)) / denom) :
+ -((int) ((c-uc + (denom>>1)) / denom)));
+ } else { /* ^^^^^^^^ rounding */
+ denom = uc;
+ return ((uc >= c) ?
+ (int) ((1000L*(uc-c) + (denom>>1)) / denom) :
+ -((int) ((1000L*(c-uc) + (denom>>1)) / denom)));
+ } /* ^^^^^^^^ rounding */
+}
+
+
+
+
+
+/************************/
+/* Function fnprint() */ /* also used by ZipInfo routines */
+/************************/
+
+void fnprint(__G) /* print filename (after filtering) and newline */
+ __GDEF
+{
+ char *name = fnfilter(G.filename, slide, (extent)(WSIZE>>1));
+
+ (*G.message)((zvoid *)&G, (uch *)name, (ulg)strlen(name), 0);
+ (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0);
+
+} /* end function fnprint() */
diff -Naur a/match.c b/match.c
--- a/match.c 2005-08-14 18:00:36.000000000 +0100
+++ b/match.c 2019-12-02 00:19:45.331163073 +0000
@@ -27,16 +27,14 @@
---------------------------------------------------------------------------
- Copyright on recmatch() from Zip's util.c (although recmatch() was almost
- certainly written by Mark Adler...ask me how I can tell :-) ):
+ Copyright on recmatch() from Zip's util.c
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
- Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
- Kai Uwe Rommel and Igor Mandrichenko.
+ See the accompanying file LICENSE, version 2004-May-22 or later
+ for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
- Permission is granted to any individual or institution to use, copy,
- or redistribute this software so long as all of the original files are
- included unmodified, that it is not sold for profit, and that this copy-
- right notice is retained.
---------------------------------------------------------------------------
@@ -53,7 +51,7 @@
A set is composed of characters or ranges; a range looks like ``character
hyphen character'' (as in 0-9 or A-Z). [0-9a-zA-Z_] is the minimal set of
- characters allowed in the [..] pattern construct. Other characters are
+ characters ALlowed in the [..] pattern construct. Other characters are
allowed (i.e., 8-bit characters) if your system will support them.
To suppress the special syntactic significance of any of ``[]*?!^-\'', in-
@@ -101,8 +99,32 @@
# define WILDCHAR '?'
# define BEG_RANGE '['
# define END_RANGE ']'
+# define WILDCHR_SINGLE '?'
+# define DIRSEP_CHR '/'
+# define WILDCHR_MULTI '*'
#endif
+#ifdef WILD_STOP_AT_DIR
+ int wild_stop_at_dir = 1; /* default wildcards do not include / in matches */
+#else
+ int wild_stop_at_dir = 0; /* default wildcards do include / in matches */
+#endif
+
+
+
+/*
+ * case mapping functions. case_map is used to ignore case in comparisons,
+ * to_up is used to force upper case even on Unix (for dosify option).
+ */
+#ifdef USE_CASE_MAP
+# define case_map(c) upper[(c) & 0xff]
+# define to_up(c) upper[(c) & 0xff]
+#else
+# define case_map(c) (c)
+# define to_up(c) ((c) >= 'a' && (c) <= 'z' ? (c)-'a'+'A' : (c))
+#endif /* USE_CASE_MAP */
+
+
#if 0 /* GRR: add this to unzip.h someday... */
#if !(defined(MSDOS) && defined(DOSWILD))
#ifdef WILD_STOP_AT_DIR
@@ -114,8 +136,8 @@
int ignore_case __WDLPRO));
#endif
#endif /* 0 */
-static int recmatch OF((ZCONST uch *pattern, ZCONST uch *string,
- int ignore_case __WDLPRO));
+static int recmatch OF((ZCONST char *, ZCONST char *,
+ int));
static char *isshexp OF((ZCONST char *p));
static int namecmp OF((ZCONST char *s1, ZCONST char *s2));
@@ -154,192 +176,240 @@
}
dospattern[j-1] = '\0'; /* nuke the end "." */
}
- j = recmatch((uch *)dospattern, (uch *)string, ignore_case __WDL);
+ j = recmatch(dospattern, string, ignore_case);
free(dospattern);
return j == 1;
} else
#endif /* MSDOS && DOSWILD */
- return recmatch((uch *)pattern, (uch *)string, ignore_case __WDL) == 1;
+ return recmatch(pattern, string, ignore_case) == 1;
}
+#ifdef _MBCS
+
+char *___tmp_ptr;
+#endif
-static int recmatch(p, s, ic __WDL)
- ZCONST uch *p; /* sh pattern to match */
- ZCONST uch *s; /* string to which to match it */
- int ic; /* true for case insensitivity */
- __WDLDEF /* directory sepchar for WildStopAtDir mode, or 0 */
+static int recmatch(p, s, ci)
+ZCONST char *p; /* sh pattern to match */
+ZCONST char *s; /* string to match it to */
+int ci; /* flag: force case-insensitive matching */
/* Recursively compare the sh pattern p with the string s and return 1 if
- * they match, and 0 or 2 if they don't or if there is a syntax error in the
- * pattern. This routine recurses on itself no more deeply than the number
- * of characters in the pattern. */
+ they match, and 0 or 2 if they don't or if there is a syntax error in the
+ pattern. This routine recurses on itself no deeper than the number of
+ characters in the pattern. */
{
- unsigned int c; /* pattern char or start of range in [-] loop */
+ int c; /* pattern char or start of range in [-] loop */
+ /* Get first character, the pattern for new recmatch calls follows */
+ /* borrowed from Zip's global.c */
+ int no_wild = 0;
+ int allow_regex=1;
+ /* This fix provided by akt@m5.dion.ne.jp for Japanese.
+ See 21 July 2006 mail.
+ It only applies when p is pointing to a doublebyte character and
+ things like / and wildcards are not doublebyte. This probably
+ should not be needed. */
- /* Get first character, the pattern for new recmatch calls follows */
- c = *p; INCSTR(p);
+#ifdef _MBCS
+ if (CLEN(p) == 2) {
+ if (CLEN(s) == 2) {
+ return (*p == *s && *(p+1) == *(s+1)) ?
+ recmatch(p + 2, s + 2, ci) : 0;
+ } else {
+ return 0;
+ }
+ }
+#endif /* ?_MBCS */
- /* If that was the end of the pattern, match if string empty too */
- if (c == 0)
- return *s == 0;
+ c = *POSTINCSTR(p);
- /* '?' (or '%') matches any character (but not an empty string). */
- if (c == WILDCHAR)
-#ifdef WILD_STOP_AT_DIR
- /* If uO.W_flag is non-zero, it won't match '/' */
- return (*s && (!sepc || *s != (uch)sepc))
- ? recmatch(p, s + CLEN(s), ic, sepc) : 0;
-#else
- return *s ? recmatch(p, s + CLEN(s), ic) : 0;
-#endif
+ /* If that was the end of the pattern, match if string empty too */
+ if (c == 0)
+ return *s == 0;
+
+ /* '?' (or '%' or '#') matches any character (but not an empty string) */
+ if (c == WILDCHR_SINGLE) {
+ if (wild_stop_at_dir)
+ return (*s && *s != DIRSEP_CHR) ? recmatch(p, s + CLEN(s), ci) : 0;
+ else
+ return *s ? recmatch(p, s + CLEN(s), ci) : 0;
+ }
- /* '*' matches any number of characters, including zero */
+ /* WILDCHR_MULTI ('*') matches any number of characters, including zero */
#ifdef AMIGA
- if (c == '#' && *p == '?') /* "#?" is Amiga-ese for "*" */
- c = '*', p++;
+ if (!no_wild && c == '#' && *p == '?') /* "#?" is Amiga-ese for "*" */
+ c = WILDCHR_MULTI, p++;
#endif /* AMIGA */
- if (c == '*') {
-#ifdef WILD_STOP_AT_DIR
- if (sepc) {
- /* check for single "*" or double "**" */
-# ifdef AMIGA
- if ((c = p[0]) == '#' && p[1] == '?') /* "#?" is Amiga-ese for "*" */
- c = '*', p++;
- if (c != '*') {
-# else /* !AMIGA */
- if (*p != '*') {
-# endif /* ?AMIGA */
- /* single "*": this doesn't match the dirsep character */
- for (; *s && *s != (uch)sepc; INCSTR(s))
- if ((c = recmatch(p, s, ic, sepc)) != 0)
- return (int)c;
- /* end of pattern: matched if at end of string, else continue */
- if (*p == '\0')
- return (*s == 0);
- /* continue to match if at sepc in pattern, else give up */
- return (*p == (uch)sepc || (*p == '\\' && p[1] == (uch)sepc))
- ? recmatch(p, s, ic, sepc) : 2;
- }
- /* "**": this matches slashes */
- ++p; /* move p behind the second '*' */
- /* and continue with the non-W_flag code variant */
- }
-#endif /* WILD_STOP_AT_DIR */
+ if (!no_wild && c == WILDCHR_MULTI)
+ {
+ if (wild_stop_at_dir) {
+ /* Check for an immediately following WILDCHR_MULTI */
+# ifdef AMIGA
+ if ((c = p[0]) == '#' && p[1] == '?') /* "#?" is Amiga-ese for "*" */
+ c = WILDCHR_MULTI, p++;
+ if (c != WILDCHR_MULTI) {
+# else /* !AMIGA */
+ if (*p != WILDCHR_MULTI) {
+# endif /* ?AMIGA */
+ /* Single WILDCHR_MULTI ('*'): this doesn't match slashes */
+ for (; *s && *s != DIRSEP_CHR; INCSTR(s))
+ if ((c = recmatch(p, s, ci)) != 0)
+ return c;
+ /* end of pattern: matched if at end of string, else continue */
if (*p == 0)
- return 1;
- if (isshexp((ZCONST char *)p) == NULL) {
- /* Optimization for rest of pattern being a literal string:
- * If there are no other shell expression chars in the rest
- * of the pattern behind the multi-char wildcard, then just
- * compare the literal string tail.
- */
- ZCONST uch *srest;
-
- srest = s + (strlen((ZCONST char *)s) - strlen((ZCONST char *)p));
- if (srest - s < 0)
- /* remaining literal string from pattern is longer than rest
- * of test string, there can't be a match
- */
- return 0;
- else
- /* compare the remaining literal pattern string with the last
- * bytes of the test string to check for a match
- */
+ return (*s == 0);
+ /* continue to match if at DIRSEP_CHR in pattern, else give up */
+ return (*p == DIRSEP_CHR || (*p == '\\' && p[1] == DIRSEP_CHR))
+ ? recmatch(p, s, ci) : 2;
+ }
+ /* Two consecutive WILDCHR_MULTI ("**"): this matches DIRSEP_CHR ('/') */
+ p++; /* move p past the second WILDCHR_MULTI */
+ /* continue with the normal non-WILD_STOP_AT_DIR code */
+ } /* wild_stop_at_dir */
+
+ /* Not wild_stop_at_dir */
+ if (*p == 0)
+ return 1;
+ if (!isshexp((char *)p))
+ {
+ /* optimization for rest of pattern being a literal string */
+
+ /* optimization to handle patterns like *.txt */
+ /* if the first char in the pattern is '*' and there */
+ /* are no other shell expression chars, i.e. a literal string */
+ /* then just compare the literal string at the end */
+
+ ZCONST char *srest;
+
+ srest = s + (strlen(s) - strlen(p));
+ if (srest - s < 0)
+ /* remaining literal string from pattern is longer than rest of
+ test string, there can't be a match
+ */
+ return 0;
+ else
+ /* compare the remaining literal pattern string with the last bytes
+ of the test string to check for a match */
#ifdef _MBCS
- {
- ZCONST uch *q = s;
+ {
+ ZCONST char *q = s;
- /* MBCS-aware code must not scan backwards into a string from
- * the end.
- * So, we have to move forward by character from our well-known
- * character position s in the test string until we have
- * advanced to the srest position.
- */
- while (q < srest)
- INCSTR(q);
- /* In case the byte *srest is a trailing byte of a multibyte
- * character in the test string s, we have actually advanced
- * past the position (srest).
- * For this case, the match has failed!
- */
- if (q != srest)
- return 0;
- return ((ic
- ? namecmp((ZCONST char *)p, (ZCONST char *)q)
- : strcmp((ZCONST char *)p, (ZCONST char *)q)
- ) == 0);
- }
+ /* MBCS-aware code must not scan backwards into a string from
+ * the end.
+ * So, we have to move forward by character from our well-known
+ * character position s in the test string until we have advanced
+ * to the srest position.
+ */
+ while (q < srest)
+ INCSTR(q);
+ /* In case the byte *srest is a trailing byte of a multibyte
+ * character, we have actually advanced past the position (srest).
+ * For this case, the match has failed!
+ */
+ if (q != srest)
+ return 0;
+ return ((!ci ? strcmp(p, q) : namecmp(p, q)) == 0);
+ }
#else /* !_MBCS */
- return ((ic
- ? namecmp((ZCONST char *)p, (ZCONST char *)srest)
- : strcmp((ZCONST char *)p, (ZCONST char *)srest)
- ) == 0);
+ return ((!ci ? strcmp(p, srest) : namecmp(p, srest)) == 0);
#endif /* ?_MBCS */
- } else {
- /* pattern contains more wildcards, continue with recursion... */
- for (; *s; INCSTR(s))
- if ((c = recmatch(p, s, ic __WDL)) != 0)
- return (int)c;
- return 2; /* 2 means give up--match will return false */
- }
}
-
- /* Parse and process the list of characters and ranges in brackets */
- if (c == BEG_RANGE) {
- int e; /* flag true if next char to be taken literally */
- ZCONST uch *q; /* pointer to end of [-] group */
- int r; /* flag true to match anything but the range */
-
- if (*s == 0) /* need a character to match */
- return 0;
- p += (r = (*p == '!' || *p == '^')); /* see if reverse */
- for (q = p, e = 0; *q; INCSTR(q)) /* find closing bracket */
- if (e)
- e = 0;
- else
- if (*q == '\\') /* GRR: change to ^ for MS-DOS, OS/2? */
- e = 1;
- else if (*q == END_RANGE)
- break;
- if (*q != END_RANGE) /* nothing matches if bad syntax */
- return 0;
- for (c = 0, e = (*p == '-'); p < q; INCSTR(p)) {
- /* go through the list */
- if (!e && *p == '\\') /* set escape flag if \ */
- e = 1;
- else if (!e && *p == '-') /* set start of range if - */
- c = *(p-1);
- else {
- unsigned int cc = Case(*s);
-
- if (*(p+1) != '-')
- for (c = c ? c : *p; c <= *p; c++) /* compare range */
- if ((unsigned)Case(c) == cc) /* typecast for MSC bug */
- return r ? 0 : recmatch(q + 1, s + 1, ic __WDL);
- c = e = 0; /* clear range, escape flags */
- }
- }
- return r ? recmatch(q + CLEN(q), s + CLEN(s), ic __WDL) : 0;
- /* bracket match failed */
+ else
+ {
+ /* pattern contains more wildcards, continue with recursion... */
+ for (; *s; INCSTR(s))
+ if ((c = recmatch(p, s, ci)) != 0)
+ return c;
+ return 2; /* 2 means give up--shmatch will return false */
}
+ }
- /* if escape ('\\'), just compare next character */
- if (c == '\\' && (c = *p++) == 0) /* if \ at end, then syntax error */
- return 0;
+#ifndef VMS /* No bracket matching in VMS */
+ /* Parse and process the list of characters and ranges in brackets */
+ if (!no_wild && allow_regex && c == '[')
+ {
+ int e; /* flag true if next char to be taken literally */
+ ZCONST char *q; /* pointer to end of [-] group */
+ int r; /* flag true to match anything but the range */
+
+ if (*s == 0) /* need a character to match */
+ return 0;
+ p += (r = (*p == '!' || *p == '^')); /* see if reverse */
+ for (q = p, e = 0; *q; q++) /* find closing bracket */
+ if (e)
+ e = 0;
+ else
+ if (*q == '\\')
+ e = 1;
+ else if (*q == ']')
+ break;
+ if (*q != ']') /* nothing matches if bad syntax */
+ return 0;
+ for (c = 0, e = *p == '-'; p < q; p++) /* go through the list */
+ {
+ if (e == 0 && *p == '\\') /* set escape flag if \ */
+ e = 1;
+ else if (e == 0 && *p == '-') /* set start of range if - */
+ c = *(p-1);
+ else
+ {
+ uch cc = (!ci ? (uch)*s : to_up((uch)*s));
+ uch uc = (uch) c;
+ if (*(p+1) != '-')
+ for (uc = uc ? uc : (uch)*p; uc <= (uch)*p; uc++)
+ /* compare range */
+ if ((!ci ? uc : to_up(uc)) == cc)
+ return r ? 0 : recmatch(q + CLEN(q), s + CLEN(s), ci);
+ c = e = 0; /* clear range, escape flags */
+ }
+ }
+ return r ? recmatch(q + CLEN(q), s + CLEN(s), ci) : 0;
+ /* bracket match failed */
+ }
+#endif /* !VMS */
- /* just a character--compare it */
-#ifdef QDOS
- return QMatch(Case((uch)c), Case(*s)) ?
- recmatch(p, s + CLEN(s), ic __WDL) : 0;
-#else
- return Case((uch)c) == Case(*s) ?
- recmatch(p, s + CLEN(s), ic __WDL) : 0;
-#endif
+ /* If escape ('\'), just compare next character */
+ if (!no_wild && c == '\\')
+ if ((c = *p++) == '\0') /* if \ at end, then syntax error */
+ return 0;
+
+#ifdef VMS
+ /* 2005-11-06 SMS.
+ Handle "..." wildcard in p with "." or "]" in s.
+ */
+ if ((c == '.') && (*p == '.') && (*(p+ CLEN( p)) == '.') &&
+ ((*s == '.') || (*s == ']')))
+ {
+ /* Match "...]" with "]". Continue after "]" in both. */
+ if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
+ return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), ci);
+
+ /* Else, look for a reduced match in s, until "]" in or end of s. */
+ for (; *s && (*s != ']'); INCSTR(s))
+ if (*s == '.')
+ /* If reduced match, then continue after "..." in p, "." in s. */
+ if ((c = recmatch( (p+ CLEN( p)), s, ci)) != 0)
+ return (int)c;
+
+ /* Match "...]" with "]". Continue after "]" in both. */
+ if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
+ return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), ci);
+
+ /* No reduced match. Quit. */
+ return 2;
+ }
+
+#endif /* def VMS */
+
+ /* Just a character--compare it */
+ return (!ci ? c == *s : to_up((uch)c) == to_up((uch)*s)) ?
+ recmatch(p, s + CLEN(s), ci) : 0;
+}
-} /* end function recmatch() */
+/*************************************************************************************************/
static char *isshexp(p)
ZCONST char *p;
/* If p is a sh expression, a pointer to the first special character is
diff -Naur a/process.c b/process.c
--- a/process.c 2009-03-06 01:25:10.000000000 +0000
+++ b/process.c 2019-12-02 01:44:23.792587920 +0000
@@ -1,5 +1,5 @@
/*
- Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
+ Copyright (c) 1990-2014 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.
@@ -1888,48 +1888,83 @@
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.
+
+ 2014-12-05 SMS.
+ Added checks to ensure that enough data are available before calling
+ makeint64() or makelong(). Replaced various sizeof() values with
+ simple ("4" or "8") constants. (The Zip64 structures do not depend
+ on our variable sizes.) Error handling is crude, but we should now
+ stay within the buffer.
---------------------------------------------------------------------------*/
+#define Z64FLGS 0xffff
+#define Z64FLGL 0xffffffff
+
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) {
+ 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! */
+ if (eb_len > (ef_len - EB_HEADSIZE))
+ {
+ /* Extra block length exceeds remaining extra field length. */
Trace((stderr,
"getZip64Data: block length %u > rest ef_size %u\n", eb_len,
ef_len - EB_HEADSIZE));
break;
}
- if (eb_id == EF_PKSZ64) {
+ 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.ucsize == Z64FLGL) || (G.lrec.ucsize == Z64FLGL))
+ {
+ if (offset+ 8 > ef_len)
+ return PK_ERR;
+
+ G.crec.ucsize = G.lrec.ucsize = makeint64(offset + ef_buf);
+ offset += 8;
}
- 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.csize == Z64FLGL) || (G.lrec.csize == Z64FLGL))
+ {
+ if (offset+ 8 > ef_len)
+ return PK_ERR;
+
+ G.csize = G.crec.csize = G.lrec.csize = makeint64(offset + ef_buf);
+ offset += 8;
}
- if (G.crec.relative_offset_local_header == 0xffffffff){
+
+ if (G.crec.relative_offset_local_header == Z64FLGL)
+ {
+ if (offset+ 8 > ef_len)
+ return PK_ERR;
+
G.crec.relative_offset_local_header = makeint64(offset + ef_buf);
- offset += sizeof(G.crec.relative_offset_local_header);
+ offset += 8;
}
- if (G.crec.disk_number_start == 0xffff){
+
+ if (G.crec.disk_number_start == Z64FLGS)
+ {
+ if (offset+ 4 > ef_len)
+ return PK_ERR;
+
G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf);
- offset += sizeof(G.crec.disk_number_start);
+ offset += 4;
}
+#if 0
+ break; /* Expect only one EF_PKSZ64 block. */
+#endif /* 0 */
}
- /* Skip this extra field block */
+ /* Skip this extra field block. */
ef_buf += (eb_len + EB_HEADSIZE);
ef_len -= (eb_len + EB_HEADSIZE);
}
@@ -2867,10 +2902,13 @@
break;
case EF_IZUNIX2:
- if (have_new_type_eb == 0) {
- flags &= ~0x0ff; /* ignore any previous IZUNIX field */
+ if (have_new_type_eb == 0) { /* (< 1) */
have_new_type_eb = 1;
}
+ if (have_new_type_eb <= 1) {
+ /* Ignore any prior (EF_IZUNIX/EF_PKUNIX) UID/GID. */
+ flags &= 0x0ff;
+ }
#ifdef IZ_HAVE_UXUIDGID
if (have_new_type_eb > 1)
break; /* IZUNIX3 overrides IZUNIX2 e.f. block ! */
@@ -2886,6 +2924,8 @@
/* new 3rd generation Unix ef */
have_new_type_eb = 2;
+ /* Ignore any prior EF_IZUNIX/EF_PKUNIX/EF_IZUNIX2 UID/GID. */
+ flags &= 0x0ff;
/*
Version 1 byte version of this extra field, currently 1
UIDSize 1 byte Size of UID field
@@ -2895,9 +2935,9 @@
*/
#ifdef IZ_HAVE_UXUIDGID
- if (eb_len >= EB_UX3_MINLEN
- && z_uidgid != NULL
- && (*((EB_HEADSIZE + 0) + ef_buf) == 1)
+ if ((eb_len >= EB_UX3_MINLEN)
+ && (z_uidgid != NULL)
+ && ((*((EB_HEADSIZE + 0) + ef_buf) == 1)))
/* only know about version 1 */
{
uch uid_size;
@@ -2906,13 +2946,11 @@
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])
+ uid_size, &z_uidgid[0])
&&
read_ux3_value((EB_HEADSIZE + uid_size + 3) + ef_buf,
- gid_size, z_uidgid[1]) )
+ gid_size, &z_uidgid[1]) )
{
flags |= EB_UX2_VALID; /* signal success */
}
diff -Naur a/process.c.orig b/process.c.orig
--- a/process.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/process.c.orig 2019-12-02 00:32:11.309743527 +0000
@@ -0,0 +1,3123 @@
+/*
+ Copyright (c) 1990-2014 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
+
+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 */
+
+#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 error_in_archive;
+
+} /* 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.
+
+ 2014-12-05 SMS.
+ Added checks to ensure that enough data are available before calling
+ makeint64() or makelong(). Replaced various sizeof() values with
+ simple ("4" or "8") constants. (The Zip64 structures do not depend
+ on our variable sizes.) Error handling is crude, but we should now
+ stay within the buffer.
+ ---------------------------------------------------------------------------*/
+
+#define Z64FLGS 0xffff
+#define Z64FLGL 0xffffffff
+
+ 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))
+ {
+ /* Extra block length exceeds remaining extra field length. */
+ 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 == Z64FLGL) || (G.lrec.ucsize == Z64FLGL))
+ {
+ if (offset+ 8 > ef_len)
+ return PK_ERR;
+
+ G.crec.ucsize = G.lrec.ucsize = makeint64(offset + ef_buf);
+ offset += 8;
+ }
+
+ if ((G.crec.csize == Z64FLGL) || (G.lrec.csize == Z64FLGL))
+ {
+ if (offset+ 8 > ef_len)
+ return PK_ERR;
+
+ G.csize = G.crec.csize = G.lrec.csize = makeint64(offset + ef_buf);
+ offset += 8;
+ }
+
+ if (G.crec.relative_offset_local_header == Z64FLGL)
+ {
+ if (offset+ 8 > ef_len)
+ return PK_ERR;
+
+ G.crec.relative_offset_local_header = makeint64(offset + ef_buf);
+ offset += 8;
+ }
+
+ if (G.crec.disk_number_start == Z64FLGS)
+ {
+ if (offset+ 4 > ef_len)
+ return PK_ERR;
+
+ G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf);
+ offset += 4;
+ }
+#if 0
+ break; /* Expect only one EF_PKSZ64 block. */
+#endif /* 0 */
+ }
+
+ /* 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) */
diff -Naur a/unix/configure b/unix/configure
--- a/unix/configure 2009-04-16 20:25:12.000000000 +0100
+++ b/unix/configure 2019-12-01 23:54:04.330597267 +0000
@@ -17,7 +17,7 @@
IZ_BZIP2=${3}
CFLAGS="${CFLAGS} -I. -DUNIX"
LFLAGS1=""
-LFLAGS2="-s"
+LFLAGS2="${LFLAGS2}"
LN="ln -s"
CFLAGS_OPT=''
@@ -640,7 +640,24 @@
D_USE_BZ2="-DUSE_BZIP2"
L_BZ2="${BZLF} -lbz2"
else
- echo "-- bzip2 sources not found - no bzip2 support"
+ echo " Check if OS already has bzip2 library installed"
+ cat > conftest.c << _EOF_
+#include "bzlib.h"
+int main()
+{
+ bz_stream strm;
+ BZ2_bzCompressEnd(&strm);
+ return 0;
+}
+_EOF_
+ $CC $CFLAGS -o conftest conftest.c -lbz2 > /dev/null 2>/dev/null
+ if test $? -eq 0; then
+ echo "-- OS supports bzip2 - linking in bzip2"
+ D_USE_BZ2="-DUSE_BZIP2"
+ L_BZ2="${BZLF} -lbz2"
+ else
+ echo "-- Either bzlib.h or libbz2.a not found - no bzip2"
+ fi
fi
fi
diff -Naur a/unix/unix.c b/unix/unix.c
--- a/unix/unix.c 2009-01-23 23:31:26.000000000 +0000
+++ b/unix/unix.c 2019-12-02 01:49:39.894641004 +0000
@@ -30,6 +30,9 @@
#define UNZIP_INTERNAL
#include "unzip.h"
+#include <iconv.h>
+#include <langinfo.h>
+
#ifdef SCO_XENIX
# define SYSNDIR
#else /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
@@ -1096,10 +1099,41 @@
#ifndef MTS
/****************************/
+/* Function CloseError() */
+/***************************/
+
+int CloseError(__G)
+ __GDEF
+{
+ int errval = PK_OK;
+
+ if (fclose(G.outfile) < 0) {
+ switch (errno) {
+ case ENOSPC:
+ /* Do we need this on fileio.c? */
+ Info(slide, 0x4a1, ((char *)slide, "%s: write error (disk full?). Continue? (y/n/^C) ",
+ FnFilter1(G.filename)));
+ fgets(G.answerbuf, 9, stdin);
+ if (*G.answerbuf == 'y') /* stop writing to this file */
+ G.disk_full = 1; /* pass to next */
+ else
+ G.disk_full = 2; /* no: exit program */
+
+ errval = PK_DISK;
+ break;
+
+ default:
+ errval = PK_WARN;
+ }
+ }
+ return errval;
+} /* End of CloseError() */
+
+/****************************/
/* Function close_outfile() */
/****************************/
-void close_outfile(__G) /* GRR: change to return PK-style warning level */
+int close_outfile(__G)
__GDEF
{
union {
@@ -1108,6 +1142,7 @@
} zt;
ulg z_uidgid[2];
int have_uidgid_flg;
+ int errval = PK_OK;
have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid);
@@ -1141,16 +1176,16 @@
Info(slide, 0x201, ((char *)slide,
"warning: symbolic link (%s) failed: mem alloc overflow\n",
FnFilter1(G.filename)));
- fclose(G.outfile);
- return;
+ errval = CloseError(G.outfile, G.filename);
+ return errval ? errval : PK_WARN;
}
if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) {
Info(slide, 0x201, ((char *)slide,
"warning: symbolic link (%s) failed: no mem\n",
FnFilter1(G.filename)));
- fclose(G.outfile);
- return;
+ errval = CloseError(G.outfile, G.filename);
+ return errval ? errval : PK_WARN;
}
slnk_entry->next = NULL;
slnk_entry->targetlen = ucsize;
@@ -1174,10 +1209,10 @@
"warning: symbolic link (%s) failed\n",
FnFilter1(G.filename)));
free(slnk_entry);
- fclose(G.outfile);
- return;
+ errval = CloseError(G.outfile, G.filename);
+ return errval ? errval : PK_WARN;
}
- fclose(G.outfile); /* close "link" file for good... */
+ errval = CloseError(G.outfile, G.filename); /* close "link" file for good... */
slnk_entry->target[ucsize] = '\0';
if (QCOND2)
Info(slide, 0, ((char *)slide, "-> %s ",
@@ -1188,7 +1223,7 @@
else
G.slink_head = slnk_entry;
G.slink_last = slnk_entry;
- return;
+ return errval;
}
#endif /* SYMLINKS */
@@ -1201,7 +1236,7 @@
#endif
#if (defined(NO_FCHOWN))
- fclose(G.outfile);
+ errval = CloseError(G.outfile, G.filename);
#endif
/* if -X option was specified and we have UID/GID info, restore it */
@@ -1227,7 +1262,7 @@
}
#if (!defined(NO_FCHOWN) && defined(NO_FCHMOD))
- fclose(G.outfile);
+ errval = CloseError(G.outfile, G.filename);
#endif
#if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD))
@@ -1239,7 +1274,7 @@
if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr)))
perror("fchmod (file attributes) error");
- fclose(G.outfile);
+ errval = CloseError(G.outfile, G.filename);
#endif /* !NO_FCHOWN && !NO_FCHMOD */
/* skip restoring time stamps on user's request */
@@ -1267,6 +1302,7 @@
#endif
#endif /* NO_FCHOWN || NO_FCHMOD */
+ return errval;
} /* end function close_outfile() */
#endif /* !MTS */
@@ -1874,3 +1910,104 @@
}
}
#endif /* QLZIP */
+
+
+typedef struct {
+ char *local_charset;
+ char *archive_charset;
+} CHARSET_MAP;
+
+/* A mapping of local <-> archive charsets used by default to convert filenames
+ * of DOS/Windows Zip archives. Currently very basic. */
+static CHARSET_MAP dos_charset_map[] = {
+ { "ANSI_X3.4-1968", "CP850" },
+ { "ISO-8859-1", "CP850" },
+ { "CP1252", "CP850" },
+ { "UTF-8", "CP866" },
+ { "KOI8-R", "CP866" },
+ { "KOI8-U", "CP866" },
+ { "ISO-8859-5", "CP866" }
+};
+
+char OEM_CP[MAX_CP_NAME] = "";
+char ISO_CP[MAX_CP_NAME] = "";
+
+/* Try to guess the default value of OEM_CP based on the current locale.
+ * ISO_CP is left alone for now. */
+void init_conversion_charsets()
+{
+ const char *local_charset;
+ int i;
+
+ /* Make a guess only if OEM_CP not already set. */
+ if(*OEM_CP == '\0') {
+ local_charset = nl_langinfo(CODESET);
+ for(i = 0; i < sizeof(dos_charset_map)/sizeof(CHARSET_MAP); i++)
+ if(!strcasecmp(local_charset, dos_charset_map[i].local_charset)) {
+ strncpy(OEM_CP, dos_charset_map[i].archive_charset,
+ MAX_CP_NAME - 1);
+
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
+ break;
+ }
+ }
+}
+
+/* Convert a string from one encoding to the current locale using iconv().
+ * Be as non-intrusive as possible. If error is encountered during covertion
+ * just leave the string intact. */
+static void charset_to_intern(char *string, char *from_charset)
+{
+ iconv_t cd;
+ char *s,*d, *buf;
+ size_t slen, dlen, buflen;
+ const char *local_charset;
+
+ if(*from_charset == '\0')
+ return;
+
+ buf = NULL;
+ local_charset = nl_langinfo(CODESET);
+
+ if((cd = iconv_open(local_charset, from_charset)) == (iconv_t)-1)
+ return;
+
+ slen = strlen(string);
+ s = string;
+
+ /* Make sure OUTBUFSIZ + 1 never ends up smaller than FILNAMSIZ
+ * as this function also gets called with G.outbuf in fileio.c
+ */
+ buflen = FILNAMSIZ;
+ if (OUTBUFSIZ + 1 < FILNAMSIZ)
+ {
+ buflen = OUTBUFSIZ + 1;
+ }
+
+ d = buf = malloc(buflen);
+ if(!d)
+ goto cleanup;
+
+ bzero(buf,buflen);
+ dlen = buflen - 1;
+
+ if(iconv(cd, &s, &slen, &d, &dlen) == (size_t)-1)
+ goto cleanup;
+ strncpy(string, buf, buflen);
+
+ cleanup:
+ free(buf);
+ iconv_close(cd);
+}
+
+/* Convert a string from OEM_CP to the current locale charset. */
+inline void oem_intern(char *string)
+{
+ charset_to_intern(string, OEM_CP);
+}
+
+/* Convert a string from ISO_CP to the current locale charset. */
+inline void iso_intern(char *string)
+{
+ charset_to_intern(string, ISO_CP);
+}
diff -Naur a/unix/unix.c.orig b/unix/unix.c.orig
--- a/unix/unix.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/unix/unix.c.orig 2019-12-01 23:53:08.675401658 +0000
@@ -0,0 +1,1909 @@
+/*
+ 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
+*/
+/*---------------------------------------------------------------------------
+
+ unix.c
+
+ Unix-specific routines for use with Info-ZIP's UnZip 5.41 and later.
+
+ Contains: readdir()
+ do_wild() <-- generic enough to put in fileio.c?
+ mapattr()
+ mapname()
+ checkdir()
+ mkdir()
+ close_outfile()
+ defer_dir_attribs()
+ set_direc_attribs()
+ stamp_file()
+ version()
+
+ ---------------------------------------------------------------------------*/
+
+
+#define UNZIP_INTERNAL
+#include "unzip.h"
+
+#ifdef SCO_XENIX
+# define SYSNDIR
+#else /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
+# if defined(__convexc__) || defined(SYSV) || defined(CRAY) || defined(BSD4_4)
+# define DIRENT
+# endif
+#endif
+#if defined(_AIX) || defined(__mpexl)
+# define DIRENT
+#endif
+#ifdef COHERENT
+# if defined(_I386) || (defined(__COHERENT__) && (__COHERENT__ >= 0x420))
+# define DIRENT
+# endif
+#endif
+
+#ifdef _POSIX_VERSION
+# ifndef DIRENT
+# define DIRENT
+# endif
+#endif
+
+#ifdef DIRENT
+# include <dirent.h>
+#else
+# ifdef SYSV
+# ifdef SYSNDIR
+# include <sys/ndir.h>
+# else
+# include <ndir.h>
+# endif
+# else /* !SYSV */
+# ifndef NO_SYSDIR
+# include <sys/dir.h>
+# endif
+# endif /* ?SYSV */
+# ifndef dirent
+# define dirent direct
+# endif
+#endif /* ?DIRENT */
+
+#ifdef SET_DIR_ATTRIB
+typedef struct uxdirattr { /* struct for holding unix style directory */
+ struct uxdirattr *next; /* info until can be sorted and set at end */
+ char *fn; /* filename of directory */
+ union {
+ iztimes t3; /* mtime, atime, ctime */
+ ztimbuf t2; /* modtime, actime */
+ } u;
+ unsigned perms; /* same as min_info.file_attr */
+ int have_uidgid; /* flag */
+ ulg uidgid[2];
+ char fnbuf[1]; /* buffer stub for directory name */
+} uxdirattr;
+#define UxAtt(d) ((uxdirattr *)d) /* typecast shortcut */
+#endif /* SET_DIR_ATTRIB */
+
+#ifdef ACORN_FTYPE_NFS
+/* Acorn bits for NFS filetyping */
+typedef struct {
+ uch ID[2];
+ uch size[2];
+ uch ID_2[4];
+ uch loadaddr[4];
+ uch execaddr[4];
+ uch attr[4];
+} RO_extra_block;
+
+#endif /* ACORN_FTYPE_NFS */
+
+/* static int created_dir; */ /* used in mapname(), checkdir() */
+/* static int renamed_fullpath; */ /* ditto */
+
+static unsigned filtattr OF((__GPRO__ unsigned perms));
+
+
+/*****************************/
+/* Strings used multiple */
+/* times in unix.c */
+/*****************************/
+
+#ifndef MTS
+/* messages of code for setting file/directory attributes */
+static ZCONST char CannotSetItemUidGid[] =
+ "warning: cannot set UID %lu and/or GID %lu for %s\n %s\n";
+static ZCONST char CannotSetUidGid[] =
+ " (warning) cannot set UID %lu and/or GID %lu\n %s";
+static ZCONST char CannotSetItemTimestamps[] =
+ "warning: cannot set modif./access times for %s\n %s\n";
+static ZCONST char CannotSetTimestamps[] =
+ " (warning) cannot set modif./access times\n %s";
+#endif /* !MTS */
+
+
+#ifndef SFX
+#ifdef NO_DIR /* for AT&T 3B1 */
+
+#define opendir(path) fopen(path,"r")
+#define closedir(dir) fclose(dir)
+typedef FILE DIR;
+typedef struct zdir {
+ FILE *dirhandle;
+ struct dirent *entry;
+} DIR
+DIR *opendir OF((ZCONST char *dirspec));
+void closedir OF((DIR *dirp));
+struct dirent *readdir OF((DIR *dirp));
+
+DIR *opendir(dirspec)
+ ZCONST char *dirspec;
+{
+ DIR *dirp;
+
+ if ((dirp = malloc(sizeof(DIR)) != NULL) {
+ if ((dirp->dirhandle = fopen(dirspec, "r")) == NULL) {
+ free(dirp);
+ dirp = NULL;
+ }
+ }
+ return dirp;
+}
+
+void closedir(dirp)
+ DIR *dirp;
+{
+ fclose(dirp->dirhandle);
+ free(dirp);
+}
+
+/*
+ * Apparently originally by Rich Salz.
+ * Cleaned up and modified by James W. Birdsall.
+ */
+struct dirent *readdir(dirp)
+ DIR *dirp;
+{
+
+ if (dirp == NULL)
+ return NULL;
+
+ for (;;)
+ if (fread(&(dirp->entry), sizeof (struct dirent), 1,
+ dirp->dirhandle) == 0)
+ return (struct dirent *)NULL;
+ else if ((dirp->entry).d_ino)
+ return &(dirp->entry);
+
+} /* end function readdir() */
+
+#endif /* NO_DIR */
+
+
+/**********************/
+/* Function do_wild() */ /* for porting: dir separator; match(ignore_case) */
+/**********************/
+
+char *do_wild(__G__ wildspec)
+ __GDEF
+ ZCONST char *wildspec; /* only used first time on a given dir */
+{
+/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in unxcfg.h:
+ static DIR *wild_dir = (DIR *)NULL;
+ static ZCONST char *wildname;
+ static char *dirname, matchname[FILNAMSIZ];
+ static int notfirstcall=FALSE, have_dirname, dirnamelen;
+*/
+ struct dirent *file;
+
+ /* Even when we're just returning wildspec, we *always* do so in
+ * matchname[]--calling routine is allowed to append four characters
+ * to the returned string, and wildspec may be a pointer to argv[].
+ */
+ if (!G.notfirstcall) { /* first call: must initialize everything */
+ G.notfirstcall = TRUE;
+
+ if (!iswild(wildspec)) {
+ strncpy(G.matchname, wildspec, FILNAMSIZ);
+ G.matchname[FILNAMSIZ-1] = '\0';
+ G.have_dirname = FALSE;
+ G.wild_dir = NULL;
+ return G.matchname;
+ }
+
+ /* break the wildspec into a directory part and a wildcard filename */
+ if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL) {
+ G.dirname = ".";
+ G.dirnamelen = 1;
+ G.have_dirname = FALSE;
+ G.wildname = wildspec;
+ } else {
+ ++G.wildname; /* point at character after '/' */
+ G.dirnamelen = G.wildname - wildspec;
+ if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == (char *)NULL) {
+ Info(slide, 0x201, ((char *)slide,
+ "warning: cannot allocate wildcard buffers\n"));
+ strncpy(G.matchname, wildspec, FILNAMSIZ);
+ G.matchname[FILNAMSIZ-1] = '\0';
+ return G.matchname; /* but maybe filespec was not a wildcard */
+ }
+ strncpy(G.dirname, wildspec, G.dirnamelen);
+ G.dirname[G.dirnamelen] = '\0'; /* terminate for strcpy below */
+ G.have_dirname = TRUE;
+ }
+
+ if ((G.wild_dir = (zvoid *)opendir(G.dirname)) != (zvoid *)NULL) {
+ while ((file = readdir((DIR *)G.wild_dir)) !=
+ (struct dirent *)NULL) {
+ Trace((stderr, "do_wild: readdir returns %s\n",
+ FnFilter1(file->d_name)));
+ if (file->d_name[0] == '.' && G.wildname[0] != '.')
+ continue; /* Unix: '*' and '?' do not match leading dot */
+ if (match(file->d_name, G.wildname, 0 WISEP) &&/*0=case sens.*/
+ /* skip "." and ".." directory entries */
+ strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {
+ Trace((stderr, "do_wild: match() succeeds\n"));
+ if (G.have_dirname) {
+ strcpy(G.matchname, G.dirname);
+ strcpy(G.matchname+G.dirnamelen, file->d_name);
+ } else
+ strcpy(G.matchname, file->d_name);
+ return G.matchname;
+ }
+ }
+ /* if we get to here directory is exhausted, so close it */
+ closedir((DIR *)G.wild_dir);
+ G.wild_dir = (zvoid *)NULL;
+ }
+ Trace((stderr, "do_wild: opendir(%s) returns NULL\n",
+ FnFilter1(G.dirname)));
+
+ /* return the raw wildspec in case that works (e.g., directory not
+ * searchable, but filespec was not wild and file is readable) */
+ strncpy(G.matchname, wildspec, FILNAMSIZ);
+ G.matchname[FILNAMSIZ-1] = '\0';
+ return G.matchname;
+ }
+
+ /* last time through, might have failed opendir but returned raw wildspec */
+ if ((DIR *)G.wild_dir == (DIR *)NULL) {
+ G.notfirstcall = FALSE; /* nothing left--reset for new wildspec */
+ if (G.have_dirname)
+ free(G.dirname);
+ return (char *)NULL;
+ }
+
+ /* If we've gotten this far, we've read and matched at least one entry
+ * successfully (in a previous call), so dirname has been copied into
+ * matchname already.
+ */
+ while ((file = readdir((DIR *)G.wild_dir)) != (struct dirent *)NULL) {
+ Trace((stderr, "do_wild: readdir returns %s\n",
+ FnFilter1(file->d_name)));
+ if (file->d_name[0] == '.' && G.wildname[0] != '.')
+ continue; /* Unix: '*' and '?' do not match leading dot */
+ if (match(file->d_name, G.wildname, 0 WISEP)) { /* 0 == case sens. */
+ Trace((stderr, "do_wild: match() succeeds\n"));
+ if (G.have_dirname) {
+ /* strcpy(G.matchname, G.dirname); */
+ strcpy(G.matchname+G.dirnamelen, file->d_name);
+ } else
+ strcpy(G.matchname, file->d_name);
+ return G.matchname;
+ }
+ }
+
+ closedir((DIR *)G.wild_dir); /* at least one entry read; nothing left */
+ G.wild_dir = (zvoid *)NULL;
+ G.notfirstcall = FALSE; /* reset for new wildspec */
+ if (G.have_dirname)
+ free(G.dirname);
+ return (char *)NULL;
+
+} /* end function do_wild() */
+
+#endif /* !SFX */
+
+
+
+
+#ifndef S_ISUID
+# define S_ISUID 0004000 /* set user id on execution */
+#endif
+#ifndef S_ISGID
+# define S_ISGID 0002000 /* set group id on execution */
+#endif
+#ifndef S_ISVTX
+# define S_ISVTX 0001000 /* save swapped text even after use */
+#endif
+
+/************************/
+/* Function filtattr() */
+/************************/
+/* This is used to clear or keep the SUID and SGID bits on file permissions.
+ * It's possible that a file in an archive could have one of these bits set
+ * and, unknown to the person unzipping, could allow others to execute the
+ * file as the user or group. The new option -K bypasses this check.
+ */
+
+static unsigned filtattr(__G__ perms)
+ __GDEF
+ unsigned perms;
+{
+ /* keep setuid/setgid/tacky perms? */
+ if (!uO.K_flag)
+ perms &= ~(S_ISUID | S_ISGID | S_ISVTX);
+
+ return (0xffff & perms);
+} /* end function filtattr() */
+
+
+
+
+
+/**********************/
+/* Function mapattr() */
+/**********************/
+
+int mapattr(__G)
+ __GDEF
+{
+ int r;
+ ulg tmp = G.crec.external_file_attributes;
+
+ G.pInfo->file_attr = 0;
+ /* initialized to 0 for check in "default" branch below... */
+
+ switch (G.pInfo->hostnum) {
+ case AMIGA_:
+ tmp = (unsigned)(tmp>>17 & 7); /* Amiga RWE bits */
+ G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
+ break;
+ case THEOS_:
+ tmp &= 0xF1FFFFFFL;
+ if ((tmp & 0xF0000000L) != 0x40000000L)
+ tmp &= 0x01FFFFFFL; /* not a dir, mask all ftype bits */
+ else
+ tmp &= 0x41FFFFFFL; /* leave directory bit as set */
+ /* fall through! */
+ case UNIX_:
+ case VMS_:
+ case ACORN_:
+ case ATARI_:
+ case ATHEOS_:
+ case BEOS_:
+ case QDOS_:
+ case TANDEM_:
+ r = FALSE;
+ G.pInfo->file_attr = (unsigned)(tmp >> 16);
+ if (G.pInfo->file_attr == 0 && G.extra_field) {
+ /* Some (non-Info-ZIP) implementations of Zip for Unix and
+ * VMS (and probably others ??) leave 0 in the upper 16-bit
+ * part of the external_file_attributes field. Instead, they
+ * store file permission attributes in some extra field.
+ * As a work-around, we search for the presence of one of
+ * these extra fields and fall back to the MSDOS compatible
+ * part of external_file_attributes if one of the known
+ * e.f. types has been detected.
+ * Later, we might implement extraction of the permission
+ * bits from the VMS extra field. But for now, the work-around
+ * should be sufficient to provide "readable" extracted files.
+ * (For ASI Unix e.f., an experimental remap of the e.f.
+ * mode value IS already provided!)
+ */
+ ush ebID;
+ unsigned ebLen;
+ uch *ef = G.extra_field;
+ unsigned ef_len = G.crec.extra_field_length;
+
+ while (!r && ef_len >= EB_HEADSIZE) {
+ ebID = makeword(ef);
+ ebLen = (unsigned)makeword(ef+EB_LEN);
+ if (ebLen > (ef_len - EB_HEADSIZE))
+ /* discoverd some e.f. inconsistency! */
+ break;
+ switch (ebID) {
+ case EF_ASIUNIX:
+ if (ebLen >= (EB_ASI_MODE+2)) {
+ G.pInfo->file_attr =
+ (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
+ /* force stop of loop: */
+ ef_len = (ebLen + EB_HEADSIZE);
+ break;
+ }
+ /* else: fall through! */
+ case EF_PKVMS:
+ /* "found nondecypherable e.f. with perm. attr" */
+ r = TRUE;
+ default:
+ break;
+ }
+ ef_len -= (ebLen + EB_HEADSIZE);
+ ef += (ebLen + EB_HEADSIZE);
+ }
+ }
+ if (!r) {
+#ifdef SYMLINKS
+ /* Check if the file is a (POSIX-compatible) symbolic link.
+ * We restrict symlink support to those "made-by" hosts that
+ * are known to support symbolic links.
+ */
+ G.pInfo->symlink = S_ISLNK(G.pInfo->file_attr) &&
+ SYMLINK_HOST(G.pInfo->hostnum);
+#endif
+ return 0;
+ }
+ /* fall through! */
+ /* all remaining cases: expand MSDOS read-only bit into write perms */
+ case FS_FAT_:
+ /* PKWARE's PKZip for Unix marks entries as FS_FAT_, but stores the
+ * Unix attributes in the upper 16 bits of the external attributes
+ * field, just like Info-ZIP's Zip for Unix. We try to use that
+ * value, after a check for consistency with the MSDOS attribute
+ * bits (see below).
+ */
+ G.pInfo->file_attr = (unsigned)(tmp >> 16);
+ /* fall through! */
+ case FS_HPFS_:
+ case FS_NTFS_:
+ case MAC_:
+ case TOPS20_:
+ default:
+ /* Ensure that DOS subdir bit is set when the entry's name ends
+ * in a '/'. Some third-party Zip programs fail to set the subdir
+ * bit for directory entries.
+ */
+ if ((tmp & 0x10) == 0) {
+ extent fnlen = strlen(G.filename);
+ if (fnlen > 0 && G.filename[fnlen-1] == '/')
+ tmp |= 0x10;
+ }
+ /* read-only bit --> write perms; subdir bit --> dir exec bit */
+ tmp = !(tmp & 1) << 1 | (tmp & 0x10) >> 4;
+ if ((G.pInfo->file_attr & 0700) == (unsigned)(0400 | tmp<<6)) {
+ /* keep previous G.pInfo->file_attr setting, when its "owner"
+ * part appears to be consistent with DOS attribute flags!
+ */
+#ifdef SYMLINKS
+ /* Entries "made by FS_FAT_" could have been zipped on a
+ * system that supports POSIX-style symbolic links.
+ */
+ G.pInfo->symlink = S_ISLNK(G.pInfo->file_attr) &&
+ (G.pInfo->hostnum == FS_FAT_);
+#endif
+ return 0;
+ }
+ G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
+ break;
+ } /* end switch (host-OS-created-by) */
+
+ /* for originating systems with no concept of "group," "other," "system": */
+ umask( (int)(tmp=umask(0)) ); /* apply mask to expanded r/w(/x) perms */
+ G.pInfo->file_attr &= ~tmp;
+
+ return 0;
+
+} /* end function mapattr() */
+
+
+
+
+
+/************************/
+/* Function mapname() */
+/************************/
+
+int mapname(__G__ renamed)
+ __GDEF
+ int renamed;
+/*
+ * returns:
+ * MPN_OK - no problem detected
+ * MPN_INF_TRUNC - caution (truncated filename)
+ * MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
+ * MPN_ERR_SKIP - error -> skip entry
+ * MPN_ERR_TOOLONG - error -> path is too long
+ * MPN_NOMEM - error (memory allocation failed) -> skip entry
+ * [also MPN_VOL_LABEL, MPN_CREATED_DIR]
+ */
+{
+ char pathcomp[FILNAMSIZ]; /* path-component buffer */
+ char *pp, *cp=(char *)NULL; /* character pointers */
+ char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
+#ifdef ACORN_FTYPE_NFS
+ char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */
+ RO_extra_block *ef_spark; /* pointer Acorn FTYPE ef block */
+#endif
+ int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
+ int error = MPN_OK;
+ register unsigned workch; /* hold the character being tested */
+
+
+/*---------------------------------------------------------------------------
+ Initialize various pointers and counters and stuff.
+ ---------------------------------------------------------------------------*/
+
+ if (G.pInfo->vollabel)
+ return MPN_VOL_LABEL; /* can't set disk volume labels in Unix */
+
+ /* can create path as long as not just freshening, or if user told us */
+ G.create_dirs = (!uO.fflag || renamed);
+
+ G.created_dir = FALSE; /* not yet */
+
+ /* user gave full pathname: don't prepend rootpath */
+ G.renamed_fullpath = (renamed && (*G.filename == '/'));
+
+ if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
+ return MPN_NOMEM; /* initialize path buffer, unless no memory */
+
+ *pathcomp = '\0'; /* initialize translation buffer */
+ pp = pathcomp; /* point to translation buffer */
+ if (uO.jflag) /* junking directories */
+ cp = (char *)strrchr(G.filename, '/');
+ if (cp == (char *)NULL) /* no '/' or not junking dirs */
+ cp = G.filename; /* point to internal zipfile-member pathname */
+ else
+ ++cp; /* point to start of last component of path */
+
+/*---------------------------------------------------------------------------
+ Begin main loop through characters in filename.
+ ---------------------------------------------------------------------------*/
+
+ while ((workch = (uch)*cp++) != 0) {
+
+ switch (workch) {
+ case '/': /* can assume -j flag not given */
+ *pp = '\0';
+ if (strcmp(pathcomp, ".") == 0) {
+ /* don't bother appending "./" to the path */
+ *pathcomp = '\0';
+ } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
+ /* "../" dir traversal detected, skip over it */
+ *pathcomp = '\0';
+ killed_ddot = TRUE; /* set "show message" flag */
+ }
+ /* when path component is not empty, append it now */
+ if (*pathcomp != '\0' &&
+ ((error = checkdir(__G__ pathcomp, APPEND_DIR))
+ & MPN_MASK) > MPN_INF_TRUNC)
+ return error;
+ pp = pathcomp; /* reset conversion buffer for next piece */
+ lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
+ break;
+
+#ifdef __CYGWIN__ /* Cygwin runs on Win32, apply FAT/NTFS filename rules */
+ case ':': /* drive spec not stored, so no colon allowed */
+ case '\\': /* '\\' may come as normal filename char (not */
+ case '<': /* dir sep char!) from unix-like file system */
+ case '>': /* no redirection symbols allowed either */
+ case '|': /* no pipe signs allowed */
+ case '"': /* no double quotes allowed */
+ case '?': /* no wildcards allowed */
+ case '*':
+ *pp++ = '_'; /* these rules apply equally to FAT and NTFS */
+ break;
+#endif
+
+ case ';': /* VMS version (or DEC-20 attrib?) */
+ lastsemi = pp;
+ *pp++ = ';'; /* keep for now; remove VMS ";##" */
+ break; /* later, if requested */
+
+#ifdef ACORN_FTYPE_NFS
+ case ',': /* NFS filetype extension */
+ lastcomma = pp;
+ *pp++ = ','; /* keep for now; may need to remove */
+ break; /* later, if requested */
+#endif
+
+#ifdef MTS
+ case ' ': /* change spaces to underscore under */
+ *pp++ = '_'; /* MTS; leave as spaces under Unix */
+ break;
+#endif
+
+ default:
+ /* disable control character filter when requested,
+ * else allow 8-bit characters (e.g. UTF-8) in filenames:
+ */
+ if (uO.cflxflag ||
+ (isprint(workch) || (128 <= workch && workch <= 254)))
+ *pp++ = (char)workch;
+ } /* end switch */
+
+ } /* end while loop */
+
+ /* Show warning when stripping insecure "parent dir" path components */
+ if (killed_ddot && QCOND2) {
+ Info(slide, 0, ((char *)slide,
+ "warning: skipped \"../\" path component(s) in %s\n",
+ FnFilter1(G.filename)));
+ if (!(error & ~MPN_MASK))
+ error = (error & MPN_MASK) | PK_WARN;
+ }
+
+/*---------------------------------------------------------------------------
+ Report if directory was created (and no file to create: filename ended
+ in '/'), check name to be sure it exists, and combine path and name be-
+ fore exiting.
+ ---------------------------------------------------------------------------*/
+
+ if (G.filename[strlen(G.filename) - 1] == '/') {
+ checkdir(__G__ G.filename, GETPATH);
+ if (G.created_dir) {
+ if (QCOND2) {
+ Info(slide, 0, ((char *)slide, " creating: %s\n",
+ FnFilter1(G.filename)));
+ }
+#ifndef NO_CHMOD
+ /* Filter out security-relevant attributes bits. */
+ G.pInfo->file_attr = filtattr(__G__ G.pInfo->file_attr);
+ /* When extracting non-UNIX directories or when extracting
+ * without UID/GID restoration or SGID preservation, any
+ * SGID flag inherited from the parent directory should be
+ * maintained to allow files extracted into this new folder
+ * to inherit the GID setting from the parent directory.
+ */
+ if (G.pInfo->hostnum != UNIX_ || !(uO.X_flag || uO.K_flag)) {
+ /* preserve SGID bit when inherited from parent dir */
+ if (!SSTAT(G.filename, &G.statbuf)) {
+ G.pInfo->file_attr |= G.statbuf.st_mode & S_ISGID;
+ } else {
+ perror("Could not read directory attributes");
+ }
+ }
+
+ /* set approx. dir perms (make sure can still read/write in dir) */
+ if (chmod(G.filename, G.pInfo->file_attr | 0700))
+ perror("chmod (directory attributes) error");
+#endif
+ /* set dir time (note trailing '/') */
+ return (error & ~MPN_MASK) | MPN_CREATED_DIR;
+ }
+ /* dir existed already; don't look for data to extract */
+ return (error & ~MPN_MASK) | MPN_INF_SKIP;
+ }
+
+ *pp = '\0'; /* done with pathcomp: terminate it */
+
+ /* if not saving them, remove VMS version numbers (appended ";###") */
+ if (!uO.V_flag && lastsemi) {
+ pp = lastsemi + 1;
+ while (isdigit((uch)(*pp)))
+ ++pp;
+ if (*pp == '\0') /* only digits between ';' and end: nuke */
+ *lastsemi = '\0';
+ }
+
+ /* On UNIX (and compatible systems), "." and ".." are reserved for
+ * directory navigation and cannot be used as regular file names.
+ * These reserved one-dot and two-dot names are mapped to "_" and "__".
+ */
+ if (strcmp(pathcomp, ".") == 0)
+ *pathcomp = '_';
+ else if (strcmp(pathcomp, "..") == 0)
+ strcpy(pathcomp, "__");
+
+#ifdef ACORN_FTYPE_NFS
+ /* translate Acorn filetype information if asked to do so */
+ if (uO.acorn_nfs_ext &&
+ (ef_spark = (RO_extra_block *)
+ getRISCOSexfield(G.extra_field, G.lrec.extra_field_length))
+ != (RO_extra_block *)NULL)
+ {
+ /* file *must* have a RISC OS extra field */
+ long ft = (long)makelong(ef_spark->loadaddr);
+ /*32-bit*/
+ if (lastcomma) {
+ pp = lastcomma + 1;
+ while (isxdigit((uch)(*pp))) ++pp;
+ if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
+ }
+ if ((ft & 1<<31)==0) ft=0x000FFD00;
+ sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
+ }
+#endif /* ACORN_FTYPE_NFS */
+
+ if (*pathcomp == '\0') {
+ Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n",
+ FnFilter1(G.filename)));
+ return (error & ~MPN_MASK) | MPN_ERR_SKIP;
+ }
+
+ checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
+ checkdir(__G__ G.filename, GETPATH);
+
+ return error;
+
+} /* end function mapname() */
+
+
+
+
+#if 0 /*========== NOTES ==========*/
+
+ extract-to dir: a:path/
+ buildpath: path1/path2/ ... (NULL-terminated)
+ pathcomp: filename
+
+ mapname():
+ loop over chars in zipfile member name
+ checkdir(path component, COMPONENT | CREATEDIR) --> map as required?
+ (d:/tmp/unzip/) (disk:[tmp.unzip.)
+ (d:/tmp/unzip/jj/) (disk:[tmp.unzip.jj.)
+ (d:/tmp/unzip/jj/temp/) (disk:[tmp.unzip.jj.temp.)
+ finally add filename itself and check for existence? (could use with rename)
+ (d:/tmp/unzip/jj/temp/msg.outdir) (disk:[tmp.unzip.jj.temp]msg.outdir)
+ checkdir(name, GETPATH) --> copy path to name and free space
+
+#endif /* 0 */
+
+
+
+
+/***********************/
+/* Function checkdir() */
+/***********************/
+
+int checkdir(__G__ pathcomp, flag)
+ __GDEF
+ char *pathcomp;
+ int flag;
+/*
+ * returns:
+ * MPN_OK - no problem detected
+ * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
+ * MPN_INF_SKIP - path doesn't exist, not allowed to create
+ * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
+ * exists and is not a directory, but is supposed to be
+ * MPN_ERR_TOOLONG - path is too long
+ * MPN_NOMEM - can't allocate memory for filename buffers
+ */
+{
+ /* static int rootlen = 0; */ /* length of rootpath */
+ /* static char *rootpath; */ /* user's "extract-to" directory */
+ /* static char *buildpath; */ /* full path (so far) to extracted file */
+ /* static char *end; */ /* pointer to end of buildpath ('\0') */
+
+# define FN_MASK 7
+# define FUNCTION (flag & FN_MASK)
+
+
+
+/*---------------------------------------------------------------------------
+ APPEND_DIR: append the path component to the path being built and check
+ for its existence. If doesn't exist and we are creating directories, do
+ so for this one; else signal success or error as appropriate.
+ ---------------------------------------------------------------------------*/
+
+ if (FUNCTION == APPEND_DIR) {
+ int too_long = FALSE;
+#ifdef SHORT_NAMES
+ char *old_end = end;
+#endif
+
+ Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
+ while ((*G.end = *pathcomp++) != '\0')
+ ++G.end;
+#ifdef SHORT_NAMES /* path components restricted to 14 chars, typically */
+ if ((G.end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
+ *(G.end = old_end + FILENAME_MAX) = '\0';
+#endif
+
+ /* GRR: could do better check, see if overrunning buffer as we go:
+ * check end-buildpath after each append, set warning variable if
+ * within 20 of FILNAMSIZ; then if var set, do careful check when
+ * appending. Clear variable when begin new path. */
+
+ /* next check: need to append '/', at least one-char name, '\0' */
+ if ((G.end-G.buildpath) > FILNAMSIZ-3)
+ too_long = TRUE; /* check if extracting dir? */
+ if (SSTAT(G.buildpath, &G.statbuf)) { /* path doesn't exist */
+ if (!G.create_dirs) { /* told not to create (freshening) */
+ free(G.buildpath);
+ return MPN_INF_SKIP; /* path doesn't exist: nothing to do */
+ }
+ if (too_long) {
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: path too long: %s\n",
+ FnFilter1(G.buildpath)));
+ free(G.buildpath);
+ /* no room for filenames: fatal */
+ return MPN_ERR_TOOLONG;
+ }
+ if (mkdir(G.buildpath, 0777) == -1) { /* create the directory */
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: cannot create %s\n\
+ %s\n\
+ unable to process %s.\n",
+ FnFilter2(G.buildpath),
+ strerror(errno),
+ FnFilter1(G.filename)));
+ free(G.buildpath);
+ /* path didn't exist, tried to create, failed */
+ return MPN_ERR_SKIP;
+ }
+ G.created_dir = TRUE;
+ } else if (!S_ISDIR(G.statbuf.st_mode)) {
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: %s exists but is not directory\n\
+ unable to process %s.\n",
+ FnFilter2(G.buildpath), FnFilter1(G.filename)));
+ free(G.buildpath);
+ /* path existed but wasn't dir */
+ return MPN_ERR_SKIP;
+ }
+ if (too_long) {
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: path too long: %s\n", FnFilter1(G.buildpath)));
+ free(G.buildpath);
+ /* no room for filenames: fatal */
+ return MPN_ERR_TOOLONG;
+ }
+ *G.end++ = '/';
+ *G.end = '\0';
+ Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
+ return MPN_OK;
+
+ } /* end if (FUNCTION == APPEND_DIR) */
+
+/*---------------------------------------------------------------------------
+ GETPATH: copy full path to the string pointed at by pathcomp, and free
+ G.buildpath.
+ ---------------------------------------------------------------------------*/
+
+ if (FUNCTION == GETPATH) {
+ strcpy(pathcomp, G.buildpath);
+ Trace((stderr, "getting and freeing path [%s]\n",
+ FnFilter1(pathcomp)));
+ free(G.buildpath);
+ G.buildpath = G.end = (char *)NULL;
+ return MPN_OK;
+ }
+
+/*---------------------------------------------------------------------------
+ APPEND_NAME: assume the path component is the filename; append it and
+ return without checking for existence.
+ ---------------------------------------------------------------------------*/
+
+ if (FUNCTION == APPEND_NAME) {
+#ifdef SHORT_NAMES
+ char *old_end = end;
+#endif
+
+ Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
+ while ((*G.end = *pathcomp++) != '\0') {
+ ++G.end;
+#ifdef SHORT_NAMES /* truncate name at 14 characters, typically */
+ if ((G.end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
+ *(G.end = old_end + FILENAME_MAX) = '\0';
+#endif
+ if ((G.end-G.buildpath) >= FILNAMSIZ) {
+ *--G.end = '\0';
+ Info(slide, 0x201, ((char *)slide,
+ "checkdir warning: path too long; truncating\n\
+ %s\n -> %s\n",
+ FnFilter1(G.filename), FnFilter2(G.buildpath)));
+ return MPN_INF_TRUNC; /* filename truncated */
+ }
+ }
+ Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
+ /* could check for existence here, prompt for new name... */
+ return MPN_OK;
+ }
+
+/*---------------------------------------------------------------------------
+ INIT: allocate and initialize buffer space for the file currently being
+ extracted. If file was renamed with an absolute path, don't prepend the
+ extract-to path.
+ ---------------------------------------------------------------------------*/
+
+/* GRR: for VMS and TOPS-20, add up to 13 to strlen */
+
+ if (FUNCTION == INIT) {
+ Trace((stderr, "initializing buildpath to "));
+#ifdef ACORN_FTYPE_NFS
+ if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+
+ (uO.acorn_nfs_ext ? 5 : 1)))
+#else
+ if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1))
+#endif
+ == (char *)NULL)
+ return MPN_NOMEM;
+ if ((G.rootlen > 0) && !G.renamed_fullpath) {
+ strcpy(G.buildpath, G.rootpath);
+ G.end = G.buildpath + G.rootlen;
+ } else {
+ *G.buildpath = '\0';
+ G.end = G.buildpath;
+ }
+ Trace((stderr, "[%s]\n", FnFilter1(G.buildpath)));
+ return MPN_OK;
+ }
+
+/*---------------------------------------------------------------------------
+ ROOT: if appropriate, store the path in rootpath and create it if
+ necessary; else assume it's a zipfile member and return. This path
+ segment gets used in extracting all members from every zipfile specified
+ on the command line.
+ ---------------------------------------------------------------------------*/
+
+#if (!defined(SFX) || defined(SFX_EXDIR))
+ if (FUNCTION == ROOT) {
+ Trace((stderr, "initializing root path to [%s]\n",
+ FnFilter1(pathcomp)));
+ if (pathcomp == (char *)NULL) {
+ G.rootlen = 0;
+ return MPN_OK;
+ }
+ if (G.rootlen > 0) /* rootpath was already set, nothing to do */
+ return MPN_OK;
+ if ((G.rootlen = strlen(pathcomp)) > 0) {
+ char *tmproot;
+
+ if ((tmproot = (char *)malloc(G.rootlen+2)) == (char *)NULL) {
+ G.rootlen = 0;
+ return MPN_NOMEM;
+ }
+ strcpy(tmproot, pathcomp);
+ if (tmproot[G.rootlen-1] == '/') {
+ tmproot[--G.rootlen] = '\0';
+ }
+ if (G.rootlen > 0 && (SSTAT(tmproot, &G.statbuf) ||
+ !S_ISDIR(G.statbuf.st_mode)))
+ { /* path does not exist */
+ if (!G.create_dirs /* || iswild(tmproot) */ ) {
+ free(tmproot);
+ G.rootlen = 0;
+ /* skip (or treat as stored file) */
+ return MPN_INF_SKIP;
+ }
+ /* create the directory (could add loop here scanning tmproot
+ * to create more than one level, but why really necessary?) */
+ if (mkdir(tmproot, 0777) == -1) {
+ Info(slide, 1, ((char *)slide,
+ "checkdir: cannot create extraction directory: %s\n\
+ %s\n",
+ FnFilter1(tmproot), strerror(errno)));
+ free(tmproot);
+ G.rootlen = 0;
+ /* path didn't exist, tried to create, and failed: */
+ /* file exists, or 2+ subdir levels required */
+ return MPN_ERR_SKIP;
+ }
+ }
+ tmproot[G.rootlen++] = '/';
+ tmproot[G.rootlen] = '\0';
+ if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
+ free(tmproot);
+ G.rootlen = 0;
+ return MPN_NOMEM;
+ }
+ Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
+ }
+ return MPN_OK;
+ }
+#endif /* !SFX || SFX_EXDIR */
+
+/*---------------------------------------------------------------------------
+ END: free rootpath, immediately prior to program exit.
+ ---------------------------------------------------------------------------*/
+
+ if (FUNCTION == END) {
+ Trace((stderr, "freeing rootpath\n"));
+ if (G.rootlen > 0) {
+ free(G.rootpath);
+ G.rootlen = 0;
+ }
+ return MPN_OK;
+ }
+
+ return MPN_INVALID; /* should never reach */
+
+} /* end function checkdir() */
+
+
+
+
+
+#ifdef NO_MKDIR
+
+/********************/
+/* Function mkdir() */
+/********************/
+
+int mkdir(path, mode)
+ ZCONST char *path;
+ int mode; /* ignored */
+/*
+ * returns: 0 - successful
+ * -1 - failed (errno not set, however)
+ */
+{
+ char command[FILNAMSIZ+40]; /* buffer for system() call */
+
+ /* GRR 930416: added single quotes around path to avoid bug with
+ * creating directories with ampersands in name; not yet tested */
+ sprintf(command, "IFS=\" \t\n\" /bin/mkdir '%s' 2>/dev/null", path);
+ if (system(command))
+ return -1;
+ return 0;
+}
+
+#endif /* NO_MKDIR */
+
+
+
+
+#if (!defined(MTS) || defined(SET_DIR_ATTRIB))
+static int get_extattribs OF((__GPRO__ iztimes *pzt, ulg z_uidgid[2]));
+
+static int get_extattribs(__G__ pzt, z_uidgid)
+ __GDEF
+ iztimes *pzt;
+ ulg z_uidgid[2];
+{
+/*---------------------------------------------------------------------------
+ Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
+ time: adjust base year from 1980 to 1970, do usual conversions from
+ yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
+ light savings time differences. If we have a Unix extra field, however,
+ we're laughing: both mtime and atime are ours. On the other hand, we
+ then have to check for restoration of UID/GID.
+ ---------------------------------------------------------------------------*/
+ int have_uidgid_flg;
+ unsigned eb_izux_flg;
+
+ eb_izux_flg = (G.extra_field ? ef_scan_for_izux(G.extra_field,
+ G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
+#ifdef IZ_CHECK_TZ
+ (G.tz_is_valid ? pzt : NULL),
+#else
+ pzt,
+#endif
+ z_uidgid) : 0);
+ if (eb_izux_flg & EB_UT_FL_MTIME) {
+ TTrace((stderr, "\nget_extattribs: Unix e.f. modif. time = %ld\n",
+ pzt->mtime));
+ } else {
+ pzt->mtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
+ }
+ if (eb_izux_flg & EB_UT_FL_ATIME) {
+ TTrace((stderr, "get_extattribs: Unix e.f. access time = %ld\n",
+ pzt->atime));
+ } else {
+ pzt->atime = pzt->mtime;
+ TTrace((stderr, "\nget_extattribs: modification/access times = %ld\n",
+ pzt->mtime));
+ }
+
+ /* if -X option was specified and we have UID/GID info, restore it */
+ have_uidgid_flg =
+#ifdef RESTORE_UIDGID
+ (uO.X_flag && (eb_izux_flg & EB_UX2_VALID));
+#else
+ 0;
+#endif
+ return have_uidgid_flg;
+}
+#endif /* !MTS || SET_DIR_ATTRIB */
+
+
+
+#ifndef MTS
+
+/****************************/
+/* Function CloseError() */
+/***************************/
+
+int CloseError(__G)
+ __GDEF
+{
+ int errval = PK_OK;
+
+ if (fclose(G.outfile) < 0) {
+ switch (errno) {
+ case ENOSPC:
+ /* Do we need this on fileio.c? */
+ Info(slide, 0x4a1, ((char *)slide, "%s: write error (disk full?). Continue? (y/n/^C) ",
+ FnFilter1(G.filename)));
+ fgets(G.answerbuf, 9, stdin);
+ if (*G.answerbuf == 'y') /* stop writing to this file */
+ G.disk_full = 1; /* pass to next */
+ else
+ G.disk_full = 2; /* no: exit program */
+
+ errval = PK_DISK;
+ break;
+
+ default:
+ errval = PK_WARN;
+ }
+ }
+ return errval;
+} /* End of CloseError() */
+
+/****************************/
+/* Function close_outfile() */
+/****************************/
+
+int close_outfile(__G)
+ __GDEF
+{
+ union {
+ iztimes t3; /* mtime, atime, ctime */
+ ztimbuf t2; /* modtime, actime */
+ } zt;
+ ulg z_uidgid[2];
+ int have_uidgid_flg;
+ int errval = PK_OK;
+
+ have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid);
+
+/*---------------------------------------------------------------------------
+ If symbolic links are supported, allocate storage for a symlink control
+ structure, put the uncompressed "data" and other required info in it, and
+ add the structure to the "deferred symlinks" chain. Since we know it's a
+ symbolic link to start with, we shouldn't have to worry about overflowing
+ unsigned ints with unsigned longs.
+ ---------------------------------------------------------------------------*/
+
+#ifdef SYMLINKS
+ if (G.symlnk) {
+ extent ucsize = (extent)G.lrec.ucsize;
+# ifdef SET_SYMLINK_ATTRIBS
+ extent attribsize = sizeof(unsigned) +
+ (have_uidgid_flg ? sizeof(z_uidgid) : 0);
+# else
+ extent attribsize = 0;
+# endif
+ /* size of the symlink entry is the sum of
+ * (struct size (includes 1st '\0') + 1 additional trailing '\0'),
+ * system specific attribute data size (might be 0),
+ * and the lengths of name and link target.
+ */
+ extent slnk_entrysize = (sizeof(slinkentry) + 1) + attribsize +
+ ucsize + strlen(G.filename);
+ slinkentry *slnk_entry;
+
+ if (slnk_entrysize < ucsize) {
+ Info(slide, 0x201, ((char *)slide,
+ "warning: symbolic link (%s) failed: mem alloc overflow\n",
+ FnFilter1(G.filename)));
+ errval = CloseError(G.outfile, G.filename);
+ return errval ? errval : PK_WARN;
+ }
+
+ if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) {
+ Info(slide, 0x201, ((char *)slide,
+ "warning: symbolic link (%s) failed: no mem\n",
+ FnFilter1(G.filename)));
+ errval = CloseError(G.outfile, G.filename);
+ return errval ? errval : PK_WARN;
+ }
+ slnk_entry->next = NULL;
+ slnk_entry->targetlen = ucsize;
+ slnk_entry->attriblen = attribsize;
+# ifdef SET_SYMLINK_ATTRIBS
+ memcpy(slnk_entry->buf, &(G.pInfo->file_attr),
+ sizeof(unsigned));
+ if (have_uidgid_flg)
+ memcpy(slnk_entry->buf + 4, z_uidgid, sizeof(z_uidgid));
+# endif
+ slnk_entry->target = slnk_entry->buf + slnk_entry->attriblen;
+ slnk_entry->fname = slnk_entry->target + ucsize + 1;
+ strcpy(slnk_entry->fname, G.filename);
+
+ /* move back to the start of the file to re-read the "link data" */
+ rewind(G.outfile);
+
+ if (fread(slnk_entry->target, 1, ucsize, G.outfile) != ucsize)
+ {
+ Info(slide, 0x201, ((char *)slide,
+ "warning: symbolic link (%s) failed\n",
+ FnFilter1(G.filename)));
+ free(slnk_entry);
+ errval = CloseError(G.outfile, G.filename);
+ return errval ? errval : PK_WARN;
+ }
+ errval = CloseError(G.outfile, G.filename); /* close "link" file for good... */
+ slnk_entry->target[ucsize] = '\0';
+ if (QCOND2)
+ Info(slide, 0, ((char *)slide, "-> %s ",
+ FnFilter1(slnk_entry->target)));
+ /* add this symlink record to the list of deferred symlinks */
+ if (G.slink_last != NULL)
+ G.slink_last->next = slnk_entry;
+ else
+ G.slink_head = slnk_entry;
+ G.slink_last = slnk_entry;
+ return errval;
+ }
+#endif /* SYMLINKS */
+
+#ifdef QLZIP
+ if (G.extra_field) {
+ static void qlfix OF((__GPRO__ uch *ef_ptr, unsigned ef_len));
+
+ qlfix(__G__ G.extra_field, G.lrec.extra_field_length);
+ }
+#endif
+
+#if (defined(NO_FCHOWN))
+ errval = CloseError(G.outfile, G.filename);
+#endif
+
+ /* if -X option was specified and we have UID/GID info, restore it */
+ if (have_uidgid_flg
+ /* check that both uid and gid values fit into their data sizes */
+ && ((ulg)(uid_t)(z_uidgid[0]) == z_uidgid[0])
+ && ((ulg)(gid_t)(z_uidgid[1]) == z_uidgid[1])) {
+ TTrace((stderr, "close_outfile: restoring Unix UID/GID info\n"));
+#if (defined(NO_FCHOWN))
+ if (chown(G.filename, (uid_t)z_uidgid[0], (gid_t)z_uidgid[1]))
+#else
+ if (fchown(fileno(G.outfile), (uid_t)z_uidgid[0], (gid_t)z_uidgid[1]))
+#endif
+ {
+ if (uO.qflag)
+ Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
+ z_uidgid[0], z_uidgid[1], FnFilter1(G.filename),
+ strerror(errno)));
+ else
+ Info(slide, 0x201, ((char *)slide, CannotSetUidGid,
+ z_uidgid[0], z_uidgid[1], strerror(errno)));
+ }
+ }
+
+#if (!defined(NO_FCHOWN) && defined(NO_FCHMOD))
+ errval = CloseError(G.outfile, G.filename);
+#endif
+
+#if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD))
+/*---------------------------------------------------------------------------
+ Change the file permissions from default ones to those stored in the
+ zipfile.
+ ---------------------------------------------------------------------------*/
+
+ if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr)))
+ perror("fchmod (file attributes) error");
+
+ errval = CloseError(G.outfile, G.filename);
+#endif /* !NO_FCHOWN && !NO_FCHMOD */
+
+ /* skip restoring time stamps on user's request */
+ if (uO.D_flag <= 1) {
+ /* set the file's access and modification times */
+ if (utime(G.filename, &(zt.t2))) {
+ if (uO.qflag)
+ Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps,
+ FnFilter1(G.filename), strerror(errno)));
+ else
+ Info(slide, 0x201, ((char *)slide, CannotSetTimestamps,
+ strerror(errno)));
+ }
+ }
+
+#if (defined(NO_FCHOWN) || defined(NO_FCHMOD))
+/*---------------------------------------------------------------------------
+ Change the file permissions from default ones to those stored in the
+ zipfile.
+ ---------------------------------------------------------------------------*/
+
+#ifndef NO_CHMOD
+ if (chmod(G.filename, filtattr(__G__ G.pInfo->file_attr)))
+ perror("chmod (file attributes) error");
+#endif
+#endif /* NO_FCHOWN || NO_FCHMOD */
+
+ return errval;
+} /* end function close_outfile() */
+
+#endif /* !MTS */
+
+
+#if (defined(SYMLINKS) && defined(SET_SYMLINK_ATTRIBS))
+int set_symlnk_attribs(__G__ slnk_entry)
+ __GDEF
+ slinkentry *slnk_entry;
+{
+ if (slnk_entry->attriblen > 0) {
+# if (!defined(NO_LCHOWN))
+ if (slnk_entry->attriblen > sizeof(unsigned)) {
+ ulg *z_uidgid_p = (zvoid *)(slnk_entry->buf + sizeof(unsigned));
+ /* check that both uid and gid values fit into their data sizes */
+ if (((ulg)(uid_t)(z_uidgid_p[0]) == z_uidgid_p[0]) &&
+ ((ulg)(gid_t)(z_uidgid_p[1]) == z_uidgid_p[1])) {
+ TTrace((stderr,
+ "set_symlnk_attribs: restoring Unix UID/GID info for\n\
+ %s\n",
+ FnFilter1(slnk_entry->fname)));
+ if (lchown(slnk_entry->fname,
+ (uid_t)z_uidgid_p[0], (gid_t)z_uidgid_p[1]))
+ {
+ Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
+ z_uidgid_p[0], z_uidgid_p[1], FnFilter1(slnk_entry->fname),
+ strerror(errno)));
+ }
+ }
+ }
+# endif /* !NO_LCHOWN */
+# if (!defined(NO_LCHMOD))
+ TTrace((stderr,
+ "set_symlnk_attribs: restoring Unix attributes for\n %s\n",
+ FnFilter1(slnk_entry->fname)));
+ if (lchmod(slnk_entry->fname,
+ filtattr(__G__ *(unsigned *)(zvoid *)slnk_entry->buf)))
+ perror("lchmod (file attributes) error");
+# endif /* !NO_LCHMOD */
+ }
+ /* currently, no error propagation... */
+ return PK_OK;
+} /* end function set_symlnk_attribs() */
+#endif /* SYMLINKS && SET_SYMLINK_ATTRIBS */
+
+
+#ifdef SET_DIR_ATTRIB
+/* messages of code for setting directory attributes */
+# ifndef NO_CHMOD
+ static ZCONST char DirlistChmodFailed[] =
+ "warning: cannot set permissions for %s\n %s\n";
+# endif
+
+
+int defer_dir_attribs(__G__ pd)
+ __GDEF
+ direntry **pd;
+{
+ uxdirattr *d_entry;
+
+ d_entry = (uxdirattr *)malloc(sizeof(uxdirattr) + strlen(G.filename));
+ *pd = (direntry *)d_entry;
+ if (d_entry == (uxdirattr *)NULL) {
+ return PK_MEM;
+ }
+ d_entry->fn = d_entry->fnbuf;
+ strcpy(d_entry->fn, G.filename);
+
+ d_entry->perms = G.pInfo->file_attr;
+
+ d_entry->have_uidgid = get_extattribs(__G__ &(d_entry->u.t3),
+ d_entry->uidgid);
+ return PK_OK;
+} /* end function defer_dir_attribs() */
+
+
+int set_direc_attribs(__G__ d)
+ __GDEF
+ direntry *d;
+{
+ int errval = PK_OK;
+
+ if (UxAtt(d)->have_uidgid &&
+ /* check that both uid and gid values fit into their data sizes */
+ ((ulg)(uid_t)(UxAtt(d)->uidgid[0]) == UxAtt(d)->uidgid[0]) &&
+ ((ulg)(gid_t)(UxAtt(d)->uidgid[1]) == UxAtt(d)->uidgid[1]) &&
+ chown(UxAtt(d)->fn, (uid_t)UxAtt(d)->uidgid[0],
+ (gid_t)UxAtt(d)->uidgid[1]))
+ {
+ Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
+ UxAtt(d)->uidgid[0], UxAtt(d)->uidgid[1], FnFilter1(d->fn),
+ strerror(errno)));
+ if (!errval)
+ errval = PK_WARN;
+ }
+ /* Skip restoring directory time stamps on user' request. */
+ if (uO.D_flag <= 0) {
+ /* restore directory timestamps */
+ if (utime(d->fn, &UxAtt(d)->u.t2)) {
+ Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps,
+ FnFilter1(d->fn), strerror(errno)));
+ if (!errval)
+ errval = PK_WARN;
+ }
+ }
+#ifndef NO_CHMOD
+ if (chmod(d->fn, UxAtt(d)->perms)) {
+ Info(slide, 0x201, ((char *)slide, DirlistChmodFailed,
+ FnFilter1(d->fn), strerror(errno)));
+ if (!errval)
+ errval = PK_WARN;
+ }
+#endif /* !NO_CHMOD */
+ return errval;
+} /* end function set_direc_attribs() */
+
+#endif /* SET_DIR_ATTRIB */
+
+
+
+
+#ifdef TIMESTAMP
+
+/***************************/
+/* Function stamp_file() */
+/***************************/
+
+int stamp_file(fname, modtime)
+ ZCONST char *fname;
+ time_t modtime;
+{
+ ztimbuf tp;
+
+ tp.modtime = tp.actime = modtime;
+ return (utime(fname, &tp));
+
+} /* end function stamp_file() */
+
+#endif /* TIMESTAMP */
+
+
+
+
+#ifndef SFX
+
+/************************/
+/* Function version() */
+/************************/
+
+void version(__G)
+ __GDEF
+{
+#if (defined(__GNUC__) && defined(NX_CURRENT_COMPILER_RELEASE))
+ char cc_namebuf[40];
+ char cc_versbuf[40];
+#else
+#if (defined(__SUNPRO_C))
+ char cc_versbuf[17];
+#else
+#if (defined(__HP_cc) || defined(__IBMC__))
+ char cc_versbuf[25];
+#else
+#if (defined(__DECC_VER))
+ char cc_versbuf[17];
+ int cc_verstyp;
+#else
+#if (defined(CRAY) && defined(_RELEASE))
+ char cc_versbuf[40];
+#endif /* (CRAY && _RELEASE) */
+#endif /* __DECC_VER */
+#endif /* __HP_cc || __IBMC__ */
+#endif /* __SUNPRO_C */
+#endif /* (__GNUC__ && NX_CURRENT_COMPILER_RELEASE) */
+
+#if ((defined(CRAY) || defined(cray)) && defined(_UNICOS))
+ char os_namebuf[40];
+#else
+#if defined(__NetBSD__)
+ char os_namebuf[40];
+#endif
+#endif
+
+ /* Pyramid, NeXT have problems with huge macro expansion, too: no Info() */
+ sprintf((char *)slide, LoadFarString(CompiledWith),
+
+#ifdef __GNUC__
+# ifdef NX_CURRENT_COMPILER_RELEASE
+ (sprintf(cc_namebuf, "NeXT DevKit %d.%02d ",
+ NX_CURRENT_COMPILER_RELEASE/100, NX_CURRENT_COMPILER_RELEASE%100),
+ cc_namebuf),
+ (strlen(__VERSION__) > 8)? "(gcc)" :
+ (sprintf(cc_versbuf, "(gcc %s)", __VERSION__), cc_versbuf),
+# else
+ "gcc ", __VERSION__,
+# endif
+#else
+#if defined(__SUNPRO_C)
+ "Sun C ", (sprintf(cc_versbuf, "version %x", __SUNPRO_C), cc_versbuf),
+#else
+#if (defined(__HP_cc))
+ "HP C ",
+ (((__HP_cc% 100) == 0) ?
+ (sprintf(cc_versbuf, "version A.%02d.%02d",
+ (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100))) :
+ (sprintf(cc_versbuf, "version A.%02d.%02d.%02d",
+ (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100), (__HP_cc% 100))),
+ cc_versbuf),
+#else
+#if (defined(__DECC_VER))
+ "DEC C ",
+ (sprintf(cc_versbuf, "%c%d.%d-%03d",
+ ((cc_verstyp = (__DECC_VER / 10000) % 10) == 6 ? 'T' :
+ (cc_verstyp == 8 ? 'S' : 'V')),
+ __DECC_VER / 10000000,
+ (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000),
+ cc_versbuf),
+#else
+#if defined(CRAY) && defined(_RELEASE)
+ "cc ", (sprintf(cc_versbuf, "version %d", _RELEASE), cc_versbuf),
+#else
+#ifdef __IBMC__
+ "IBM C ",
+ (sprintf(cc_versbuf, "version %d.%d.%d",
+ (__IBMC__ / 100), ((__IBMC__ / 10) % 10), (__IBMC__ % 10)),
+ cc_versbuf),
+#else
+#ifdef __VERSION__
+# ifndef IZ_CC_NAME
+# define IZ_CC_NAME "cc "
+# endif
+ IZ_CC_NAME, __VERSION__
+#else
+# ifndef IZ_CC_NAME
+# define IZ_CC_NAME "cc"
+# endif
+ IZ_CC_NAME, "",
+#endif /* ?__VERSION__ */
+#endif /* ?__IBMC__ */
+#endif /* ?(CRAY && _RELEASE) */
+#endif /* ?__DECC_VER */
+#endif /* ?__HP_cc */
+#endif /* ?__SUNPRO_C */
+#endif /* ?__GNUC__ */
+
+#ifndef IZ_OS_NAME
+# define IZ_OS_NAME "Unix"
+#endif
+ IZ_OS_NAME,
+
+#if defined(sgi) || defined(__sgi)
+ " (Silicon Graphics IRIX)",
+#else
+#ifdef sun
+# ifdef sparc
+# ifdef __SVR4
+ " (Sun SPARC/Solaris)",
+# else /* may or may not be SunOS */
+ " (Sun SPARC)",
+# endif
+# else
+# if defined(sun386) || defined(i386)
+ " (Sun 386i)",
+# else
+# if defined(mc68020) || defined(__mc68020__)
+ " (Sun 3)",
+# else /* mc68010 or mc68000: Sun 2 or earlier */
+ " (Sun 2)",
+# endif
+# endif
+# endif
+#else
+#ifdef __hpux
+ " (HP-UX)",
+#else
+#ifdef __osf__
+ " (DEC OSF/1)",
+#else
+#ifdef _AIX
+ " (IBM AIX)",
+#else
+#ifdef aiws
+ " (IBM RT/AIX)",
+#else
+#if defined(CRAY) || defined(cray)
+# ifdef _UNICOS
+ (sprintf(os_namebuf, " (Cray UNICOS release %d)", _UNICOS), os_namebuf),
+# else
+ " (Cray UNICOS)",
+# endif
+#else
+#if defined(uts) || defined(UTS)
+ " (Amdahl UTS)",
+#else
+#ifdef NeXT
+# ifdef mc68000
+ " (NeXTStep/black)",
+# else
+ " (NeXTStep for Intel)",
+# endif
+#else /* the next dozen or so are somewhat order-dependent */
+#ifdef LINUX
+# ifdef __ELF__
+ " (Linux ELF)",
+# else
+ " (Linux a.out)",
+# endif
+#else
+#ifdef MINIX
+ " (Minix)",
+#else
+#ifdef M_UNIX
+ " (SCO Unix)",
+#else
+#ifdef M_XENIX
+ " (SCO Xenix)",
+#else
+#ifdef __NetBSD__
+# ifdef NetBSD0_8
+ (sprintf(os_namebuf, " (NetBSD 0.8%c)", (char)(NetBSD0_8 - 1 + 'A')),
+ os_namebuf),
+# else
+# ifdef NetBSD0_9
+ (sprintf(os_namebuf, " (NetBSD 0.9%c)", (char)(NetBSD0_9 - 1 + 'A')),
+ os_namebuf),
+# else
+# ifdef NetBSD1_0
+ (sprintf(os_namebuf, " (NetBSD 1.0%c)", (char)(NetBSD1_0 - 1 + 'A')),
+ os_namebuf),
+# else
+ (BSD4_4 == 0.5)? " (NetBSD before 0.9)" : " (NetBSD 1.1 or later)",
+# endif
+# endif
+# endif
+#else
+#ifdef __FreeBSD__
+ (BSD4_4 == 0.5)? " (FreeBSD 1.x)" : " (FreeBSD 2.0 or later)",
+#else
+#ifdef __bsdi__
+ (BSD4_4 == 0.5)? " (BSD/386 1.0)" : " (BSD/386 1.1 or later)",
+#else
+#ifdef __386BSD__
+ (BSD4_4 == 1)? " (386BSD, post-4.4 release)" : " (386BSD)",
+#else
+#ifdef __CYGWIN__
+ " (Cygwin)",
+#else
+#if defined(i686) || defined(__i686) || defined(__i686__)
+ " (Intel 686)",
+#else
+#if defined(i586) || defined(__i586) || defined(__i586__)
+ " (Intel 586)",
+#else
+#if defined(i486) || defined(__i486) || defined(__i486__)
+ " (Intel 486)",
+#else
+#if defined(i386) || defined(__i386) || defined(__i386__)
+ " (Intel 386)",
+#else
+#ifdef pyr
+ " (Pyramid)",
+#else
+#ifdef ultrix
+# ifdef mips
+ " (DEC/MIPS)",
+# else
+# ifdef vax
+ " (DEC/VAX)",
+# else /* __alpha? */
+ " (DEC/Alpha)",
+# endif
+# endif
+#else
+#ifdef gould
+ " (Gould)",
+#else
+#ifdef MTS
+ " (MTS)",
+#else
+#ifdef __convexc__
+ " (Convex)",
+#else
+#ifdef __QNX__
+ " (QNX 4)",
+#else
+#ifdef __QNXNTO__
+ " (QNX Neutrino)",
+#else
+#ifdef Lynx
+ " (LynxOS)",
+#else
+#ifdef __APPLE__
+# ifdef __i386__
+ " Mac OS X Intel i32",
+# else
+# ifdef __ppc__
+ " Mac OS X PowerPC",
+# else
+# ifdef __ppc64__
+ " Mac OS X PowerPC64",
+# else
+ " Mac OS X",
+# endif /* __ppc64__ */
+# endif /* __ppc__ */
+# endif /* __i386__ */
+#else
+ "",
+#endif /* Apple */
+#endif /* Lynx */
+#endif /* QNX Neutrino */
+#endif /* QNX 4 */
+#endif /* Convex */
+#endif /* MTS */
+#endif /* Gould */
+#endif /* DEC */
+#endif /* Pyramid */
+#endif /* 386 */
+#endif /* 486 */
+#endif /* 586 */
+#endif /* 686 */
+#endif /* Cygwin */
+#endif /* 386BSD */
+#endif /* BSDI BSD/386 */
+#endif /* NetBSD */
+#endif /* FreeBSD */
+#endif /* SCO Xenix */
+#endif /* SCO Unix */
+#endif /* Minix */
+#endif /* Linux */
+#endif /* NeXT */
+#endif /* Amdahl */
+#endif /* Cray */
+#endif /* RT/AIX */
+#endif /* AIX */
+#endif /* OSF/1 */
+#endif /* HP-UX */
+#endif /* Sun */
+#endif /* SGI */
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+ (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
+
+} /* end function version() */
+
+#endif /* !SFX */
+
+
+
+
+#ifdef QLZIP
+
+struct qdirect {
+ long d_length __attribute__ ((packed)); /* file length */
+ unsigned char d_access __attribute__ ((packed)); /* file access type */
+ unsigned char d_type __attribute__ ((packed)); /* file type */
+ long d_datalen __attribute__ ((packed)); /* data length */
+ long d_reserved __attribute__ ((packed));/* Unused */
+ short d_szname __attribute__ ((packed)); /* size of name */
+ char d_name[36] __attribute__ ((packed));/* name area */
+ long d_update __attribute__ ((packed)); /* last update */
+ long d_refdate __attribute__ ((packed));
+ long d_backup __attribute__ ((packed)); /* EOD */
+};
+
+#define LONGID "QDOS02"
+#define EXTRALEN (sizeof(struct qdirect) + 8)
+#define JBLONGID "QZHD"
+#define JBEXTRALEN (sizeof(jbextra) - 4 * sizeof(char))
+
+typedef struct {
+ char eb_header[4] __attribute__ ((packed)); /* place_holder */
+ char longid[8] __attribute__ ((packed));
+ struct qdirect header __attribute__ ((packed));
+} qdosextra;
+
+typedef struct {
+ char eb_header[4]; /* place_holder */
+ char longid[4];
+ struct qdirect header;
+} jbextra;
+
+
+
+/* The following two functions SH() and LG() convert big-endian short
+ * and long numbers into native byte order. They are some kind of
+ * counterpart to the generic UnZip's makeword() and makelong() functions.
+ */
+static ush SH(ush val)
+{
+ uch swapbuf[2];
+
+ swapbuf[1] = (uch)(val & 0xff);
+ swapbuf[0] = (uch)(val >> 8);
+ return (*(ush *)swapbuf);
+}
+
+
+
+static ulg LG(ulg val)
+{
+ /* convert the big-endian unsigned long number `val' to the machine
+ * dependent representation
+ */
+ ush swapbuf[2];
+
+ swapbuf[1] = SH((ush)(val & 0xffff));
+ swapbuf[0] = SH((ush)(val >> 16));
+ return (*(ulg *)swapbuf);
+}
+
+
+
+static void qlfix(__G__ ef_ptr, ef_len)
+ __GDEF
+ uch *ef_ptr;
+ unsigned ef_len;
+{
+ while (ef_len >= EB_HEADSIZE)
+ {
+ unsigned eb_id = makeword(EB_ID + ef_ptr);
+ unsigned eb_len = makeword(EB_LEN + ef_ptr);
+
+ if (eb_len > (ef_len - EB_HEADSIZE)) {
+ /* discovered some extra field inconsistency! */
+ Trace((stderr,
+ "qlfix: block length %u > rest ef_size %u\n", eb_len,
+ ef_len - EB_HEADSIZE));
+ break;
+ }
+
+ switch (eb_id) {
+ case EF_QDOS:
+ {
+ struct _ntc_
+ {
+ long id;
+ long dlen;
+ } ntc;
+ long dlen = 0;
+
+ qdosextra *extra = (qdosextra *)ef_ptr;
+ jbextra *jbp = (jbextra *)ef_ptr;
+
+ if (!strncmp(extra->longid, LONGID, strlen(LONGID)))
+ {
+ if (eb_len != EXTRALEN)
+ if (uO.qflag)
+ Info(slide, 0x201, ((char *)slide,
+ "warning: invalid length in Qdos field for %s\n",
+ FnFilter1(G.filename)));
+ else
+ Info(slide, 0x201, ((char *)slide,
+ "warning: invalid length in Qdos field"));
+
+ if (extra->header.d_type)
+ {
+ dlen = extra->header.d_datalen;
+ }
+ }
+
+ if (!strncmp(jbp->longid, JBLONGID, strlen(JBLONGID)))
+ {
+ if (eb_len != JBEXTRALEN)
+ if (uO.qflag)
+ Info(slide, 0x201, ((char *)slide,
+ "warning: invalid length in QZ field for %s\n",
+ FnFilter1(G.filename)));
+ else
+ Info(slide, 0x201, ((char *)slide,
+ "warning: invalid length in QZ field"));
+ if (jbp->header.d_type)
+ {
+ dlen = jbp->header.d_datalen;
+ }
+ }
+
+ if ((long)LG(dlen) > 0)
+ {
+ zfseeko(G.outfile, -8, SEEK_END);
+ fread(&ntc, 8, 1, G.outfile);
+ if (ntc.id != *(long *)"XTcc")
+ {
+ ntc.id = *(long *)"XTcc";
+ ntc.dlen = dlen;
+ fwrite (&ntc, 8, 1, G.outfile);
+ }
+ Info(slide, 0x201, ((char *)slide, "QData = %d", LG(dlen)));
+ }
+ return; /* finished, cancel further extra field scanning */
+ }
+
+ default:
+ Trace((stderr,"qlfix: unknown extra field block, ID=%d\n",
+ eb_id));
+ }
+
+ /* Skip this extra field block */
+ ef_ptr += (eb_len + EB_HEADSIZE);
+ ef_len -= (eb_len + EB_HEADSIZE);
+ }
+}
+#endif /* QLZIP */
diff -Naur a/unix/unxcfg.h b/unix/unxcfg.h
--- a/unix/unxcfg.h 2009-04-16 19:36:12.000000000 +0100
+++ b/unix/unxcfg.h 2019-12-02 01:49:39.894641004 +0000
@@ -227,4 +227,30 @@
/* wild_dir, dirname, wildname, matchname[], dirnamelen, have_dirname, */
/* and notfirstcall are used by do_wild(). */
+
+#define MAX_CP_NAME 25 + 1
+
+#ifdef SETLOCALE
+# undef SETLOCALE
+#endif
+#define SETLOCALE(category, locale) setlocale(category, locale)
+#include <locale.h>
+
+#ifdef _ISO_INTERN
+# undef _ISO_INTERN
+#endif
+#define _ISO_INTERN(str1) iso_intern(str1)
+
+#ifdef _OEM_INTERN
+# undef _OEM_INTERN
+#endif
+#ifndef IZ_OEM2ISO_ARRAY
+# define IZ_OEM2ISO_ARRAY
+#endif
+#define _OEM_INTERN(str1) oem_intern(str1)
+
+void iso_intern(char *);
+void oem_intern(char *);
+void init_conversion_charsets(void);
+
#endif /* !__unxcfg_h */
diff -Naur a/unix/unxcfg.h.orig b/unix/unxcfg.h.orig
--- a/unix/unxcfg.h.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/unix/unxcfg.h.orig 2009-04-16 19:36:12.000000000 +0100
@@ -0,0 +1,230 @@
+/*
+ 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
+*/
+/*---------------------------------------------------------------------------
+ Unix specific configuration section:
+ ---------------------------------------------------------------------------*/
+
+#ifndef __unxcfg_h
+#define __unxcfg_h
+
+
+/* LARGE FILE SUPPORT - 10/6/04 EG */
+/* This needs to be set before the includes so they set the right sizes */
+
+#if (defined(NO_LARGE_FILE_SUPPORT) && defined(LARGE_FILE_SUPPORT))
+# undef LARGE_FILE_SUPPORT
+#endif
+
+/* Automatically set ZIP64_SUPPORT if LFS */
+#ifdef LARGE_FILE_SUPPORT
+# if (!defined(NO_ZIP64_SUPPORT) && !defined(ZIP64_SUPPORT))
+# define ZIP64_SUPPORT
+# endif
+#endif
+
+/* NO_ZIP64_SUPPORT takes preceedence over ZIP64_SUPPORT */
+#if defined(NO_ZIP64_SUPPORT) && defined(ZIP64_SUPPORT)
+# undef ZIP64_SUPPORT
+#endif
+
+#ifdef LARGE_FILE_SUPPORT
+ /* 64-bit Large File Support */
+
+ /* The following Large File Summit (LFS) defines turn on large file support
+ on Linux (probably 2.4 or later kernel) and many other unixen */
+
+ /* These have to be before any include that sets types so the large file
+ versions of the types are set in the includes */
+
+# define _LARGEFILE_SOURCE /* some OSes need this for fseeko */
+# define _LARGEFILE64_SOURCE
+# define _FILE_OFFSET_BITS 64 /* select default interface as 64 bit */
+# define _LARGE_FILES /* some OSes need this for 64-bit off_t */
+# define __USE_LARGEFILE64
+#endif /* LARGE_FILE_SUPPORT */
+
+
+#include <sys/types.h> /* off_t, time_t, dev_t, ... */
+#include <sys/stat.h>
+
+#ifdef NO_OFF_T
+ typedef long zoff_t;
+#else
+ typedef off_t zoff_t;
+#endif
+#define ZOFF_T_DEFINED
+typedef struct stat z_stat;
+#define Z_STAT_DEFINED
+
+#ifndef COHERENT
+# include <fcntl.h> /* O_BINARY for open() w/o CR/LF translation */
+#else /* COHERENT */
+# ifdef _I386
+# include <fcntl.h> /* Coherent 4.0.x, Mark Williams C */
+# else
+# include <sys/fcntl.h> /* Coherent 3.10, Mark Williams C */
+# endif
+# define SHORT_SYMS
+# ifndef __COHERENT__ /* Coherent 4.2 has tzset() */
+# define tzset settz
+# endif
+#endif /* ?COHERENT */
+
+#ifndef NO_PARAM_H
+# ifdef NGROUPS_MAX
+# undef NGROUPS_MAX /* SCO bug: defined again in <sys/param.h> */
+# endif
+# ifdef BSD
+# define TEMP_BSD /* may be defined again in <sys/param.h> */
+# undef BSD
+# endif
+# include <sys/param.h> /* conflict with <sys/types.h>, some systems? */
+# ifdef TEMP_BSD
+# undef TEMP_BSD
+# ifndef BSD
+# define BSD
+# endif
+# endif
+#endif /* !NO_PARAM_H */
+
+#ifdef __osf__
+# define DIRENT
+# ifdef BSD
+# undef BSD
+# endif
+#endif /* __osf__ */
+
+#ifdef __CYGWIN__
+# include <unistd.h>
+# define DIRENT
+# define HAVE_TERMIOS_H
+# ifndef timezone
+# define timezone _timezone
+# endif
+#endif
+
+#ifdef BSD
+# include <sys/time.h>
+# include <sys/timeb.h>
+# if (defined(_AIX) || defined(__GLIBC__) || defined(__GNU__))
+# include <time.h>
+# endif
+#else
+# include <time.h>
+ struct tm *gmtime(), *localtime();
+#endif
+
+#if (defined(BSD4_4) || (defined(SYSV) && defined(MODERN)))
+# include <unistd.h> /* this includes utime.h on SGIs */
+# if (defined(BSD4_4) || defined(linux) || defined(__GLIBC__))
+# include <utime.h>
+# define GOT_UTIMBUF
+# endif
+# if (!defined(GOT_UTIMBUF) && (defined(__hpux) || defined(__SUNPRO_C)))
+# include <utime.h>
+# define GOT_UTIMBUF
+# endif
+# if (!defined(GOT_UTIMBUF) && defined(__GNU__))
+# include <utime.h>
+# define GOT_UTIMBUF
+# endif
+#endif
+#if (defined(__DGUX__) && !defined(GOT_UTIMBUF))
+ /* DG/UX requires this because of a non-standard struct utimebuf */
+# include <utime.h>
+# define GOT_UTIMBUF
+#endif
+
+#if (defined(V7) || defined(pyr_bsd))
+# define strchr index
+# define strrchr rindex
+#endif
+#ifdef V7
+# define O_RDONLY 0
+# define O_WRONLY 1
+# define O_RDWR 2
+#endif
+
+#if defined(NO_UNICODE_SUPPORT) && defined(UNICODE_SUPPORT)
+ /* disable Unicode (UTF-8) support when requested */
+# undef UNICODE_SUPPORT
+#endif
+
+#if (defined(_MBCS) && defined(NO_MBCS))
+ /* disable MBCS support when requested */
+# undef _MBCS
+#endif
+
+#if (!defined(NO_SETLOCALE) && !defined(_MBCS))
+# if (!defined(UNICODE_SUPPORT) || !defined(UTF8_MAYBE_NATIVE))
+ /* enable setlocale here, unless this happens later for UTF-8 and/or
+ * MBCS support */
+# include <locale.h>
+# ifndef SETLOCALE
+# define SETLOCALE(category, locale) setlocale(category, locale)
+# endif
+# endif
+#endif
+#ifndef NO_SETLOCALE
+# if (!defined(NO_WORKING_ISPRINT) && !defined(HAVE_WORKING_ISPRINT))
+ /* enable "enhanced" unprintable chars detection in fnfilter() */
+# define HAVE_WORKING_ISPRINT
+# endif
+#endif
+
+#ifdef MINIX
+# include <stdio.h>
+#endif
+#if (!defined(HAVE_STRNICMP) & !defined(NO_STRNICMP))
+# define NO_STRNICMP
+#endif
+#ifndef DATE_FORMAT
+# define DATE_FORMAT DF_MDY /* GRR: customize with locale.h somehow? */
+#endif
+#define lenEOL 1
+#ifdef EBCDIC
+# define PutNativeEOL *q++ = '\n';
+#else
+# define PutNativeEOL *q++ = native(LF);
+#endif
+#define SCREENSIZE(ttrows, ttcols) screensize(ttrows, ttcols)
+#define SCREENWIDTH 80
+#define SCREENLWRAP 1
+#define USE_EF_UT_TIME
+#if (!defined(NO_LCHOWN) || !defined(NO_LCHMOD))
+# define SET_SYMLINK_ATTRIBS
+#endif
+#ifdef MTS
+# ifdef SET_DIR_ATTRIB
+# undef SET_DIR_ATTRIB
+# endif
+#else /* !MTS */
+# define SET_DIR_ATTRIB
+# if (!defined(NOTIMESTAMP) && !defined(TIMESTAMP)) /* GRR 970513 */
+# define TIMESTAMP
+# endif
+# define RESTORE_UIDGID
+#endif /* ?MTS */
+
+/* Static variables that we have to add to Uz_Globs: */
+#define SYSTEM_SPECIFIC_GLOBALS \
+ int created_dir, renamed_fullpath;\
+ char *rootpath, *buildpath, *end;\
+ ZCONST char *wildname;\
+ char *dirname, matchname[FILNAMSIZ];\
+ int rootlen, have_dirname, dirnamelen, notfirstcall;\
+ zvoid *wild_dir;
+
+/* created_dir, and renamed_fullpath are used by both mapname() and */
+/* checkdir(). */
+/* rootlen, rootpath, buildpath and end are used by checkdir(). */
+/* wild_dir, dirname, wildname, matchname[], dirnamelen, have_dirname, */
+/* and notfirstcall are used by do_wild(). */
+
+#endif /* !__unxcfg_h */
diff -Naur a/unzip.c b/unzip.c
--- a/unzip.c 2009-04-16 19:26:52.000000000 +0100
+++ b/unzip.c 2019-12-02 01:49:39.895641007 +0000
@@ -327,11 +327,21 @@
-2 just filenames but allow -h/-t/-z -l long Unix \"ls -l\" format\n\
-v verbose, multi-page format\n";
+#ifndef UNIX
static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\
-h print header line -t print totals for listed files or for all\n\
-z print zipfile comment -T print file times in sortable decimal format\
\n -C be case-insensitive %s\
-x exclude filenames that follow from listing\n";
+#else /* UNIX */
+static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\
+ -h print header line -t print totals for listed files or for all\n\
+ -z print zipfile comment %c-T%c print file times in sortable decimal format\
+\n %c-C%c be case-insensitive %s\
+ -x exclude filenames that follow from listing\n\
+ -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
+ -I CHARSET specify a character encoding for UNIX and other archives\n";
+#endif /* !UNIX */
#ifdef MORE
static ZCONST char Far ZipInfoUsageLine4[] =
" -M page output through built-in \"more\"\n";
@@ -665,6 +675,17 @@
-U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\
-C match filenames case-insensitively -L make (some) names \
lowercase\n %-42s -V retain VMS version numbers\n%s";
+#elif (defined UNIX)
+static ZCONST char Far UnzipUsageLine4[] = "\
+modifiers:\n\
+ -n never overwrite existing files -q quiet mode (-qq => quieter)\n\
+ -o overwrite files WITHOUT prompting -a auto-convert any text files\n\
+ -j junk paths (do not make directories) -aa treat ALL files as text\n\
+ -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\
+ -C match filenames case-insensitively -L make (some) names \
+lowercase\n %-42s -V retain VMS version numbers\n%s\
+ -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
+ -I CHARSET specify a character encoding for UNIX and other archives\n\n";
#else /* !VMS */
static ZCONST char Far UnzipUsageLine4[] = "\
modifiers:\n\
@@ -803,6 +824,10 @@
#endif /* UNICODE_SUPPORT */
+#ifdef UNIX
+ init_conversion_charsets();
+#endif
+
#if (defined(__IBMC__) && defined(__DEBUG_ALLOC__))
extern void DebugMalloc(void);
@@ -1336,6 +1361,11 @@
argc = *pargc;
argv = *pargv;
+#ifdef UNIX
+ extern char OEM_CP[MAX_CP_NAME];
+ extern char ISO_CP[MAX_CP_NAME];
+#endif
+
while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) {
s = *argv + 1;
while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */
@@ -1517,6 +1547,37 @@
}
break;
#endif /* MACOS */
+#ifdef UNIX
+ case ('I'):
+ if (negative) {
+ Info(slide, 0x401, ((char *)slide,
+ "error: encodings can't be negated"));
+ return(PK_PARAM);
+ } else {
+ if(*s) { /* Handle the -Icharset case */
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
+ if(*s == '-') {
+ Info(slide, 0x401, ((char *)slide,
+ "error: a valid character encoding should follow the -I argument"));
+ return(PK_PARAM);
+ }
+ strncpy(ISO_CP, s, MAX_CP_NAME - 1);
+ ISO_CP[MAX_CP_NAME - 1] = '\0';
+ } else { /* -I charset */
+ ++argv;
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
+ Info(slide, 0x401, ((char *)slide,
+ "error: a valid character encoding should follow the -I argument"));
+ return(PK_PARAM);
+ }
+ s = *argv;
+ strncpy(ISO_CP, s, MAX_CP_NAME - 1);
+ ISO_CP[MAX_CP_NAME - 1] = '\0';
+ }
+ while(*(++s)); /* No params straight after charset name */
+ }
+ break;
+#endif /* ?UNIX */
case ('j'): /* junk pathnames/directory structure */
if (negative)
uO.jflag = FALSE, negative = 0;
@@ -1592,6 +1653,37 @@
} else
++uO.overwrite_all;
break;
+#ifdef UNIX
+ case ('O'):
+ if (negative) {
+ Info(slide, 0x401, ((char *)slide,
+ "error: encodings can't be negated"));
+ return(PK_PARAM);
+ } else {
+ if(*s) { /* Handle the -Ocharset case */
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
+ if(*s == '-') {
+ Info(slide, 0x401, ((char *)slide,
+ "error: a valid character encoding should follow the -I argument"));
+ return(PK_PARAM);
+ }
+ strncpy(OEM_CP, s, MAX_CP_NAME - 1);
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
+ } else { /* -O charset */
+ ++argv;
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
+ Info(slide, 0x401, ((char *)slide,
+ "error: a valid character encoding should follow the -O argument"));
+ return(PK_PARAM);
+ }
+ s = *argv;
+ strncpy(OEM_CP, s, MAX_CP_NAME - 1);
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
+ }
+ while(*(++s)); /* No params straight after charset name */
+ }
+ break;
+#endif /* ?UNIX */
case ('p'): /* pipes: extract to stdout, no messages */
if (negative) {
uO.cflag = FALSE;
diff -Naur a/unzip.c.orig b/unzip.c.orig
--- a/unzip.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/unzip.c.orig 2009-04-16 19:26:52.000000000 +0100
@@ -0,0 +1,2655 @@
+/*
+ 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
+*/
+/*---------------------------------------------------------------------------
+
+ unzip.c
+
+ UnZip - a zipfile extraction utility. See below for make instructions, or
+ read the comments in Makefile and the various Contents files for more de-
+ tailed explanations. To report a bug, submit a *complete* description via
+ //www.info-zip.org/zip-bug.html; include machine type, operating system and
+ version, compiler and version, and reasonably detailed error messages or
+ problem report. To join Info-ZIP, see the instructions in README.
+
+ UnZip 5.x is a greatly expanded and partially rewritten successor to 4.x,
+ which in turn was almost a complete rewrite of version 3.x. For a detailed
+ revision history, see UnzpHist.zip at quest.jpl.nasa.gov. For a list of
+ the many (near infinite) contributors, see "CONTRIBS" in the UnZip source
+ distribution.
+
+ UnZip 6.0 adds support for archives larger than 4 GiB using the Zip64
+ extensions as well as support for Unicode information embedded per the
+ latest zip standard additions.
+
+ ---------------------------------------------------------------------------
+
+ [from original zipinfo.c]
+
+ This program reads great gobs of totally nifty information, including the
+ central directory stuff, from ZIP archives ("zipfiles" for short). It
+ started as just a testbed for fooling with zipfiles, but at this point it
+ is actually a useful utility. It also became the basis for the rewrite of
+ UnZip (3.16 -> 4.0), using the central directory for processing rather than
+ the individual (local) file headers.
+
+ As of ZipInfo v2.0 and UnZip v5.1, the two programs are combined into one.
+ If the executable is named "unzip" (or "unzip.exe", depending), it behaves
+ like UnZip by default; if it is named "zipinfo" or "ii", it behaves like
+ ZipInfo. The ZipInfo behavior may also be triggered by use of unzip's -Z
+ option; for example, "unzip -Z [zipinfo_options] archive.zip".
+
+ Another dandy product from your buddies at Newtware!
+
+ Author: Greg Roelofs, newt@pobox.com, http://pobox.com/~newt/
+ 23 August 1990 -> April 1997
+
+ ---------------------------------------------------------------------------
+
+ Version: unzip5??.{tar.Z | tar.gz | zip} for Unix, VMS, OS/2, MS-DOS, Amiga,
+ Atari, Windows 3.x/95/NT/CE, Macintosh, Human68K, Acorn RISC OS,
+ AtheOS, BeOS, SMS/QDOS, VM/CMS, MVS, AOS/VS, Tandem NSK, Theos
+ and TOPS-20.
+
+ Copyrights: see accompanying file "LICENSE" in UnZip source distribution.
+ (This software is free but NOT IN THE PUBLIC DOMAIN.)
+
+ ---------------------------------------------------------------------------*/
+
+
+
+#define __UNZIP_C /* identifies this source module */
+#define UNZIP_INTERNAL
+#include "unzip.h" /* includes, typedefs, macros, prototypes, etc. */
+#include "crypt.h"
+#include "unzvers.h"
+
+#ifndef WINDLL /* The WINDLL port uses windll/windll.c instead... */
+
+/***************************/
+/* Local type declarations */
+/***************************/
+
+#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS))
+typedef struct _sign_info
+ {
+ struct _sign_info *previous;
+ void (*sighandler)(int);
+ int sigtype;
+ } savsigs_info;
+#endif
+
+/*******************/
+/* Local Functions */
+/*******************/
+
+#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS))
+static int setsignalhandler OF((__GPRO__ savsigs_info **p_savedhandler_chain,
+ int signal_type, void (*newhandler)(int)));
+#endif
+#ifndef SFX
+static void help_extended OF((__GPRO));
+static void show_version_info OF((__GPRO));
+#endif
+
+
+/*************/
+/* Constants */
+/*************/
+
+#include "consts.h" /* all constant global variables are in here */
+ /* (non-constant globals were moved to globals.c) */
+
+/* constant local variables: */
+
+#ifndef SFX
+#ifndef _WIN32_WCE /* Win CE does not support environment variables */
+ static ZCONST char Far EnvUnZip[] = ENV_UNZIP;
+ static ZCONST char Far EnvUnZip2[] = ENV_UNZIP2;
+ static ZCONST char Far EnvZipInfo[] = ENV_ZIPINFO;
+ static ZCONST char Far EnvZipInfo2[] = ENV_ZIPINFO2;
+#ifdef RISCOS
+ static ZCONST char Far EnvUnZipExts[] = ENV_UNZIPEXTS;
+#endif /* RISCOS */
+ static ZCONST char Far NoMemEnvArguments[] =
+ "envargs: cannot get memory for arguments";
+#endif /* !_WIN32_WCE */
+ static ZCONST char Far CmdLineParamTooLong[] =
+ "error: command line parameter #%d exceeds internal size limit\n";
+#endif /* !SFX */
+
+#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS))
+ static ZCONST char Far CantSaveSigHandler[] =
+ "error: cannot save signal handler settings\n";
+#endif
+
+#if (!defined(SFX) || defined(SFX_EXDIR))
+ static ZCONST char Far NotExtracting[] =
+ "caution: not extracting; -d ignored\n";
+ static ZCONST char Far MustGiveExdir[] =
+ "error: must specify directory to which to extract with -d option\n";
+ static ZCONST char Far OnlyOneExdir[] =
+ "error: -d option used more than once (only one exdir allowed)\n";
+#endif
+#if (defined(UNICODE_SUPPORT) && !defined(UNICODE_WCHAR))
+ static ZCONST char Far UTF8EscapeUnSupp[] =
+ "warning: -U \"escape all non-ASCII UTF-8 chars\" is not supported\n";
+#endif
+
+#if CRYPT
+ static ZCONST char Far MustGivePasswd[] =
+ "error: must give decryption password with -P option\n";
+#endif
+
+#ifndef SFX
+ static ZCONST char Far Zfirst[] =
+ "error: -Z must be first option for ZipInfo mode (check UNZIP variable?)\n";
+#endif
+static ZCONST char Far InvalidOptionsMsg[] = "error:\
+ -fn or any combination of -c, -l, -p, -t, -u and -v options invalid\n";
+static ZCONST char Far IgnoreOOptionMsg[] =
+ "caution: both -n and -o specified; ignoring -o\n";
+
+/* usage() strings */
+#ifndef SFX
+#ifdef VMS
+ static ZCONST char Far Example3[] = "vms.c";
+ static ZCONST char Far Example2[] = " unzip \"-V\" foo \"Bar\"\
+ (Quote names to preserve case, unless SET PROC/PARS=EXT)\n";
+#else /* !VMS */
+ static ZCONST char Far Example3[] = "ReadMe";
+#ifdef RISCOS
+ static ZCONST char Far Example2[] =
+" unzip foo -d RAM:$ => extract all files from foo into RAMDisc\n";
+#else /* !RISCOS */
+#if (defined(OS2) || (defined(DOS_FLX_OS2_W32) && defined(MORE)))
+ static ZCONST char Far Example2[] =
+ ""; /* no room: too many local3[] items */
+#else /* !OS2 */
+#ifdef MACOS
+ static ZCONST char Far Example2[] = ""; /* not needed */
+#else /* !MACOS */
+ static ZCONST char Far Example2[] = " \
+ unzip -p foo | more => send contents of foo.zip via pipe into program more\n";
+#endif /* ?MACOS */
+#endif /* ?OS2 */
+#endif /* ?RISCOS */
+#endif /* ?VMS */
+
+/* local1[]: command options */
+#if defined(TIMESTAMP)
+ static ZCONST char Far local1[] =
+ " -T timestamp archive to latest";
+#else /* !TIMESTAMP */
+ static ZCONST char Far local1[] = "";
+#endif /* ?TIMESTAMP */
+
+/* local2[] and local3[]: modifier options */
+#ifdef DOS_FLX_H68_OS2_W32
+#ifdef FLEXOS
+ static ZCONST char Far local2[] = "";
+#else
+ static ZCONST char Far local2[] =
+ " -$ label removables (-$$ => fixed disks)";
+#endif
+#ifdef OS2
+#ifdef MORE
+ static ZCONST char Far local3[] = "\
+ -X restore ACLs if supported -s spaces in filenames => '_'\n\
+ -M pipe through \"more\" pager\n";
+#else
+ static ZCONST char Far local3[] = " \
+ -X restore ACLs if supported -s spaces in filenames => '_'\n\n";
+#endif /* ?MORE */
+#else /* !OS2 */
+#ifdef WIN32
+#ifdef NTSD_EAS
+#ifdef MORE
+ static ZCONST char Far local3[] = "\
+ -X restore ACLs (-XX => use privileges) -s spaces in filenames => '_'\n\
+ -M pipe through \"more\" pager\n";
+#else
+ static ZCONST char Far local3[] = " \
+ -X restore ACLs (-XX => use privileges) -s spaces in filenames => '_'\n\n";
+#endif /* ?MORE */
+#else /* !NTSD_EAS */
+#ifdef MORE
+ static ZCONST char Far local3[] = "\
+ -M pipe through \"more\" pager \
+ -s spaces in filenames => '_'\n\n";
+#else
+ static ZCONST char Far local3[] = " \
+ -s spaces in filenames => '_'\n\n";
+#endif /* ?MORE */
+#endif /* ?NTSD_EAS */
+#else /* !WIN32 */
+#ifdef MORE
+ static ZCONST char Far local3[] = " -\
+M pipe through \"more\" pager -s spaces in filenames => '_'\n\n";
+#else
+ static ZCONST char Far local3[] = "\
+ -s spaces in filenames => '_'\n";
+#endif
+#endif /* ?WIN32 */
+#endif /* ?OS2 || ?WIN32 */
+#else /* !DOS_FLX_OS2_W32 */
+#ifdef VMS
+ static ZCONST char Far local2[] = " -X restore owner/ACL protection info";
+#ifdef MORE
+ static ZCONST char Far local3[] = "\
+ -Y treat \".nnn\" as \";nnn\" version -2 force ODS2 names\n\
+ --D restore dir (-D: no) timestamps -M pipe through \"more\" pager\n\
+ (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)\
+\n\n";
+#else
+ static ZCONST char Far local3[] = "\n\
+ -Y treat \".nnn\" as \";nnn\" version -2 force ODS2 names\n\
+ --D restore dir (-D: no) timestamps\n\
+ (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)\
+\n\n";
+#endif
+#else /* !VMS */
+#ifdef ATH_BEO_UNX
+ static ZCONST char Far local2[] = " -X restore UID/GID info";
+#ifdef MORE
+ static ZCONST char Far local3[] = "\
+ -K keep setuid/setgid/tacky permissions -M pipe through \"more\" pager\n";
+#else
+ static ZCONST char Far local3[] = "\
+ -K keep setuid/setgid/tacky permissions\n";
+#endif
+#else /* !ATH_BEO_UNX */
+#ifdef TANDEM
+ static ZCONST char Far local2[] = "\
+ -X restore Tandem User ID -r remove file extensions\n\
+ -b create 'C' (180) text files ";
+#ifdef MORE
+ static ZCONST char Far local3[] = " \
+ -M pipe through \"more\" pager\n";
+#else
+ static ZCONST char Far local3[] = "\n";
+#endif
+#else /* !TANDEM */
+#ifdef AMIGA
+ static ZCONST char Far local2[] = " -N restore comments as filenotes";
+#ifdef MORE
+ static ZCONST char Far local3[] = " \
+ -M pipe through \"more\" pager\n";
+#else
+ static ZCONST char Far local3[] = "\n";
+#endif
+#else /* !AMIGA */
+#ifdef MACOS
+ static ZCONST char Far local2[] = " -E show Mac info during extraction";
+ static ZCONST char Far local3[] = " \
+ -i ignore filenames in mac extra info -J junk (ignore) Mac extra info\n\
+\n";
+#else /* !MACOS */
+#ifdef MORE
+ static ZCONST char Far local2[] = " -M pipe through \"more\" pager";
+ static ZCONST char Far local3[] = "\n";
+#else
+ static ZCONST char Far local2[] = ""; /* Atari, Mac, CMS/MVS etc. */
+ static ZCONST char Far local3[] = "";
+#endif
+#endif /* ?MACOS */
+#endif /* ?AMIGA */
+#endif /* ?TANDEM */
+#endif /* ?ATH_BEO_UNX */
+#endif /* ?VMS */
+#endif /* ?DOS_FLX_OS2_W32 */
+#endif /* !SFX */
+
+#ifndef NO_ZIPINFO
+#ifdef VMS
+ static ZCONST char Far ZipInfoExample[] = "* or % (e.g., \"*font-%.zip\")";
+#else
+ static ZCONST char Far ZipInfoExample[] = "*, ?, [] (e.g., \"[a-j]*.zip\")";
+#endif
+
+static ZCONST char Far ZipInfoUsageLine1[] = "\
+ZipInfo %d.%d%d%s of %s, by Greg Roelofs and the Info-ZIP group.\n\
+\n\
+List name, date/time, attribute, size, compression method, etc., about files\n\
+in list (excluding those in xlist) contained in the specified .zip archive(s).\
+\n\"file[.zip]\" may be a wildcard name containing %s.\n\n\
+ usage: zipinfo [-12smlvChMtTz] file[.zip] [list...] [-x xlist...]\n\
+ or: unzip %s-Z%s [-12smlvChMtTz] file[.zip] [list...] [-x xlist...]\n";
+
+static ZCONST char Far ZipInfoUsageLine2[] = "\nmain\
+ listing-format options: -s short Unix \"ls -l\" format (def.)\n\
+ -1 filenames ONLY, one per line -m medium Unix \"ls -l\" format\n\
+ -2 just filenames but allow -h/-t/-z -l long Unix \"ls -l\" format\n\
+ -v verbose, multi-page format\n";
+
+static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\
+ -h print header line -t print totals for listed files or for all\n\
+ -z print zipfile comment -T print file times in sortable decimal format\
+\n -C be case-insensitive %s\
+ -x exclude filenames that follow from listing\n";
+#ifdef MORE
+ static ZCONST char Far ZipInfoUsageLine4[] =
+ " -M page output through built-in \"more\"\n";
+#else /* !MORE */
+ static ZCONST char Far ZipInfoUsageLine4[] = "";
+#endif /* ?MORE */
+#endif /* !NO_ZIPINFO */
+
+#ifdef BETA
+# ifdef VMSCLI
+ /* BetaVersion[] is also used in vms/cmdline.c: do not make it static */
+ ZCONST char Far BetaVersion[] = "%s\
+ THIS IS STILL A BETA VERSION OF UNZIP%s -- DO NOT DISTRIBUTE.\n\n";
+# else
+ static ZCONST char Far BetaVersion[] = "%s\
+ THIS IS STILL A BETA VERSION OF UNZIP%s -- DO NOT DISTRIBUTE.\n\n";
+# endif
+#endif
+
+#ifdef SFX
+# ifdef VMSCLI
+ /* UnzipSFXBanner[] is also used in vms/cmdline.c: do not make it static */
+ ZCONST char Far UnzipSFXBanner[] =
+# else
+ static ZCONST char Far UnzipSFXBanner[] =
+# endif
+ "UnZipSFX %d.%d%d%s of %s, by Info-ZIP (http://www.info-zip.org).\n";
+# ifdef SFX_EXDIR
+ static ZCONST char Far UnzipSFXOpts[] =
+ "Valid options are -tfupcz and -d <exdir>; modifiers are -abjnoqCL%sV%s.\n";
+# else
+ static ZCONST char Far UnzipSFXOpts[] =
+ "Valid options are -tfupcz; modifiers are -abjnoqCL%sV%s.\n";
+# endif
+#else /* !SFX */
+ static ZCONST char Far CompileOptions[] =
+ "UnZip special compilation options:\n";
+ static ZCONST char Far CompileOptFormat[] = " %s\n";
+#ifndef _WIN32_WCE /* Win CE does not support environment variables */
+ static ZCONST char Far EnvOptions[] =
+ "\nUnZip and ZipInfo environment options:\n";
+ static ZCONST char Far EnvOptFormat[] = "%16s: %.1024s\n";
+#endif
+ static ZCONST char Far None[] = "[none]";
+# ifdef ACORN_FTYPE_NFS
+ static ZCONST char Far AcornFtypeNFS[] = "ACORN_FTYPE_NFS";
+# endif
+# ifdef ASM_CRC
+ static ZCONST char Far AsmCRC[] = "ASM_CRC";
+# endif
+# ifdef ASM_INFLATECODES
+ static ZCONST char Far AsmInflateCodes[] = "ASM_INFLATECODES";
+# endif
+# ifdef CHECK_VERSIONS
+ static ZCONST char Far Check_Versions[] = "CHECK_VERSIONS";
+# endif
+# ifdef COPYRIGHT_CLEAN
+ static ZCONST char Far Copyright_Clean[] =
+ "COPYRIGHT_CLEAN (PKZIP 0.9x unreducing method not supported)";
+# endif
+# ifdef DEBUG
+ static ZCONST char Far UDebug[] = "DEBUG";
+# endif
+# ifdef DEBUG_TIME
+ static ZCONST char Far DebugTime[] = "DEBUG_TIME";
+# endif
+# ifdef DLL
+ static ZCONST char Far Dll[] = "DLL";
+# endif
+# ifdef DOSWILD
+ static ZCONST char Far DosWild[] = "DOSWILD";
+# endif
+# ifdef LZW_CLEAN
+ static ZCONST char Far LZW_Clean[] =
+ "LZW_CLEAN (PKZIP/Zip 1.x unshrinking method not supported)";
+# endif
+# ifndef MORE
+ static ZCONST char Far No_More[] = "NO_MORE";
+# endif
+# ifdef NO_ZIPINFO
+ static ZCONST char Far No_ZipInfo[] = "NO_ZIPINFO";
+# endif
+# ifdef NTSD_EAS
+ static ZCONST char Far NTSDExtAttrib[] = "NTSD_EAS";
+# endif
+# if defined(WIN32) && defined(NO_W32TIMES_IZFIX)
+ static ZCONST char Far W32NoIZTimeFix[] = "NO_W32TIMES_IZFIX";
+# endif
+# ifdef OLD_THEOS_EXTRA
+ static ZCONST char Far OldTheosExtra[] =
+ "OLD_THEOS_EXTRA (handle also old Theos port extra field)";
+# endif
+# ifdef OS2_EAS
+ static ZCONST char Far OS2ExtAttrib[] = "OS2_EAS";
+# endif
+# ifdef QLZIP
+ static ZCONST char Far SMSExFldOnUnix[] = "QLZIP";
+# endif
+# ifdef REENTRANT
+ static ZCONST char Far Reentrant[] = "REENTRANT";
+# endif
+# ifdef REGARGS
+ static ZCONST char Far RegArgs[] = "REGARGS";
+# endif
+# ifdef RETURN_CODES
+ static ZCONST char Far Return_Codes[] = "RETURN_CODES";
+# endif
+# ifdef SET_DIR_ATTRIB
+ static ZCONST char Far SetDirAttrib[] = "SET_DIR_ATTRIB";
+# endif
+# ifdef SYMLINKS
+ static ZCONST char Far SymLinkSupport[] =
+ "SYMLINKS (symbolic links supported, if RTL and file system permit)";
+# endif
+# ifdef TIMESTAMP
+ static ZCONST char Far TimeStamp[] = "TIMESTAMP";
+# endif
+# ifdef UNIXBACKUP
+ static ZCONST char Far UnixBackup[] = "UNIXBACKUP";
+# endif
+# ifdef USE_EF_UT_TIME
+ static ZCONST char Far Use_EF_UT_time[] = "USE_EF_UT_TIME";
+# endif
+# ifndef LZW_CLEAN
+ static ZCONST char Far Use_Unshrink[] =
+ "USE_UNSHRINK (PKZIP/Zip 1.x unshrinking method supported)";
+# endif
+# ifndef COPYRIGHT_CLEAN
+ static ZCONST char Far Use_Smith_Code[] =
+ "USE_SMITH_CODE (PKZIP 0.9x unreducing method supported)";
+# endif
+# ifdef USE_DEFLATE64
+ static ZCONST char Far Use_Deflate64[] =
+ "USE_DEFLATE64 (PKZIP 4.x Deflate64(tm) supported)";
+# endif
+# ifdef UNICODE_SUPPORT
+# ifdef UTF8_MAYBE_NATIVE
+# ifdef UNICODE_WCHAR
+ /* direct native UTF-8 check AND charset transform via wchar_t */
+ static ZCONST char Far Use_Unicode[] =
+ "UNICODE_SUPPORT [wide-chars, char coding: %s] (handle UTF-8 paths)";
+# else
+ /* direct native UTF-8 check, only */
+ static ZCONST char Far Use_Unicode[] =
+ "UNICODE_SUPPORT [char coding: %s] (handle UTF-8 paths)";
+# endif
+ static ZCONST char Far SysChUTF8[] = "UTF-8";
+ static ZCONST char Far SysChOther[] = "other";
+# else /* !UTF8_MAYBE_NATIVE */
+ /* charset transform via wchar_t, no native UTF-8 support */
+ static ZCONST char Far Use_Unicode[] =
+ "UNICODE_SUPPORT [wide-chars] (handle UTF-8 paths)";
+# endif /* ?UTF8_MAYBE_NATIVE */
+# endif /* UNICODE_SUPPORT */
+# ifdef _MBCS
+ static ZCONST char Far Have_MBCS_Support[] =
+ "MBCS-support (multibyte character support, MB_CUR_MAX = %u)";
+# endif
+# ifdef MULT_VOLUME
+ static ZCONST char Far Use_MultiVol[] =
+ "MULT_VOLUME (multi-volume archives supported)";
+# endif
+# ifdef LARGE_FILE_SUPPORT
+ static ZCONST char Far Use_LFS[] =
+ "LARGE_FILE_SUPPORT (large files over 2 GiB supported)";
+# endif
+# ifdef ZIP64_SUPPORT
+ static ZCONST char Far Use_Zip64[] =
+ "ZIP64_SUPPORT (archives using Zip64 for large files supported)";
+# endif
+# if (defined(__DJGPP__) && (__DJGPP__ >= 2))
+# ifdef USE_DJGPP_ENV
+ static ZCONST char Far Use_DJGPP_Env[] = "USE_DJGPP_ENV";
+# endif
+# ifdef USE_DJGPP_GLOB
+ static ZCONST char Far Use_DJGPP_Glob[] = "USE_DJGPP_GLOB";
+# endif
+# endif /* __DJGPP__ && (__DJGPP__ >= 2) */
+# ifdef USE_VFAT
+ static ZCONST char Far Use_VFAT_support[] = "USE_VFAT";
+# endif
+# ifdef USE_ZLIB
+ static ZCONST char Far UseZlib[] =
+ "USE_ZLIB (compiled with version %s; using version %s)";
+# endif
+# ifdef USE_BZIP2
+ static ZCONST char Far UseBZip2[] =
+ "USE_BZIP2 (PKZIP 4.6+, using bzip2 lib version %s)";
+# endif
+# ifdef VMS_TEXT_CONV
+ static ZCONST char Far VmsTextConv[] = "VMS_TEXT_CONV";
+# endif
+# ifdef VMSCLI
+ static ZCONST char Far VmsCLI[] = "VMSCLI";
+# endif
+# ifdef VMSWILD
+ static ZCONST char Far VmsWild[] = "VMSWILD";
+# endif
+# ifdef WILD_STOP_AT_DIR
+ static ZCONST char Far WildStopAtDir[] = "WILD_STOP_AT_DIR";
+# endif
+# if CRYPT
+# ifdef PASSWD_FROM_STDIN
+ static ZCONST char Far PasswdStdin[] = "PASSWD_FROM_STDIN";
+# endif
+ static ZCONST char Far Decryption[] =
+ " [decryption, version %d.%d%s of %s]\n";
+ static ZCONST char Far CryptDate[] = CR_VERSION_DATE;
+# endif
+# ifndef __RSXNT__
+# ifdef __EMX__
+ static ZCONST char Far EnvEMX[] = "EMX";
+ static ZCONST char Far EnvEMXOPT[] = "EMXOPT";
+# endif
+# if (defined(__GO32__) && (!defined(__DJGPP__) || (__DJGPP__ < 2)))
+ static ZCONST char Far EnvGO32[] = "GO32";
+ static ZCONST char Far EnvGO32TMP[] = "GO32TMP";
+# endif
+# endif /* !__RSXNT__ */
+
+#ifdef VMS
+/* UnzipUsageLine1[] is also used in vms/cmdline.c: do not make it static */
+ ZCONST char Far UnzipUsageLine1[] = "\
+UnZip %d.%d%d%s of %s, by Info-ZIP. For more details see: unzip -v.\n\n";
+# ifdef COPYRIGHT_CLEAN
+ static ZCONST char Far UnzipUsageLine1v[] = "\
+UnZip %d.%d%d%s of %s, by Info-ZIP. Maintained by C. Spieler. Send\n\
+bug reports using http://www.info-zip.org/zip-bug.html; see README for details.\
+\n\n";
+# else
+ static ZCONST char Far UnzipUsageLine1v[] = "\
+UnZip %d.%d%d%s of %s, by Info-ZIP. UnReduce (c) 1989 by S. H. Smith.\n\
+Send bug reports using //www.info-zip.org/zip-bug.html; see README for details.\
+\n\n";
+# endif /* ?COPYRIGHT_CLEAN */
+#else /* !VMS */
+# ifdef COPYRIGHT_CLEAN
+ static ZCONST char Far UnzipUsageLine1[] = "\
+UnZip %d.%d%d%s of %s, by Info-ZIP. Maintained by C. Spieler. Send\n\
+bug reports using http://www.info-zip.org/zip-bug.html; see README for details.\
+\n\n";
+# else
+ static ZCONST char Far UnzipUsageLine1[] = "\
+UnZip %d.%d%d%s of %s, by Info-ZIP. UnReduce (c) 1989 by S. H. Smith.\n\
+Send bug reports using //www.info-zip.org/zip-bug.html; see README for details.\
+\n\n";
+# endif /* ?COPYRIGHT_CLEAN */
+# define UnzipUsageLine1v UnzipUsageLine1
+#endif /* ?VMS */
+
+static ZCONST char Far UnzipUsageLine2v[] = "\
+Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip/ ;\
+\nsee ftp://ftp.info-zip.org/pub/infozip/UnZip.html for other sites.\
+\n\n";
+
+#ifdef MACOS
+static ZCONST char Far UnzipUsageLine2[] = "\
+Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-d exdir]\n \
+ Default action is to extract files in list, to exdir;\n\
+ file[.zip] may be a wildcard. %s\n";
+#else /* !MACOS */
+#ifdef VM_CMS
+static ZCONST char Far UnzipUsageLine2[] = "\
+Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d fm]\n \
+ Default action is to extract files in list, except those in xlist, to disk fm;\
+\n file[.zip] may be a wildcard. %s\n";
+#else /* !VM_CMS */
+static ZCONST char Far UnzipUsageLine2[] = "\
+Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]\n \
+ Default action is to extract files in list, except those in xlist, to exdir;\n\
+ file[.zip] may be a wildcard. %s\n";
+#endif /* ?VM_CMS */
+#endif /* ?MACOS */
+
+#ifdef NO_ZIPINFO
+# define ZIPINFO_MODE_OPTION ""
+ static ZCONST char Far ZipInfoMode[] =
+ "(ZipInfo mode is disabled in this version.)";
+#else
+# define ZIPINFO_MODE_OPTION "[-Z] "
+ static ZCONST char Far ZipInfoMode[] =
+ "-Z => ZipInfo mode (\"unzip -Z\" for usage).";
+#endif /* ?NO_ZIPINFO */
+
+#ifdef VMS
+ static ZCONST char Far VMSusageLine2b[] = "\
+=> define foreign command symbol in LOGIN.COM: $ unzip :== $dev:[dir]unzip.exe\
+\n";
+#endif
+
+#ifdef MACOS
+static ZCONST char Far UnzipUsageLine3[] = "\n\
+ -d extract files into exdir -l list files (short format)\n\
+ -f freshen existing files, create none -t test compressed archive data\n\
+ -u update files, create if necessary -z display archive comment only\n\
+ -v list verbosely/show version info %s\n";
+#else /* !MACOS */
+#ifdef VM_CMS
+static ZCONST char Far UnzipUsageLine3[] = "\n\
+ -p extract files to pipe, no messages -l list files (short format)\n\
+ -f freshen existing files, create none -t test compressed archive data\n\
+ -u update files, create if necessary -z display archive comment only\n\
+ -v list verbosely/show version info %s\n\
+ -x exclude files that follow (in xlist) -d extract files onto disk fm\n";
+#else /* !VM_CMS */
+static ZCONST char Far UnzipUsageLine3[] = "\n\
+ -p extract files to pipe, no messages -l list files (short format)\n\
+ -f freshen existing files, create none -t test compressed archive data\n\
+ -u update files, create if necessary -z display archive comment only\n\
+ -v list verbosely/show version info %s\n\
+ -x exclude files that follow (in xlist) -d extract files into exdir\n";
+#endif /* ?VM_CMS */
+#endif /* ?MACOS */
+
+/* There is not enough space on a standard 80x25 Windows console screen for
+ * the additional line advertising the UTF-8 debugging options. This may
+ * eventually also be the case for other ports. Probably, the -U option need
+ * not be shown on the introductory screen at all. [Chr. Spieler, 2008-02-09]
+ *
+ * Likely, other advanced options should be moved to an extended help page and
+ * the option to list that page put here. [E. Gordon, 2008-3-16]
+ */
+#if (defined(UNICODE_SUPPORT) && !defined(WIN32))
+#ifdef VMS
+static ZCONST char Far UnzipUsageLine4[] = "\
+modifiers:\n\
+ -n never overwrite or make a new version of an existing file\n\
+ -o always make a new version (-oo: overwrite original) of an existing file\n\
+ -q quiet mode (-qq => quieter) -a auto-convert any text files\n\
+ -j junk paths (do not make directories) -aa treat ALL files as text\n\
+ -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\
+ -C match filenames case-insensitively -L make (some) names \
+lowercase\n %-42s -V retain VMS version numbers\n%s";
+#else /* !VMS */
+static ZCONST char Far UnzipUsageLine4[] = "\
+modifiers:\n\
+ -n never overwrite existing files -q quiet mode (-qq => quieter)\n\
+ -o overwrite files WITHOUT prompting -a auto-convert any text files\n\
+ -j junk paths (do not make directories) -aa treat ALL files as text\n\
+ -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\
+ -C match filenames case-insensitively -L make (some) names \
+lowercase\n %-42s -V retain VMS version numbers\n%s";
+#endif /* ?VMS */
+#else /* !UNICODE_SUPPORT */
+#ifdef VMS
+static ZCONST char Far UnzipUsageLine4[] = "\
+modifiers:\n\
+ -n never overwrite or make a new version of an existing file\n\
+ -o always make a new version (-oo: overwrite original) of an existing file\n\
+ -q quiet mode (-qq => quieter) -a auto-convert any text files\n\
+ -j junk paths (do not make directories) -aa treat ALL files as text\n\
+ -C match filenames case-insensitively -L make (some) names \
+lowercase\n %-42s -V retain VMS version numbers\n%s";
+#else /* !VMS */
+static ZCONST char Far UnzipUsageLine4[] = "\
+modifiers:\n\
+ -n never overwrite existing files -q quiet mode (-qq => quieter)\n\
+ -o overwrite files WITHOUT prompting -a auto-convert any text files\n\
+ -j junk paths (do not make directories) -aa treat ALL files as text\n\
+ -C match filenames case-insensitively -L make (some) names \
+lowercase\n %-42s -V retain VMS version numbers\n%s";
+#endif /* ?VMS */
+#endif /* ?UNICODE_SUPPORT */
+
+static ZCONST char Far UnzipUsageLine5[] = "\
+See \"unzip -hh\" or unzip.txt for more help. Examples:\n\
+ unzip data1 -x joe => extract all files except joe from zipfile data1.zip\n\
+%s\
+ unzip -fo foo %-6s => quietly replace existing %s if archive file newer\n";
+#endif /* ?SFX */
+
+
+
+
+
+/*****************************/
+/* main() / UzpMain() stub */
+/*****************************/
+
+int MAIN(argc, argv) /* return PK-type error code (except under VMS) */
+ int argc;
+ char *argv[];
+{
+ int r;
+
+ CONSTRUCTGLOBALS();
+ r = unzip(__G__ argc, argv);
+ DESTROYGLOBALS();
+ RETURN(r);
+}
+
+
+
+
+/*******************************/
+/* Primary UnZip entry point */
+/*******************************/
+
+int unzip(__G__ argc, argv)
+ __GDEF
+ int argc;
+ char *argv[];
+{
+#ifndef NO_ZIPINFO
+ char *p;
+#endif
+#if (defined(DOS_FLX_H68_NLM_OS2_W32) || !defined(SFX))
+ int i;
+#endif
+ int retcode, error=FALSE;
+#ifndef NO_EXCEPT_SIGNALS
+#ifdef REENTRANT
+ savsigs_info *oldsighandlers = NULL;
+# define SET_SIGHANDLER(sigtype, newsighandler) \
+ if ((retcode = setsignalhandler(__G__ &oldsighandlers, (sigtype), \
+ (newsighandler))) > PK_WARN) \
+ goto cleanup_and_exit
+#else
+# define SET_SIGHANDLER(sigtype, newsighandler) \
+ signal((sigtype), (newsighandler))
+#endif
+#endif /* NO_EXCEPT_SIGNALS */
+
+ /* initialize international char support to the current environment */
+ SETLOCALE(LC_CTYPE, "");
+
+#ifdef UNICODE_SUPPORT
+ /* see if can use UTF-8 Unicode locale */
+# ifdef UTF8_MAYBE_NATIVE
+ {
+ char *codeset;
+# if !(defined(NO_NL_LANGINFO) || defined(NO_LANGINFO_H))
+ /* get the codeset (character set encoding) currently used */
+# include <langinfo.h>
+
+ codeset = nl_langinfo(CODESET);
+# else /* NO_NL_LANGINFO || NO_LANGINFO_H */
+ /* query the current locale setting for character classification */
+ codeset = setlocale(LC_CTYPE, NULL);
+ if (codeset != NULL) {
+ /* extract the codeset portion of the locale name */
+ codeset = strchr(codeset, '.');
+ if (codeset != NULL) ++codeset;
+ }
+# endif /* ?(NO_NL_LANGINFO || NO_LANGINFO_H) */
+ /* is the current codeset UTF-8 ? */
+ if ((codeset != NULL) && (strcmp(codeset, "UTF-8") == 0)) {
+ /* successfully found UTF-8 char coding */
+ G.native_is_utf8 = TRUE;
+ } else {
+ /* Current codeset is not UTF-8 or cannot be determined. */
+ G.native_is_utf8 = FALSE;
+ }
+ /* Note: At least for UnZip, trying to change the process codeset to
+ * UTF-8 does not work. For the example Linux setup of the
+ * UnZip maintainer, a successful switch to "en-US.UTF-8"
+ * resulted in garbage display of all non-basic ASCII characters.
+ */
+ }
+# endif /* UTF8_MAYBE_NATIVE */
+
+ /* initialize Unicode */
+ G.unicode_escape_all = 0;
+ G.unicode_mismatch = 0;
+
+ G.unipath_version = 0;
+ G.unipath_checksum = 0;
+ G.unipath_filename = NULL;
+#endif /* UNICODE_SUPPORT */
+
+
+#if (defined(__IBMC__) && defined(__DEBUG_ALLOC__))
+ extern void DebugMalloc(void);
+
+ atexit(DebugMalloc);
+#endif
+
+#ifdef MALLOC_WORK
+ /* The following (rather complex) expression determines the allocation
+ size of the decompression work area. It simulates what the
+ combined "union" and "struct" declaration of the "static" work
+ area reservation achieves automatically at compile time.
+ Any decent compiler should evaluate this expression completely at
+ compile time and provide constants to the zcalloc() call.
+ (For better readability, some subexpressions are encapsulated
+ in temporarly defined macros.)
+ */
+# define UZ_SLIDE_CHUNK (sizeof(shrint)+sizeof(uch)+sizeof(uch))
+# define UZ_NUMOF_CHUNKS \
+ (unsigned)(((WSIZE+UZ_SLIDE_CHUNK-1)/UZ_SLIDE_CHUNK > HSIZE) ? \
+ (WSIZE+UZ_SLIDE_CHUNK-1)/UZ_SLIDE_CHUNK : HSIZE)
+ G.area.Slide = (uch *)zcalloc(UZ_NUMOF_CHUNKS, UZ_SLIDE_CHUNK);
+# undef UZ_SLIDE_CHUNK
+# undef UZ_NUMOF_CHUNKS
+ G.area.shrink.Parent = (shrint *)G.area.Slide;
+ G.area.shrink.value = G.area.Slide + (sizeof(shrint)*(HSIZE));
+ G.area.shrink.Stack = G.area.Slide +
+ (sizeof(shrint) + sizeof(uch))*(HSIZE);
+#endif
+
+/*---------------------------------------------------------------------------
+ Set signal handler for restoring echo, warn of zipfile corruption, etc.
+ ---------------------------------------------------------------------------*/
+#ifndef NO_EXCEPT_SIGNALS
+#ifdef SIGINT
+ SET_SIGHANDLER(SIGINT, handler);
+#endif
+#ifdef SIGTERM /* some systems really have no SIGTERM */
+ SET_SIGHANDLER(SIGTERM, handler);
+#endif
+#if defined(SIGABRT) && !(defined(AMIGA) && defined(__SASC))
+ SET_SIGHANDLER(SIGABRT, handler);
+#endif
+#ifdef SIGBREAK
+ SET_SIGHANDLER(SIGBREAK, handler);
+#endif
+#ifdef SIGBUS
+ SET_SIGHANDLER(SIGBUS, handler);
+#endif
+#ifdef SIGILL
+ SET_SIGHANDLER(SIGILL, handler);
+#endif
+#ifdef SIGSEGV
+ SET_SIGHANDLER(SIGSEGV, handler);
+#endif
+#endif /* NO_EXCEPT_SIGNALS */
+
+#if (defined(WIN32) && defined(__RSXNT__))
+ for (i = 0 ; i < argc; i++) {
+ _ISO_INTERN(argv[i]);
+ }
+#endif
+
+/*---------------------------------------------------------------------------
+ Macintosh initialization code.
+ ---------------------------------------------------------------------------*/
+
+#ifdef MACOS
+ {
+ int a;
+
+ for (a = 0; a < 4; ++a)
+ G.rghCursor[a] = GetCursor(a+128);
+ G.giCursor = 0;
+ }
+#endif
+
+/*---------------------------------------------------------------------------
+ NetWare initialization code.
+ ---------------------------------------------------------------------------*/
+
+#ifdef NLM
+ InitUnZipConsole();
+#endif
+
+/*---------------------------------------------------------------------------
+ Acorn RISC OS initialization code.
+ ---------------------------------------------------------------------------*/
+
+#ifdef RISCOS
+ set_prefix();
+#endif
+
+/*---------------------------------------------------------------------------
+ Theos initialization code.
+ ---------------------------------------------------------------------------*/
+
+#ifdef THEOS
+ /* The easiest way found to force creation of libraries when selected
+ * members are to be unzipped. Explicitly add libraries names to the
+ * arguments list before the first member of the library.
+ */
+ if (! _setargv(&argc, &argv)) {
+ Info(slide, 0x401, ((char *)slide, "cannot process argv\n"));
+ retcode = PK_MEM;
+ goto cleanup_and_exit;
+ }
+#endif
+
+/*---------------------------------------------------------------------------
+ Sanity checks. Commentary by Otis B. Driftwood and Fiorello:
+
+ D: It's all right. That's in every contract. That's what they
+ call a sanity clause.
+
+ F: Ha-ha-ha-ha-ha. You can't fool me. There ain't no Sanity
+ Claus.
+ ---------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+# ifdef LARGE_FILE_SUPPORT
+ /* test if we can support large files - 10/6/04 EG */
+ if (sizeof(zoff_t) < 8) {
+ Info(slide, 0x401, ((char *)slide, "LARGE_FILE_SUPPORT set but not supported\n"));
+ retcode = PK_BADERR;
+ goto cleanup_and_exit;
+ }
+ /* test if we can show 64-bit values */
+ {
+ zoff_t z = ~(zoff_t)0; /* z should be all 1s now */
+ char *sz;
+
+ sz = FmZofft(z, FZOFFT_HEX_DOT_WID, "X");
+ if ((sz[0] != 'F') || (strlen(sz) != 16))
+ {
+ z = 0;
+ }
+
+ /* shift z so only MSB is set */
+ z <<= 63;
+ sz = FmZofft(z, FZOFFT_HEX_DOT_WID, "X");
+ if ((sz[0] != '8') || (strlen(sz) != 16))
+ {
+ Info(slide, 0x401, ((char *)slide,
+ "Can't show 64-bit values correctly\n"));
+ retcode = PK_BADERR;
+ goto cleanup_and_exit;
+ }
+ }
+# endif /* LARGE_FILE_SUPPORT */
+
+ /* 2004-11-30 SMS.
+ Test the NEXTBYTE macro for proper operation.
+ */
+ {
+ int test_char;
+ static uch test_buf[2] = { 'a', 'b' };
+
+ G.inptr = test_buf;
+ G.incnt = 1;
+
+ test_char = NEXTBYTE; /* Should get 'a'. */
+ if (test_char == 'a')
+ {
+ test_char = NEXTBYTE; /* Should get EOF, not 'b'. */
+ }
+ if (test_char != EOF)
+ {
+ Info(slide, 0x401, ((char *)slide,
+ "NEXTBYTE macro failed. Try compiling with ALT_NEXTBYTE defined?"));
+
+ retcode = PK_BADERR;
+ goto cleanup_and_exit;
+ }
+ }
+#endif /* DEBUG */
+
+/*---------------------------------------------------------------------------
+ First figure out if we're running in UnZip mode or ZipInfo mode, and put
+ the appropriate environment-variable options into the queue. Then rip
+ through any command-line options lurking about...
+ ---------------------------------------------------------------------------*/
+
+#ifdef SFX
+ G.argv0 = argv[0];
+#if (defined(OS2) || defined(WIN32))
+ G.zipfn = GetLoadPath(__G);/* non-MSC NT puts path into G.filename[] */
+#else
+ G.zipfn = G.argv0;
+#endif
+
+#ifdef VMSCLI
+ {
+ ulg status = vms_unzip_cmdline(&argc, &argv);
+ if (!(status & 1)) {
+ retcode = (int)status;
+ goto cleanup_and_exit;
+ }
+ }
+#endif /* VMSCLI */
+
+ uO.zipinfo_mode = FALSE;
+ error = uz_opts(__G__ &argc, &argv); /* UnZipSFX call only */
+
+#else /* !SFX */
+
+#ifdef RISCOS
+ /* get the extensions to swap from environment */
+ getRISCOSexts(ENV_UNZIPEXTS);
+#endif
+
+#ifdef MSDOS
+ /* extract MKS extended argument list from environment (before envargs!) */
+ mksargs(&argc, &argv);
+#endif
+
+#ifdef VMSCLI
+ {
+ ulg status = vms_unzip_cmdline(&argc, &argv);
+ if (!(status & 1)) {
+ retcode = (int)status;
+ goto cleanup_and_exit;
+ }
+ }
+#endif /* VMSCLI */
+
+ G.noargs = (argc == 1); /* no options, no zipfile, no anything */
+
+#ifndef NO_ZIPINFO
+ for (p = argv[0] + strlen(argv[0]); p >= argv[0]; --p) {
+ if (*p == DIR_END
+#ifdef DIR_END2
+ || *p == DIR_END2
+#endif
+ )
+ break;
+ }
+ ++p;
+
+#ifdef THEOS
+ if (strncmp(p, "ZIPINFO.",8) == 0 || strstr(p, ".ZIPINFO:") != NULL ||
+ strncmp(p, "II.",3) == 0 || strstr(p, ".II:") != NULL ||
+#else
+ if (STRNICMP(p, LoadFarStringSmall(Zipnfo), 7) == 0 ||
+ STRNICMP(p, "ii", 2) == 0 ||
+#endif
+ (argc > 1 && strncmp(argv[1], "-Z", 2) == 0))
+ {
+ uO.zipinfo_mode = TRUE;
+#ifndef _WIN32_WCE /* Win CE does not support environment variables */
+ if ((error = envargs(&argc, &argv, LoadFarStringSmall(EnvZipInfo),
+ LoadFarStringSmall2(EnvZipInfo2))) != PK_OK)
+ perror(LoadFarString(NoMemEnvArguments));
+#endif
+ } else
+#endif /* !NO_ZIPINFO */
+ {
+ uO.zipinfo_mode = FALSE;
+#ifndef _WIN32_WCE /* Win CE does not support environment variables */
+ if ((error = envargs(&argc, &argv, LoadFarStringSmall(EnvUnZip),
+ LoadFarStringSmall2(EnvUnZip2))) != PK_OK)
+ perror(LoadFarString(NoMemEnvArguments));
+#endif
+ }
+
+ if (!error) {
+ /* Check the length of all passed command line parameters.
+ * Command arguments might get sent through the Info() message
+ * system, which uses the sliding window area as string buffer.
+ * As arguments may additionally get fed through one of the FnFilter
+ * macros, we require all command line arguments to be shorter than
+ * WSIZE/4 (and ca. 2 standard line widths for fixed message text).
+ */
+ for (i = 1 ; i < argc; i++) {
+ if (strlen(argv[i]) > ((WSIZE>>2) - 160)) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(CmdLineParamTooLong), i));
+ retcode = PK_PARAM;
+ goto cleanup_and_exit;
+ }
+ }
+#ifndef NO_ZIPINFO
+ if (uO.zipinfo_mode)
+ error = zi_opts(__G__ &argc, &argv);
+ else
+#endif /* !NO_ZIPINFO */
+ error = uz_opts(__G__ &argc, &argv);
+ }
+
+#endif /* ?SFX */
+
+ if ((argc < 0) || error) {
+ retcode = error;
+ goto cleanup_and_exit;
+ }
+
+/*---------------------------------------------------------------------------
+ Now get the zipfile name from the command line and then process any re-
+ maining options and file specifications.
+ ---------------------------------------------------------------------------*/
+
+#ifdef DOS_FLX_H68_NLM_OS2_W32
+ /* convert MSDOS-style 'backward slash' directory separators to Unix-style
+ * 'forward slashes' for user's convenience (include zipfile name itself)
+ */
+#ifdef SFX
+ for (G.pfnames = argv, i = argc; i > 0; --i) {
+#else
+ /* argc does not include the zipfile specification */
+ for (G.pfnames = argv, i = argc+1; i > 0; --i) {
+#endif
+#ifdef __human68k__
+ extern char *_toslash(char *);
+ _toslash(*G.pfnames);
+#else /* !__human68k__ */
+ char *q = *G.pfnames;
+
+ while (*q != '\0') {
+ if (*q == '\\')
+ *q = '/';
+ INCSTR(q);
+ }
+#endif /* ?__human68k__ */
+ ++G.pfnames;
+ }
+#endif /* DOS_FLX_H68_NLM_OS2_W32 */
+
+#ifndef SFX
+ G.wildzipfn = *argv++;
+#endif
+
+#if (defined(SFX) && !defined(SFX_EXDIR)) /* only check for -x */
+
+ G.filespecs = argc;
+ G.xfilespecs = 0;
+
+ if (argc > 0) {
+ char **pp = argv-1;
+
+ G.pfnames = argv;
+ while (*++pp)
+ if (strcmp(*pp, "-x") == 0) {
+ if (pp > argv) {
+ *pp = 0; /* terminate G.pfnames */
+ G.filespecs = pp - G.pfnames;
+ } else {
+ G.pfnames = (char **)fnames; /* defaults */
+ G.filespecs = 0;
+ }
+ G.pxnames = pp + 1; /* excluded-names ptr: _after_ -x */
+ G.xfilespecs = argc - G.filespecs - 1;
+ break; /* skip rest of args */
+ }
+ G.process_all_files = FALSE;
+ } else
+ G.process_all_files = TRUE; /* for speed */
+
+#else /* !SFX || SFX_EXDIR */ /* check for -x or -d */
+
+ G.filespecs = argc;
+ G.xfilespecs = 0;
+
+ if (argc > 0) {
+ int in_files=FALSE, in_xfiles=FALSE;
+ char **pp = argv-1;
+
+ G.process_all_files = FALSE;
+ G.pfnames = argv;
+ while (*++pp) {
+ Trace((stderr, "pp - argv = %d\n", pp-argv));
+#ifdef CMS_MVS
+ if (!uO.exdir && STRNICMP(*pp, "-d", 2) == 0) {
+#else
+ if (!uO.exdir && strncmp(*pp, "-d", 2) == 0) {
+#endif
+ int firstarg = (pp == argv);
+
+ uO.exdir = (*pp) + 2;
+ if (in_files) { /* ... zipfile ... -d exdir ... */
+ *pp = (char *)NULL; /* terminate G.pfnames */
+ G.filespecs = pp - G.pfnames;
+ in_files = FALSE;
+ } else if (in_xfiles) {
+ *pp = (char *)NULL; /* terminate G.pxnames */
+ G.xfilespecs = pp - G.pxnames;
+ /* "... -x xlist -d exdir": nothing left */
+ }
+ /* first check for "-dexdir", then for "-d exdir" */
+ if (*uO.exdir == '\0') {
+ if (*++pp)
+ uO.exdir = *pp;
+ else {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(MustGiveExdir)));
+ /* don't extract here by accident */
+ retcode = PK_PARAM;
+ goto cleanup_and_exit;
+ }
+ }
+ if (firstarg) { /* ... zipfile -d exdir ... */
+ if (pp[1]) {
+ G.pfnames = pp + 1; /* argv+2 */
+ G.filespecs = argc - (G.pfnames-argv); /* for now... */
+ } else {
+ G.process_all_files = TRUE;
+ G.pfnames = (char **)fnames; /* GRR: necessary? */
+ G.filespecs = 0; /* GRR: necessary? */
+ break;
+ }
+ }
+ } else if (!in_xfiles) {
+ if (strcmp(*pp, "-x") == 0) {
+ in_xfiles = TRUE;
+ if (pp == G.pfnames) {
+ G.pfnames = (char **)fnames; /* defaults */
+ G.filespecs = 0;
+ } else if (in_files) {
+ *pp = 0; /* terminate G.pfnames */
+ G.filespecs = pp - G.pfnames; /* adjust count */
+ in_files = FALSE;
+ }
+ G.pxnames = pp + 1; /* excluded-names ptr starts after -x */
+ G.xfilespecs = argc - (G.pxnames-argv); /* anything left */
+ } else
+ in_files = TRUE;
+ }
+ }
+ } else
+ G.process_all_files = TRUE; /* for speed */
+
+ if (uO.exdir != (char *)NULL && !G.extract_flag) /* -d ignored */
+ Info(slide, 0x401, ((char *)slide, LoadFarString(NotExtracting)));
+#endif /* ?(SFX && !SFX_EXDIR) */
+
+#ifdef UNICODE_SUPPORT
+ /* set Unicode-escape-all if option -U used */
+ if (uO.U_flag == 1)
+# ifdef UNICODE_WCHAR
+ G.unicode_escape_all = TRUE;
+# else
+ Info(slide, 0x401, ((char *)slide, LoadFarString(UTF8EscapeUnSupp)));
+# endif
+#endif
+
+
+/*---------------------------------------------------------------------------
+ Okey dokey, we have everything we need to get started. Let's roll.
+ ---------------------------------------------------------------------------*/
+
+ retcode = process_zipfiles(__G);
+
+cleanup_and_exit:
+#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS))
+ /* restore all signal handlers back to their state at function entry */
+ while (oldsighandlers != NULL) {
+ savsigs_info *thissigsav = oldsighandlers;
+
+ signal(thissigsav->sigtype, thissigsav->sighandler);
+ oldsighandlers = thissigsav->previous;
+ free(thissigsav);
+ }
+#endif
+#if (defined(MALLOC_WORK) && !defined(REENTRANT))
+ if (G.area.Slide != (uch *)NULL) {
+ free(G.area.Slide);
+ G.area.Slide = (uch *)NULL;
+ }
+#endif
+#if (defined(MSDOS) && !defined(SFX) && !defined(WINDLL))
+ if (retcode != PK_OK)
+ check_for_windows("UnZip");
+#endif
+ return(retcode);
+
+} /* end main()/unzip() */
+
+
+
+
+
+#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS))
+/*******************************/
+/* Function setsignalhandler() */
+/*******************************/
+
+static int setsignalhandler(__G__ p_savedhandler_chain, signal_type,
+ newhandler)
+ __GDEF
+ savsigs_info **p_savedhandler_chain;
+ int signal_type;
+ void (*newhandler)(int);
+{
+ savsigs_info *savsig;
+
+ savsig = malloc(sizeof(savsigs_info));
+ if (savsig == NULL) {
+ /* error message and break */
+ Info(slide, 0x401, ((char *)slide, LoadFarString(CantSaveSigHandler)));
+ return PK_MEM;
+ }
+ savsig->sigtype = signal_type;
+ savsig->sighandler = signal(SIGINT, newhandler);
+ if (savsig->sighandler == SIG_ERR) {
+ free(savsig);
+ } else {
+ savsig->previous = *p_savedhandler_chain;
+ *p_savedhandler_chain = savsig;
+ }
+ return PK_OK;
+
+} /* end function setsignalhandler() */
+
+#endif /* REENTRANT && !NO_EXCEPT_SIGNALS */
+
+
+
+
+
+/**********************/
+/* Function uz_opts() */
+/**********************/
+
+int uz_opts(__G__ pargc, pargv)
+ __GDEF
+ int *pargc;
+ char ***pargv;
+{
+ char **argv, *s;
+ int argc, c, error=FALSE, negative=0, showhelp=0;
+
+
+ argc = *pargc;
+ argv = *pargv;
+
+ while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) {
+ s = *argv + 1;
+ while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */
+#ifdef CMS_MVS
+ switch (tolower(c))
+#else
+ switch (c)
+#endif
+ {
+ case ('-'):
+ ++negative;
+ break;
+#ifdef RISCOS
+ case ('/'):
+ if (negative) { /* negative not allowed with -/ swap */
+ Info(slide, 0x401, ((char *)slide,
+ "error: must give extensions list"));
+ return(PK_PARAM); /* don't extract here by accident */
+ }
+ exts2swap = s; /* override Unzip$Exts */
+ s += strlen(s);
+ break;
+#endif
+ case ('a'):
+ if (negative) {
+ uO.aflag = MAX(uO.aflag-negative,0);
+ negative = 0;
+ } else
+ ++uO.aflag;
+ break;
+#if (defined(DLL) && defined(API_DOC))
+ case ('A'): /* extended help for API */
+ APIhelp(__G__ argc, argv);
+ *pargc = -1; /* signal to exit successfully */
+ return 0;
+#endif
+ case ('b'):
+ if (negative) {
+#if (defined(TANDEM) || defined(VMS))
+ uO.bflag = MAX(uO.bflag-negative,0);
+#endif
+ negative = 0; /* do nothing: "-b" is default */
+ } else {
+#ifdef VMS
+ if (uO.aflag == 0)
+ ++uO.bflag;
+#endif
+#ifdef TANDEM
+ ++uO.bflag;
+#endif
+ uO.aflag = 0;
+ }
+ break;
+#ifdef UNIXBACKUP
+ case ('B'): /* -B: back up existing files */
+ if (negative)
+ uO.B_flag = FALSE, negative = 0;
+ else
+ uO.B_flag = TRUE;
+ break;
+#endif
+ case ('c'):
+ if (negative) {
+ uO.cflag = FALSE, negative = 0;
+#ifdef NATIVE
+ uO.aflag = 0;
+#endif
+ } else {
+ uO.cflag = TRUE;
+#ifdef NATIVE
+ uO.aflag = 2; /* so you can read it on the screen */
+#endif
+#ifdef DLL
+ if (G.redirect_text)
+ G.redirect_data = 2;
+#endif
+ }
+ break;
+#ifndef CMS_MVS
+ case ('C'): /* -C: match filenames case-insensitively */
+ if (negative)
+ uO.C_flag = FALSE, negative = 0;
+ else
+ uO.C_flag = TRUE;
+ break;
+#endif /* !CMS_MVS */
+#if (!defined(SFX) || defined(SFX_EXDIR))
+ case ('d'):
+ if (negative) { /* negative not allowed with -d exdir */
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(MustGiveExdir)));
+ return(PK_PARAM); /* don't extract here by accident */
+ }
+ if (uO.exdir != (char *)NULL) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(OnlyOneExdir)));
+ return(PK_PARAM); /* GRR: stupid restriction? */
+ } else {
+ /* first check for "-dexdir", then for "-d exdir" */
+ uO.exdir = s;
+ if (*uO.exdir == '\0') {
+ if (argc > 1) {
+ --argc;
+ uO.exdir = *++argv;
+ if (*uO.exdir == '-') {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(MustGiveExdir)));
+ return(PK_PARAM);
+ }
+ /* else uO.exdir points at extraction dir */
+ } else {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(MustGiveExdir)));
+ return(PK_PARAM);
+ }
+ }
+ /* uO.exdir now points at extraction dir (-dexdir or
+ * -d exdir); point s at end of exdir to avoid mis-
+ * interpretation of exdir characters as more options
+ */
+ if (*s != 0)
+ while (*++s != 0)
+ ;
+ }
+ break;
+#endif /* !SFX || SFX_EXDIR */
+#if (!defined(NO_TIMESTAMPS))
+ case ('D'): /* -D: Skip restoring dir (or any) timestamp. */
+ if (negative) {
+ uO.D_flag = MAX(uO.D_flag-negative,0);
+ negative = 0;
+ } else
+ uO.D_flag++;
+ break;
+#endif /* (!NO_TIMESTAMPS) */
+ case ('e'): /* just ignore -e, -x options (extract) */
+ break;
+#ifdef MACOS
+ case ('E'): /* -E [MacOS] display Mac e.f. when restoring */
+ if( negative ) {
+ uO.E_flag = FALSE, negative = 0;
+ } else {
+ uO.E_flag = TRUE;
+ }
+ break;
+#endif /* MACOS */
+ case ('f'): /* "freshen" (extract only newer files) */
+ if (negative)
+ uO.fflag = uO.uflag = FALSE, negative = 0;
+ else
+ uO.fflag = uO.uflag = TRUE;
+ break;
+#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
+ case ('F'): /* Acorn filetype & NFS extension handling */
+ if (negative)
+ uO.acorn_nfs_ext = FALSE, negative = 0;
+ else
+ uO.acorn_nfs_ext = TRUE;
+ break;
+#endif /* RISCOS || ACORN_FTYPE_NFS */
+ case ('h'): /* just print help message and quit */
+ if (showhelp == 0) {
+#ifndef SFX
+ if (*s == 'h')
+ showhelp = 2;
+ else
+#endif /* !SFX */
+ {
+ showhelp = 1;
+ }
+ }
+ break;
+#ifdef MACOS
+ case ('i'): /* -i [MacOS] ignore filenames stored in Mac ef */
+ if( negative ) {
+ uO.i_flag = FALSE, negative = 0;
+ } else {
+ uO.i_flag = TRUE;
+ }
+ break;
+#endif /* MACOS */
+ case ('j'): /* junk pathnames/directory structure */
+ if (negative)
+ uO.jflag = FALSE, negative = 0;
+ else
+ uO.jflag = TRUE;
+ break;
+#if (defined(ATH_BEO) || defined(MACOS))
+ case ('J'): /* Junk AtheOS, BeOS or MacOS file attributes */
+ if( negative ) {
+ uO.J_flag = FALSE, negative = 0;
+ } else {
+ uO.J_flag = TRUE;
+ }
+ break;
+#endif /* ATH_BEO || MACOS */
+#ifdef ATH_BEO_UNX
+ case ('K'):
+ if (negative) {
+ uO.K_flag = FALSE, negative = 0;
+ } else {
+ uO.K_flag = TRUE;
+ }
+ break;
+#endif /* ATH_BEO_UNX */
+#ifndef SFX
+ case ('l'):
+ if (negative) {
+ uO.vflag = MAX(uO.vflag-negative,0);
+ negative = 0;
+ } else
+ ++uO.vflag;
+ break;
+#endif /* !SFX */
+#ifndef CMS_MVS
+ case ('L'): /* convert (some) filenames to lowercase */
+ if (negative) {
+ uO.L_flag = MAX(uO.L_flag-negative,0);
+ negative = 0;
+ } else
+ ++uO.L_flag;
+ break;
+#endif /* !CMS_MVS */
+#ifdef MORE
+#ifdef CMS_MVS
+ case ('m'):
+#endif
+ case ('M'): /* send all screen output through "more" fn. */
+/* GRR: eventually check for numerical argument => height */
+ if (negative)
+ G.M_flag = FALSE, negative = 0;
+ else
+ G.M_flag = TRUE;
+ break;
+#endif /* MORE */
+ case ('n'): /* don't overwrite any files */
+ if (negative)
+ uO.overwrite_none = FALSE, negative = 0;
+ else
+ uO.overwrite_none = TRUE;
+ break;
+#ifdef AMIGA
+ case ('N'): /* restore comments as filenotes */
+ if (negative)
+ uO.N_flag = FALSE, negative = 0;
+ else
+ uO.N_flag = TRUE;
+ break;
+#endif /* AMIGA */
+ case ('o'): /* OK to overwrite files without prompting */
+ if (negative) {
+ uO.overwrite_all = MAX(uO.overwrite_all-negative,0);
+ negative = 0;
+ } else
+ ++uO.overwrite_all;
+ break;
+ case ('p'): /* pipes: extract to stdout, no messages */
+ if (negative) {
+ uO.cflag = FALSE;
+ uO.qflag = MAX(uO.qflag-999,0);
+ negative = 0;
+ } else {
+ uO.cflag = TRUE;
+ uO.qflag += 999;
+ }
+ break;
+#if CRYPT
+ /* GRR: yes, this is highly insecure, but dozens of people
+ * have pestered us for this, so here we go... */
+ case ('P'):
+ if (negative) { /* negative not allowed with -P passwd */
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(MustGivePasswd)));
+ return(PK_PARAM); /* don't extract here by accident */
+ }
+ if (uO.pwdarg != (char *)NULL) {
+/*
+ GRR: eventually support multiple passwords?
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(OnlyOnePasswd)));
+ return(PK_PARAM);
+ */
+ } else {
+ /* first check for "-Ppasswd", then for "-P passwd" */
+ uO.pwdarg = s;
+ if (*uO.pwdarg == '\0') {
+ if (argc > 1) {
+ --argc;
+ uO.pwdarg = *++argv;
+ if (*uO.pwdarg == '-') {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(MustGivePasswd)));
+ return(PK_PARAM);
+ }
+ /* else pwdarg points at decryption password */
+ } else {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(MustGivePasswd)));
+ return(PK_PARAM);
+ }
+ }
+ /* pwdarg now points at decryption password (-Ppasswd or
+ * -P passwd); point s at end of passwd to avoid mis-
+ * interpretation of passwd characters as more options
+ */
+ if (*s != 0)
+ while (*++s != 0)
+ ;
+ }
+ break;
+#endif /* CRYPT */
+ case ('q'): /* quiet: fewer comments/messages */
+ if (negative) {
+ uO.qflag = MAX(uO.qflag-negative,0);
+ negative = 0;
+ } else
+ ++uO.qflag;
+ break;
+#ifdef QDOS
+ case ('Q'): /* QDOS flags */
+ qlflag ^= strtol(s, &s, 10);
+ break; /* we XOR this as we can config qlflags */
+#endif
+#ifdef TANDEM
+ case ('r'): /* remove file extensions */
+ if (negative)
+ uO.rflag = FALSE, negative = 0;
+ else
+ uO.rflag = TRUE;
+ break;
+#endif /* TANDEM */
+#ifdef DOS_FLX_NLM_OS2_W32
+ case ('s'): /* spaces in filenames: allow by default */
+ if (negative)
+ uO.sflag = FALSE, negative = 0;
+ else
+ uO.sflag = TRUE;
+ break;
+#endif /* DOS_FLX_NLM_OS2_W32 */
+#ifdef VMS
+ /* VMS: extract "text" files in Stream_LF format (-a[a]) */
+ case ('S'):
+ if (negative)
+ uO.S_flag = FALSE, negative = 0;
+ else
+ uO.S_flag = TRUE;
+ break;
+#endif /* VMS */
+ case ('t'):
+ if (negative)
+ uO.tflag = FALSE, negative = 0;
+ else
+ uO.tflag = TRUE;
+ break;
+#ifdef TIMESTAMP
+ case ('T'):
+ if (negative)
+ uO.T_flag = FALSE, negative = 0;
+ else
+ uO.T_flag = TRUE;
+ break;
+#endif
+ case ('u'): /* update (extract only new and newer files) */
+ if (negative)
+ uO.uflag = FALSE, negative = 0;
+ else
+ uO.uflag = TRUE;
+ break;
+#ifdef UNICODE_SUPPORT
+ case ('U'): /* escape UTF-8, or disable UTF-8 support */
+ if (negative) {
+ uO.U_flag = MAX(uO.U_flag-negative,0);
+ negative = 0;
+ } else
+ uO.U_flag++;
+ break;
+#else /* !UNICODE_SUPPORT */
+#ifndef CMS_MVS
+ case ('U'): /* obsolete; to be removed in version 6.0 */
+ if (negative)
+ uO.L_flag = TRUE, negative = 0;
+ else
+ uO.L_flag = FALSE;
+ break;
+#endif /* !CMS_MVS */
+#endif /* ?UNICODE_SUPPORT */
+#ifndef SFX
+ case ('v'): /* verbose */
+ if (negative) {
+ uO.vflag = MAX(uO.vflag-negative,0);
+ negative = 0;
+ } else if (uO.vflag)
+ ++uO.vflag;
+ else
+ uO.vflag = 2;
+ break;
+#endif /* !SFX */
+#ifndef CMS_MVS
+ case ('V'): /* Version (retain VMS/DEC-20 file versions) */
+ if (negative)
+ uO.V_flag = FALSE, negative = 0;
+ else
+ uO.V_flag = TRUE;
+ break;
+#endif /* !CMS_MVS */
+#ifdef WILD_STOP_AT_DIR
+ case ('W'): /* Wildcard interpretation (stop at '/'?) */
+ if (negative)
+ uO.W_flag = FALSE, negative = 0;
+ else
+ uO.W_flag = TRUE;
+ break;
+#endif /* WILD_STOP_AT_DIR */
+ case ('x'): /* extract: default */
+#ifdef SFX
+ /* when 'x' is the only option in this argument, and the
+ * next arg is not an option, assume this initiates an
+ * exclusion list (-x xlist): terminate option-scanning
+ * and leave uz_opts with argv still pointing to "-x";
+ * the xlist is processed later
+ */
+ if (s - argv[0] == 2 && *s == '\0' &&
+ argc > 1 && argv[1][0] != '-') {
+ /* break out of nested loops without "++argv;--argc" */
+ goto opts_done;
+ }
+#endif /* SFX */
+ break;
+#if (defined(RESTORE_UIDGID) || defined(RESTORE_ACL))
+ case ('X'): /* restore owner/protection info (need privs?) */
+ if (negative) {
+ uO.X_flag = MAX(uO.X_flag-negative,0);
+ negative = 0;
+ } else
+ ++uO.X_flag;
+ break;
+#endif /* RESTORE_UIDGID || RESTORE_ACL */
+#ifdef VMS
+ case ('Y'): /* Treat ".nnn" as ";nnn" version. */
+ if (negative)
+ uO.Y_flag = FALSE, negative = 0;
+ else
+ uO.Y_flag = TRUE;
+ break;
+#endif /* VMS */
+ case ('z'): /* display only the archive comment */
+ if (negative) {
+ uO.zflag = MAX(uO.zflag-negative,0);
+ negative = 0;
+ } else
+ ++uO.zflag;
+ break;
+#ifndef SFX
+ case ('Z'): /* should have been first option (ZipInfo) */
+ Info(slide, 0x401, ((char *)slide, LoadFarString(Zfirst)));
+ error = TRUE;
+ break;
+#endif /* !SFX */
+#ifdef VMS
+ case ('2'): /* Force ODS2-compliant names. */
+ if (negative)
+ uO.ods2_flag = FALSE, negative = 0;
+ else
+ uO.ods2_flag = TRUE;
+ break;
+#endif /* VMS */
+#ifdef DOS_H68_OS2_W32
+ case ('$'):
+ if (negative) {
+ uO.volflag = MAX(uO.volflag-negative,0);
+ negative = 0;
+ } else
+ ++uO.volflag;
+ break;
+#endif /* DOS_H68_OS2_W32 */
+#if (!defined(RISCOS) && !defined(CMS_MVS) && !defined(TANDEM))
+ case (':'): /* allow "parent dir" path components */
+ if (negative) {
+ uO.ddotflag = MAX(uO.ddotflag-negative,0);
+ negative = 0;
+ } else
+ ++uO.ddotflag;
+ break;
+#endif /* !RISCOS && !CMS_MVS && !TANDEM */
+#ifdef UNIX
+ case ('^'): /* allow control chars in filenames */
+ if (negative) {
+ uO.cflxflag = MAX(uO.cflxflag-negative,0);
+ negative = 0;
+ } else
+ ++uO.cflxflag;
+ break;
+#endif /* UNIX */
+ default:
+ error = TRUE;
+ break;
+
+ } /* end switch */
+ } /* end while (not end of argument string) */
+ } /* end while (not done with switches) */
+
+/*---------------------------------------------------------------------------
+ Check for nonsensical combinations of options.
+ ---------------------------------------------------------------------------*/
+
+#ifdef SFX
+opts_done: /* yes, very ugly...but only used by UnZipSFX with -x xlist */
+#endif
+
+ if (showhelp > 0) { /* just print help message and quit */
+ *pargc = -1;
+#ifndef SFX
+ if (showhelp == 2) {
+ help_extended(__G);
+ return PK_OK;
+ } else
+#endif /* !SFX */
+ {
+ return USAGE(PK_OK);
+ }
+ }
+
+ if ((uO.cflag && (uO.tflag || uO.uflag)) ||
+ (uO.tflag && uO.uflag) || (uO.fflag && uO.overwrite_none))
+ {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(InvalidOptionsMsg)));
+ error = TRUE;
+ }
+ if (uO.aflag > 2)
+ uO.aflag = 2;
+#ifdef VMS
+ if (uO.bflag > 2)
+ uO.bflag = 2;
+ /* Clear -s flag when converting text files. */
+ if (uO.aflag <= 0)
+ uO.S_flag = 0;
+#endif /* VMS */
+ if (uO.overwrite_all && uO.overwrite_none) {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(IgnoreOOptionMsg)));
+ uO.overwrite_all = FALSE;
+ }
+#ifdef MORE
+ if (G.M_flag && !isatty(1)) /* stdout redirected: "more" func. useless */
+ G.M_flag = 0;
+#endif
+
+#ifdef SFX
+ if (error)
+#else
+ if ((argc-- == 0) || error)
+#endif
+ {
+ *pargc = argc;
+ *pargv = argv;
+#ifndef SFX
+ if (uO.vflag >= 2 && argc == -1) { /* "unzip -v" */
+ show_version_info(__G);
+ return PK_OK;
+ }
+ if (!G.noargs && !error)
+ error = TRUE; /* had options (not -h or -v) but no zipfile */
+#endif /* !SFX */
+ return USAGE(error);
+ }
+
+#ifdef SFX
+ /* print our banner unless we're being fairly quiet */
+ if (uO.qflag < 2)
+ Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner),
+ UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
+ LoadFarStringSmall(VersionDate)));
+#ifdef BETA
+ /* always print the beta warning: no unauthorized distribution!! */
+ Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(BetaVersion), "\n",
+ "SFX"));
+#endif
+#endif /* SFX */
+
+ if (uO.cflag || uO.tflag || uO.vflag || uO.zflag
+#ifdef TIMESTAMP
+ || uO.T_flag
+#endif
+ )
+ G.extract_flag = FALSE;
+ else
+ G.extract_flag = TRUE;
+
+ *pargc = argc;
+ *pargv = argv;
+ return PK_OK;
+
+} /* end function uz_opts() */
+
+
+
+
+/********************/
+/* Function usage() */
+/********************/
+
+#ifdef SFX
+# ifdef VMS
+# define LOCAL "X.\n\
+(Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)"
+# endif
+# ifdef UNIX
+# define LOCAL "X"
+# endif
+# ifdef DOS_OS2_W32
+# define LOCAL "s$"
+# endif
+# if (defined(FLEXOS) || defined(NLM))
+# define LOCAL "s"
+# endif
+# ifdef AMIGA
+# define LOCAL "N"
+# endif
+ /* Default for all other systems: */
+# ifndef LOCAL
+# define LOCAL ""
+# endif
+
+# ifndef NO_TIMESTAMP
+# ifdef MORE
+# define SFXOPT1 "DM"
+# else
+# define SFXOPT1 "D"
+# endif
+# else
+# ifdef MORE
+# define SFXOPT1 "M"
+# else
+# define SFXOPT1 ""
+# endif
+# endif
+
+int usage(__G__ error) /* return PK-type error code */
+ __GDEF
+ int error;
+{
+ Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner),
+ UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
+ LoadFarStringSmall(VersionDate)));
+ Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXOpts),
+ SFXOPT1, LOCAL));
+#ifdef BETA
+ Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(BetaVersion), "\n",
+ "SFX"));
+#endif
+
+ if (error)
+ return PK_PARAM;
+ else
+ return PK_COOL; /* just wanted usage screen: no error */
+
+} /* end function usage() */
+
+
+
+
+
+#else /* !SFX */
+# ifdef VMS
+# define QUOT '\"'
+# define QUOTS "\""
+# else
+# define QUOT ' '
+# define QUOTS ""
+# endif
+
+int usage(__G__ error) /* return PK-type error code */
+ __GDEF
+ int error;
+{
+ int flag = (error? 1 : 0);
+
+
+/*---------------------------------------------------------------------------
+ Print either ZipInfo usage or UnZip usage, depending on incantation.
+ (Strings must be no longer than 512 bytes for Turbo C, apparently.)
+ ---------------------------------------------------------------------------*/
+
+ if (uO.zipinfo_mode) {
+
+#ifndef NO_ZIPINFO
+
+ Info(slide, flag, ((char *)slide, LoadFarString(ZipInfoUsageLine1),
+ ZI_MAJORVER, ZI_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
+ LoadFarStringSmall(VersionDate),
+ LoadFarStringSmall2(ZipInfoExample), QUOTS,QUOTS));
+ Info(slide, flag, ((char *)slide, LoadFarString(ZipInfoUsageLine2)));
+ Info(slide, flag, ((char *)slide, LoadFarString(ZipInfoUsageLine3),
+ LoadFarStringSmall(ZipInfoUsageLine4)));
+#ifdef VMS
+ Info(slide, flag, ((char *)slide, "\n\
+You must quote non-lowercase options and filespecs, unless SET PROC/PARSE=EXT.\
+\n"));
+#endif
+
+#endif /* !NO_ZIPINFO */
+
+ } else { /* UnZip mode */
+
+ Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine1),
+ UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
+ LoadFarStringSmall(VersionDate)));
+#ifdef BETA
+ Info(slide, flag, ((char *)slide, LoadFarString(BetaVersion), "", ""));
+#endif
+
+ Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine2),
+ ZIPINFO_MODE_OPTION, LoadFarStringSmall(ZipInfoMode)));
+#ifdef VMS
+ if (!error) /* maybe no command-line tail found; show extra help */
+ Info(slide, flag, ((char *)slide, LoadFarString(VMSusageLine2b)));
+#endif
+
+ Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine3),
+ LoadFarStringSmall(local1)));
+
+ Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine4),
+ LoadFarStringSmall(local2), LoadFarStringSmall2(local3)));
+
+ /* This is extra work for SMALL_MEM, but it will work since
+ * LoadFarStringSmall2 uses the same buffer. Remember, this
+ * is a hack. */
+ Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine5),
+ LoadFarStringSmall(Example2), LoadFarStringSmall2(Example3),
+ LoadFarStringSmall2(Example3)));
+
+ } /* end if (uO.zipinfo_mode) */
+
+ if (error)
+ return PK_PARAM;
+ else
+ return PK_COOL; /* just wanted usage screen: no error */
+
+} /* end function usage() */
+
+#endif /* ?SFX */
+
+
+
+
+#ifndef SFX
+
+/* Print extended help to stdout. */
+static void help_extended(__G)
+ __GDEF
+{
+ extent i; /* counter for help array */
+
+ /* help array */
+ static ZCONST char *text[] = {
+ "",
+ "Extended Help for UnZip",
+ "",
+ "See the UnZip Manual for more detailed help",
+ "",
+ "",
+ "UnZip lists and extracts files in zip archives. The default action is to",
+ "extract zipfile entries to the current directory, creating directories as",
+ "needed. With appropriate options, UnZip lists the contents of archives",
+ "instead.",
+ "",
+ "Basic unzip command line:",
+ " unzip [-Z] options archive[.zip] [file ...] [-x xfile ...] [-d exdir]",
+ "",
+ "Some examples:",
+ " unzip -l foo.zip - list files in short format in archive foo.zip",
+ "",
+ " unzip -t foo - test the files in archive foo",
+ "",
+ " unzip -Z foo - list files using more detailed zipinfo format",
+ "",
+ " unzip foo - unzip the contents of foo in current dir",
+ "",
+ " unzip -a foo - unzip foo and convert text files to local OS",
+ "",
+ "If unzip is run in zipinfo mode, a more detailed list of archive contents",
+ "is provided. The -Z option sets zipinfo mode and changes the available",
+ "options.",
+ "",
+ "Basic zipinfo command line:",
+ " zipinfo options archive[.zip] [file ...] [-x xfile ...]",
+ " unzip -Z options archive[.zip] [file ...] [-x xfile ...]",
+ "",
+ "Below, Mac OS refers to Mac OS before Mac OS X. Mac OS X is a Unix based",
+ "port and is referred to as Unix Apple.",
+ "",
+ "",
+ "unzip options:",
+ " -Z Switch to zipinfo mode. Must be first option.",
+ " -hh Display extended help.",
+ " -A [OS/2, Unix DLL] Print extended help for DLL.",
+ " -c Extract files to stdout/screen. As -p but include names. Also,",
+ " -a allowed and EBCDIC conversions done if needed.",
+ " -f Freshen by extracting only if older file on disk.",
+ " -l List files using short form.",
+ " -p Extract files to pipe (stdout). Only file data is output and all",
+ " files extracted in binary mode (as stored).",
+ " -t Test archive files.",
+ " -T Set timestamp on archive(s) to that of newest file. Similar to",
+ " zip -o but faster.",
+ " -u Update existing older files on disk as -f and extract new files.",
+ " -v Use verbose list format. If given alone as unzip -v show version",
+ " information. Also can be added to other list commands for more",
+ " verbose output.",
+ " -z Display only archive comment.",
+ "",
+ "unzip modifiers:",
+ " -a Convert text files to local OS format. Convert line ends, EOF",
+ " marker, and from or to EBCDIC character set as needed.",
+ " -b Treat all files as binary. [Tandem] Force filecode 180 ('C').",
+ " [VMS] Autoconvert binary files. -bb forces convert of all files.",
+ " -B [UNIXBACKUP compile option enabled] Save a backup copy of each",
+ " overwritten file in foo~ or foo~99999 format.",
+ " -C Use case-insensitive matching.",
+ " -D Skip restoration of timestamps for extracted directories. On VMS this",
+ " is on by default and -D essentially becames -DD.",
+ " -DD Skip restoration of timestamps for all entries.",
+ " -E [MacOS (not Unix Apple)] Display contents of MacOS extra field during",
+ " restore.",
+ " -F [Acorn] Suppress removal of NFS filetype extension. [Non-Acorn if",
+ " ACORN_FTYPE_NFS] Translate filetype and append to name.",
+ " -i [MacOS] Ignore filenames in MacOS extra field. Instead, use name in",
+ " standard header.",
+ " -j Junk paths and deposit all files in extraction directory.",
+ " -J [BeOS] Junk file attributes. [MacOS] Ignore MacOS specific info.",
+ " -K [AtheOS, BeOS, Unix] Restore SUID/SGID/Tacky file attributes.",
+ " -L Convert to lowercase any names from uppercase only file system.",
+ " -LL Convert all files to lowercase.",
+ " -M Pipe all output through internal pager similar to Unix more(1).",
+ " -n Never overwrite existing files. Skip extracting that file, no prompt.",
+ " -N [Amiga] Extract file comments as Amiga filenotes.",
+ " -o Overwrite existing files without prompting. Useful with -f. Use with",
+ " care.",
+ " -P p Use password p to decrypt files. THIS IS INSECURE! Some OS show",
+ " command line to other users.",
+ " -q Perform operations quietly. The more q (as in -qq) the quieter.",
+ " -s [OS/2, NT, MS-DOS] Convert spaces in filenames to underscores.",
+ " -S [VMS] Convert text files (-a, -aa) into Stream_LF format.",
+ " -U [UNICODE enabled] Show non-local characters as #Uxxxx or #Lxxxxxx ASCII",
+ " text escapes where x is hex digit. [Old] -U used to leave names",
+ " uppercase if created on MS-DOS, VMS, etc. See -L.",
+ " -UU [UNICODE enabled] Disable use of stored UTF-8 paths. Note that UTF-8",
+ " paths stored as native local paths are still processed as Unicode.",
+ " -V Retain VMS file version numbers.",
+ " -W [Only if WILD_STOP_AT_DIR] Modify pattern matching so ? and * do not",
+ " match directory separator /, but ** does. Allows matching at specific",
+ " directory levels.",
+ " -X [VMS, Unix, OS/2, NT, Tandem] Restore UICs and ACL entries under VMS,",
+ " or UIDs/GIDs under Unix, or ACLs under certain network-enabled",
+ " versions of OS/2, or security ACLs under Windows NT. Can require",
+ " user privileges.",
+ " -XX [NT] Extract NT security ACLs after trying to enable additional",
+ " system privileges.",
+ " -Y [VMS] Treat archived name endings of .nnn as VMS version numbers.",
+ " -$ [MS-DOS, OS/2, NT] Restore volume label if extraction medium is",
+ " removable. -$$ allows fixed media (hard drives) to be labeled.",
+ " -/ e [Acorn] Use e as extension list.",
+ " -: [All but Acorn, VM/CMS, MVS, Tandem] Allow extract archive members into",
+ " locations outside of current extraction root folder. This allows",
+ " paths such as ../foo to be extracted above the current extraction",
+ " directory, which can be a security problem.",
+ " -^ [Unix] Allow control characters in names of extracted entries. Usually",
+ " this is not a good thing and should be avoided.",
+ " -2 [VMS] Force unconditional conversion of names to ODS-compatible names.",
+ " Default is to exploit destination file system, preserving cases and",
+ " extended name characters on ODS5 and applying ODS2 filtering on ODS2.",
+ "",
+ "",
+ "Wildcards:",
+ " Internally unzip supports the following wildcards:",
+ " ? (or %% or #, depending on OS) matches any single character",
+ " * matches any number of characters, including zero",
+ " [list] matches char in list (regex), can do range [ac-f], all but [!bf]",
+ " If port supports [], must escape [ as [[]",
+ " For shells that expand wildcards, escape (\\* or \"*\") so unzip can recurse.",
+ "",
+ "Include and Exclude:",
+ " -i pattern pattern ... include files that match a pattern",
+ " -x pattern pattern ... exclude files that match a pattern",
+ " Patterns are paths with optional wildcards and match paths as stored in",
+ " archive. Exclude and include lists end at next option or end of line.",
+ " unzip archive -x pattern pattern ...",
+ "",
+ "Multi-part (split) archives (archives created as a set of split files):",
+ " Currently split archives are not readable by unzip. A workaround is",
+ " to use zip to convert the split archive to a single-file archive and",
+ " use unzip on that. See the manual page for Zip 3.0 or later.",
+ "",
+ "Streaming (piping into unzip):",
+ " Currently unzip does not support streaming. The funzip utility can be",
+ " used to process the first entry in a stream.",
+ " cat archive | funzip",
+ "",
+ "Testing archives:",
+ " -t test contents of archive",
+ " This can be modified using -q for quieter operation, and -qq for even",
+ " quieter operation.",
+ "",
+ "Unicode:",
+ " If compiled with Unicode support, unzip automatically handles archives",
+ " with Unicode entries. Currently Unicode on Win32 systems is limited.",
+ " Characters not in the current character set are shown as ASCII escapes",
+ " in the form #Uxxxx where the Unicode character number fits in 16 bits,",
+ " or #Lxxxxxx where it doesn't, where x is the ASCII character for a hex",
+ " digit.",
+ "",
+ "",
+ "zipinfo options (these are used in zipinfo mode (unzip -Z ...)):",
+ " -1 List names only, one per line. No headers/trailers. Good for scripts.",
+ " -2 List names only as -1, but include headers, trailers, and comments.",
+ " -s List archive entries in short Unix ls -l format. Default list format.",
+ " -m List in long Unix ls -l format. As -s, but includes compression %.",
+ " -l List in long Unix ls -l format. As -m, but compression in bytes.",
+ " -v List zipfile information in verbose, multi-page format.",
+ " -h List header line. Includes archive name, actual size, total files.",
+ " -M Pipe all output through internal pager similar to Unix more(1) command.",
+ " -t List totals for files listed or for all files. Includes uncompressed",
+ " and compressed sizes, and compression factors.",
+ " -T Print file dates and times in a sortable decimal format (yymmdd.hhmmss)",
+ " Default date and time format is a more human-readable version.",
+ " -U [UNICODE] If entry has a UTF-8 Unicode path, display any characters",
+ " not in current character set as text #Uxxxx and #Lxxxxxx escapes",
+ " representing the Unicode character number of the character in hex.",
+ " -UU [UNICODE] Disable use of any UTF-8 path information.",
+ " -z Include archive comment if any in listing.",
+ "",
+ "",
+ "funzip stream extractor:",
+ " funzip extracts the first member in an archive to stdout. Typically",
+ " used to unzip the first member of a stream or pipe. If a file argument",
+ " is given, read from that file instead of stdin.",
+ "",
+ "funzip command line:",
+ " funzip [-password] [input[.zip|.gz]]",
+ "",
+ "",
+ "unzipsfx self extractor:",
+ " Self-extracting archives made with unzipsfx are no more (or less)",
+ " portable across different operating systems than unzip executables.",
+ " In general, a self-extracting archive made on a particular Unix system,",
+ " for example, will only self-extract under the same flavor of Unix.",
+ " Regular unzip may still be used to extract embedded archive however.",
+ "",
+ "unzipsfx command line:",
+ " <unzipsfx+archive_filename> [-options] [file(s) ... [-x xfile(s) ...]]",
+ "",
+ "unzipsfx options:",
+ " -c, -p - Output to pipe. (See above for unzip.)",
+ " -f, -u - Freshen and Update, as for unzip.",
+ " -t - Test embedded archive. (Can be used to list contents.)",
+ " -z - Print archive comment. (See unzip above.)",
+ "",
+ "unzipsfx modifiers:",
+ " Most unzip modifiers are supported. These include",
+ " -a - Convert text files.",
+ " -n - Never overwrite.",
+ " -o - Overwrite without prompting.",
+ " -q - Quiet operation.",
+ " -C - Match names case-insensitively.",
+ " -j - Junk paths.",
+ " -V - Keep version numbers.",
+ " -s - Convert spaces to underscores.",
+ " -$ - Restore volume label.",
+ "",
+ "If unzipsfx compiled with SFX_EXDIR defined, -d option also available:",
+ " -d exd - Extract to directory exd.",
+ "By default, all files extracted to current directory. This option",
+ "forces extraction to specified directory.",
+ "",
+ "See unzipsfx manual page for more information.",
+ ""
+ };
+
+ for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+ {
+ Info(slide, 0, ((char *)slide, "%s\n", text[i]));
+ }
+} /* end function help_extended() */
+
+
+
+
+#ifndef _WIN32_WCE /* Win CE does not support environment variables */
+#if (!defined(MODERN) || defined(NO_STDLIB_H))
+/* Declare getenv() to be sure (might be missing in some environments) */
+extern char *getenv();
+#endif
+#endif
+
+/********************************/
+/* Function show_version_info() */
+/********************************/
+
+static void show_version_info(__G)
+ __GDEF
+{
+ if (uO.qflag > 3) /* "unzip -vqqqq" */
+ Info(slide, 0, ((char *)slide, "%d\n",
+ (UZ_MAJORVER*100 + UZ_MINORVER*10 + UZ_PATCHLEVEL)));
+ else {
+#ifndef _WIN32_WCE /* Win CE does not support environment variables */
+ char *envptr;
+#endif
+ int numopts = 0;
+
+ Info(slide, 0, ((char *)slide, LoadFarString(UnzipUsageLine1v),
+ UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
+ LoadFarStringSmall(VersionDate)));
+ Info(slide, 0, ((char *)slide,
+ LoadFarString(UnzipUsageLine2v)));
+ version(__G);
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptions)));
+#ifdef ACORN_FTYPE_NFS
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(AcornFtypeNFS)));
+ ++numopts;
+#endif
+#ifdef ASM_CRC
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(AsmCRC)));
+ ++numopts;
+#endif
+#ifdef ASM_INFLATECODES
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(AsmInflateCodes)));
+ ++numopts;
+#endif
+#ifdef CHECK_VERSIONS
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Check_Versions)));
+ ++numopts;
+#endif
+#ifdef COPYRIGHT_CLEAN
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Copyright_Clean)));
+ ++numopts;
+#endif
+#ifdef DEBUG
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(UDebug)));
+ ++numopts;
+#endif
+#ifdef DEBUG_TIME
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(DebugTime)));
+ ++numopts;
+#endif
+#ifdef DLL
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Dll)));
+ ++numopts;
+#endif
+#ifdef DOSWILD
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(DosWild)));
+ ++numopts;
+#endif
+#ifdef LZW_CLEAN
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(LZW_Clean)));
+ ++numopts;
+#endif
+#ifndef MORE
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(No_More)));
+ ++numopts;
+#endif
+#ifdef NO_ZIPINFO
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(No_ZipInfo)));
+ ++numopts;
+#endif
+#ifdef NTSD_EAS
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(NTSDExtAttrib)));
+ ++numopts;
+#endif
+#if defined(WIN32) && defined(NO_W32TIMES_IZFIX)
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(W32NoIZTimeFix)));
+ ++numopts;
+#endif
+#ifdef OLD_THEOS_EXTRA
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(OldTheosExtra)));
+ ++numopts;
+#endif
+#ifdef OS2_EAS
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(OS2ExtAttrib)));
+ ++numopts;
+#endif
+#ifdef QLZIP
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(SMSExFldOnUnix)));
+ ++numopts;
+#endif
+#ifdef REENTRANT
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Reentrant)));
+ ++numopts;
+#endif
+#ifdef REGARGS
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(RegArgs)));
+ ++numopts;
+#endif
+#ifdef RETURN_CODES
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Return_Codes)));
+ ++numopts;
+#endif
+#ifdef SET_DIR_ATTRIB
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(SetDirAttrib)));
+ ++numopts;
+#endif
+#ifdef SYMLINKS
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(SymLinkSupport)));
+ ++numopts;
+#endif
+#ifdef TIMESTAMP
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(TimeStamp)));
+ ++numopts;
+#endif
+#ifdef UNIXBACKUP
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(UnixBackup)));
+ ++numopts;
+#endif
+#ifdef USE_EF_UT_TIME
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_EF_UT_time)));
+ ++numopts;
+#endif
+#ifndef COPYRIGHT_CLEAN
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_Smith_Code)));
+ ++numopts;
+#endif
+#ifndef LZW_CLEAN
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_Unshrink)));
+ ++numopts;
+#endif
+#ifdef USE_DEFLATE64
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_Deflate64)));
+ ++numopts;
+#endif
+#ifdef UNICODE_SUPPORT
+# ifdef UTF8_MAYBE_NATIVE
+ sprintf((char *)(slide+256), LoadFarStringSmall(Use_Unicode),
+ LoadFarStringSmall2(G.native_is_utf8 ? SysChUTF8 : SysChOther));
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ (char *)(slide+256)));
+# else
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_Unicode)));
+# endif
+ ++numopts;
+#endif
+#ifdef _MBCS
+ sprintf((char *)(slide+256), LoadFarStringSmall(Have_MBCS_Support),
+ (unsigned int)MB_CUR_MAX);
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ (char *)(slide+256)));
+ ++numopts;
+#endif
+#ifdef MULT_VOLUME
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_MultiVol)));
+ ++numopts;
+#endif
+#ifdef LARGE_FILE_SUPPORT
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_LFS)));
+ ++numopts;
+#endif
+#ifdef ZIP64_SUPPORT
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_Zip64)));
+ ++numopts;
+#endif
+#if (defined(__DJGPP__) && (__DJGPP__ >= 2))
+# ifdef USE_DJGPP_ENV
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_DJGPP_Env)));
+ ++numopts;
+# endif
+# ifdef USE_DJGPP_GLOB
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_DJGPP_Glob)));
+ ++numopts;
+# endif
+#endif /* __DJGPP__ && (__DJGPP__ >= 2) */
+#ifdef USE_VFAT
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(Use_VFAT_support)));
+ ++numopts;
+#endif
+#ifdef USE_ZLIB
+ sprintf((char *)(slide+256), LoadFarStringSmall(UseZlib),
+ ZLIB_VERSION, zlibVersion());
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ (char *)(slide+256)));
+ ++numopts;
+#endif
+#ifdef USE_BZIP2
+ sprintf((char *)(slide+256), LoadFarStringSmall(UseBZip2),
+ BZ2_bzlibVersion());
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ (char *)(slide+256)));
+ ++numopts;
+#endif
+#ifdef VMS_TEXT_CONV
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(VmsTextConv)));
+ ++numopts;
+#endif
+#ifdef VMSCLI
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(VmsCLI)));
+ ++numopts;
+#endif
+#ifdef VMSWILD
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(VmsWild)));
+ ++numopts;
+#endif
+#ifdef WILD_STOP_AT_DIR
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(WildStopAtDir)));
+ ++numopts;
+#endif
+#if CRYPT
+# ifdef PASSWD_FROM_STDIN
+ Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(PasswdStdin)));
+# endif
+ Info(slide, 0, ((char *)slide, LoadFarString(Decryption),
+ CR_MAJORVER, CR_MINORVER, CR_BETA_VER,
+ LoadFarStringSmall(CryptDate)));
+ ++numopts;
+#endif /* CRYPT */
+ if (numopts == 0)
+ Info(slide, 0, ((char *)slide,
+ LoadFarString(CompileOptFormat),
+ LoadFarStringSmall(None)));
+
+#ifndef _WIN32_WCE /* Win CE does not support environment variables */
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptions)));
+ envptr = getenv(LoadFarStringSmall(EnvUnZip));
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat),
+ LoadFarStringSmall(EnvUnZip),
+ (envptr == (char *)NULL || *envptr == 0)?
+ LoadFarStringSmall2(None) : envptr));
+ envptr = getenv(LoadFarStringSmall(EnvUnZip2));
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat),
+ LoadFarStringSmall(EnvUnZip2),
+ (envptr == (char *)NULL || *envptr == 0)?
+ LoadFarStringSmall2(None) : envptr));
+ envptr = getenv(LoadFarStringSmall(EnvZipInfo));
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat),
+ LoadFarStringSmall(EnvZipInfo),
+ (envptr == (char *)NULL || *envptr == 0)?
+ LoadFarStringSmall2(None) : envptr));
+ envptr = getenv(LoadFarStringSmall(EnvZipInfo2));
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat),
+ LoadFarStringSmall(EnvZipInfo2),
+ (envptr == (char *)NULL || *envptr == 0)?
+ LoadFarStringSmall2(None) : envptr));
+#ifndef __RSXNT__
+#ifdef __EMX__
+ envptr = getenv(LoadFarStringSmall(EnvEMX));
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat),
+ LoadFarStringSmall(EnvEMX),
+ (envptr == (char *)NULL || *envptr == 0)?
+ LoadFarStringSmall2(None) : envptr));
+ envptr = getenv(LoadFarStringSmall(EnvEMXOPT));
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat),
+ LoadFarStringSmall(EnvEMXOPT),
+ (envptr == (char *)NULL || *envptr == 0)?
+ LoadFarStringSmall2(None) : envptr));
+#endif /* __EMX__ */
+#if (defined(__GO32__) && (!defined(__DJGPP__) || (__DJGPP__ < 2)))
+ envptr = getenv(LoadFarStringSmall(EnvGO32));
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat),
+ LoadFarStringSmall(EnvGO32),
+ (envptr == (char *)NULL || *envptr == 0)?
+ LoadFarStringSmall2(None) : envptr));
+ envptr = getenv(LoadFarStringSmall(EnvGO32TMP));
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat),
+ LoadFarStringSmall(EnvGO32TMP),
+ (envptr == (char *)NULL || *envptr == 0)?
+ LoadFarStringSmall2(None) : envptr));
+#endif /* __GO32__ && !(__DJGPP__ >= 2) */
+#endif /* !__RSXNT__ */
+#ifdef RISCOS
+ envptr = getenv(LoadFarStringSmall(EnvUnZipExts));
+ Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat),
+ LoadFarStringSmall(EnvUnZipExts),
+ (envptr == (char *)NULL || *envptr == 0)?
+ LoadFarStringSmall2(None) : envptr));
+#endif /* RISCOS */
+#endif /* !_WIN32_WCE */
+ }
+} /* end function show_version() */
+
+#endif /* !SFX */
+#endif /* !WINDLL */
diff -Naur a/unzpriv.h b/unzpriv.h
--- a/unzpriv.h 2009-04-20 00:59:26.000000000 +0100
+++ b/unzpriv.h 2019-12-02 01:05:52.857702371 +0000
@@ -1211,6 +1211,7 @@
# ifdef UNICODE_WCHAR
# if !(defined(_WIN32_WCE) || defined(POCKET_UNZIP))
# include <wchar.h>
+# include <wctype.h>
# endif
# endif
# ifndef _MBCS /* no need to include <locale.h> twice, see below */
@@ -1806,6 +1807,8 @@
#define EB_NTSD_VERSION 4 /* offset of NTSD version byte */
#define EB_NTSD_MAX_VER (0) /* maximum version # we know how to handle */
+#define EB_PKVMS_MINLEN 4 /* minimum data length of PKVMS extra block */
+
#define EB_ASI_CRC32 0 /* offset of ASI Unix field's crc32 checksum */
#define EB_ASI_MODE 4 /* offset of ASI Unix permission mode field */
@@ -2393,6 +2396,12 @@
char *fnfilter OF((ZCONST char *raw, uch *space,
extent size));
+# if defined( UNICODE_SUPPORT) && defined( _MBCS)
+wchar_t *fnfilterw OF((ZCONST wchar_t *src, wchar_t *dst,
+ extent siz));
+#endif
+
+
/*---------------------------------------------------------------------------
Decompression functions:
---------------------------------------------------------------------------*/
@@ -2604,7 +2613,7 @@
int SetFileSize OF((FILE *file, zusz_t filesize)); /* local */
#endif
#ifndef MTS /* macro in MTS */
- void close_outfile OF((__GPRO)); /* local */
+ int close_outfile OF((__GPRO)); /* local */
#endif
#ifdef SET_SYMLINK_ATTRIBS
int set_symlnk_attribs OF((__GPRO__ slinkentry *slnk_entry)); /* local */
@@ -3008,7 +3017,7 @@
!(((islochdr) || (isuxatt)) && \
((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
(hostnum) == FS_HPFS_ || \
- ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
+ ((hostnum) == FS_NTFS_ /* && (hostver) == 50 */ )) { \
_OEM_INTERN((string)); \
} else { \
_ISO_INTERN((string)); \
diff -Naur a/unzpriv.h.orig b/unzpriv.h.orig
--- a/unzpriv.h.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/unzpriv.h.orig 2019-12-02 01:04:10.077348607 +0000
@@ -0,0 +1,3125 @@
+/*
+ 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
+*/
+/*---------------------------------------------------------------------------
+
+ unzpriv.h
+
+ This header file contains private (internal) macros, typedefs, prototypes
+ and global-variable declarations used by all of the UnZip source files.
+ In a prior life it was part of the main unzip.h header, but now it is only
+ included by that header if UNZIP_INTERNAL is defined.
+
+ ---------------------------------------------------------------------------*/
+
+
+
+#ifndef __unzpriv_h /* prevent multiple inclusions */
+#define __unzpriv_h
+
+/* First thing: Signal all following code that we compile UnZip utilities! */
+#ifndef UNZIP
+# define UNZIP
+#endif
+
+/* GRR 960204: MORE defined here in preparation for removal altogether */
+#ifndef MORE
+# ifndef RISCOS
+# define MORE
+# endif
+#endif
+
+/* fUnZip should never need to be reentrant */
+#ifdef FUNZIP
+# ifdef REENTRANT
+# undef REENTRANT
+# endif
+# ifdef DLL
+# undef DLL
+# endif
+# ifdef SFX /* fUnZip is NOT the sfx stub! */
+# undef SFX
+# endif
+# ifdef USE_BZIP2 /* fUnZip does not support bzip2 decompression */
+# undef USE_BZIP2
+# endif
+#endif
+
+#if (defined(USE_ZLIB) && !defined(HAVE_ZL_INFLAT64) && !defined(NO_DEFLATE64))
+ /* zlib does not (yet?) provide Deflate64(tm) support */
+# define NO_DEFLATE64
+#endif
+
+#ifdef NO_DEFLATE64
+ /* disable support for Deflate64(tm) */
+# ifdef USE_DEFLATE64
+# undef USE_DEFLATE64
+# endif
+#else
+ /* enable Deflate64(tm) support unless compiling for SFX stub */
+# if (!defined(USE_DEFLATE64) && !defined(SFX))
+# define USE_DEFLATE64
+# endif
+#endif
+
+/* disable bzip2 support for SFX stub, unless explicitly requested */
+#if (defined(SFX) && !defined(BZIP2_SFX) && defined(USE_BZIP2))
+# undef USE_BZIP2
+#endif
+
+#if (defined(NO_VMS_TEXT_CONV) || defined(VMS))
+# ifdef VMS_TEXT_CONV
+# undef VMS_TEXT_CONV
+# endif
+#else
+# if (!defined(VMS_TEXT_CONV) && !defined(SFX))
+# define VMS_TEXT_CONV
+# endif
+#endif
+
+/* Enable -B option per default on specific systems, to allow backing up
+ * files that would be overwritten.
+ * (This list of systems must be kept in sync with the list of systems
+ * that add the B_flag to the UzpOpts structure, see unzip.h.)
+ */
+#if (!defined(NO_UNIXBACKUP) && !defined(UNIXBACKUP))
+# if defined(UNIX) || defined(OS2) || defined(WIN32)
+# define UNIXBACKUP
+# endif
+#endif
+
+#if (defined(DLL) && !defined(REENTRANT))
+# define REENTRANT
+#endif
+
+#if (!defined(DYNAMIC_CRC_TABLE) && !defined(FUNZIP))
+# define DYNAMIC_CRC_TABLE
+#endif
+
+#if (defined(DYNAMIC_CRC_TABLE) && !defined(REENTRANT))
+# ifndef DYNALLOC_CRCTAB
+# define DYNALLOC_CRCTAB
+# endif
+#endif
+
+/*---------------------------------------------------------------------------
+ OS-dependent configuration for UnZip internals
+ ---------------------------------------------------------------------------*/
+
+/* Some compiler distributions for Win32/i386 systems try to emulate
+ * a Unix (POSIX-compatible) environment.
+ */
+#if (defined(WIN32) && defined(UNIX))
+ /* UnZip does not support merging both ports in a single executable. */
+# if (defined(FORCE_WIN32_OVER_UNIX) && defined(FORCE_UNIX_OVER_WIN32))
+ /* conflicting choice requests -> we prefer the Win32 environment */
+# undef FORCE_UNIX_OVER_WIN32
+# endif
+# ifdef FORCE_WIN32_OVER_UNIX
+ /* native Win32 support was explicitly requested... */
+# undef UNIX
+# else
+ /* use the POSIX (Unix) emulation features by default... */
+# undef WIN32
+# endif
+#endif
+
+/* bad or (occasionally?) missing stddef.h: */
+#if (defined(M_XENIX) || defined(DNIX))
+# define NO_STDDEF_H
+#endif
+
+#if (defined(M_XENIX) && !defined(M_UNIX)) /* SCO Xenix only, not SCO Unix */
+# define SCO_XENIX
+# define NO_LIMITS_H /* no limits.h, but MODERN defined */
+# define NO_UID_GID /* no uid_t/gid_t */
+# define size_t int
+#endif
+
+#ifdef realix /* Modcomp Real/IX, real-time SysV.3 variant */
+# define SYSV
+# define NO_UID_GID /* no uid_t/gid_t */
+#endif
+
+#if (defined(_AIX) && !defined(_ALL_SOURCE))
+# define _ALL_SOURCE
+#endif
+
+#if defined(apollo) /* defines __STDC__ */
+# define NO_STDLIB_H
+#endif
+
+#ifdef DNIX
+# define SYSV
+# define SHORT_NAMES /* 14-char limitation on path components */
+/* # define FILENAME_MAX 14 */
+# define FILENAME_MAX NAME_MAX /* GRR: experiment */
+#endif
+
+#if (defined(SYSTEM_FIVE) || defined(__SYSTEM_FIVE))
+# ifndef SYSV
+# define SYSV
+# endif
+#endif /* SYSTEM_FIVE || __SYSTEM_FIVE */
+#if (defined(M_SYSV) || defined(M_SYS5))
+# ifndef SYSV
+# define SYSV
+# endif
+#endif /* M_SYSV || M_SYS5 */
+/* __SVR4 and __svr4__ catch Solaris on at least some combos of compiler+OS */
+#if (defined(__SVR4) || defined(__svr4__) || defined(sgi) || defined(__hpux))
+# ifndef SYSV
+# define SYSV
+# endif
+#endif /* __SVR4 || __svr4__ || sgi || __hpux */
+#if (defined(LINUX) || defined(__QNX__))
+# ifndef SYSV
+# define SYSV
+# endif
+#endif /* LINUX || __QNX__ */
+
+#if (defined(ultrix) || defined(__ultrix) || defined(bsd4_2))
+# if (!defined(BSD) && !defined(SYSV))
+# define BSD
+# endif
+#endif /* ultrix || __ultrix || bsd4_2 */
+#if (defined(sun) || defined(pyr) || defined(CONVEX))
+# if (!defined(BSD) && !defined(SYSV))
+# define BSD
+# endif
+#endif /* sun || pyr || CONVEX */
+
+#ifdef pyr /* Pyramid: has BSD and AT&T "universes" */
+# ifdef BSD
+# define pyr_bsd
+# define USE_STRINGS_H /* instead of more common string.h */
+# define ZMEM /* ZMEM now uses bcopy/bzero: not in AT&T universe */
+# endif /* (AT&T memcpy claimed to be very slow, though) */
+# define DECLARE_ERRNO
+#endif /* pyr */
+
+/* stat() bug for Borland, VAX C RTL, and Atari ST MiNT on TOS
+ * filesystems: returns 0 for wildcards! (returns 0xffffffff on Minix
+ * filesystem or `U:' drive under Atari MiNT.) Watcom C was previously
+ * included on this list; it would be good to know what version the problem
+ * was fixed at, if it did exist. */
+#if (defined(__TURBOC__) && !defined(WIN32))
+/*# define WILD_STAT_BUG*/
+#endif
+#if (defined(VMS) || defined(__MINT__))
+# define WILD_STAT_BUG
+#endif
+
+/*---------------------------------------------------------------------------
+ OS-dependent includes
+ ---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------
+ API (DLL) section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef DLL
+# define MAIN UZ_EXP UzpMain /* was UzpUnzip */
+# ifdef OS2DLL
+# undef Info
+# define REDIRECTC(c) varputchar(__G__ c)
+# define REDIRECTPRINT(buf,size) varmessage(__G__ buf, size)
+# define FINISH_REDIRECT() finish_REXX_redirect(__G)
+# else
+# define REDIRECTC(c)
+# define REDIRECTPRINT(buf,size) 0
+# define FINISH_REDIRECT() close_redirect(__G)
+# endif
+#endif
+
+/*---------------------------------------------------------------------------
+ Acorn RISCOS section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef RISCOS
+# include "acorn/riscos.h"
+#endif
+
+/*---------------------------------------------------------------------------
+ Amiga section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef AMIGA
+# include "amiga/amiga.h"
+#endif
+
+/*---------------------------------------------------------------------------
+ AOS/VS section (somewhat similar to Unix, apparently):
+ ---------------------------------------------------------------------------*/
+
+#ifdef AOS_VS
+# ifdef __FILEIO_C
+# include "aosvs/aosvs.h"
+# endif
+#endif
+
+/*---------------------------------------------------------------------------
+ Atari ST section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef ATARI
+# include <time.h>
+# include <stat.h>
+# include <fcntl.h>
+# include <limits.h>
+# define SYMLINKS
+# define EXE_EXTENSION ".tos"
+# ifndef DATE_FORMAT
+# define DATE_FORMAT DF_DMY
+# endif
+# define DIR_END '/'
+# define INT_SPRINTF
+# define timezone _timezone
+# define lenEOL 2
+# define PutNativeEOL {*q++ = native(CR); *q++ = native(LF);}
+# undef SHORT_NAMES
+# if (!defined(NOTIMESTAMP) && !defined(TIMESTAMP))
+# define TIMESTAMP
+# endif
+#endif
+
+/*---------------------------------------------------------------------------
+ AtheOS section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef __ATHEOS__
+# include "atheos/athcfg.h"
+#endif
+
+/*---------------------------------------------------------------------------
+ BeOS section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef __BEOS__
+# include "beos/beocfg.h"
+#endif
+
+/*---------------------------------------------------------------------------
+ Human68k/X680x0 section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef __human68k__
+ /* DO NOT DEFINE DOS_OS2 HERE! If Human68k is so much */
+ /* like MS-DOS and/or OS/2, create DOS_H68_OS2 macro. */
+# if (!defined(_MBCS) && !defined(NO_MBCS))
+ /* enable MBCS support by default for this system */
+# define _MBCS
+# endif
+# if (defined(_MBCS) && defined(NO_MBCS))
+ /* disable MBCS support when explicitely requested */
+# undef _MBCS
+# endif
+# include <time.h>
+# include <fcntl.h>
+# include <io.h>
+# include <conio.h>
+# include <sys/stat.h>
+# ifdef HAVE_MBSTRING_H
+# include <mbstring.h>
+# endif
+# ifdef HAVE_MBCTYPE_H
+# include <mbctype.h>
+# else
+# ifndef _ismbblead
+# define _ismbblead(c) (0x80 <= (c) && ((c) < 0xa0 || 0xe0 <= (c)))
+# endif
+# endif
+# ifndef DATE_FORMAT
+# define DATE_FORMAT DF_YMD /* Japanese standard */
+# endif
+# define lenEOL 1
+# define PutNativeEOL *q++ = native(LF);
+# define INT_SPRINTF
+# define SYMLINKS
+# ifdef SFX
+# define MAIN main_sfx
+# endif
+#endif
+
+/*---------------------------------------------------------------------------
+ Mac section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef MACOS
+# include "maccfg.h"
+#endif /* MACOS */
+
+/*---------------------------------------------------------------------------
+ MS-DOS, OS/2, FLEXOS section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef WINDLL
+# ifdef MORE
+# undef MORE
+# endif
+# ifdef OS2_EAS
+# undef OS2_EAS
+# endif
+#endif
+
+#if (defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__)))
+# ifndef MSC
+# define MSC /* This should work for older MSC, too! */
+# endif
+#endif
+
+#if (defined(MSDOS) || defined(OS2) || defined(FLEXOS))
+# include <sys/types.h> /* off_t, time_t, dev_t, ... */
+# include <sys/stat.h>
+# include <io.h> /* lseek(), open(), setftime(), dup(), creat() */
+# include <time.h> /* localtime() */
+# include <fcntl.h> /* O_BINARY for open() w/o CR/LF translation */
+
+# ifdef OS2 /* defined for all OS/2 compilers */
+# include "os2/os2cfg.h"
+# else
+# ifdef FLEXOS
+# include "flexos/flxcfg.h"
+# else
+# include "msdos/doscfg.h"
+# endif
+# endif
+
+# if (defined(_MSC_VER) && (_MSC_VER == 700) && !defined(GRR))
+ /*
+ * ARGH. MSC 7.0 libraries think times are based on 1899 Dec 31 00:00, not
+ * 1970 Jan 1 00:00. So we have to diddle time_t's appropriately: add or
+ * subtract 70 years' worth of seconds; i.e., number of days times 86400;
+ * i.e., (70*365 regular days + 17 leap days + 1 1899 day) * 86400 ==
+ * (25550 + 17 + 1) * 86400 == 2209075200 seconds. We know time_t is an
+ * unsigned long (ulg) on the only system with this bug.
+ */
+# define TIMET_TO_NATIVE(x) (x) += (ulg)2209075200L;
+# define NATIVE_TO_TIMET(x) (x) -= (ulg)2209075200L;
+# endif
+# if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x0450))
+# define timezone _timezone
+# endif
+# if (defined(__GO32__) || defined(FLEXOS))
+# define DIR_END '/'
+# else
+# define DIR_END '\\' /* OS uses '\\' as directory separator */
+# define DIR_END2 '/' /* also check for '/' (RTL may convert) */
+# endif
+# ifdef DATE_FORMAT
+# undef DATE_FORMAT
+# endif
+# define DATE_FORMAT dateformat()
+# define lenEOL 2
+# define PutNativeEOL {*q++ = native(CR); *q++ = native(LF);}
+# if (!defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME))
+# define USE_EF_UT_TIME
+# endif
+#endif /* MSDOS || OS2 || FLEXOS */
+
+/*---------------------------------------------------------------------------
+ MTS section (piggybacks UNIX, I think):
+ ---------------------------------------------------------------------------*/
+
+#ifdef MTS
+# include <sys/types.h> /* off_t, time_t, dev_t, ... */
+# include <sys/stat.h>
+# include <sys/file.h> /* MTS uses this instead of fcntl.h */
+# include <timeb.h>
+# include <time.h>
+# include <unix.h> /* some important non-ANSI routines */
+# define mkdir(s,n) (-1) /* no "make directory" capability */
+# define EBCDIC /* set EBCDIC conversion on */
+# define NO_STRNICMP /* unzip's is as good the one in MTS */
+# define USE_FWRITE
+# define close_outfile() fclose(G.outfile) /* can't set time on files */
+# define umask(n) /* don't have umask() on MTS */
+# define FOPWT "w" /* open file for writing in TEXT mode */
+# ifndef DATE_FORMAT
+# define DATE_FORMAT DF_MDY
+# endif
+# define lenEOL 1
+# define PutNativeEOL *q++ = native(LF);
+#endif /* MTS */
+
+ /*---------------------------------------------------------------------------
+ Novell Netware NLM section
+ ---------------------------------------------------------------------------*/
+
+#ifdef NLM
+# include "netware/nlmcfg.h"
+#endif
+
+ /*---------------------------------------------------------------------------
+ QDOS section
+ ---------------------------------------------------------------------------*/
+
+#ifdef QDOS
+# define DIRENT
+# include <fcntl.h>
+# include <unistd.h>
+# include <sys/stat.h>
+# include <time.h>
+# include "qdos/izqdos.h"
+# ifndef DATE_FORMAT
+# define DATE_FORMAT DF_MDY
+# endif
+# define lenEOL 1
+# define PutNativeEOL *q++ = native(LF);
+# define DIR_END '_'
+# define RETURN QReturn
+# undef PATH_MAX
+# define PATH_MAX 36
+# if (!defined(NOTIMESTAMP) && !defined(TIMESTAMP))
+# define TIMESTAMP
+# endif
+# define SCREENSIZE(ttrows, ttcols) screensize(ttrows, ttcols)
+# define SCREENWIDTH 80
+#endif
+
+/*---------------------------------------------------------------------------
+ Tandem NSK section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef TANDEM
+# include "tandem.h"
+# include <fcntl.h>
+# ifndef __INT32
+ /* We are compiling with non-WIDE memory model, int = 16 bits */
+# ifndef INT_16BIT
+# define INT_16BIT /* report "int" size is 16-bit to inflate setup */
+# endif
+# ifdef USE_DEFLATE64
+ /* Following required for 64k WSIZE of Deflate64 support */
+# define MED_MEM /* else OUTBUFSIZ is 64K and fails in do_string */
+# define INBUFSIZ 8192 /* but larger buffer for real OSes */
+# endif
+# endif
+ /* use a single LF delimiter so that writes to 101 text files work */
+# define PutNativeEOL *q++ = native(LF);
+# define lenEOL 1
+# ifndef DATE_FORMAT
+# define DATE_FORMAT DF_DMY
+# endif
+# define SCREENLINES 25
+ /* USE_EF_UT_TIME is set in tandem.h */
+# define RESTORE_UIDGID
+# define NO_STRNICMP
+#endif
+
+/*---------------------------------------------------------------------------
+ THEOS section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef THEOS
+# include "theos/thscfg.h"
+#endif
+
+/*---------------------------------------------------------------------------
+ TOPS-20 section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef TOPS20
+# include <sys/types.h> /* off_t, time_t, dev_t, ... */
+# include <sys/stat.h>
+# include <sys/param.h>
+# include <sys/time.h>
+# include <sys/timeb.h>
+# include <sys/file.h>
+# include <timex.h>
+# include <monsym.h> /* get amazing monsym() macro */
+ extern int open(), close(), read();
+ extern int stat(), unlink(), jsys(), fcntl();
+ extern long lseek(), dup(), creat();
+# define strchr index /* GRR: necessary? */
+# define strrchr rindex
+# define REALLY_SHORT_SYMS
+# define NO_MKDIR
+# ifndef HAVE_STRNICMP
+# define NO_STRNICMP /* probably not provided by TOPS20 C RTL */
+# endif
+# define DIR_BEG '<'
+# define DIR_END '>'
+# define DIR_EXT ".directory"
+# ifndef DATE_FORMAT
+# define DATE_FORMAT DF_MDY
+# endif
+# define EXE_EXTENSION ".exe" /* just a guess... */
+#endif /* TOPS20 */
+
+/*---------------------------------------------------------------------------
+ Unix section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef UNIX
+# include "unix/unxcfg.h"
+#endif /* UNIX */
+
+/*---------------------------------------------------------------------------
+ VM/CMS and MVS section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef CMS_MVS
+# include "vmmvs.h"
+# define CLOSE_INFILE() close_infile(__G)
+#endif
+
+/*---------------------------------------------------------------------------
+ VMS section:
+ ---------------------------------------------------------------------------*/
+
+#ifdef VMS
+# include "vms/vmscfg.h"
+#endif /* VMS */
+
+/*---------------------------------------------------------------------------
+ Win32 (Windows 95/NT) section:
+ ---------------------------------------------------------------------------*/
+
+#if (defined(WIN32) && !defined(POCKET_UNZIP) && !defined(_WIN32_WCE))
+# include "win32/w32cfg.h"
+#endif
+
+/*---------------------------------------------------------------------------
+ Win32 Windows CE section (also POCKET_UNZIP)
+ ---------------------------------------------------------------------------*/
+
+#if (defined(_WIN32_WCE) || defined(POCKET_UNZIP))
+# include "wince/wcecfg.h"
+#endif
+
+
+
+/* ----------------------------------------------------------------------------
+ MUST BE AFTER LARGE FILE INCLUDES
+ ---------------------------------------------------------------------------- */
+/* This stuff calls in types and messes up large file includes. It needs to
+ go after large file defines in local includes.
+ I am guessing that moving them here probably broke some ports, but hey.
+ 10/31/2004 EG */
+/* ----------------------------------------------------------------------------
+ Common includes
+ ---------------------------------------------------------------------------- */
+
+/* Some ports apply specific adjustments which must be in effect before
+ reading the "standard" include headers.
+ */
+
+#ifdef EFT
+# define Z_OFF_T off_t /* Amdahl UTS nonsense ("extended file types") */
+#else
+#if (defined(UNIX) && defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64))
+# define Z_OFF_T off_t /* 64bit offsets to support 2GB < zipfile size < 4GB */
+#else
+# define Z_OFF_T long
+#endif
+#endif
+
+#ifndef ZOFF_T_DEFINED
+ typedef Z_OFF_T zoff_t;
+# define ZOFF_T_DEFINED
+#endif
+#ifndef Z_STAT_DEFINED
+ typedef struct stat z_stat;
+# define Z_STAT_DEFINED
+#endif
+
+#ifndef MINIX /* Minix needs it after all the other includes (?) */
+# include <stdio.h>
+#endif
+
+#include <ctype.h> /* skip for VMS, to use tolower() function? */
+#include <errno.h> /* used in mapname() */
+#ifdef USE_STRINGS_H
+# include <strings.h> /* strcpy, strcmp, memcpy, index/rindex, etc. */
+#else
+# include <string.h> /* strcpy, strcmp, memcpy, strchr/strrchr, etc. */
+#endif
+#if (defined(MODERN) && !defined(NO_LIMITS_H))
+# include <limits.h> /* MAX/MIN constant symbols for system types... */
+#endif
+
+/* this include must be down here for SysV.4, for some reason... */
+#include <signal.h> /* used in unzip.c, fileio.c */
+
+
+#ifdef MODERN
+# ifndef NO_STDDEF_H
+# include <stddef.h>
+# endif
+# ifndef NO_STDLIB_H
+# include <stdlib.h> /* standard library prototypes, malloc(), etc. */
+# endif
+ typedef size_t extent;
+#else /* !MODERN */
+# ifndef AOS_VS /* mostly modern? */
+ Z_OFF_T lseek();
+# ifdef VAXC /* not fully modern, but has stdlib.h and void */
+# include <stdlib.h>
+# else
+ char *malloc();
+# endif /* ?VAXC */
+# endif /* !AOS_VS */
+ typedef unsigned int extent;
+#endif /* ?MODERN */
+
+
+
+
+/*************/
+/* Defines */
+/*************/
+
+#define UNZIP_BZ2VERS 46
+#ifdef ZIP64_SUPPORT
+# ifdef USE_BZIP2
+# define UNZIP_VERSION UNZIP_BZ2VERS
+# else
+# define UNZIP_VERSION 45
+# endif
+#else
+#ifdef USE_DEFLATE64
+# define UNZIP_VERSION 21 /* compatible with PKUNZIP 4.0 */
+#else
+# define UNZIP_VERSION 20 /* compatible with PKUNZIP 2.0 */
+#endif
+#endif
+#define VMS_UNZIP_VERSION 42 /* if OS-needed-to-extract is VMS: can do */
+
+#if (defined(MSDOS) || defined(OS2))
+# define DOS_OS2
+#endif
+
+#if (defined(OS2) || defined(WIN32))
+# define OS2_W32
+#endif
+
+#if (defined(DOS_OS2) || defined(WIN32))
+# define DOS_OS2_W32
+# define DOS_W32_OS2 /* historical: don't use */
+#endif
+
+#if (defined(DOS_OS2_W32) || defined(__human68k__))
+# define DOS_H68_OS2_W32
+#endif
+
+#if (defined(DOS_OS2) || defined(FLEXOS))
+# define DOS_FLX_OS2
+#endif
+
+#if (defined(DOS_OS2_W32) || defined(FLEXOS))
+# define DOS_FLX_OS2_W32
+#endif
+
+#if (defined(DOS_H68_OS2_W32) || defined(FLEXOS))
+# define DOS_FLX_H68_OS2_W32
+#endif
+
+#if (defined(DOS_FLX_OS2) || defined(NLM))
+# define DOS_FLX_NLM_OS2
+#endif
+
+#if (defined(DOS_FLX_OS2_W32) || defined(NLM))
+# define DOS_FLX_NLM_OS2_W32
+#endif
+
+#if (defined(DOS_FLX_H68_OS2_W32) || defined(NLM))
+# define DOS_FLX_H68_NLM_OS2_W32
+#endif
+
+#if (defined(TOPS20) || defined(VMS))
+# define T20_VMS
+#endif
+
+#if (defined(MSDOS) || defined(T20_VMS))
+# define DOS_T20_VMS
+#endif
+
+#if (defined(__ATHEOS__) || defined(__BEOS__))
+# define ATH_BEO
+#endif
+
+#if (defined(ATH_BEO) || defined(UNIX))
+# define ATH_BEO_UNX
+#endif
+
+#if (defined(ATH_BEO_UNX) || defined(THEOS))
+# define ATH_BEO_THS_UNX
+#endif
+
+/* clean up with a few defaults */
+#ifndef DIR_END
+# define DIR_END '/' /* last char before program name or filename */
+#endif
+#ifndef DATE_FORMAT
+# ifdef DATEFMT_ISO_DEFAULT
+# define DATE_FORMAT DF_YMD /* defaults to invariant ISO-style */
+# else
+# define DATE_FORMAT DF_MDY /* defaults to US convention */
+# endif
+#endif
+#ifndef DATE_SEPCHAR
+# define DATE_SEPCHAR '-'
+#endif
+#ifndef CLOSE_INFILE
+# define CLOSE_INFILE() close(G.zipfd)
+#endif
+#ifndef RETURN
+# define RETURN return /* only used in main() */
+#endif
+#ifndef EXIT
+# define EXIT exit
+#endif
+#ifndef USAGE
+# define USAGE(ret) usage(__G__ (ret)) /* used in unzip.c, zipinfo.c */
+#endif
+#ifndef TIMET_TO_NATIVE /* everybody but MSC 7.0 and Macintosh */
+# define TIMET_TO_NATIVE(x)
+# define NATIVE_TO_TIMET(x)
+#endif
+#ifndef STRNICMP
+# ifdef NO_STRNICMP
+# define STRNICMP zstrnicmp
+# else
+# define STRNICMP strnicmp
+# endif
+#endif
+
+
+#if (defined(DOS_FLX_NLM_OS2_W32) || defined(ATH_BEO_UNX) || defined(RISCOS))
+# ifndef HAVE_UNLINK
+# define HAVE_UNLINK
+# endif
+#endif
+#if (defined(AOS_VS) || defined(ATARI)) /* GRR: others? */
+# ifndef HAVE_UNLINK
+# define HAVE_UNLINK
+# endif
+#endif
+
+/* OS-specific exceptions to the "ANSI <--> INT_SPRINTF" rule */
+
+#if (!defined(PCHAR_SPRINTF) && !defined(INT_SPRINTF))
+# if (defined(SYSV) || defined(CONVEX) || defined(NeXT) || defined(BSD4_4))
+# define INT_SPRINTF /* sprintf() returns int: SysVish/Posix */
+# endif
+# if (defined(DOS_FLX_NLM_OS2_W32) || defined(VMS) || defined(AMIGA))
+# define INT_SPRINTF /* sprintf() returns int: ANSI */
+# endif
+# if (defined(ultrix) || defined(__ultrix)) /* Ultrix 4.3 and newer */
+# if (defined(POSIX) || defined(__POSIX))
+# define INT_SPRINTF /* sprintf() returns int: ANSI/Posix */
+# endif
+# ifdef __GNUC__
+# define PCHAR_SPRINTF /* undetermined actual return value */
+# endif
+# endif
+# if (defined(__osf__) || defined(_AIX) || defined(CMS_MVS) || defined(THEOS))
+# define INT_SPRINTF /* sprintf() returns int: ANSI/Posix */
+# endif
+# if defined(sun)
+# define PCHAR_SPRINTF /* sprintf() returns char *: SunOS cc *and* gcc */
+# endif
+#endif
+
+/* defaults that we hope will take care of most machines in the future */
+
+#if (!defined(PCHAR_SPRINTF) && !defined(INT_SPRINTF))
+# ifdef __STDC__
+# define INT_SPRINTF /* sprintf() returns int: ANSI */
+# endif
+# ifndef INT_SPRINTF
+# define PCHAR_SPRINTF /* sprintf() returns char *: BSDish */
+# endif
+#endif
+
+#define MSG_STDERR(f) (f & 1) /* bit 0: 0 = stdout, 1 = stderr */
+#define MSG_INFO(f) ((f & 6) == 0) /* bits 1 and 2: 0 = info */
+#define MSG_WARN(f) ((f & 6) == 2) /* bits 1 and 2: 1 = warning */
+#define MSG_ERROR(f) ((f & 6) == 4) /* bits 1 and 2: 2 = error */
+#define MSG_FATAL(f) ((f & 6) == 6) /* bits 1 and 2: (3 = fatal error) */
+#define MSG_ZFN(f) (f & 0x0008) /* bit 3: 1 = print zipfile name */
+#define MSG_FN(f) (f & 0x0010) /* bit 4: 1 = print filename */
+#define MSG_LNEWLN(f) (f & 0x0020) /* bit 5: 1 = leading newline if !SOL */
+#define MSG_TNEWLN(f) (f & 0x0040) /* bit 6: 1 = trailing newline if !SOL */
+#define MSG_MNEWLN(f) (f & 0x0080) /* bit 7: 1 = trailing NL for prompts */
+/* the following are subject to change */
+#define MSG_NO_WGUI(f) (f & 0x0100) /* bit 8: 1 = skip if Windows GUI */
+#define MSG_NO_AGUI(f) (f & 0x0200) /* bit 9: 1 = skip if Acorn GUI */
+#define MSG_NO_DLL2(f) (f & 0x0400) /* bit 10: 1 = skip if OS/2 DLL */
+#define MSG_NO_NDLL(f) (f & 0x0800) /* bit 11: 1 = skip if WIN32 DLL */
+#define MSG_NO_WDLL(f) (f & 0x1000) /* bit 12: 1 = skip if Windows DLL */
+
+#if (defined(MORE) && !defined(SCREENLINES))
+# ifdef DOS_FLX_NLM_OS2_W32
+# define SCREENLINES 25 /* can be (should be) a function instead */
+# else
+# define SCREENLINES 24 /* VT-100s are assumed to be minimal hardware */
+# endif
+#endif
+#if (defined(MORE) && !defined(SCREENSIZE))
+# ifndef SCREENWIDTH
+# define SCREENSIZE(scrrows, scrcols) { \
+ if ((scrrows) != NULL) *(scrrows) = SCREENLINES; }
+# else
+# define SCREENSIZE(scrrows, scrcols) { \
+ if ((scrrows) != NULL) *(scrrows) = SCREENLINES; \
+ if ((scrcols) != NULL) *(scrcols) = SCREENWIDTH; }
+# endif
+#endif
+
+#if (defined(__16BIT__) || defined(MED_MEM) || defined(SMALL_MEM))
+# define DIR_BLKSIZ 64 /* number of directory entries per block
+ * (should fit in 4096 bytes, usually) */
+#else
+# define DIR_BLKSIZ 16384 /* use more memory, to reduce long-range seeks */
+#endif
+
+#ifndef WSIZE
+# ifdef USE_DEFLATE64
+# define WSIZE 65536L /* window size--must be a power of two, and */
+# else /* at least 64K for PKZip's deflate64 method */
+# define WSIZE 0x8000 /* window size--must be a power of two, and */
+# endif /* at least 32K for zip's deflate method */
+#endif
+
+#ifdef __16BIT__
+# ifndef INT_16BIT
+# define INT_16BIT /* on 16-bit systems int size is 16 bits */
+# endif
+#else
+# define nearmalloc malloc
+# define nearfree free
+# if (!defined(__IBMC__) || !defined(OS2))
+# ifndef near
+# define near
+# endif
+# ifndef far
+# define far
+# endif
+# endif
+#endif
+
+#if (defined(DYNALLOC_CRCTAB) && !defined(DYNAMIC_CRC_TABLE))
+# undef DYNALLOC_CRCTAB
+#endif
+
+#if (defined(DYNALLOC_CRCTAB) && defined(REENTRANT))
+# undef DYNALLOC_CRCTAB /* not safe with reentrant code */
+#endif
+
+#if (defined(USE_ZLIB) && !defined(USE_OWN_CRCTAB))
+# ifdef DYNALLOC_CRCTAB
+# undef DYNALLOC_CRCTAB
+# endif
+#endif
+
+#if (defined(USE_ZLIB) && defined(ASM_CRC))
+# undef ASM_CRC
+#endif
+
+#ifdef USE_ZLIB
+# ifdef IZ_CRC_BE_OPTIMIZ
+# undef IZ_CRC_BE_OPTIMIZ
+# endif
+# ifdef IZ_CRC_LE_OPTIMIZ
+# undef IZ_CRC_LE_OPTIMIZ
+# endif
+#endif
+#if (!defined(IZ_CRC_BE_OPTIMIZ) && !defined(IZ_CRC_LE_OPTIMIZ))
+# ifdef IZ_CRCOPTIM_UNFOLDTBL
+# undef IZ_CRCOPTIM_UNFOLDTBL
+# endif
+#endif
+
+#ifndef INBUFSIZ
+# if (defined(MED_MEM) || defined(SMALL_MEM))
+# define INBUFSIZ 2048 /* works for MS-DOS small model */
+# else
+# define INBUFSIZ 8192 /* larger buffers for real OSes */
+# endif
+#endif
+
+#if (defined(INT_16BIT) && (defined(USE_DEFLATE64) || lenEOL > 1))
+ /* For environments using 16-bit integers OUTBUFSIZ must be limited to
+ * less than 64k (do_string() uses "unsigned" in calculations involving
+ * OUTBUFSIZ). This is achieved by defining MED_MEM when WSIZE = 64k (aka
+ * Deflate64 support enabled) or EOL markers contain multiple characters.
+ * (The rule gets applied AFTER the default rule for INBUFSIZ because it
+ * is not neccessary to reduce INBUFSIZE in this case.)
+ */
+# if (!defined(SMALL_MEM) && !defined(MED_MEM))
+# define MED_MEM
+# endif
+#endif
+
+/* Logic for case of small memory, length of EOL > 1: if OUTBUFSIZ == 2048,
+ * OUTBUFSIZ>>1 == 1024 and OUTBUFSIZ>>7 == 16; therefore rawbuf is 1008 bytes
+ * and transbuf 1040 bytes. Have room for 32 extra EOL chars; 1008/32 == 31.5
+ * chars/line, smaller than estimated 35-70 characters per line for C source
+ * and normal text. Hence difference is sufficient for most "average" files.
+ * (Argument scales for larger OUTBUFSIZ.)
+ */
+#ifdef SMALL_MEM /* i.e., 16-bit OSes: MS-DOS, OS/2 1.x, etc. */
+# define LoadFarString(x) fLoadFarString(__G__ (x))
+# define LoadFarStringSmall(x) fLoadFarStringSmall(__G__ (x))
+# define LoadFarStringSmall2(x) fLoadFarStringSmall2(__G__ (x))
+# if (defined(_MSC_VER) && (_MSC_VER >= 600))
+# define zfstrcpy(dest, src) _fstrcpy((dest), (src))
+# define zfstrcmp(s1, s2) _fstrcmp((s1), (s2))
+# endif
+# if !(defined(SFX) || defined(FUNZIP))
+# if (defined(_MSC_VER))
+# define zfmalloc(sz) _fmalloc((sz))
+# define zffree(x) _ffree(x)
+# endif
+# if (defined(__TURBOC__))
+# include <alloc.h>
+# define zfmalloc(sz) farmalloc((unsigned long)(sz))
+# define zffree(x) farfree(x)
+# endif
+# endif /* !(SFX || FUNZIP) */
+# ifndef Far
+# define Far far /* __far only works for MSC 6.00, not 6.0a or Borland */
+# endif
+# define OUTBUFSIZ INBUFSIZ
+# if (lenEOL == 1)
+# define RAWBUFSIZ (OUTBUFSIZ>>1)
+# else
+# define RAWBUFSIZ ((OUTBUFSIZ>>1) - (OUTBUFSIZ>>7))
+# endif
+# define TRANSBUFSIZ (OUTBUFSIZ-RAWBUFSIZ)
+ typedef short shrint; /* short/int or "shrink int" (unshrink) */
+#else
+# define zfstrcpy(dest, src) strcpy((dest), (src))
+# define zfstrcmp(s1, s2) strcmp((s1), (s2))
+# define zfmalloc malloc
+# define zffree(x) free(x)
+# ifdef QDOS
+# define LoadFarString(x) Qstrfix(x) /* fix up _ for '.' */
+# define LoadFarStringSmall(x) Qstrfix(x)
+# define LoadFarStringSmall2(x) Qstrfix(x)
+# else
+# define LoadFarString(x) (char *)(x)
+# define LoadFarStringSmall(x) (char *)(x)
+# define LoadFarStringSmall2(x) (char *)(x)
+# endif
+# ifdef MED_MEM
+# define OUTBUFSIZ 0xFF80 /* can't malloc arrays of 0xFFE8 or more */
+# define TRANSBUFSIZ 0xFF80
+ typedef short shrint;
+# else
+# define OUTBUFSIZ (lenEOL*WSIZE) /* more efficient text conversion */
+# define TRANSBUFSIZ (lenEOL*OUTBUFSIZ)
+# ifdef AMIGA
+ typedef short shrint;
+# else
+ typedef int shrint; /* for efficiency/speed, we hope... */
+# endif
+# endif /* ?MED_MEM */
+# define RAWBUFSIZ OUTBUFSIZ
+#endif /* ?SMALL_MEM */
+
+#ifndef Far
+# define Far
+#endif
+
+#ifndef Cdecl
+# define Cdecl
+#endif
+
+#ifndef MAIN
+# define MAIN main
+#endif
+
+#ifdef SFX /* disable some unused features for SFX executables */
+# ifndef NO_ZIPINFO
+# define NO_ZIPINFO
+# endif
+# ifdef TIMESTAMP
+# undef TIMESTAMP
+# endif
+#endif
+
+#ifdef SFX
+# ifdef CHEAP_SFX_AUTORUN
+# ifndef NO_SFX_EXDIR
+# define NO_SFX_EXDIR
+# endif
+# endif
+# ifndef NO_SFX_EXDIR
+# ifndef SFX_EXDIR
+# define SFX_EXDIR
+# endif
+# else
+# ifdef SFX_EXDIR
+# undef SFX_EXDIR
+# endif
+# endif
+#endif
+
+/* user may have defined both by accident... NOTIMESTAMP takes precedence */
+#if (defined(TIMESTAMP) && defined(NOTIMESTAMP))
+# undef TIMESTAMP
+#endif
+
+#if (!defined(COPYRIGHT_CLEAN) && !defined(USE_SMITH_CODE))
+# define COPYRIGHT_CLEAN
+#endif
+
+/* The LZW patent is expired worldwide since 2004-Jul-07, so USE_UNSHRINK
+ * is now enabled by default. See unshrink.c.
+ */
+#if (!defined(LZW_CLEAN) && !defined(USE_UNSHRINK))
+# define USE_UNSHRINK
+#endif
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+#ifndef PIPE_ERROR
+# ifndef EPIPE
+# define EPIPE -1
+# endif
+# define PIPE_ERROR (errno == EPIPE)
+#endif
+
+/* File operations--use "b" for binary if allowed or fixed length 512 on VMS */
+#ifdef VMS
+# define FOPR "r","ctx=stm"
+# define FOPM "r+","ctx=stm","rfm=fix","mrs=512"
+# define FOPW "w","ctx=stm","rfm=fix","mrs=512"
+# define FOPWR "w+","ctx=stm","rfm=fix","mrs=512"
+#endif /* VMS */
+
+#ifdef CMS_MVS
+/* Binary files must be RECFM=F,LRECL=1 for ftell() to get correct pos */
+/* ...unless byteseek is used. Let's try that for a while. */
+# define FOPR "rb,byteseek"
+# define FOPM "r+b,byteseek"
+# ifdef MVS
+# define FOPW "wb,recfm=u,lrecl=32760,byteseek" /* New binary files */
+# define FOPWE "wb" /* Existing binary files */
+# define FOPWT "w,lrecl=133" /* New text files */
+# define FOPWTE "w" /* Existing text files */
+# else
+# define FOPW "wb,recfm=v,lrecl=32760"
+# define FOPWT "w"
+# endif
+#endif /* CMS_MVS */
+
+#ifdef TOPS20 /* TOPS-20 MODERN? You kidding? */
+# define FOPW "w8"
+#endif /* TOPS20 */
+
+/* Defaults when nothing special has been defined previously. */
+#ifdef MODERN
+# ifndef FOPR
+# define FOPR "rb"
+# endif
+# ifndef FOPM
+# define FOPM "r+b"
+# endif
+# ifndef FOPW
+# define FOPW "wb"
+# endif
+# ifndef FOPWT
+# define FOPWT "wt"
+# endif
+# ifndef FOPWR
+# define FOPWR "w+b"
+# endif
+#else /* !MODERN */
+# ifndef FOPR
+# define FOPR "r"
+# endif
+# ifndef FOPM
+# define FOPM "r+"
+# endif
+# ifndef FOPW
+# define FOPW "w"
+# endif
+# ifndef FOPWT
+# define FOPWT "w"
+# endif
+# ifndef FOPWR
+# define FOPWR "w+"
+# endif
+#endif /* ?MODERN */
+
+/*
+ * If <limits.h> exists on most systems, should include that, since it may
+ * define some or all of the following: NAME_MAX, PATH_MAX, _POSIX_NAME_MAX,
+ * _POSIX_PATH_MAX.
+ */
+#ifdef DOS_FLX_NLM_OS2_W32
+# include <limits.h>
+#endif
+
+/* 2008-07-22 SMS.
+ * Unfortunately, on VMS, <limits.h> exists, and is included by <stdlib.h>
+ * (so it's pretty much unavoidable), and it defines PATH_MAX to a fixed
+ * short value (256, correct only for older systems without ODS-5 support),
+ * rather than one based on the real RMS NAM[L] situation. So, we
+ * artificially undefine it here, to allow our better-defined _MAX_PATH
+ * (see vms/vmscfg.h) to be used.
+ */
+#ifdef VMS
+# undef PATH_MAX
+#endif
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+# define PATH_MAX MAXPATHLEN /* in <sys/param.h> on some systems */
+# else
+# ifdef _MAX_PATH
+# define PATH_MAX _MAX_PATH
+# else
+# if FILENAME_MAX > 255
+# define PATH_MAX FILENAME_MAX /* used like PATH_MAX on some systems */
+# else
+# define PATH_MAX 1024
+# endif
+# endif /* ?_MAX_PATH */
+# endif /* ?MAXPATHLEN */
+#endif /* !PATH_MAX */
+
+/*
+ * buffer size required to hold the longest legal local filepath
+ * (including the trailing '\0')
+ */
+#define FILNAMSIZ PATH_MAX
+
+#ifdef UNICODE_SUPPORT
+# if !(defined(UTF8_MAYBE_NATIVE) || defined(UNICODE_WCHAR))
+# undef UNICODE_SUPPORT
+# endif
+#endif
+/* 2007-09-18 SMS.
+ * Include <locale.h> here if it will be needed later for Unicode.
+ * Otherwise, SETLOCALE may be defined here, and then defined again
+ * (differently) when <locale.h> is read later.
+ */
+#ifdef UNICODE_SUPPORT
+# ifdef UNICODE_WCHAR
+# if !(defined(_WIN32_WCE) || defined(POCKET_UNZIP))
+# include <wchar.h>
+# endif
+# endif
+# ifndef _MBCS /* no need to include <locale.h> twice, see below */
+# include <locale.h>
+# ifndef SETLOCALE
+# define SETLOCALE(category, locale) setlocale(category, locale)
+# endif
+# endif
+#endif /* UNICODE_SUPPORT */
+
+/* DBCS support for Info-ZIP (mainly for japanese (-: )
+ * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp)
+ */
+#ifdef _MBCS
+# include <locale.h>
+ /* Multi Byte Character Set */
+# define ___MBS_TMP_DEF char *___tmp_ptr;
+# define ___TMP_PTR ___tmp_ptr
+# ifndef CLEN
+# define NEED_UZMBCLEN
+# define CLEN(ptr) (int)uzmbclen((ZCONST unsigned char *)(ptr))
+# endif
+# ifndef PREINCSTR
+# define PREINCSTR(ptr) (ptr += CLEN(ptr))
+# endif
+# define POSTINCSTR(ptr) (___TMP_PTR=(char *)(ptr), PREINCSTR(ptr),___TMP_PTR)
+ char *plastchar OF((ZCONST char *ptr, extent len));
+# define lastchar(ptr, len) ((int)(unsigned)*plastchar(ptr, len))
+# ifndef MBSCHR
+# define NEED_UZMBSCHR
+# define MBSCHR(str,c) (char *)uzmbschr((ZCONST unsigned char *)(str), c)
+# endif
+# ifndef MBSRCHR
+# define NEED_UZMBSRCHR
+# define MBSRCHR(str,c) (char *)uzmbsrchr((ZCONST unsigned char *)(str), c)
+# endif
+# ifndef SETLOCALE
+# define SETLOCALE(category, locale) setlocale(category, locale)
+# endif
+#else /* !_MBCS */
+# define ___MBS_TMP_DEF
+# define ___TMP_PTR
+# define CLEN(ptr) 1
+# define PREINCSTR(ptr) (++(ptr))
+# define POSTINCSTR(ptr) ((ptr)++)
+# define plastchar(ptr, len) (&ptr[(len)-1])
+# define lastchar(ptr, len) (ptr[(len)-1])
+# define MBSCHR(str, c) strchr(str, c)
+# define MBSRCHR(str, c) strrchr(str, c)
+# ifndef SETLOCALE
+# define SETLOCALE(category, locale)
+# endif
+#endif /* ?_MBCS */
+#define INCSTR(ptr) PREINCSTR(ptr)
+
+
+#if (defined(MALLOC_WORK) && !defined(MY_ZCALLOC))
+ /* Any system without a special calloc function */
+# ifndef zcalloc
+# define zcalloc(items, size) \
+ (zvoid far *)calloc((unsigned)(items), (unsigned)(size))
+# endif
+# ifndef zcfree
+# define zcfree free
+# endif
+#endif /* MALLOC_WORK && !MY_ZCALLOC */
+
+#if (defined(CRAY) && defined(ZMEM))
+# undef ZMEM
+#endif
+
+#ifdef ZMEM
+# undef ZMEM
+# define memcmp(b1,b2,len) bcmp(b2,b1,len)
+# define memcpy(dest,src,len) bcopy(src,dest,len)
+# define memzero bzero
+#else
+# define memzero(dest,len) memset(dest,0,len)
+#endif
+
+#ifndef TRUE
+# define TRUE 1 /* sort of obvious */
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+# define SEEK_CUR 1
+# define SEEK_END 2
+#endif
+
+#if (!defined(S_IEXEC) && defined(S_IXUSR))
+# define S_IEXEC S_IXUSR
+#endif
+
+#if (defined(UNIX) && defined(S_IFLNK) && !defined(MTS))
+# define SYMLINKS
+# ifndef S_ISLNK
+# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+# endif
+#endif /* UNIX && S_IFLNK && !MTS */
+
+#ifndef S_ISDIR
+# ifdef CMS_MVS
+# define S_ISDIR(m) (FALSE)
+# else
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# endif
+#endif
+
+#ifndef IS_VOLID
+# define IS_VOLID(m) ((m) & 0x08)
+#endif
+
+/***********************************/
+/* LARGE_FILE_SUPPORT */
+/***********************************/
+/* This whole section lifted from Zip 3b tailor.h
+
+ * Types are in OS dependent headers (eg, w32cfg.h)
+ *
+ * LARGE_FILE_SUPPORT and ZIP64_SUPPORT are automatically
+ * set in OS dependent headers (for some ports) based on the port and compiler.
+ *
+ * Function prototypes are below as OF is defined earlier in this file
+ * but after OS dependent header is included.
+ *
+ * E. Gordon 9/21/2003
+ * Updated 1/28/2004
+ * Lifted and placed here 6/7/2004 - Myles Bennett
+ */
+#ifdef LARGE_FILE_SUPPORT
+ /* 64-bit Large File Support */
+
+/* ---------------------------- */
+
+# if defined(UNIX) || defined(VMS)
+
+ /* 64-bit stat functions */
+# define zstat stat
+# define zfstat fstat
+
+ /* 64-bit fseeko */
+# define zlseek lseek
+# define zfseeko fseeko
+
+ /* 64-bit ftello */
+# define zftello ftello
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif /* UNIX || VMS */
+
+/* ---------------------------- */
+
+# ifdef WIN32
+
+# if defined(_MSC_VER) || defined(__MINGW32__) || defined(__LCC__)
+ /* MS C (VC), MinGW GCC port and LCC-32 use the MS C Runtime lib */
+
+ /* 64-bit stat functions */
+# define zstat _stati64
+# define zfstat _fstati64
+
+ /* 64-bit lseek */
+# define zlseek _lseeki64
+
+# if defined(_MSC_VER) && (_MSC_VER >= 1400)
+ /* Beginning with VS 8.0 (Visual Studio 2005, MSC 14), the Microsoft
+ C rtl publishes its (previously internal) implmentations of
+ "fseeko" and "ftello" for 64-bit file offsets. */
+ /* 64-bit fseeko */
+# define zfseeko _fseeki64
+ /* 64-bit ftello */
+# define zftello _ftelli64
+
+# else /* not (defined(_MSC_VER) && (_MSC_VER >= 1400)) */
+
+# if defined(__MSVCRT_VERSION__) && (__MSVCRT_VERSION__ >= 0x800)
+ /* Up-to-date versions of MinGW define the macro __MSVCRT_VERSION__
+ to denote the version of the MS C rtl dll used for linking. When
+ configured to link against the runtime of MS Visual Studio 8 (or
+ newer), the built-in 64-bit fseek/ftell functions are available. */
+ /* 64-bit fseeko */
+# define zfseeko _fseeki64
+ /* 64-bit ftello */
+# define zftello _ftelli64
+
+# else /* !(defined(__MSVCRT_VERSION__) && (__MSVCRT_VERSION__>=0x800)) */
+ /* The version of the C runtime is lower than MSC 14 or unknown. */
+
+ /* The newest MinGW port contains built-in extensions to the MSC rtl
+ that provide fseeko and ftello, but our implementations will do
+ for now. */
+ /* 64-bit fseeko */
+ int zfseeko OF((FILE *, zoff_t, int));
+
+ /* 64-bit ftello */
+ zoff_t zftello OF((FILE *));
+
+# endif /* ? (__MSVCRT_VERSION__ >= 0x800) */
+# endif /* ? (_MSC_VER >= 1400) */
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif /* _MSC_VER || __MINGW__ || __LCC__ */
+
+# ifdef __CYGWIN__
+ /* CYGWIN GCC Posix emulator on Windows
+ (configuration not yet finished/tested) */
+
+ /* 64-bit stat functions */
+# define zstat _stati64
+# define zfstat _fstati64
+
+ /* 64-bit lseek */
+# define zlseek _lseeki64
+
+ /* 64-bit fseeko */
+# define zfseeko fseeko
+
+ /* 64-bit ftello */
+# define zftello ftello
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif
+# if defined(__WATCOMC__) || defined(__BORLANDC__)
+ /* WATCOM C and Borland C provide their own C runtime libraries,
+ but they are sufficiently compatible with MS CRTL. */
+
+ /* 64-bit stat functions */
+# define zstat _stati64
+# define zfstat _fstati64
+
+# ifdef __WATCOMC__
+ /* 64-bit lseek */
+# define zlseek _lseeki64
+# endif
+
+ /* 64-bit fseeko */
+ int zfseeko OF((FILE *, zoff_t, int));
+
+ /* 64-bit ftello */
+ zoff_t zftello OF((FILE *));
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif
+# ifdef __IBMC__
+ /* IBM C */
+
+ /* 64-bit stat functions */
+
+ /* 64-bit fseeko */
+
+ /* 64-bit ftello */
+
+ /* 64-bit fopen */
+
+# endif
+
+# endif /* WIN32 */
+
+#else
+ /* No Large File Support */
+
+# ifndef REGULUS /* returns the inode number on success(!)...argh argh argh */
+# define zstat stat
+# endif
+# define zfstat fstat
+# define zlseek lseek
+# define zfseeko fseek
+# define zftello ftell
+# define zfopen fopen
+# define zfdopen fdopen
+
+# if defined(UNIX) || defined(VMS) || defined(WIN32)
+ /* For these systems, implement "64bit file vs. 32bit prog" check */
+# ifndef DO_SAFECHECK_2GB
+# define DO_SAFECHECK_2GB
+# endif
+# endif
+
+#endif
+
+/* No "64bit file vs. 32bit prog" check for SFX stub, to save space */
+#if (defined(DO_SAFECHECK_2GB) && defined(SFX))
+# undef DO_SAFECHECK_2GB
+#endif
+
+#ifndef SSTAT
+# ifdef WILD_STAT_BUG
+# define SSTAT(path,pbuf) (iswild(path) || zstat(path,pbuf))
+# else
+# define SSTAT zstat
+# endif
+#endif
+
+
+/* Default fzofft() format selection. */
+
+#ifndef FZOFFT_FMT
+
+# ifdef LARGE_FILE_SUPPORT
+# define FZOFFT_FMT "ll"
+# define FZOFFT_HEX_WID_VALUE "16"
+# else /* def LARGE_FILE_SUPPORT */
+# define FZOFFT_FMT "l"
+# define FZOFFT_HEX_WID_VALUE "8"
+# endif /* def LARGE_FILE_SUPPORT */
+
+#endif /* ndef FZOFFT_FMT */
+
+#define FZOFFT_HEX_WID ((char *) -1)
+#define FZOFFT_HEX_DOT_WID ((char *) -2)
+
+#define FZOFFT_NUM 4 /* Number of chambers. */
+#define FZOFFT_LEN 24 /* Number of characters/chamber. */
+
+
+#ifdef SHORT_SYMS /* Mark Williams C, ...? */
+# define extract_or_test_files xtr_or_tst_files
+# define extract_or_test_member xtr_or_tst_member
+#endif
+
+#ifdef REALLY_SHORT_SYMS /* TOPS-20 linker: first 6 chars */
+# define process_cdir_file_hdr XXpcdfh
+# define process_local_file_hdr XXplfh
+# define extract_or_test_files XXxotf /* necessary? */
+# define extract_or_test_member XXxotm /* necessary? */
+# define check_for_newer XXcfn
+# define overwrite_all XXoa
+# define process_all_files XXpaf
+# define extra_field XXef
+# define explode_lit8 XXel8
+# define explode_lit4 XXel4
+# define explode_nolit8 XXnl8
+# define explode_nolit4 XXnl4
+# define cpdist8 XXcpdist8
+# define inflate_codes XXic
+# define inflate_stored XXis
+# define inflate_fixed XXif
+# define inflate_dynamic XXid
+# define inflate_block XXib
+# define maxcodemax XXmax
+#endif
+
+#ifndef S_TIME_T_MAX /* max value of signed (>= 32-bit) time_t */
+# define S_TIME_T_MAX ((time_t)(ulg)0x7fffffffL)
+#endif
+#ifndef U_TIME_T_MAX /* max value of unsigned (>= 32-bit) time_t */
+# define U_TIME_T_MAX ((time_t)(ulg)0xffffffffL)
+#endif
+#ifdef DOSTIME_MINIMUM /* min DOSTIME value (1980-01-01) */
+# undef DOSTIME_MINIMUM
+#endif
+#define DOSTIME_MINIMUM ((ulg)0x00210000L)
+#ifdef DOSTIME_2038_01_18 /* approximate DOSTIME equivalent of */
+# undef DOSTIME_2038_01_18 /* the signed-32-bit time_t limit */
+#endif
+#define DOSTIME_2038_01_18 ((ulg)0x74320000L)
+
+#ifdef QDOS
+# define ZSUFX "_zip"
+# define ALT_ZSUFX ".zip"
+#else
+# ifdef RISCOS
+# define ZSUFX "/zip"
+# else
+# define ZSUFX ".zip"
+# endif
+# define ALT_ZSUFX ".ZIP" /* Unix-only so far (only case-sensitive fs) */
+#endif
+
+#define CENTRAL_HDR_SIG "\001\002" /* the infamous "PK" signature bytes, */
+#define LOCAL_HDR_SIG "\003\004" /* w/o "PK" (so unzip executable not */
+#define END_CENTRAL_SIG "\005\006" /* mistaken for zipfile itself) */
+#define EXTD_LOCAL_SIG "\007\010" /* [ASCII "\113" == EBCDIC "\080" ??] */
+
+/** internal-only return codes **/
+#define IZ_DIR 76 /* potential zipfile is a directory */
+/* special return codes for mapname() */
+#define MPN_OK 0 /* mapname successful */
+#define MPN_INF_TRUNC (1<<8) /* caution - filename truncated */
+#define MPN_INF_SKIP (2<<8) /* info - skipped because nothing to do */
+#define MPN_ERR_SKIP (3<<8) /* error - entry skipped */
+#define MPN_ERR_TOOLONG (4<<8) /* error - path too long */
+#define MPN_NOMEM (10<<8) /* error - out of memory, file skipped */
+#define MPN_CREATED_DIR (16<<8) /* directory created: set time & permission */
+#define MPN_VOL_LABEL (17<<8) /* volume label, but can't set on hard disk */
+#define MPN_INVALID (99<<8) /* internal logic error, should never reach */
+/* mask for internal mapname&checkdir return codes */
+#define MPN_MASK 0x7F00
+/* error code for extracting/testing extra field blocks */
+#define IZ_EF_TRUNC 79 /* local extra field truncated (PKZIP'd) */
+
+/* choice of activities for do_string() */
+#define SKIP 0 /* skip header block */
+#define DISPLAY 1 /* display archive comment (ASCII) */
+#define DISPL_8 5 /* display file comment (ext. ASCII) */
+#define DS_FN 2 /* read filename (ext. ASCII, chead) */
+#define DS_FN_C 2 /* read filename from central header */
+#define DS_FN_L 6 /* read filename from local header */
+#define EXTRA_FIELD 3 /* copy extra field into buffer */
+#define DS_EF 3
+#ifdef AMIGA
+# define FILENOTE 4 /* convert file comment to filenote */
+#endif
+#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
+# define CHECK_AUTORUN 7 /* copy command, display remainder */
+# define CHECK_AUTORUN_Q 8 /* copy command, skip remainder */
+#endif
+
+#define DOES_NOT_EXIST -1 /* return values for check_for_newer() */
+#define EXISTS_AND_OLDER 0
+#define EXISTS_AND_NEWER 1
+
+#define OVERWRT_QUERY 0 /* status values for G.overwrite_mode */
+#define OVERWRT_ALWAYS 1
+#define OVERWRT_NEVER 2
+
+#define IS_OVERWRT_ALL (G.overwrite_mode == OVERWRT_ALWAYS)
+#define IS_OVERWRT_NONE (G.overwrite_mode == OVERWRT_NEVER)
+
+#ifdef VMS
+ /* return codes for VMS-specific open_outfile() function */
+# define OPENOUT_OK 0 /* file openend normally */
+# define OPENOUT_FAILED 1 /* file open failed */
+# define OPENOUT_SKIPOK 2 /* file not opened, skip at error level OK */
+# define OPENOUT_SKIPWARN 3 /* file not opened, skip at error level WARN */
+#endif /* VMS */
+
+#define ROOT 0 /* checkdir() extract-to path: called once */
+#define INIT 1 /* allocate buildpath: called once per member */
+#define APPEND_DIR 2 /* append a dir comp.: many times per member */
+#define APPEND_NAME 3 /* append actual filename: once per member */
+#define GETPATH 4 /* retrieve the complete path and free it */
+#define END 5 /* free root path prior to exiting program */
+
+/* version_made_by codes (central dir): make sure these */
+/* are not defined on their respective systems!! */
+#define FS_FAT_ 0 /* filesystem used by MS-DOS, OS/2, Win32 */
+#define AMIGA_ 1
+#define VMS_ 2
+#define UNIX_ 3
+#define VM_CMS_ 4
+#define ATARI_ 5 /* what if it's a minix filesystem? [cjh] */
+#define FS_HPFS_ 6 /* filesystem used by OS/2 (and NT 3.x) */
+#define MAC_ 7 /* HFS filesystem used by MacOS */
+#define Z_SYSTEM_ 8
+#define CPM_ 9
+#define TOPS20_ 10
+#define FS_NTFS_ 11 /* filesystem used by Windows NT */
+#define QDOS_ 12
+#define ACORN_ 13 /* Archimedes Acorn RISC OS */
+#define FS_VFAT_ 14 /* filesystem used by Windows 95, NT */
+#define MVS_ 15
+#define BEOS_ 16 /* hybrid POSIX/database filesystem */
+#define TANDEM_ 17 /* Tandem NSK */
+#define THEOS_ 18 /* THEOS */
+#define MAC_OSX_ 19 /* Mac OS/X (Darwin) */
+#define ATHEOS_ 30 /* AtheOS */
+#define NUM_HOSTS 31 /* index of last system + 1 */
+/* don't forget to update zipinfo.c appropiately if NUM_HOSTS changes! */
+
+#define STORED 0 /* compression methods */
+#define SHRUNK 1
+#define REDUCED1 2
+#define REDUCED2 3
+#define REDUCED3 4
+#define REDUCED4 5
+#define IMPLODED 6
+#define TOKENIZED 7
+#define DEFLATED 8
+#define ENHDEFLATED 9
+#define DCLIMPLODED 10
+#define BZIPPED 12
+#define LZMAED 14
+#define IBMTERSED 18
+#define IBMLZ77ED 19
+#define WAVPACKED 97
+#define PPMDED 98
+#define NUM_METHODS 17 /* number of known method IDs */
+/* don't forget to update list.c (list_files()), extract.c and zipinfo.c
+ * appropriately if NUM_METHODS changes */
+
+/* (the PK-class error codes are public and have been moved into unzip.h) */
+
+#define DF_MDY 0 /* date format 10/26/91 (USA only) */
+#define DF_DMY 1 /* date format 26/10/91 (most of the world) */
+#define DF_YMD 2 /* date format 91/10/26 (a few countries) */
+
+/*---------------------------------------------------------------------------
+ Extra-field block ID values and offset info.
+ ---------------------------------------------------------------------------*/
+/* extra-field ID values, all little-endian: */
+#define EF_PKSZ64 0x0001 /* PKWARE's 64-bit filesize extensions */
+#define EF_AV 0x0007 /* PKWARE's authenticity verification */
+#define EF_EFS 0x0008 /* PKWARE's extended language encoding */
+#define EF_OS2 0x0009 /* OS/2 extended attributes */
+#define EF_PKW32 0x000a /* PKWARE's Win95/98/WinNT filetimes */
+#define EF_PKVMS 0x000c /* PKWARE's VMS */
+#define EF_PKUNIX 0x000d /* PKWARE's Unix */
+#define EF_PKFORK 0x000e /* PKWARE's future stream/fork descriptors */
+#define EF_PKPATCH 0x000f /* PKWARE's patch descriptor */
+#define EF_PKPKCS7 0x0014 /* PKWARE's PKCS#7 store for X.509 Certs */
+#define EF_PKFX509 0x0015 /* PKWARE's file X.509 Cert&Signature ID */
+#define EF_PKCX509 0x0016 /* PKWARE's central dir X.509 Cert ID */
+#define EF_PKENCRHD 0x0017 /* PKWARE's Strong Encryption header */
+#define EF_PKRMCTL 0x0018 /* PKWARE's Record Management Controls*/
+#define EF_PKLSTCS7 0x0019 /* PKWARE's PKCS#7 Encr. Recipient Cert List */
+#define EF_PKIBM 0x0065 /* PKWARE's IBM S/390 & AS/400 attributes */
+#define EF_PKIBM2 0x0066 /* PKWARE's IBM S/390 & AS/400 compr. attribs */
+#define EF_IZVMS 0x4d49 /* Info-ZIP's VMS ("IM") */
+#define EF_IZUNIX 0x5855 /* Info-ZIP's first Unix[1] ("UX") */
+#define EF_IZUNIX2 0x7855 /* Info-ZIP's second Unix[2] ("Ux") */
+#define EF_IZUNIX3 0x7875 /* Info-ZIP's newest Unix[3] ("ux") */
+#define EF_TIME 0x5455 /* universal timestamp ("UT") */
+#define EF_UNIPATH 0x7075 /* Info-ZIP Unicode Path ("up") */
+#define EF_UNICOMNT 0x6375 /* Info-ZIP Unicode Comment ("uc") */
+#define EF_MAC3 0x334d /* Info-ZIP's new Macintosh (= "M3") */
+#define EF_JLMAC 0x07c8 /* Johnny Lee's old Macintosh (= 1992) */
+#define EF_ZIPIT 0x2605 /* Thomas Brown's Macintosh (ZipIt) */
+#define EF_ZIPIT2 0x2705 /* T. Brown's Mac (ZipIt) v 1.3.8 and newer ? */
+#define EF_SMARTZIP 0x4d63 /* Mac SmartZip by Marco Bambini */
+#define EF_VMCMS 0x4704 /* Info-ZIP's VM/CMS ("\004G") */
+#define EF_MVS 0x470f /* Info-ZIP's MVS ("\017G") */
+#define EF_ACL 0x4c41 /* (OS/2) access control list ("AL") */
+#define EF_NTSD 0x4453 /* NT security descriptor ("SD") */
+#define EF_ATHEOS 0x7441 /* AtheOS ("At") */
+#define EF_BEOS 0x6542 /* BeOS ("Be") */
+#define EF_QDOS 0xfb4a /* SMS/QDOS ("J\373") */
+#define EF_AOSVS 0x5356 /* AOS/VS ("VS") */
+#define EF_SPARK 0x4341 /* David Pilling's Acorn/SparkFS ("AC") */
+#define EF_TANDEM 0x4154 /* Tandem NSK ("TA") */
+#define EF_THEOS 0x6854 /* Jean-Michel Dubois' Theos "Th" */
+#define EF_THEOSO 0x4854 /* old Theos port */
+#define EF_MD5 0x4b46 /* Fred Kantor's MD5 ("FK") */
+#define EF_ASIUNIX 0x756e /* ASi's Unix ("nu") */
+
+#define EB_HEADSIZE 4 /* length of extra field block header */
+#define EB_ID 0 /* offset of block ID in header */
+#define EB_LEN 2 /* offset of data length field in header */
+#define EB_UCSIZE_P 0 /* offset of ucsize field in compr. data */
+#define EB_CMPRHEADLEN 6 /* lenght of compression header */
+
+#define EB_UX_MINLEN 8 /* minimal "UX" field contains atime, mtime */
+#define EB_UX_FULLSIZE 12 /* full "UX" field (atime, mtime, uid, gid) */
+#define EB_UX_ATIME 0 /* offset of atime in "UX" extra field data */
+#define EB_UX_MTIME 4 /* offset of mtime in "UX" extra field data */
+#define EB_UX_UID 8 /* byte offset of UID in "UX" field data */
+#define EB_UX_GID 10 /* byte offset of GID in "UX" field data */
+
+#define EB_UX2_MINLEN 4 /* minimal "Ux" field contains UID/GID */
+#define EB_UX2_UID 0 /* byte offset of UID in "Ux" field data */
+#define EB_UX2_GID 2 /* byte offset of GID in "Ux" field data */
+#define EB_UX2_VALID (1 << 8) /* UID/GID present */
+
+#define EB_UX3_MINLEN 7 /* minimal "ux" field size (2-byte UID/GID) */
+
+#define EB_UT_MINLEN 1 /* minimal UT field contains Flags byte */
+#define EB_UT_FLAGS 0 /* byte offset of Flags field */
+#define EB_UT_TIME1 1 /* byte offset of 1st time value */
+#define EB_UT_FL_MTIME (1 << 0) /* mtime present */
+#define EB_UT_FL_ATIME (1 << 1) /* atime present */
+#define EB_UT_FL_CTIME (1 << 2) /* ctime present */
+
+#define EB_FLGS_OFFS 4 /* offset of flags area in generic compressed
+ extra field blocks (BEOS, MAC, and others) */
+#define EB_OS2_HLEN 4 /* size of OS2/ACL compressed data header */
+#define EB_BEOS_HLEN 5 /* length of BeOS&AtheOS e.f attribute header */
+#define EB_BE_FL_UNCMPR 0x01 /* "BeOS&AtheOS attribs uncompr." bit flag */
+#define EB_MAC3_HLEN 14 /* length of Mac3 attribute block header */
+#define EB_SMARTZIP_HLEN 64 /* fixed length of the SmartZip extra field */
+#define EB_M3_FL_DATFRK 0x01 /* "this entry is data fork" flag */
+#define EB_M3_FL_UNCMPR 0x04 /* "Mac3 attributes uncompressed" bit flag */
+#define EB_M3_FL_TIME64 0x08 /* "Mac3 time fields are 64 bit wide" flag */
+#define EB_M3_FL_NOUTC 0x10 /* "Mac3 timezone offset fields missing" flag */
+
+#define EB_NTSD_C_LEN 4 /* length of central NT security data */
+#define EB_NTSD_L_LEN 5 /* length of minimal local NT security data */
+#define EB_NTSD_VERSION 4 /* offset of NTSD version byte */
+#define EB_NTSD_MAX_VER (0) /* maximum version # we know how to handle */
+
+#define EB_PKVMS_MINLEN 4 /* minimum data length of PKVMS extra block */
+
+#define EB_ASI_CRC32 0 /* offset of ASI Unix field's crc32 checksum */
+#define EB_ASI_MODE 4 /* offset of ASI Unix permission mode field */
+
+#define EB_IZVMS_HLEN 12 /* length of IZVMS attribute block header */
+#define EB_IZVMS_FLGS 4 /* offset of compression type flag */
+#define EB_IZVMS_UCSIZ 6 /* offset of ucsize field in IZVMS header */
+#define EB_IZVMS_BCMASK 07 /* 3 bits for compression type */
+#define EB_IZVMS_BCSTOR 0 /* Stored */
+#define EB_IZVMS_BC00 1 /* 0byte -> 0bit compression */
+#define EB_IZVMS_BCDEFL 2 /* Deflated */
+
+
+/*---------------------------------------------------------------------------
+ True sizes of the various headers (excluding their 4-byte signatures),
+ as defined by PKWARE--so it is not likely that these will ever change.
+ But if they do, make sure both these defines AND the typedefs below get
+ updated accordingly.
+
+ 12/27/2006
+ The Zip64 End Of Central Directory record is variable size and now
+ comes in two flavors, version 1 and the new version 2 that supports
+ central directory encryption. We only use the old fields at the
+ top of the Zip64 EOCDR, and this block is a fixed size still, but
+ need to be aware of the stuff following.
+ ---------------------------------------------------------------------------*/
+#define LREC_SIZE 26 /* lengths of local file headers, central */
+#define CREC_SIZE 42 /* directory headers, end-of-central-dir */
+#define ECREC_SIZE 18 /* record, zip64 end-of-cent-dir locator */
+#define ECLOC64_SIZE 16 /* and zip64 end-of-central-dir record, */
+#define ECREC64_SIZE 52 /* respectively */
+
+#define MAX_BITS 13 /* used in unshrink() */
+#define HSIZE (1 << MAX_BITS) /* size of global work area */
+
+#define LF 10 /* '\n' on ASCII machines; must be 10 due to EBCDIC */
+#define CR 13 /* '\r' on ASCII machines; must be 13 due to EBCDIC */
+#define CTRLZ 26 /* DOS & OS/2 EOF marker (used in fileio.c, vms.c) */
+
+#ifdef EBCDIC
+# define foreign(c) ascii[(uch)(c)]
+# define native(c) ebcdic[(uch)(c)]
+# define NATIVE "EBCDIC"
+# define NOANSIFILT
+#endif
+
+#ifdef VMS
+# define ENV_UNZIP "UNZIP_OPTS" /* names of environment variables */
+# define ENV_ZIPINFO "ZIPINFO_OPTS"
+#endif /* VMS */
+#ifdef RISCOS
+# define ENV_UNZIP "Unzip$Options"
+# define ENV_ZIPINFO "Zipinfo$Options"
+# define ENV_UNZIPEXTS "Unzip$Exts"
+#endif /* RISCOS */
+#ifndef ENV_UNZIP
+# define ENV_UNZIP "UNZIP" /* the standard names */
+# define ENV_ZIPINFO "ZIPINFO"
+#endif
+#define ENV_UNZIP2 "UNZIPOPT" /* alternate names, for zip compat. */
+#define ENV_ZIPINFO2 "ZIPINFOOPT"
+
+#if (!defined(QQ) && !defined(NOQQ))
+# define QQ
+#endif
+
+#ifdef QQ /* Newtware version: no file */
+# define QCOND (!uO.qflag) /* comments with -vq or -vqq */
+#else /* Bill Davidsen version: no way to */
+# define QCOND (longhdr) /* kill file comments when listing */
+#endif
+
+#ifdef OLD_QQ
+# define QCOND2 (uO.qflag < 2)
+#else
+# define QCOND2 (!uO.qflag)
+#endif
+
+#ifdef WILD_STOP_AT_DIR
+# define __WDLPRO , int sepc
+# define __WDL , sepc
+# define __WDLDEF int sepc;
+# define WISEP , (uO.W_flag ? '/' : '\0')
+#else
+# define __WDLPRO
+# define __WDL
+# define __WDLDEF
+# define WISEP
+#endif
+
+
+
+
+/**************/
+/* Typedefs */
+/**************/
+
+#ifdef ZIP64_SUPPORT
+# ifndef Z_UINT8_DEFINED
+# if (defined(__GNUC__) || defined(__hpux) || defined(__SUNPRO_C))
+ typedef unsigned long long z_uint8;
+# else
+ typedef unsigned __int64 z_uint8;
+# endif
+# define Z_UINT8_DEFINED
+# endif
+#endif
+#ifndef Z_UINT4_DEFINED
+# if (defined(MODERN) && !defined(NO_LIMITS_H))
+# if (defined(UINT_MAX) && (UINT_MAX == 0xffffffffUL))
+ typedef unsigned int z_uint4;
+# define Z_UINT4_DEFINED
+# else
+# if (defined(ULONG_MAX) && (ULONG_MAX == 0xffffffffUL))
+ typedef unsigned long z_uint4;
+# define Z_UINT4_DEFINED
+# else
+# if (defined(USHRT_MAX) && (USHRT_MAX == 0xffffffffUL))
+ typedef unsigned short z_uint4;
+# define Z_UINT4_DEFINED
+# endif
+# endif
+# endif
+# endif /* MODERN && !NO_LIMITS_H */
+#endif /* !Z_UINT4_DEFINED */
+#ifndef Z_UINT4_DEFINED
+ typedef ulg z_uint4;
+# define Z_UINT4_DEFINED
+#endif
+
+/* The following three user-defined unsigned integer types are used for
+ holding zipfile entities (required widths without / with Zip64 support):
+ a) sizes and offset of zipfile entries
+ (4 bytes / 8 bytes)
+ b) enumeration and counts of zipfile entries
+ (2 bytes / 8 bytes)
+ Remark: internally, we use 4 bytes for archive member counting in the
+ No-Zip64 case, because UnZip supports more than 64k entries for
+ classic Zip archives without Zip64 extensions.
+ c) enumeration and counts of zipfile volumes of multivolume archives
+ (2 bytes / 4 bytes)
+ */
+#ifdef ZIP64_SUPPORT
+ typedef z_uint8 zusz_t; /* zipentry sizes & offsets */
+ typedef z_uint8 zucn_t; /* archive entry counts */
+ typedef z_uint4 zuvl_t; /* multivolume numbers */
+# define MASK_ZUCN64 (~(zucn_t)0)
+/* In case we ever get to support an environment where z_uint8 may be WIDER
+ than 64 bit wide, we will have to apply a construct similar to
+ #define MASK_ZUCN64 (~(zucn_t)0 & (zucn_t)0xffffffffffffffffULL)
+ for the 64-bit mask.
+ */
+#else
+ typedef ulg zusz_t; /* zipentry sizes & offsets */
+ typedef unsigned int zucn_t; /* archive entry counts */
+ typedef unsigned short zuvl_t; /* multivolume numbers */
+# define MASK_ZUCN64 (~(zucn_t)0)
+#endif
+#define MASK_ZUCN16 ((zucn_t)0xFFFF)
+
+#ifdef NO_UID_GID
+# ifdef UID_USHORT
+ typedef unsigned short uid_t; /* TI SysV.3 */
+ typedef unsigned short gid_t;
+# else
+ typedef unsigned int uid_t; /* SCO Xenix */
+ typedef unsigned int gid_t;
+# endif
+#endif
+
+#if (defined(GOT_UTIMBUF) || defined(sgi) || defined(ATARI))
+ typedef struct utimbuf ztimbuf;
+#else
+ typedef struct ztimbuf {
+ time_t actime; /* new access time */
+ time_t modtime; /* new modification time */
+ } ztimbuf;
+#endif
+
+typedef struct iztimes {
+ time_t atime; /* new access time */
+ time_t mtime; /* new modification time */
+ time_t ctime; /* used for creation time; NOT same as st_ctime */
+} iztimes;
+
+#ifdef SET_DIR_ATTRIB
+ typedef struct direntry { /* head of system-specific struct holding */
+ struct direntry *next; /* defered directory attributes info */
+ char *fn; /* filename of directory */
+ char buf[1]; /* start of system-specific internal data */
+ } direntry;
+#endif /* SET_DIR_ATTRIB */
+
+#ifdef SYMLINKS
+ typedef struct slinkentry { /* info for deferred symlink creation */
+ struct slinkentry *next; /* pointer to next entry in chain */
+ extent targetlen; /* length of target filespec */
+ extent attriblen; /* length of system-specific attrib data */
+ char *target; /* pointer to target filespec */
+ char *fname; /* pointer to name of link */
+ char buf[1]; /* data/name/link buffer */
+ } slinkentry;
+#endif /* SYMLINKS */
+
+typedef struct min_info {
+ zoff_t offset;
+ zusz_t compr_size; /* compressed size (needed if extended header) */
+ zusz_t uncompr_size; /* uncompressed size (needed if extended header) */
+ ulg crc; /* crc (needed if extended header) */
+ zuvl_t diskstart; /* no of volume where this entry starts */
+ uch hostver;
+ uch hostnum;
+ unsigned file_attr; /* local flavor, as used by creat(), chmod()... */
+ unsigned encrypted : 1; /* file encrypted: decrypt before uncompressing */
+ unsigned ExtLocHdr : 1; /* use time instead of CRC for decrypt check */
+ unsigned textfile : 1; /* file is text (according to zip) */
+ unsigned textmode : 1; /* file is to be extracted as text */
+ unsigned lcflag : 1; /* convert filename to lowercase */
+ unsigned vollabel : 1; /* "file" is an MS-DOS volume (disk) label */
+#ifdef SYMLINKS
+ unsigned symlink : 1; /* file is a symbolic link */
+#endif
+ unsigned HasUxAtt : 1; /* crec ext_file_attr has Unix style mode bits */
+#ifdef UNICODE_SUPPORT
+ unsigned GPFIsUTF8: 1; /* crec gen_purpose_flag UTF-8 bit 11 is set */
+#endif
+#ifndef SFX
+ char Far *cfilname; /* central header version of filename */
+#endif
+} min_info;
+
+typedef struct VMStimbuf {
+ char *revdate; /* (both roughly correspond to Unix modtime/st_mtime) */
+ char *credate;
+} VMStimbuf;
+
+/*---------------------------------------------------------------------------
+ Zipfile work area declarations.
+ ---------------------------------------------------------------------------*/
+
+#ifdef MALLOC_WORK
+ union work {
+ struct { /* unshrink(): */
+ shrint *Parent; /* pointer to (8192 * sizeof(shrint)) */
+ uch *value; /* pointer to 8KB char buffer */
+ uch *Stack; /* pointer to another 8KB char buffer */
+ } shrink;
+ uch *Slide; /* explode(), inflate(), unreduce() */
+ };
+#else /* !MALLOC_WORK */
+ union work {
+ struct { /* unshrink(): */
+ shrint Parent[HSIZE]; /* (8192 * sizeof(shrint)) == 16KB minimum */
+ uch value[HSIZE]; /* 8KB */
+ uch Stack[HSIZE]; /* 8KB */
+ } shrink; /* total = 32KB minimum; 80KB on Cray/Alpha */
+ uch Slide[WSIZE]; /* explode(), inflate(), unreduce() */
+ };
+#endif /* ?MALLOC_WORK */
+
+#define slide G.area.Slide
+
+#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
+# define redirSlide G.redirect_sldptr
+#else
+# define redirSlide G.area.Slide
+#endif
+
+/*---------------------------------------------------------------------------
+ Zipfile layout declarations. If these headers ever change, make sure the
+ xxREC_SIZE defines (above) change with them!
+ ---------------------------------------------------------------------------*/
+
+ typedef uch local_byte_hdr[ LREC_SIZE ];
+# define L_VERSION_NEEDED_TO_EXTRACT_0 0
+# define L_VERSION_NEEDED_TO_EXTRACT_1 1
+# define L_GENERAL_PURPOSE_BIT_FLAG 2
+# define L_COMPRESSION_METHOD 4
+# define L_LAST_MOD_DOS_DATETIME 6
+# define L_CRC32 10
+# define L_COMPRESSED_SIZE 14
+# define L_UNCOMPRESSED_SIZE 18
+# define L_FILENAME_LENGTH 22
+# define L_EXTRA_FIELD_LENGTH 24
+
+ typedef uch cdir_byte_hdr[ CREC_SIZE ];
+# define C_VERSION_MADE_BY_0 0
+# define C_VERSION_MADE_BY_1 1
+# define C_VERSION_NEEDED_TO_EXTRACT_0 2
+# define C_VERSION_NEEDED_TO_EXTRACT_1 3
+# define C_GENERAL_PURPOSE_BIT_FLAG 4
+# define C_COMPRESSION_METHOD 6
+# define C_LAST_MOD_DOS_DATETIME 8
+# define C_CRC32 12
+# define C_COMPRESSED_SIZE 16
+# define C_UNCOMPRESSED_SIZE 20
+# define C_FILENAME_LENGTH 24
+# define C_EXTRA_FIELD_LENGTH 26
+# define C_FILE_COMMENT_LENGTH 28
+# define C_DISK_NUMBER_START 30
+# define C_INTERNAL_FILE_ATTRIBUTES 32
+# define C_EXTERNAL_FILE_ATTRIBUTES 34
+# define C_RELATIVE_OFFSET_LOCAL_HEADER 38
+
+ typedef uch ec_byte_rec[ ECREC_SIZE+4 ];
+/* define SIGNATURE 0 space-holder only */
+# define NUMBER_THIS_DISK 4
+# define NUM_DISK_WITH_START_CEN_DIR 6
+# define NUM_ENTRIES_CEN_DIR_THS_DISK 8
+# define TOTAL_ENTRIES_CENTRAL_DIR 10
+# define SIZE_CENTRAL_DIRECTORY 12
+# define OFFSET_START_CENTRAL_DIRECTORY 16
+# define ZIPFILE_COMMENT_LENGTH 20
+
+ typedef uch ec_byte_loc64[ ECLOC64_SIZE+4 ];
+# define NUM_DISK_START_EOCDR64 4
+# define OFFSET_START_EOCDR64 8
+# define NUM_THIS_DISK_LOC64 16
+
+ typedef uch ec_byte_rec64[ ECREC64_SIZE+4 ];
+# define ECREC64_LENGTH 4
+# define EC_VERSION_MADE_BY_0 12
+# define EC_VERSION_NEEDED_0 14
+# define NUMBER_THIS_DSK_REC64 16
+# define NUM_DISK_START_CEN_DIR64 20
+# define NUM_ENTRIES_CEN_DIR_THS_DISK64 24
+# define TOTAL_ENTRIES_CENTRAL_DIR64 32
+# define SIZE_CENTRAL_DIRECTORY64 40
+# define OFFSET_START_CENTRAL_DIRECT64 48
+
+
+/* The following structs are used to hold all header data of a zip entry.
+ Traditionally, the structs' layouts followed the data layout of the
+ corresponding zipfile header structures. However, the zipfile header
+ layouts were designed in the old ages of 16-bit CPUs, they are subject
+ to structure padding and/or alignment issues on newer systems with a
+ "natural word width" of more than 2 bytes.
+ Please note that the structure members are now reordered by size
+ (top-down), to prevent internal padding and optimize memory usage!
+ */
+ typedef struct local_file_header { /* LOCAL */
+ zusz_t csize;
+ zusz_t ucsize;
+ ulg last_mod_dos_datetime;
+ ulg crc32;
+ uch version_needed_to_extract[2];
+ ush general_purpose_bit_flag;
+ ush compression_method;
+ ush filename_length;
+ ush extra_field_length;
+ } local_file_hdr;
+
+ typedef struct central_directory_file_header { /* CENTRAL */
+ zusz_t csize;
+ zusz_t ucsize;
+ zusz_t relative_offset_local_header;
+ ulg last_mod_dos_datetime;
+ ulg crc32;
+ ulg external_file_attributes;
+ zuvl_t disk_number_start;
+ ush internal_file_attributes;
+ uch version_made_by[2];
+ uch version_needed_to_extract[2];
+ ush general_purpose_bit_flag;
+ ush compression_method;
+ ush filename_length;
+ ush extra_field_length;
+ ush file_comment_length;
+ } cdir_file_hdr;
+
+ typedef struct end_central_dir_record { /* END CENTRAL */
+ zusz_t size_central_directory;
+ zusz_t offset_start_central_directory;
+ zucn_t num_entries_centrl_dir_ths_disk;
+ zucn_t total_entries_central_dir;
+ zuvl_t number_this_disk;
+ zuvl_t num_disk_start_cdir;
+ int have_ecr64; /* valid Zip64 ecdir-record exists */
+ int is_zip64_archive; /* Zip64 ecdir-record is mandatory */
+ ush zipfile_comment_length;
+ } ecdir_rec;
+
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..16. e == 31 is EOB (end of block), e == 32
+ means that v is a literal, 32 < e < 64 means that v is a pointer to
+ the next table, which codes (e & 31) bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+
+typedef struct _APIDocStruct {
+ char *compare;
+ char *function;
+ char *syntax;
+ char *purpose;
+} APIDocStruct;
+
+
+
+
+/*************/
+/* Globals */
+/*************/
+
+#if (defined(OS2) && !defined(FUNZIP))
+# include "os2/os2data.h"
+#endif
+
+#include "globals.h"
+
+
+
+/*************************/
+/* Function Prototypes */
+/*************************/
+
+/*---------------------------------------------------------------------------
+ Functions in unzip.c (initialization routines):
+ ---------------------------------------------------------------------------*/
+
+#ifndef WINDLL
+ int MAIN OF((int argc, char **argv));
+ int unzip OF((__GPRO__ int argc, char **argv));
+ int uz_opts OF((__GPRO__ int *pargc, char ***pargv));
+ int usage OF((__GPRO__ int error));
+#endif /* !WINDLL */
+
+/*---------------------------------------------------------------------------
+ Functions in process.c (main driver routines):
+ ---------------------------------------------------------------------------*/
+
+int process_zipfiles OF((__GPRO));
+void free_G_buffers OF((__GPRO));
+/* static int do_seekable OF((__GPRO__ int lastchance)); */
+/* static int find_ecrec OF((__GPRO__ long searchlen)); */
+/* static int process_central_comment OF((__GPRO)); */
+int process_cdir_file_hdr OF((__GPRO));
+int process_local_file_hdr OF((__GPRO));
+int getZip64Data OF((__GPRO__ ZCONST uch *ef_buf,
+ unsigned ef_len));
+#ifdef UNICODE_SUPPORT
+ int getUnicodeData OF((__GPRO__ ZCONST uch *ef_buf,
+ unsigned ef_len));
+#endif
+unsigned ef_scan_for_izux OF((ZCONST uch *ef_buf, unsigned ef_len,
+ int ef_is_c, ulg dos_mdatetime,
+ iztimes *z_utim, ulg *z_uidgid));
+#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
+ zvoid *getRISCOSexfield OF((ZCONST uch *ef_buf, unsigned ef_len));
+#endif
+
+#ifndef SFX
+
+/*---------------------------------------------------------------------------
+ Functions in zipinfo.c (`zipinfo-style' listing routines):
+ ---------------------------------------------------------------------------*/
+
+#ifndef NO_ZIPINFO
+#ifndef WINDLL
+ int zi_opts OF((__GPRO__ int *pargc, char ***pargv));
+#endif
+void zi_end_central OF((__GPRO));
+int zipinfo OF((__GPRO));
+/* static int zi_long OF((__GPRO__ zusz_t *pEndprev)); */
+/* static int zi_short OF((__GPRO)); */
+/* static char *zi_time OF((__GPRO__ ZCONST ulg *datetimez,
+ ZCONST time_t *modtimez, char *d_t_str));*/
+#endif /* !NO_ZIPINFO */
+
+/*---------------------------------------------------------------------------
+ Functions in list.c (generic zipfile-listing routines):
+ ---------------------------------------------------------------------------*/
+
+int list_files OF((__GPRO));
+#ifdef TIMESTAMP
+ int get_time_stamp OF((__GPRO__ time_t *last_modtime,
+ ulg *nmember));
+#endif
+int ratio OF((zusz_t uc, zusz_t c));
+void fnprint OF((__GPRO));
+
+#endif /* !SFX */
+
+/*---------------------------------------------------------------------------
+ Functions in fileio.c:
+ ---------------------------------------------------------------------------*/
+
+int open_input_file OF((__GPRO));
+int open_outfile OF((__GPRO)); /* also vms.c */
+void undefer_input OF((__GPRO));
+void defer_leftover_input OF((__GPRO));
+unsigned readbuf OF((__GPRO__ char *buf, register unsigned len));
+int readbyte OF((__GPRO));
+int fillinbuf OF((__GPRO));
+int seek_zipf OF((__GPRO__ zoff_t abs_offset));
+#ifdef FUNZIP
+ int flush OF((__GPRO__ ulg size)); /* actually funzip.c */
+#else
+ int flush OF((__GPRO__ uch *buf, ulg size, int unshrink));
+#endif
+/* static int disk_error OF((__GPRO)); */
+void handler OF((int signal));
+time_t dos_to_unix_time OF((ulg dos_datetime));
+int check_for_newer OF((__GPRO__ char *filename)); /* os2,vmcms,vms */
+int do_string OF((__GPRO__ unsigned int length, int option));
+ush makeword OF((ZCONST uch *b));
+ulg makelong OF((ZCONST uch *sig));
+zusz_t makeint64 OF((ZCONST uch *sig));
+char *fzofft OF((__GPRO__ zoff_t val,
+ ZCONST char *pre, ZCONST char *post));
+#if (!defined(STR_TO_ISO) || defined(NEED_STR2ISO))
+ char *str2iso OF((char *dst, ZCONST char *src));
+#endif
+#if (!defined(STR_TO_OEM) || defined(NEED_STR2OEM))
+ char *str2oem OF((char *dst, ZCONST char *src));
+#endif
+#ifdef NO_STRNICMP
+ int zstrnicmp OF((register ZCONST char *s1,
+ register ZCONST char *s2,
+ register unsigned n));
+#endif
+#ifdef REGULUS
+ int zstat OF((ZCONST char *p, struct stat *s));
+#endif
+#ifdef ZMEM /* MUST be ifdef'd because of conflicts with the standard def. */
+ zvoid *memset OF((register zvoid *, register int, register unsigned int));
+ int memcmp OF((register ZCONST zvoid*, register ZCONST zvoid *,
+ register unsigned int));
+ zvoid *memcpy OF((register zvoid *, register ZCONST zvoid *,
+ register unsigned int));
+#endif
+#ifdef NEED_UZMBCLEN
+ extent uzmbclen OF((ZCONST unsigned char *ptr));
+#endif
+#ifdef NEED_UZMBSCHR
+ unsigned char *uzmbschr OF((ZCONST unsigned char *str, unsigned int c));
+#endif
+#ifdef NEED_UZMBSRCHR
+ unsigned char *uzmbsrchr OF((ZCONST unsigned char *str, unsigned int c));
+#endif
+#ifdef SMALL_MEM
+ char *fLoadFarString OF((__GPRO__ const char Far *sz));
+ char *fLoadFarStringSmall OF((__GPRO__ const char Far *sz));
+ char *fLoadFarStringSmall2 OF((__GPRO__ const char Far *sz));
+ #ifndef zfstrcpy
+ char Far * Far zfstrcpy OF((char Far *s1, const char Far *s2));
+ #endif
+ #if (!defined(SFX) && !defined(zfstrcmp))
+ int Far zfstrcmp OF((const char Far *s1, const char Far *s2));
+ #endif
+#endif
+
+
+/*---------------------------------------------------------------------------
+ Functions in extract.c:
+ ---------------------------------------------------------------------------*/
+
+int extract_or_test_files OF((__GPRO));
+/* static int store_info OF((void)); */
+/* static int extract_or_test_member OF((__GPRO)); */
+/* static int TestExtraField OF((__GPRO__ uch *ef, unsigned ef_len)); */
+/* static int test_OS2 OF((__GPRO__ uch *eb, unsigned eb_size)); */
+/* static int test_NT OF((__GPRO__ uch *eb, unsigned eb_size)); */
+#ifndef SFX
+ unsigned find_compr_idx OF((unsigned compr_methodnum));
+#endif
+int memextract OF((__GPRO__ uch *tgt, ulg tgtsize,
+ ZCONST uch *src, ulg srcsize));
+int memflush OF((__GPRO__ ZCONST uch *rawbuf, ulg size));
+#if (defined(VMS) || defined(VMS_TEXT_CONV))
+ uch *extract_izvms_block OF((__GPRO__ ZCONST uch *ebdata,
+ unsigned size, unsigned *retlen,
+ ZCONST uch *init, unsigned needlen));
+#endif
+char *fnfilter OF((ZCONST char *raw, uch *space,
+ extent size));
+
+/*---------------------------------------------------------------------------
+ Decompression functions:
+ ---------------------------------------------------------------------------*/
+
+#if (!defined(SFX) && !defined(FUNZIP))
+int explode OF((__GPRO)); /* explode.c */
+#endif
+int huft_free OF((struct huft *t)); /* inflate.c */
+int huft_build OF((__GPRO__ ZCONST unsigned *b, unsigned n,
+ unsigned s, ZCONST ush *d, ZCONST uch *e,
+ struct huft **t, unsigned *m));
+#ifdef USE_ZLIB
+ int UZinflate OF((__GPRO__ int is_defl64)); /* inflate.c */
+# define inflate_free(x) inflateEnd(&((Uz_Globs *)(&G))->dstrm)
+#else
+ int inflate OF((__GPRO__ int is_defl64)); /* inflate.c */
+ int inflate_free OF((__GPRO)); /* inflate.c */
+#endif /* ?USE_ZLIB */
+#if (!defined(SFX) && !defined(FUNZIP))
+#ifndef COPYRIGHT_CLEAN
+ int unreduce OF((__GPRO)); /* unreduce.c */
+/* static void LoadFollowers OF((__GPRO__ f_array *follower, uch *Slen));
+ * unreduce.c */
+#endif /* !COPYRIGHT_CLEAN */
+#ifndef LZW_CLEAN
+ int unshrink OF((__GPRO)); /* unshrink.c */
+/* static void partial_clear OF((__GPRO)); * unshrink.c */
+#endif /* !LZW_CLEAN */
+#endif /* !SFX && !FUNZIP */
+#ifdef USE_BZIP2
+ int UZbunzip2 OF((__GPRO)); /* extract.c */
+ void bz_internal_error OF((int bzerrcode)); /* ubz2err.c */
+#endif
+
+/*---------------------------------------------------------------------------
+ Internal API functions (only included in DLL versions):
+ ---------------------------------------------------------------------------*/
+
+#ifdef DLL
+ void setFileNotFound OF((__GPRO)); /* api.c */
+ int unzipToMemory OF((__GPRO__ char *zip, char *file,
+ UzpBuffer *retstr)); /* api.c */
+ int redirect_outfile OF((__GPRO)); /* api.c */
+ int writeToMemory OF((__GPRO__ ZCONST uch *rawbuf,
+ extent size)); /* api.c */
+ int close_redirect OF((__GPRO)); /* api.c */
+ /* this obsolescent entry point kept for compatibility: */
+ int UzpUnzip OF((int argc, char **argv));/* use UzpMain */
+#ifdef OS2DLL
+ int varmessage OF((__GPRO__ ZCONST uch *buf, ulg size));
+ int varputchar OF((__GPRO__ int c)); /* rexxapi.c */
+ int finish_REXX_redirect OF((__GPRO)); /* rexxapi.c */
+#endif
+#ifdef API_DOC
+ void APIhelp OF((__GPRO__ int argc, char **argv));
+#endif /* apihelp.c */
+#endif /* DLL */
+
+/*---------------------------------------------------------------------------
+ MSDOS-only functions:
+ ---------------------------------------------------------------------------*/
+
+#ifdef MSDOS
+#if (!defined(FUNZIP) && !defined(SFX) && !defined(WINDLL))
+ void check_for_windows OF((ZCONST char *app)); /* msdos.c */
+#endif
+#if (defined(__GO32__) || defined(__EMX__))
+ unsigned _dos_getcountryinfo(void *); /* msdos.c */
+#if (!defined(__DJGPP__) || (__DJGPP__ < 2))
+ unsigned _dos_setftime(int, unsigned, unsigned); /* msdos.c */
+ unsigned _dos_setfileattr(const char *, unsigned); /* msdos.c */
+ unsigned _dos_creat(const char *, unsigned, int *); /* msdos.c */
+ void _dos_getdrive(unsigned *); /* msdos.c */
+ unsigned _dos_close(int); /* msdos.c */
+#endif /* !__DJGPP__ || (__DJGPP__ < 2) */
+#endif /* __GO32__ || __EMX__ */
+#endif
+
+/*---------------------------------------------------------------------------
+ OS/2-only functions:
+ ---------------------------------------------------------------------------*/
+
+#ifdef OS2 /* GetFileTime conflicts with something in Win32 header files */
+#if (defined(REENTRANT) && defined(USETHREADID))
+ ulg GetThreadId OF((void));
+#endif
+ int GetCountryInfo OF((void)); /* os2.c */
+ long GetFileTime OF((ZCONST char *name)); /* os2.c */
+/* static void SetPathAttrTimes OF((__GPRO__ int flags, int dir)); os2.c */
+/* static int SetEAs OF((__GPRO__ const char *path,
+ void *eablock)); os2.c */
+/* static int SetACL OF((__GPRO__ const char *path,
+ void *eablock)); os2.c */
+/* static int IsFileNameValid OF((const char *name)); os2.c */
+/* static void map2fat OF((char *pathcomp, char **pEndFAT)); os2.c */
+/* static int SetLongNameEA OF((char *name, char *longname)); os2.c */
+/* static void InitNLS OF((void)); os2.c */
+ int IsUpperNLS OF((int nChr)); /* os2.c */
+ int ToLowerNLS OF((int nChr)); /* os2.c */
+ void DebugMalloc OF((void)); /* os2.c */
+#endif
+
+/*---------------------------------------------------------------------------
+ QDOS-only functions:
+ ---------------------------------------------------------------------------*/
+
+#ifdef QDOS
+ int QMatch (uch, uch);
+ void QFilename (__GPRO__ char *);
+ char *Qstrfix (char *);
+ int QReturn (int zip_error);
+#endif
+
+/*---------------------------------------------------------------------------
+ TOPS20-only functions:
+ ---------------------------------------------------------------------------*/
+
+#ifdef TOPS20
+ int upper OF((char *s)); /* tops20.c */
+ int enquote OF((char *s)); /* tops20.c */
+ int dequote OF((char *s)); /* tops20.c */
+ int fnlegal OF(()); /* error if prototyped? */ /* tops20.c */
+#endif
+
+/*---------------------------------------------------------------------------
+ VM/CMS- and MVS-only functions:
+ ---------------------------------------------------------------------------*/
+
+#ifdef CMS_MVS
+ extent getVMMVSexfield OF((char *type, uch *ef_block, unsigned datalen));
+ FILE *vmmvs_open_infile OF((__GPRO)); /* vmmvs.c */
+ void close_infile OF((__GPRO)); /* vmmvs.c */
+#endif
+
+/*---------------------------------------------------------------------------
+ VMS-only functions:
+ ---------------------------------------------------------------------------*/
+
+#ifdef VMS
+ int check_format OF((__GPRO)); /* vms.c */
+/* int open_outfile OF((__GPRO)); * (see fileio.c) vms.c */
+/* int flush OF((__GPRO__ uch *rawbuf, unsigned size,
+ int final_flag)); * (see fileio.c) vms.c */
+ char *vms_msg_text OF((void)); /* vms.c */
+#ifdef RETURN_CODES
+ void return_VMS OF((__GPRO__ int zip_error)); /* vms.c */
+#else
+ void return_VMS OF((int zip_error)); /* vms.c */
+#endif
+#ifdef VMSCLI
+ ulg vms_unzip_cmdline OF((int *, char ***)); /* cmdline.c */
+ int VMSCLI_usage OF((__GPRO__ int error)); /* cmdline.c */
+#endif
+#endif
+
+/*---------------------------------------------------------------------------
+ WIN32-only functions:
+ ---------------------------------------------------------------------------*/
+
+#ifdef WIN32
+ int IsWinNT OF((void)); /* win32.c */
+#ifdef NTSD_EAS
+ void process_defer_NT OF((__GPRO)); /* win32.c */
+ int test_NTSD OF((__GPRO__ uch *eb, unsigned eb_size,
+ uch *eb_ucptr, ulg eb_ucsize)); /* win32.c */
+# define TEST_NTSD test_NTSD
+#endif
+#ifdef W32_STAT_BANDAID
+ int zstat_win32 OF((__W32STAT_GLOBALS__
+ const char *path, z_stat *buf)); /* win32.c */
+#endif
+#endif
+
+/*---------------------------------------------------------------------------
+ Miscellaneous/shared functions:
+ ---------------------------------------------------------------------------*/
+
+Uz_Globs *globalsCtor OF((void)); /* globals.c */
+
+int envargs OF((int *Pargc, char ***Pargv,
+ ZCONST char *envstr, ZCONST char *envstr2));
+ /* envargs.c */
+void mksargs OF((int *argcp, char ***argvp)); /* envargs.c */
+
+int match OF((ZCONST char *s, ZCONST char *p,
+ int ic __WDLPRO)); /* match.c */
+int iswild OF((ZCONST char *p)); /* match.c */
+
+/* declarations of public CRC-32 functions have been moved into crc32.h
+ (free_crc_table(), get_crc_table(), crc32()) crc32.c */
+
+int dateformat OF((void)); /* local */
+char dateseparator OF((void)); /* local */
+#ifndef WINDLL
+ void version OF((__GPRO)); /* local */
+#endif
+int mapattr OF((__GPRO)); /* local */
+int mapname OF((__GPRO__ int renamed)); /* local */
+int checkdir OF((__GPRO__ char *pathcomp, int flag)); /* local */
+char *do_wild OF((__GPRO__ ZCONST char *wildzipfn)); /* local */
+char *GetLoadPath OF((__GPRO)); /* local */
+#if (defined(MORE) && (defined(ATH_BEO_UNX) || defined(QDOS) || defined(VMS)))
+ int screensize OF((int *tt_rows, int *tt_cols)); /* local */
+# if defined(VMS)
+ int screenlinewrap OF((void)); /* local */
+# endif
+#endif /* MORE && (ATH_BEO_UNX || QDOS || VMS) */
+#ifdef OS2_W32
+ int SetFileSize OF((FILE *file, zusz_t filesize)); /* local */
+#endif
+#ifndef MTS /* macro in MTS */
+ int close_outfile OF((__GPRO)); /* local */
+#endif
+#ifdef SET_SYMLINK_ATTRIBS
+ int set_symlnk_attribs OF((__GPRO__ slinkentry *slnk_entry)); /* local */
+#endif
+#ifdef SET_DIR_ATTRIB
+ int defer_dir_attribs OF((__GPRO__ direntry **pd)); /* local */
+ int set_direc_attribs OF((__GPRO__ direntry *d)); /* local */
+#endif
+#ifdef TIMESTAMP
+# ifdef WIN32
+ int stamp_file OF((__GPRO__
+ ZCONST char *fname, time_t modtime)); /* local */
+# else
+ int stamp_file OF((ZCONST char *fname, time_t modtime)); /* local */
+# endif
+#endif
+#ifdef NEED_ISO_OEM_INIT
+ void prepare_ISO_OEM_translat OF((__GPRO)); /* local */
+#endif
+#if (defined(MALLOC_WORK) && defined(MY_ZCALLOC))
+ zvoid far *zcalloc OF((unsigned int, unsigned int));
+ zvoid zcfree OF((zvoid far *));
+#endif /* MALLOC_WORK && MY_ZCALLOC */
+#ifdef SYSTEM_SPECIFIC_CTOR
+ void SYSTEM_SPECIFIC_CTOR OF((__GPRO)); /* local */
+#endif
+#ifdef SYSTEM_SPECIFIC_DTOR
+ void SYSTEM_SPECIFIC_DTOR OF((__GPRO)); /* local */
+#endif
+
+
+
+
+
+/************/
+/* Macros */
+/************/
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifdef DEBUG
+# if (defined(THEOS) && defined(NO_BOGUS_SPC))
+# define NO_DEBUG_IN_MACROS
+# define Trace(x) _fprintf x
+# else
+# define Trace(x) fprintf x
+# endif
+#else
+# define Trace(x)
+#endif
+
+#ifdef DEBUG_TIME
+# define TTrace(x) fprintf x
+#else
+# define TTrace(x)
+#endif
+
+#ifdef NO_DEBUG_IN_MACROS
+# define MTrace(x)
+#else
+# define MTrace(x) Trace(x)
+#endif
+
+#if (defined(UNIX) || defined(T20_VMS)) /* generally old systems */
+# define ToLower(x) ((char)(isupper((int)x)? tolower((int)x) : x))
+#else
+# define ToLower tolower /* assumed "smart"; used in match() */
+#endif
+
+#ifdef USE_STRM_INPUT
+ /* ``Replace'' the unbuffered UNIX style I/O function with similar
+ * standard C functions from <stdio.h>.
+ */
+# define read(fd,buf,n) fread((buf),1,(n),(FILE *)(fd))
+# ifdef zlseek
+# undef zlseek
+# endif
+# define zlseek(fd,o,w) zfseeko((FILE *)(fd),(o),(w))
+# define close(fd) fclose((FILE *)(fd))
+#endif /* USE_STRM_INPUT */
+
+/* The return value of the Info() "macro function" is never checked in
+ * UnZip. Otherwise, to get the same behaviour as for (*G.message)(), the
+ * Info() definition for "FUNZIP" would have to be corrected:
+ * #define Info(buf,flag,sprf_arg) \
+ * (fputs((char *)(sprintf sprf_arg, (buf)), \
+ * (flag)&1? stderr : stdout) < 0)
+ */
+#ifndef Info /* may already have been defined for redirection */
+# ifdef FUNZIP
+# define Info(buf,flag,sprf_arg) \
+ fputs((char *)(sprintf sprf_arg, (buf)), (flag)&1? stderr : stdout)
+# else
+# ifdef INT_SPRINTF /* optimized version for "int sprintf()" flavour */
+# define Info(buf,flag,sprf_arg) \
+ (*G.message)((zvoid *)&G, (uch *)(buf), (ulg)sprintf sprf_arg, (flag))
+# else /* generic version, does not use sprintf() return value */
+# define Info(buf,flag,sprf_arg) \
+ (*G.message)((zvoid *)&G, (uch *)(buf), \
+ (ulg)(sprintf sprf_arg, strlen((char *)(buf))), (flag))
+# endif
+# endif
+#endif /* !Info */
+
+/* This wrapper macro around fzofft() is just defined to "hide" the
+ * argument needed to reference the global storage buffers.
+ */
+#define FmZofft(val, pre, post) fzofft(__G__ val, pre, post)
+
+/* The following macro wrappers around the fnfilter function are used many
+ * times to prepare archive entry names or name components for displaying
+ * listings and (warning/error) messages. They use sections in the upper half
+ * of 'slide' as buffer, since their output is normally fed through the
+ * Info() macro with 'slide' (the start of this area) as message buffer.
+ */
+#define FnFilter1(fname) \
+ fnfilter((fname), slide + (extent)(WSIZE>>1), (extent)(WSIZE>>2))
+#define FnFilter2(fname) \
+ fnfilter((fname), slide + (extent)((WSIZE>>1) + (WSIZE>>2)),\
+ (extent)(WSIZE>>2))
+
+#ifndef FUNZIP /* used only in inflate.c */
+# define MESSAGE(str,len,flag) (*G.message)((zvoid *)&G,(str),(len),(flag))
+#endif
+
+#if 0 /* Optimization: use the (const) result of crc32(0L,NULL,0) */
+# define CRCVAL_INITIAL crc32(0L, NULL, 0)
+#else
+# define CRCVAL_INITIAL 0L
+#endif
+
+#ifdef SYMLINKS
+ /* This macro defines the Zip "made by" hosts that are considered
+ to support storing symbolic link entries. */
+# define SYMLINK_HOST(hn) ((hn) == UNIX_ || (hn) == ATARI_ || \
+ (hn) == ATHEOS_ || (hn) == BEOS_ || (hn) == VMS_)
+#endif
+
+#ifndef TEST_NTSD /* "NTSD valid?" checking function */
+# define TEST_NTSD NULL /* ... is not available */
+#endif
+
+#define SKIP_(length) if(length&&((error=do_string(__G__ length,SKIP))!=0))\
+ {error_in_archive=error; if(error>1) return error;}
+
+/*
+ * Skip a variable-length field, and report any errors. Used in zipinfo.c
+ * and unzip.c in several functions.
+ *
+ * macro SKIP_(length)
+ * ush length;
+ * {
+ * if (length && ((error = do_string(length, SKIP)) != 0)) {
+ * error_in_archive = error; /-* might be warning *-/
+ * if (error > 1) /-* fatal *-/
+ * return (error);
+ * }
+ * }
+ *
+ */
+
+
+#ifdef FUNZIP
+# define FLUSH(w) flush(__G__ (ulg)(w))
+# define NEXTBYTE getc(G.in) /* redefined in crypt.h if full version */
+#else
+# define FLUSH(w) ((G.mem_mode) ? memflush(__G__ redirSlide,(ulg)(w)) \
+ : flush(__G__ redirSlide,(ulg)(w),0))
+# define NEXTBYTE (G.incnt-- > 0 ? (int)(*G.inptr++) : readbyte(__G))
+#endif
+
+
+#define READBITS(nbits,zdest) {if(nbits>G.bits_left) {int temp; G.zipeof=1;\
+ while (G.bits_left<=8*(int)(sizeof(G.bitbuf)-1) && (temp=NEXTBYTE)!=EOF) {\
+ G.bitbuf|=(ulg)temp<<G.bits_left; G.bits_left+=8; G.zipeof=0;}}\
+ zdest=(shrint)((unsigned)G.bitbuf&mask_bits[nbits]);G.bitbuf>>=nbits;\
+ G.bits_left-=nbits;}
+
+/*
+ * macro READBITS(nbits,zdest) * only used by unreduce and unshrink *
+ * {
+ * if (nbits > G.bits_left) { * fill G.bitbuf, 8*sizeof(ulg) bits *
+ * int temp;
+ *
+ * G.zipeof = 1;
+ * while (G.bits_left <= 8*(int)(sizeof(G.bitbuf)-1) &&
+ * (temp = NEXTBYTE) != EOF) {
+ * G.bitbuf |= (ulg)temp << G.bits_left;
+ * G.bits_left += 8;
+ * G.zipeof = 0;
+ * }
+ * }
+ * zdest = (shrint)((unsigned)G.bitbuf & mask_bits[nbits]);
+ * G.bitbuf >>= nbits;
+ * G.bits_left -= nbits;
+ * }
+ *
+ */
+
+
+/* GRR: should use StringLower for STRLOWER macro if possible */
+
+/*
+ * Copy the zero-terminated string in str1 into str2, converting any
+ * uppercase letters to lowercase as we go. str2 gets zero-terminated
+ * as well, of course. str1 and str2 may be the same character array.
+ */
+#ifdef _MBCS
+# define STRLOWER(str1, str2) \
+ { \
+ char *p, *q, c; unsigned i; \
+ p = (char *)(str1); \
+ q = (char *)(str2); \
+ while ((c = *p) != '\0') { \
+ if ((i = CLEN(p)) > 1) { \
+ while (i--) *q++ = *p++; \
+ } else { \
+ *q++ = (char)(isupper((int)(c))? tolower((int)(c)) : c); \
+ p++; \
+ } \
+ } \
+ *q = '\0'; \
+ }
+#else
+# define STRLOWER(str1, str2) \
+ { \
+ char *p, *q; \
+ p = (char *)(str1) - 1; \
+ q = (char *)(str2); \
+ while (*++p) \
+ *q++ = (char)(isupper((int)(*p))? tolower((int)(*p)) : *p); \
+ *q = '\0'; \
+ }
+#endif
+/*
+ * NOTES: This macro makes no assumptions about the characteristics of
+ * the tolower() function or macro (beyond its existence), nor does it
+ * make assumptions about the structure of the character set (i.e., it
+ * should work on EBCDIC machines, too). The fact that either or both
+ * of isupper() and tolower() may be macros has been taken into account;
+ * watch out for "side effects" (in the C sense) when modifying this
+ * macro.
+ */
+
+#ifndef foreign
+# define foreign(c) (c)
+#endif
+
+#ifndef native
+# define native(c) (c)
+# define A_TO_N(str1)
+#else
+# ifndef NATIVE
+# define NATIVE "native chars"
+# endif
+# define A_TO_N(str1) {register uch *p;\
+ for (p=(uch *)(str1); *p; p++) *p=native(*p);}
+#endif
+/*
+ * Translate the zero-terminated string in str1 from ASCII to the native
+ * character set. The translation is performed in-place and uses the
+ * "native" macro to translate each character.
+ *
+ * NOTE: Using the "native" macro means that is it the only part of unzip
+ * which knows which translation table (if any) is actually in use to
+ * produce the native character set. This makes adding new character set
+ * translation tables easy, insofar as all that is needed is an appropriate
+ * "native" macro definition and the translation table itself. Currently,
+ * the only non-ASCII native character set implemented is EBCDIC, but this
+ * may not always be so.
+ */
+
+
+/* default setup for internal codepage: assume ISO 8859-1 compatibility!! */
+#if (!defined(NATIVE) && !defined(CRTL_CP_IS_ISO) && !defined(CRTL_CP_IS_OEM))
+# define CRTL_CP_IS_ISO
+#endif
+
+
+/* Translate "extended ASCII" chars (OEM coding for DOS and OS/2; else
+ * ISO-8859-1 [ISO Latin 1, Win Ansi,...]) into the internal "native"
+ * code page. As with A_TO_N(), conversion is done in place.
+ */
+#ifndef _ISO_INTERN
+# ifdef CRTL_CP_IS_OEM
+# ifndef IZ_ISO2OEM_ARRAY
+# define IZ_ISO2OEM_ARRAY
+# endif
+# define _ISO_INTERN(str1) if (iso2oem) {register uch *p;\
+ for (p=(uch *)(str1); *p; p++)\
+ *p = native((*p & 0x80) ? iso2oem[*p & 0x7f] : *p);}
+# else
+# define _ISO_INTERN(str1) A_TO_N(str1)
+# endif
+#endif
+
+#ifndef _OEM_INTERN
+# ifdef CRTL_CP_IS_OEM
+# define _OEM_INTERN(str1) A_TO_N(str1)
+# else
+# ifndef IZ_OEM2ISO_ARRAY
+# define IZ_OEM2ISO_ARRAY
+# endif
+# define _OEM_INTERN(str1) if (oem2iso) {register uch *p;\
+ for (p=(uch *)(str1); *p; p++)\
+ *p = native((*p & 0x80) ? oem2iso[*p & 0x7f] : *p);}
+# endif
+#endif
+
+#ifndef STR_TO_ISO
+# ifdef CRTL_CP_IS_ISO
+# define STR_TO_ISO strcpy
+# else
+# define STR_TO_ISO str2iso
+# define NEED_STR2ISO
+# endif
+#endif
+
+#ifndef STR_TO_OEM
+# ifdef CRTL_CP_IS_OEM
+# define STR_TO_OEM strcpy
+# else
+# define STR_TO_OEM str2oem
+# define NEED_STR2OEM
+# endif
+#endif
+
+#if (!defined(INTERN_TO_ISO) && !defined(ASCII2ISO))
+# ifdef CRTL_CP_IS_OEM
+ /* know: "ASCII" is "OEM" */
+# define ASCII2ISO(c) \
+ ((((c) & 0x80) && oem2iso) ? oem2iso[(c) & 0x7f] : (c))
+# if (defined(NEED_STR2ISO) && !defined(CRYP_USES_OEM2ISO))
+# define CRYP_USES_OEM2ISO
+# endif
+# else
+ /* assume: "ASCII" is "ISO-ANSI" */
+# define ASCII2ISO(c) (c)
+# endif
+#endif
+
+#if (!defined(INTERN_TO_OEM) && !defined(ASCII2OEM))
+# ifdef CRTL_CP_IS_OEM
+ /* know: "ASCII" is "OEM" */
+# define ASCII2OEM(c) (c)
+# else
+ /* assume: "ASCII" is "ISO-ANSI" */
+# define ASCII2OEM(c) \
+ ((((c) & 0x80) && iso2oem) ? iso2oem[(c) & 0x7f] : (c))
+# if (defined(NEED_STR2OEM) && !defined(CRYP_USES_ISO2OEM))
+# define CRYP_USES_ISO2OEM
+# endif
+# endif
+#endif
+
+/* codepage conversion setup for testp() in crypt.c */
+#ifdef CRTL_CP_IS_ISO
+# ifndef STR_TO_CP2
+# define STR_TO_CP2 STR_TO_OEM
+# endif
+#else
+# ifdef CRTL_CP_IS_OEM
+# ifndef STR_TO_CP2
+# define STR_TO_CP2 STR_TO_ISO
+# endif
+# else /* native internal CP is neither ISO nor OEM */
+# ifndef STR_TO_CP1
+# define STR_TO_CP1 STR_TO_ISO
+# endif
+# ifndef STR_TO_CP2
+# define STR_TO_CP2 STR_TO_OEM
+# endif
+# endif
+#endif
+
+
+/* Convert filename (and file comment string) into "internal" charset.
+ * This macro assumes that Zip entry filenames are coded in OEM (IBM DOS)
+ * codepage when made on
+ * -> DOS (this includes 16-bit Windows 3.1) (FS_FAT_)
+ * -> OS/2 (FS_HPFS_)
+ * -> Win95/WinNT with Nico Mak's WinZip (FS_NTFS_ && hostver == "5.0")
+ * EXCEPTIONS:
+ * PKZIP for Windows 2.5, 2.6, and 4.0 flag their entries as "FS_FAT_", but
+ * the filename stored in the local header is coded in Windows ANSI (CP 1252
+ * resp. ISO 8859-1 on US and western Europe locale settings).
+ * Likewise, PKZIP for UNIX 2.51 flags its entries as "FS_FAT_", but the
+ * filenames stored in BOTH the local and the central header are coded
+ * in the local system's codepage (usually ANSI codings like ISO 8859-1).
+ *
+ * All other ports are assumed to code zip entry filenames in ISO 8859-1.
+ */
+#ifndef Ext_ASCII_TO_Native
+# define Ext_ASCII_TO_Native(string, hostnum, hostver, isuxatt, islochdr) \
+ if (((hostnum) == FS_FAT_ && \
+ !(((islochdr) || (isuxatt)) && \
+ ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
+ (hostnum) == FS_HPFS_ || \
+ ((hostnum) == FS_NTFS_ /* && (hostver) == 50 */ )) { \
+ _OEM_INTERN((string)); \
+ } else { \
+ _ISO_INTERN((string)); \
+ }
+#endif
+
+
+
+/**********************/
+/* Global constants */
+/**********************/
+
+ extern ZCONST unsigned near mask_bits[17];
+ extern ZCONST char *fnames[2];
+
+#ifdef EBCDIC
+ extern ZCONST uch ebcdic[];
+#endif
+#ifdef IZ_ISO2OEM_ARRAY
+ extern ZCONST uch Far *iso2oem;
+ extern ZCONST uch Far iso2oem_850[];
+#endif
+#ifdef IZ_OEM2ISO_ARRAY
+ extern ZCONST uch Far *oem2iso;
+ extern ZCONST uch Far oem2iso_850[];
+#endif
+
+ extern ZCONST char Far VersionDate[];
+ extern ZCONST char Far CentSigMsg[];
+#ifndef SFX
+ extern ZCONST char Far EndSigMsg[];
+#endif
+ extern ZCONST char Far SeekMsg[];
+ extern ZCONST char Far FilenameNotMatched[];
+ extern ZCONST char Far ExclFilenameNotMatched[];
+ extern ZCONST char Far ReportMsg[];
+
+#ifndef SFX
+ extern ZCONST char Far Zipnfo[];
+ extern ZCONST char Far CompiledWith[];
+#endif /* !SFX */
+
+
+
+/***********************************/
+/* Global (shared?) RTL variables */
+/***********************************/
+
+#ifdef DECLARE_ERRNO
+ extern int errno;
+#endif
+
+/*---------------------------------------------------------------------
+ Unicode Support
+ 28 August 2005
+ ---------------------------------------------------------------------*/
+#if (defined(UNICODE_SUPPORT) && defined(UNICODE_WCHAR))
+
+ /* Default character when a zwchar too big for wchar_t */
+# define zwchar_to_wchar_t_default_char '_'
+
+ /* Default character string when wchar_t does not convert to mb */
+# define wide_to_mb_default_string "_"
+
+ /* wide character type */
+ typedef unsigned long zwchar;
+
+ /* UTF-8 related conversion functions, currently found in process.c */
+
+# if 0 /* currently unused */
+ /* check if string is all ASCII */
+ int is_ascii_string OF((ZCONST char *mbstring));
+# endif /* unused */
+
+ /* convert UTF-8 string to multi-byte string */
+ char *utf8_to_local_string OF((ZCONST char *utf8_string, int escape_all));
+
+ /* convert UTF-8 string to wide string */
+ zwchar *utf8_to_wide_string OF((ZCONST char *utf8_string));
+
+ /* convert wide string to multi-byte string */
+ char *wide_to_local_string OF((ZCONST zwchar *wide_string, int escape_all));
+
+# if 0 /* currently unused */
+ /* convert local string to multi-byte display string */
+ char *local_to_display_string OF((ZCONST char *local_string));
+# endif /* unused */
+
+ /* convert wide character to escape string */
+ char *wide_to_escape_string OF((unsigned long));
+
+# define utf8_to_escaped_string(utf8_string) \
+ utf8_to_local_string(utf8_string, TRUE)
+
+# if 0 /* currently unused */
+ /* convert escape string to wide character */
+ unsigned long escape_string_to_wide OF((ZCONST char *escape_string));
+
+ /* convert local to UTF-8 */
+ char *local_to_utf8_string OF ((ZCONST char *local_string));
+
+ /* convert local to wide string */
+ zwchar *local_to_wide_string OF ((ZCONST char *local_string));
+
+ /* convert wide string to UTF-8 */
+ char *wide_to_utf8_string OF((ZCONST zwchar *wide_string));
+# endif /* unused */
+
+#endif /* UNICODE_SUPPORT && UNICODE_WCHAR */
+
+
+#endif /* !__unzpriv_h */
diff -Naur a/zipinfo.c b/zipinfo.c
--- a/zipinfo.c 2009-02-08 17:04:30.000000000 +0000
+++ b/zipinfo.c 2019-12-02 01:49:39.895641007 +0000
@@ -457,6 +457,10 @@
int tflag_slm=TRUE, tflag_2v=FALSE;
int explicit_h=FALSE, explicit_t=FALSE;
+#ifdef UNIX
+ extern char OEM_CP[MAX_CP_NAME];
+ extern char ISO_CP[MAX_CP_NAME];
+#endif
#ifdef MACOS
uO.lflag = LFLAG; /* reset default on each call */
@@ -501,6 +505,37 @@
uO.lflag = 0;
}
break;
+#ifdef UNIX
+ case ('I'):
+ if (negative) {
+ Info(slide, 0x401, ((char *)slide,
+ "error: encodings can't be negated"));
+ return(PK_PARAM);
+ } else {
+ if(*s) { /* Handle the -Icharset case */
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
+ if(*s == '-') {
+ Info(slide, 0x401, ((char *)slide,
+ "error: a valid character encoding should follow the -I argument"));
+ return(PK_PARAM);
+ }
+ strncpy(ISO_CP, s, MAX_CP_NAME - 1);
+ ISO_CP[MAX_CP_NAME - 1] = '\0';
+ } else { /* -I charset */
+ ++argv;
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
+ Info(slide, 0x401, ((char *)slide,
+ "error: a valid character encoding should follow the -I argument"));
+ return(PK_PARAM);
+ }
+ s = *argv;
+ strncpy(ISO_CP, s, MAX_CP_NAME - 1);
+ ISO_CP[MAX_CP_NAME - 1] = '\0';
+ }
+ while(*(++s)); /* No params straight after charset name */
+ }
+ break;
+#endif /* ?UNIX */
case 'l': /* longer form of "ls -l" type listing */
if (negative)
uO.lflag = -2, negative = 0;
@@ -521,6 +556,37 @@
G.M_flag = TRUE;
break;
#endif
+#ifdef UNIX
+ case ('O'):
+ if (negative) {
+ Info(slide, 0x401, ((char *)slide,
+ "error: encodings can't be negated"));
+ return(PK_PARAM);
+ } else {
+ if(*s) { /* Handle the -Ocharset case */
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
+ if(*s == '-') {
+ Info(slide, 0x401, ((char *)slide,
+ "error: a valid character encoding should follow the -I argument"));
+ return(PK_PARAM);
+ }
+ strncpy(OEM_CP, s, MAX_CP_NAME - 1);
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
+ } else { /* -O charset */
+ ++argv;
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
+ Info(slide, 0x401, ((char *)slide,
+ "error: a valid character encoding should follow the -O argument"));
+ return(PK_PARAM);
+ }
+ s = *argv;
+ strncpy(OEM_CP, s, MAX_CP_NAME - 1);
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
+ }
+ while(*(++s)); /* No params straight after charset name */
+ }
+ break;
+#endif /* ?UNIX */
case 's': /* default: shorter "ls -l" type listing */
if (negative)
uO.lflag = -2, negative = 0;
@@ -771,7 +837,7 @@
Info(slide, 0x401,
((char *)slide, LoadFarString(CentSigMsg), j));
Info(slide, 0x401,
- ((char *)slide, LoadFarString(ReportMsg)));
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
error_in_archive = PK_BADERR; /* sig not found */
break;
}
@@ -960,7 +1026,8 @@
&& (!G.ecrec.is_zip64_archive)
&& (memcmp(G.sig, end_central_sig, 4) != 0)
) { /* just to make sure again */
- Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
+ Info(slide, 0x401,
+ ((char *)slide,"%s", LoadFarString(EndSigMsg)));
error_in_archive = PK_WARN; /* didn't find sig */
}
@@ -1881,7 +1948,7 @@
#endif
int k, error, error_in_archive=PK_COOL;
unsigned hostnum, hostver, methid, methnum, xattr;
- char *p, workspace[12], attribs[16];
+ char *p, workspace[12], attribs[17];
char methbuf[5];
static ZCONST char dtype[5]="NXFS"; /* normal, maximum, fast, superfast */
static ZCONST char Far os[NUM_HOSTS+1][4] = {
@@ -1921,7 +1988,19 @@
ush dnum=(ush)((G.crec.general_purpose_bit_flag>>1) & 3);
methbuf[3] = dtype[dnum];
} else if (methnum >= NUM_METHODS) { /* unknown */
- sprintf(&methbuf[1], "%03u", G.crec.compression_method);
+ /* 2016-12-05 SMS.
+ * https://launchpad.net/bugs/1643750
+ * Unexpectedly large compression methods overflow
+ * &methbuf[]. Use the old, three-digit decimal format
+ * for values which fit. Otherwise, sacrifice the "u",
+ * and use four-digit hexadecimal.
+ */
+ if (G.crec.compression_method <= 999) {
+ sprintf( &methbuf[ 1], "%03u", G.crec.compression_method);
+ } else {
+ sprintf( &methbuf[ 0], "%04X", G.crec.compression_method);
+ }
+
}
for (k = 0; k < 15; ++k)