From 5b3c74344e85875830c0e2a2fcdf3b256602f927 Mon Sep 17 00:00:00 2001 From: ngn Date: Fri, 23 Aug 2024 12:50:50 +0300 Subject: [PATCH] fix: move remote unzip patche to local directory --- src/unzip/pkg.sh | 33 +- .../unzip-6.0-consolidated_fixes-1.patch | 16713 ++++++++++++++++ 2 files changed, 16736 insertions(+), 10 deletions(-) create mode 100644 src/unzip/unzip-6.0-consolidated_fixes-1.patch diff --git a/src/unzip/pkg.sh b/src/unzip/pkg.sh index 6bacf3a..d55fe78 100644 --- a/src/unzip/pkg.sh +++ b/src/unzip/pkg.sh @@ -1,24 +1,37 @@ NAME="unzip" DESC="contains ZIP extraction utilities" VERSION="6.0" + FILES=( - "https://downloads.sourceforge.net/infozip/unzip60.tar.gz" - "https://www.linuxfromscratch.org/patches/blfs/12.0/unzip-$VERSION-consolidated_fixes-1.patch" + "https://downloads.sourceforge.net/infozip/unzip${VERSION/./}.tar.gz" + "unzip-${VERSION}-consolidated_fixes-1.patch" ) HASHES=( "62b490407489521db863b523a7f86375" "02cfd942875ca492c8fd27dff773e633a4f0b9bb47af2c3ad2697e8df8aa79f8" ) -DEPENDS=() + +DEPENDS=("bash" "bzip2") +BUILD=() PACKAGE() { - tar xf $NAME"60.tar.gz" - cd $NAME"60" + tar xf "${NAME}${VERSION/./}.tar.gz" + cd "${NAME}${VERSION/./}" - patch -Np1 -i ../unzip-$VERSION-consolidated_fixes-1.patch - make -f unix/Makefile generic - make prefix=$ROOTDIR/usr MANDIR=$ROOTDIR/usr/share/man/man1 \ - -f unix/Makefile install + patch -Np1 -i "../unzip-${VERSION}-consolidated_fixes-1.patch" - cd .. && rm -rf $NAME"60" + DEFINES='-DACORN_FTYPE_NFS -DWILD_STOP_AT_DIR -DLARGE_FILE_SUPPORT \ + -DUNICODE_SUPPORT -DUNICODE_WCHAR -DUTF8_MAYBE_NATIVE -DNO_LCHMOD \ + -DDATE_FORMAT=DF_YMD -DUSE_BZIP2 -DNOMEMCPY -DNO_WORKING_ISPRINT' + + make -f unix/Makefile prefix=/usr \ + D_USE_BZ2=-DUSE_BZIP2 L_BZ2=-lbz2 \ + LF2="${LDFLAGS}" CF="${CFLAGS} ${CPPFLAGS} -I. ${DEFINES}" \ + unzips + + make -f unix/Makefile prefix="${ROOTDIR}/usr" \ + MANDIR="${ROOTDIR}/usr/share/man/man1" \ + install + + cd .. && rm -rf "${NAME}${VERSIO/./}" } diff --git a/src/unzip/unzip-6.0-consolidated_fixes-1.patch b/src/unzip/unzip-6.0-consolidated_fixes-1.patch new file mode 100644 index 0000000..35fecc0 --- /dev/null +++ b/src/unzip/unzip-6.0-consolidated_fixes-1.patch @@ -0,0 +1,16713 @@ +Submitted By: Ken Moffat +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_methodENHDEFLATED \ ++ && 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]; /* %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 ++#include ++ + #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 ++#else ++# ifdef SYSV ++# ifdef SYSNDIR ++# include ++# else ++# include ++# endif ++# else /* !SYSV */ ++# ifndef NO_SYSDIR ++# include ++# 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 ++ ++#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 /* off_t, time_t, dev_t, ... */ ++#include ++ ++#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 /* O_BINARY for open() w/o CR/LF translation */ ++#else /* COHERENT */ ++# ifdef _I386 ++# include /* Coherent 4.0.x, Mark Williams C */ ++# else ++# include /* 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 */ ++# endif ++# ifdef BSD ++# define TEMP_BSD /* may be defined again in */ ++# undef BSD ++# endif ++# include /* conflict with , 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 ++# define DIRENT ++# define HAVE_TERMIOS_H ++# ifndef timezone ++# define timezone _timezone ++# endif ++#endif ++ ++#ifdef BSD ++# include ++# include ++# if (defined(_AIX) || defined(__GLIBC__) || defined(__GNU__)) ++# include ++# endif ++#else ++# include ++ struct tm *gmtime(), *localtime(); ++#endif ++ ++#if (defined(BSD4_4) || (defined(SYSV) && defined(MODERN))) ++# include /* this includes utime.h on SGIs */ ++# if (defined(BSD4_4) || defined(linux) || defined(__GLIBC__)) ++# include ++# define GOT_UTIMBUF ++# endif ++# if (!defined(GOT_UTIMBUF) && (defined(__hpux) || defined(__SUNPRO_C))) ++# include ++# define GOT_UTIMBUF ++# endif ++# if (!defined(GOT_UTIMBUF) && defined(__GNU__)) ++# include ++# define GOT_UTIMBUF ++# endif ++#endif ++#if (defined(__DGUX__) && !defined(GOT_UTIMBUF)) ++ /* DG/UX requires this because of a non-standard struct utimebuf */ ++# include ++# 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 ++# 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 ++#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 ; 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 ++ ++ 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:", ++ " [-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 ++# include + # endif + # endif + # ifndef _MBCS /* no need to include 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 ++# include ++# include ++# include ++# 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 ++# include ++# include ++# include ++# include ++# ifdef HAVE_MBSTRING_H ++# include ++# endif ++# ifdef HAVE_MBCTYPE_H ++# include ++# 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 /* off_t, time_t, dev_t, ... */ ++# include ++# include /* lseek(), open(), setftime(), dup(), creat() */ ++# include /* localtime() */ ++# include /* 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 /* off_t, time_t, dev_t, ... */ ++# include ++# include /* MTS uses this instead of fcntl.h */ ++# include ++# include ++# include /* 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 ++# include ++# include ++# include ++# 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 ++# 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 /* off_t, time_t, dev_t, ... */ ++# include ++# include ++# include ++# include ++# include ++# include ++# include /* 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 ++#endif ++ ++#include /* skip for VMS, to use tolower() function? */ ++#include /* used in mapname() */ ++#ifdef USE_STRINGS_H ++# include /* strcpy, strcmp, memcpy, index/rindex, etc. */ ++#else ++# include /* strcpy, strcmp, memcpy, strchr/strrchr, etc. */ ++#endif ++#if (defined(MODERN) && !defined(NO_LIMITS_H)) ++# include /* MAX/MIN constant symbols for system types... */ ++#endif ++ ++/* this include must be down here for SysV.4, for some reason... */ ++#include /* used in unzip.c, fileio.c */ ++ ++ ++#ifdef MODERN ++# ifndef NO_STDDEF_H ++# include ++# endif ++# ifndef NO_STDLIB_H ++# include /* 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 ++# 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 ++# 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 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 ++#endif ++ ++/* 2008-07-22 SMS. ++ * Unfortunately, on VMS, exists, and is included by ++ * (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 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 here if it will be needed later for Unicode. ++ * Otherwise, SETLOCALE may be defined here, and then defined again ++ * (differently) when is read later. ++ */ ++#ifdef UNICODE_SUPPORT ++# ifdef UNICODE_WCHAR ++# if !(defined(_WIN32_WCE) || defined(POCKET_UNZIP)) ++# include ++# endif ++# endif ++# ifndef _MBCS /* no need to include twice, see below */ ++# include ++# 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 ++ /* 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 . ++ */ ++# 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<>=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)