From af4687cc3f2331a23dc336183ab58fe001cda082 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 10 Jun 2022 04:54:37 -0700 Subject: [PATCH] Add Info-ZIP unzip.com --- Makefile | 1 + libc/calls/ioctl.h | 1 - libc/calls/ioctl_siocgifconf.c | 1 + third_party/third_party.mk | 1 + third_party/unzip/LICENSE | 62 + third_party/unzip/README.cosmo | 27 + third_party/unzip/api.c | 706 +++ third_party/unzip/apihelp.c | 156 + third_party/unzip/consts.h | 56 + third_party/unzip/crc32.c | 733 +++ third_party/unzip/crc32.h | 65 + third_party/unzip/crypt.c | 653 +++ third_party/unzip/crypt.h | 171 + third_party/unzip/ebcdic.h | 298 + third_party/unzip/envargs.c | 318 ++ third_party/unzip/explode.c | 618 +++ third_party/unzip/extract.c | 3615 ++++++++++++ third_party/unzip/fileio.c | 3123 +++++++++++ third_party/unzip/globals.c | 223 + third_party/unzip/globals.h | 468 ++ third_party/unzip/inflate.c | 1785 ++++++ third_party/unzip/inflate.h | 40 + third_party/unzip/list.c | 728 +++ third_party/unzip/match.c | 456 ++ third_party/unzip/process.c | 3178 +++++++++++ third_party/unzip/timezone.c | 813 +++ third_party/unzip/timezone.h | 84 + third_party/unzip/ttyio.c | 694 +++ third_party/unzip/ttyio.h | 225 + third_party/unzip/ubz2err.c | 57 + third_party/unzip/unix.c | 2125 +++++++ third_party/unzip/unix/Contents | 14 + third_party/unzip/unix/Makefile | 1038 ++++ third_party/unzip/unix/Packaging/README | 44 + third_party/unzip/unix/Packaging/pkginfo.in | 13 + third_party/unzip/unix/Packaging/postinstall | 22 + .../unzip/unix/Packaging/preinstall.in | 26 + third_party/unzip/unix/Packaging/prototype | 33 + third_party/unzip/unix/configure | 725 +++ third_party/unzip/unix/macosx.h | 49 + third_party/unzip/unix/zipgrep | 123 + third_party/unzip/unreduce.c | 36 + third_party/unzip/unshrink.c | 337 ++ third_party/unzip/unxcfg.h | 238 + third_party/unzip/unzip.c | 4869 +++++++++++++++++ third_party/unzip/unzip.h | 715 +++ third_party/unzip/unzip.mk | 76 + third_party/unzip/unzip.txt | 955 ++++ third_party/unzip/unzpriv.h | 2869 ++++++++++ third_party/unzip/unzvers.h | 96 + third_party/unzip/zip.h | 26 + third_party/unzip/zipinfo.c | 2522 +++++++++ third_party/unzip/zipinfo.txt | 436 ++ third_party/zip/zip.mk | 2 +- tool/viz/basicidea.c | 1 + 55 files changed, 36744 insertions(+), 2 deletions(-) create mode 100644 third_party/unzip/LICENSE create mode 100644 third_party/unzip/README.cosmo create mode 100644 third_party/unzip/api.c create mode 100644 third_party/unzip/apihelp.c create mode 100644 third_party/unzip/consts.h create mode 100644 third_party/unzip/crc32.c create mode 100644 third_party/unzip/crc32.h create mode 100644 third_party/unzip/crypt.c create mode 100644 third_party/unzip/crypt.h create mode 100644 third_party/unzip/ebcdic.h create mode 100644 third_party/unzip/envargs.c create mode 100644 third_party/unzip/explode.c create mode 100644 third_party/unzip/extract.c create mode 100644 third_party/unzip/fileio.c create mode 100644 third_party/unzip/globals.c create mode 100644 third_party/unzip/globals.h create mode 100644 third_party/unzip/inflate.c create mode 100644 third_party/unzip/inflate.h create mode 100644 third_party/unzip/list.c create mode 100644 third_party/unzip/match.c create mode 100644 third_party/unzip/process.c create mode 100644 third_party/unzip/timezone.c create mode 100644 third_party/unzip/timezone.h create mode 100644 third_party/unzip/ttyio.c create mode 100644 third_party/unzip/ttyio.h create mode 100644 third_party/unzip/ubz2err.c create mode 100644 third_party/unzip/unix.c create mode 100644 third_party/unzip/unix/Contents create mode 100644 third_party/unzip/unix/Makefile create mode 100644 third_party/unzip/unix/Packaging/README create mode 100644 third_party/unzip/unix/Packaging/pkginfo.in create mode 100644 third_party/unzip/unix/Packaging/postinstall create mode 100644 third_party/unzip/unix/Packaging/preinstall.in create mode 100644 third_party/unzip/unix/Packaging/prototype create mode 100644 third_party/unzip/unix/configure create mode 100644 third_party/unzip/unix/macosx.h create mode 100644 third_party/unzip/unix/zipgrep create mode 100644 third_party/unzip/unreduce.c create mode 100644 third_party/unzip/unshrink.c create mode 100644 third_party/unzip/unxcfg.h create mode 100644 third_party/unzip/unzip.c create mode 100644 third_party/unzip/unzip.h create mode 100644 third_party/unzip/unzip.mk create mode 100644 third_party/unzip/unzip.txt create mode 100644 third_party/unzip/unzpriv.h create mode 100644 third_party/unzip/unzvers.h create mode 100644 third_party/unzip/zip.h create mode 100644 third_party/unzip/zipinfo.c create mode 100644 third_party/unzip/zipinfo.txt diff --git a/Makefile b/Makefile index 9e12e9e35..7776bbf39 100644 --- a/Makefile +++ b/Makefile @@ -155,6 +155,7 @@ include third_party/mbedtls/test/test.mk include third_party/quickjs/quickjs.mk include third_party/lz4cli/lz4cli.mk include third_party/zip/zip.mk +include third_party/unzip/unzip.mk include tool/build/lib/buildlib.mk include third_party/chibicc/chibicc.mk include third_party/chibicc/test/test.mk diff --git a/libc/calls/ioctl.h b/libc/calls/ioctl.h index 766ce38bf..525581077 100644 --- a/libc/calls/ioctl.h +++ b/libc/calls/ioctl.h @@ -1,6 +1,5 @@ #ifndef COSMOPOLITAN_LIBC_CALLS_IOCTL_H_ #define COSMOPOLITAN_LIBC_CALLS_IOCTL_H_ -#include "libc/macros.internal.h" #include "libc/sysv/consts/fio.h" #include "libc/sysv/consts/sio.h" #include "libc/sysv/consts/termios.h" diff --git a/libc/calls/ioctl_siocgifconf.c b/libc/calls/ioctl_siocgifconf.c index d9752d391..4d4c178b1 100644 --- a/libc/calls/ioctl_siocgifconf.c +++ b/libc/calls/ioctl_siocgifconf.c @@ -22,6 +22,7 @@ #include "libc/calls/ioctl.h" #include "libc/calls/strace.internal.h" #include "libc/calls/syscall-sysv.internal.h" +#include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" diff --git a/third_party/third_party.mk b/third_party/third_party.mk index a8ed97d61..71579b3ed 100644 --- a/third_party/third_party.mk +++ b/third_party/third_party.mk @@ -25,6 +25,7 @@ o/$(MODE)/third_party: \ o/$(MODE)/third_party/sqlite3 \ o/$(MODE)/third_party/stb \ o/$(MODE)/third_party/tidy \ + o/$(MODE)/third_party/unzip \ o/$(MODE)/third_party/xed \ o/$(MODE)/third_party/zip \ o/$(MODE)/third_party/zlib diff --git a/third_party/unzip/LICENSE b/third_party/unzip/LICENSE new file mode 100644 index 000000000..81411a1f3 --- /dev/null +++ b/third_party/unzip/LICENSE @@ -0,0 +1,62 @@ +This is version 2009-Jan-02 of the Info-ZIP license. +The definitive version of this document should be available at +ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and +a copy at http://www.info-zip.org/pub/infozip/license.html. + + +Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + +For the purposes of this copyright and license, "Info-ZIP" is defined as +the following set of individuals: + + Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, + Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth, + Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, + David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, + Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, + Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda, + Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren, + Rich Wales, Mike White. + +This software is provided "as is," without warranty of any kind, express +or implied. In no event shall Info-ZIP or its contributors be held liable +for any direct, indirect, incidental, special or consequential damages +arising out of the use of or inability to use this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the above disclaimer and the following restrictions: + + 1. Redistributions of source code (in whole or in part) must retain + the above copyright notice, definition, disclaimer, and this list + of conditions. + + 2. Redistributions in binary form (compiled executables and libraries) + must reproduce the above copyright notice, definition, disclaimer, + and this list of conditions in documentation and/or other materials + provided with the distribution. Additional documentation is not needed + for executables where a command line license option provides these and + a note regarding this option is in the executable's startup banner. The + sole exception to this condition is redistribution of a standard + UnZipSFX binary (including SFXWiz) as part of a self-extracting archive; + that is permitted without inclusion of this license, as long as the + normal SFX banner has not been removed from the binary or disabled. + + 3. Altered versions--including, but not limited to, ports to new operating + systems, existing ports with new graphical interfaces, versions with + modified or added functionality, and dynamic, shared, or static library + versions not from Info-ZIP--must be plainly marked as such and must not + be misrepresented as being the original source or, if binaries, + compiled from the original source. Such altered versions also must not + be misrepresented as being Info-ZIP releases--including, but not + limited to, labeling of the altered versions with the names "Info-ZIP" + (or any variation thereof, including, but not limited to, different + capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the + explicit permission of Info-ZIP. Such altered versions are further + prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP + e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP + will provide support for the altered versions. + + 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," + "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its + own source and binary releases. diff --git a/third_party/unzip/README.cosmo b/third_party/unzip/README.cosmo new file mode 100644 index 000000000..85432be94 --- /dev/null +++ b/third_party/unzip/README.cosmo @@ -0,0 +1,27 @@ +DESCRIPTION + + The UNIX unzip command, courtesy of the Info-ZIP project. + +PROVENANCE + + unzip610b.zip (circa 2010) + https://sourceforge.net/projects/infozip/files/unreleased%20Betas/UnZip%20betas/ + +LICENSE + + BSD-like with Apache-like requirement that changes be documented. + +LOCAL CHANGES + + The only way this software differs from the normal InfoZIP sources is + that we're linking the Cosmopolitan C Library, which enables it to be + built as an Actually Portable Executable. + + Minor changes include: + + - Normalization of header / build config for platform / repository + sed -i -e '/# *include *<.*/d' *.* + sed -i -e 's!# *include *"!#include "third_party/unzip/!' *.* + sed -i -e '1 i\// clang-format off' *.c *.h + + - Fixed a lot of static analysis buffer overflow warnings. diff --git a/third_party/unzip/api.c b/third_party/unzip/api.c new file mode 100644 index 000000000..4c03677ee --- /dev/null +++ b/third_party/unzip/api.c @@ -0,0 +1,706 @@ +// clang-format off +/* + 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 +*/ +/*--------------------------------------------------------------------------- + + api.c + + This module supplies an UnZip engine for use directly from C/C++ + programs. The functions are: + + ZCONST UzpVer *UzpVersion(void); + unsigned UzpVersion2(UzpVer2 *version) + int UzpMain(int argc, char *argv[]); + int UzpAltMain(int argc, char *argv[], UzpInit *init); + int UzpValidate(char *archive, int AllCodes); + void UzpFreeMemBuffer(UzpBuffer *retstr); + int UzpUnzipToMemory(char *zip, char *file, UzpOpts *optflgs, + UzpCB *UsrFuncts, UzpBuffer *retstr); + + non-WINDLL only (a special WINDLL variant is defined in windll/windll.c): + int UzpGrep(char *archive, char *file, char *pattern, int cmd, int SkipBin, + UzpCB *UsrFuncts); + + OS/2 only (for now): + int UzpFileTree(char *name, cbList(callBack), char *cpInclude[], + char *cpExclude[]); + + You must define `DLL' in order to include the API extensions. + + ---------------------------------------------------------------------------*/ + + +#ifdef OS2 +# define INCL_DOSMEMMGR +#endif + +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" +#include "third_party/unzip/unzvers.h" + +#ifdef DLL /* This source file supplies DLL-only interface code. */ + +#ifndef POCKET_UNZIP /* WinCE pUnZip defines this elsewhere. */ +jmp_buf dll_error_return; +#endif + +/*--------------------------------------------------------------------------- + Documented API entry points + ---------------------------------------------------------------------------*/ + + +ZCONST UzpVer * UZ_EXP UzpVersion() /* returns pointer to const struct */ +{ + static ZCONST UzpVer version = { /* doesn't change between calls */ + /* structure size */ + UZPVER_LEN, + /* version flags */ +#ifdef BETA +# ifdef ZLIB_VERSION + 3, +# else + 1, +# endif +#else +# ifdef ZLIB_VERSION + 2, +# else + 0, +# endif +#endif + /* betalevel and date strings */ + UZ_BETALEVEL, UZ_VERSION_DATE, + /* zlib_version string */ +#ifdef ZLIB_VERSION + ZLIB_VERSION, +#else + NULL, +#endif + /*== someday each of these may have a separate patchlevel: ==*/ + /* unzip version */ + {UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, 0}, + /* zipinfo version */ + {ZI_MAJORVER, ZI_MINORVER, UZ_PATCHLEVEL, 0}, + /* os2dll version (retained for backward compatibility) */ + {UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, 0}, + /* windll version (retained for backward compatibility)*/ + {UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, 0}, +#ifdef OS2DLL + /* os2dll API minimum compatible version*/ + {UZ_OS2API_COMP_MAJOR, UZ_OS2API_COMP_MINOR, UZ_OS2API_COMP_REVIS, 0} +#else /* !OS2DLL */ +#ifdef WINDLL + /* windll API minimum compatible version*/ + {UZ_WINAPI_COMP_MAJOR, UZ_WINAPI_COMP_MINOR, UZ_WINAPI_COMP_REVIS, 0} +#else /* !WINDLL */ + /* generic DLL API minimum compatible version*/ + {UZ_GENAPI_COMP_MAJOR, UZ_GENAPI_COMP_MINOR, UZ_GENAPI_COMP_REVIS, 0} +#endif /* ?WINDLL */ +#endif /* ?OS2DLL */ + }; + + return &version; +} + +unsigned UZ_EXP UzpVersion2(UzpVer2 *version) +{ + + if (version->structlen != sizeof(UzpVer2)) + return sizeof(UzpVer2); + +#ifdef BETA + version->flag = 1; +#else + version->flag = 0; +#endif + strcpy(version->betalevel, UZ_BETALEVEL); + strcpy(version->date, UZ_VERSION_DATE); + +#ifdef ZLIB_VERSION + /* Although ZLIB_VERSION is a compile-time constant, we implement an + "overrun-safe" copy because its actual value is not under our control. + */ + strncpy(version->zlib_version, ZLIB_VERSION, + sizeof(version->zlib_version) - 1); + version->zlib_version[sizeof(version->zlib_version) - 1] = '\0'; + version->flag |= 2; +#else + version->zlib_version[0] = '\0'; +#endif + + /* someday each of these may have a separate patchlevel: */ + version->unzip.major = UZ_MAJORVER; + version->unzip.minor = UZ_MINORVER; + version->unzip.patchlevel = UZ_PATCHLEVEL; + + version->zipinfo.major = ZI_MAJORVER; + version->zipinfo.minor = ZI_MINORVER; + version->zipinfo.patchlevel = UZ_PATCHLEVEL; + + /* these are retained for backward compatibility only: */ + version->os2dll.major = UZ_MAJORVER; + version->os2dll.minor = UZ_MINORVER; + version->os2dll.patchlevel = UZ_PATCHLEVEL; + + version->windll.major = UZ_MAJORVER; + version->windll.minor = UZ_MINORVER; + version->windll.patchlevel = UZ_PATCHLEVEL; + +#ifdef OS2DLL + /* os2dll API minimum compatible version*/ + version->dllapimin.major = UZ_OS2API_COMP_MAJOR; + version->dllapimin.minor = UZ_OS2API_COMP_MINOR; + version->dllapimin.patchlevel = UZ_OS2API_COMP_REVIS; +#else /* !OS2DLL */ +#ifdef WINDLL + /* windll API minimum compatible version*/ + version->dllapimin.major = UZ_WINAPI_COMP_MAJOR; + version->dllapimin.minor = UZ_WINAPI_COMP_MINOR; + version->dllapimin.patchlevel = UZ_WINAPI_COMP_REVIS; +#else /* !WINDLL */ + /* generic DLL API minimum compatible version*/ + version->dllapimin.major = UZ_GENAPI_COMP_MAJOR; + version->dllapimin.minor = UZ_GENAPI_COMP_MINOR; + version->dllapimin.patchlevel = UZ_GENAPI_COMP_REVIS; +#endif /* ?WINDLL */ +#endif /* ?OS2DLL */ + return 0; +} + + + + + +#ifndef SFX +#ifndef WINDLL + +int UZ_EXP UzpAltMain(int argc, char *argv[], UzpInit *init) +{ + int r, (*dummyfn)(); + + + CONSTRUCTGLOBALS(); + + if (init->structlen >= (sizeof(ulg) + sizeof(dummyfn)) && init->msgfn) + G.message = init->msgfn; + + if (init->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) && init->inputfn) + G.input = init->inputfn; + + if (init->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) && init->pausefn) + G.mpause = init->pausefn; + + if (init->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) && init->userfn) + (*init->userfn)(); /* allow void* arg? */ + + r = unzip(__G__ argc, argv); + DESTROYGLOBALS(); + RETURN(r); +} + +#endif /* !WINDLL */ + + + + +#ifndef __16BIT__ + +void UZ_EXP UzpFreeMemBuffer(UzpBuffer *retstr) +{ + if (retstr != NULL && retstr->strptr != NULL) { + free(retstr->strptr); + retstr->strptr = NULL; + retstr->strlength = 0; + } +} + + + + +#ifndef WINDLL + +static int UzpDLL_Init OF((zvoid *pG, UzpCB *UsrFuncts)); + +static int UzpDLL_Init(pG, UsrFuncts) +zvoid *pG; +UzpCB *UsrFuncts; +{ + int (*dummyfn)(); + + if (UsrFuncts->structlen >= (sizeof(ulg) + sizeof(dummyfn)) && + UsrFuncts->msgfn) + ((Uz_Globs *)pG)->message = UsrFuncts->msgfn; + else + return FALSE; + + if (UsrFuncts->structlen >= (sizeof(ulg) + 2*sizeof(dummyfn)) && + UsrFuncts->inputfn) + ((Uz_Globs *)pG)->input = UsrFuncts->inputfn; + + if (UsrFuncts->structlen >= (sizeof(ulg) + 3*sizeof(dummyfn)) && + UsrFuncts->pausefn) + ((Uz_Globs *)pG)->mpause = UsrFuncts->pausefn; + + if (UsrFuncts->structlen >= (sizeof(ulg) + 4*sizeof(dummyfn)) && + UsrFuncts->passwdfn) + ((Uz_Globs *)pG)->decr_passwd = UsrFuncts->passwdfn; + + if (UsrFuncts->structlen >= (sizeof(ulg) + 5*sizeof(dummyfn)) && + UsrFuncts->statrepfn) + ((Uz_Globs *)pG)->statreportcb = UsrFuncts->statrepfn; + + return TRUE; +} + + +int UZ_EXP UzpUnzipToMemory(char *zip, char *file, UzpOpts *optflgs, + UzpCB *UsrFuncts, UzpBuffer *retstr) +{ + int r; +#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) + char *intern_zip, *intern_file; +#endif + + CONSTRUCTGLOBALS(); +#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) + intern_zip = (char *)malloc(strlen(zip)+1); + if (intern_zip == NULL) { + DESTROYGLOBALS(); + return PK_MEM; + } + intern_file = (char *)malloc(strlen(file)+1); + if (intern_file == NULL) { + DESTROYGLOBALS(); + free(intern_zip); + return PK_MEM; + } + ISO_TO_INTERN(zip, intern_zip); + ISO_TO_INTERN(file, intern_file); +# define zip intern_zip +# define file intern_file +#endif + /* Copy those options that are meaningful for UzpUnzipToMemory, instead of + * a simple "memcpy(G.UzO, optflgs, sizeof(UzpOpts));" + */ + uO.pwdarg = optflgs->pwdarg; + uO.aflag = optflgs->aflag; + uO.C_flag = optflgs->C_flag; + uO.qflag = optflgs->qflag; /* currently, overridden in unzipToMemory */ + + if (!UzpDLL_Init((zvoid *)&G, UsrFuncts)) { + DESTROYGLOBALS(); + return PK_BADERR; + } + G.redirect_data = 1; + + r = (unzipToMemory(__G__ zip, file, retstr) <= PK_WARN); + + DESTROYGLOBALS(); +#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) +# undef file +# undef zip + free(intern_file); + free(intern_zip); +#endif + if (!r && retstr->strlength) { + free(retstr->strptr); + retstr->strptr = NULL; + } + return r; +} +#endif /* !WINDLL */ +#endif /* !__16BIT__ */ + + + + + +#ifdef OS2DLL + +int UZ_EXP UzpFileTree(char *name, cbList(callBack), char *cpInclude[], + char *cpExclude[]) +{ + int r; + + CONSTRUCTGLOBALS(); + uO.qflag = 2; + uO.vflag = 1; + uO.C_flag = 1; + G.wildzipfn = name; + G.process_all_files = TRUE; + if (cpInclude) { + char **ptr = cpInclude; + + while (*ptr != NULL) ptr++; + G.filespecs = ptr - cpInclude; + G.pfnames = cpInclude, G.process_all_files = FALSE; + } + if (cpExclude) { + char **ptr = cpExclude; + + while (*ptr != NULL) ptr++; + G.xfilespecs = ptr - cpExclude; + G.pxnames = cpExclude, G.process_all_files = FALSE; + } + + G.processExternally = callBack; + r = process_zipfiles(__G)==0; + DESTROYGLOBALS(); + return r; +} + +#endif /* OS2DLL */ +#endif /* !SFX */ + + + + +/*--------------------------------------------------------------------------- + Helper functions + ---------------------------------------------------------------------------*/ + + +void setFileNotFound(__G) + __GDEF +{ + G.filenotfound++; +} + + +#ifndef SFX + +int unzipToMemory(__GPRO__ char *zip, char *file, UzpBuffer *retstr) +{ + int r; + char *incname[2]; + + if ((zip == NULL) || (strlen(zip) > ((WSIZE>>2) - 160))) + return PK_PARAM; + if ((file == NULL) || (strlen(file) > ((WSIZE>>2) - 160))) + return PK_PARAM; + + G.process_all_files = FALSE; + G.extract_flag = TRUE; + uO.qflag = 2; + G.wildzipfn = zip; + + G.pfnames = incname; + incname[0] = file; + incname[1] = NULL; + G.filespecs = 1; + + r = process_zipfiles(__G); + if (retstr) { + retstr->strptr = (char *)G.redirect_buffer; + retstr->strlength = G.redirect_size; + } + return r; /* returns `PK_???' error values */ +} + +#endif /* !SFX */ + +/* + With the advent of 64 bit support, for now I am assuming that + if the size of the file is greater than an unsigned long, there + will simply not be enough memory to handle it, and am returning + FALSE. +*/ +int redirect_outfile(__G) + __GDEF +{ +#ifdef ZIP64_SUPPORT + __int64 check_conversion; +#endif + + if (G.redirect_size != 0 || G.redirect_buffer != NULL) + return FALSE; + +#ifndef NO_SLIDE_REDIR + G.redirect_slide = !G.pInfo->textmode; +#endif +#if (lenEOL != 1) + if (G.pInfo->textmode) { + G.redirect_size = (ulg)(G.lrec.ucsize * lenEOL); + if (G.redirect_size < G.lrec.ucsize) + G.redirect_size = (ulg)((G.lrec.ucsize > (ulg)-2L) ? + G.lrec.ucsize : -2L); +#ifdef ZIP64_SUPPORT + check_conversion = G.lrec.ucsize * lenEOL; +#endif + } else +#endif + { + G.redirect_size = (ulg)G.lrec.ucsize; +#ifdef ZIP64_SUPPORT + check_conversion = (__int64)G.lrec.ucsize; +#endif + } + +#ifdef ZIP64_SUPPORT + if ((__int64)G.redirect_size != check_conversion) + return FALSE; +#endif + +#ifdef __16BIT__ + if ((ulg)((extent)G.redirect_size) != G.redirect_size) + return FALSE; +#endif +#ifdef OS2 + DosAllocMem((void **)&G.redirect_buffer, G.redirect_size+1, + PAG_READ|PAG_WRITE|PAG_COMMIT); + G.redirect_pointer = G.redirect_buffer; +#else + G.redirect_pointer = + G.redirect_buffer = malloc((extent)(G.redirect_size+1)); +#endif + if (!G.redirect_buffer) + return FALSE; + G.redirect_pointer[G.redirect_size] = '\0'; + return TRUE; +} + + + +int writeToMemory(__GPRO__ ZCONST uch *rawbuf, extent size) +{ + int errflg = FALSE; + + if ((uch *)rawbuf != G.redirect_pointer) { + extent redir_avail = (G.redirect_buffer + G.redirect_size) - + G.redirect_pointer; + + /* Check for output buffer overflow */ + if (size > redir_avail) { + /* limit transfer data to available space, set error return flag */ + size = redir_avail; + errflg = TRUE; + } + memcpy(G.redirect_pointer, rawbuf, size); + } + G.redirect_pointer += size; + return errflg; +} + + + + +int close_redirect(__G) + __GDEF +{ + if (G.pInfo->textmode) { + *G.redirect_pointer = '\0'; + G.redirect_size = (ulg)(G.redirect_pointer - G.redirect_buffer); + if ((G.redirect_buffer = + realloc(G.redirect_buffer, G.redirect_size + 1)) == NULL) { + G.redirect_size = 0; + return EOF; + } + } + return 0; +} + + + + +#ifndef SFX +#ifndef __16BIT__ +#ifndef WINDLL + +/* Purpose: Determine if file in archive contains the string szSearch + + Parameters: archive = archive name + file = file contained in the archive. This cannot be + a wildcard to be meaningful + pattern = string to search for + cmd = 0 - case-insensitive search + 1 - case-sensitve search + 2 - case-insensitive, whole words only + 3 - case-sensitive, whole words only + SkipBin = if true, skip any files that have control + characters other than CR, LF, or tab in the first + 100 characters. + + Returns: TRUE if a match is found + FALSE if no match is found + -1 on error + + Comments: This does not pretend to be as useful as the standard + Unix grep, which returns the strings associated with a + particular pattern, nor does it search past the first + matching occurrence of the pattern. + */ + +int UZ_EXP UzpGrep(char *archive, char *file, char *pattern, int cmd, + int SkipBin, UzpCB *UsrFuncts) +{ + int retcode = FALSE, compare; + ulg i, j, patternLen, buflen; + char * sz, *p; + UzpOpts flgopts; + UzpBuffer retstr; + + memzero(&flgopts, sizeof(UzpOpts)); /* no special options */ + + if (!UzpUnzipToMemory(archive, file, &flgopts, UsrFuncts, &retstr)) { + return -1; /* not enough memory, file not found, or other error */ + } + + if (SkipBin) { + if (retstr.strlength < 100) + buflen = retstr.strlength; + else + buflen = 100; + for (i = 0; i < buflen; i++) { + if (iscntrl(retstr.strptr[i])) { + if ((retstr.strptr[i] != 0x0A) && + (retstr.strptr[i] != 0x0D) && + (retstr.strptr[i] != 0x09)) + { + /* OK, we now think we have a binary file of some sort */ + free(retstr.strptr); + return FALSE; + } + } + } + } + + patternLen = strlen(pattern); + + if (retstr.strlength < patternLen) { + free(retstr.strptr); + return FALSE; + } + + sz = malloc(patternLen + 3); /* add two in case doing whole words only */ + if (cmd > 1) { + strcpy(sz, " "); + strcat(sz, pattern); + strcat(sz, " "); + } else + strcpy(sz, pattern); + + if ((cmd == 0) || (cmd == 2)) { + for (i = 0; i < strlen(sz); i++) + sz[i] = toupper(sz[i]); + for (i = 0; i < retstr.strlength; i++) + retstr.strptr[i] = toupper(retstr.strptr[i]); + } + + for (i = 0; i < (retstr.strlength - patternLen); i++) { + p = &retstr.strptr[i]; + compare = TRUE; + for (j = 0; j < patternLen; j++) { + /* We cannot do strncmp here, as we may be dealing with a + * "binary" file, such as a word processing file, or perhaps + * even a true executable of some sort. */ + if (p[j] != sz[j]) { + compare = FALSE; + break; + } + } + if (compare == TRUE) { + retcode = TRUE; + break; + } + } + + free(sz); + free(retstr.strptr); + + return retcode; +} +#endif /* !WINDLL */ +#endif /* !__16BIT__ */ + + + +int UZ_EXP UzpValidate(char *archive, int AllCodes) +{ + int retcode; + CONSTRUCTGLOBALS(); + + uO.jflag = 1; + uO.tflag = 1; + uO.overwrite_none = 0; + G.extract_flag = (!uO.zipinfo_mode && + !uO.cflag && !uO.tflag && !uO.vflag && !uO.zflag +#ifdef TIMESTAMP + && !uO.T_flag +#endif + ); + + uO.qflag = 2; /* turn off all messages */ + G.fValidate = TRUE; + G.pfnames = (char **)&fnames[0]; /* assign default filename vector */ + + if (archive == NULL) { /* something is screwed up: no filename */ + DESTROYGLOBALS(); + retcode = PK_NOZIP; + goto exit_retcode; + } + + if (strlen(archive) >= FILNAMSIZ) { + /* length of supplied archive name exceed the system's filename limit */ + DESTROYGLOBALS(); + retcode = PK_PARAM; + goto exit_retcode; + } + + G.wildzipfn = (char *)malloc(FILNAMSIZ); + strcpy(G.wildzipfn, archive); +#if (defined(WINDLL) && !defined(CRTL_CP_IS_ISO)) + _ISO_INTERN(G.wildzipfn); +#endif + +#ifdef WINDLL + Wiz_NoPrinting(TRUE); +#endif + + G.process_all_files = TRUE; /* for speed */ + + if (setjmp(dll_error_return) != 0) { +#ifdef WINDLL + Wiz_NoPrinting(FALSE); +#endif + free(G.wildzipfn); + DESTROYGLOBALS(); + retcode = PK_BADERR; + goto exit_retcode; + } + + retcode = process_zipfiles(__G); + + free(G.wildzipfn); +#ifdef WINDLL + Wiz_NoPrinting(FALSE); +#endif + DESTROYGLOBALS(); + + /* PK_WARN == 1 and PK_FIND == 11. When we are just looking at an + archive, we should still be able to see the files inside it, + even if we can't decode them for some reason. + + We also still want to be able to get at files even if there is + something odd about the zip archive, hence allow PK_WARN, + PK_FIND, IZ_UNSUP as well as PK_ERR + */ + +exit_retcode: + if (AllCodes) + return retcode; + + if ((retcode == PK_OK) || (retcode == PK_WARN) || (retcode == PK_ERR) || + (retcode == IZ_UNSUP) || (retcode == PK_FIND)) + return TRUE; + else + return FALSE; +} + +#endif /* !SFX */ +#endif /* DLL */ diff --git a/third_party/unzip/apihelp.c b/third_party/unzip/apihelp.c new file mode 100644 index 000000000..a555cedc3 --- /dev/null +++ b/third_party/unzip/apihelp.c @@ -0,0 +1,156 @@ +// clang-format off +/* + Copyright (c) 1990-2001 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 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 +*/ +/* apihelp.c */ + +#ifdef API_DOC + +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" +#include "third_party/unzip/unzvers.h" + + +APIDocStruct APIDoc[] = { + { + "UZPVERSION" , "UzpVersion" , + "UzpVer *UzpVersion(void);", + "Get version numbers of the API and the underlying UnZip code.\n\n" + "\t\tThis is used for comparing the version numbers of the run-time\n" + "\t\tDLL code with those expected from the unzip.h at compile time.\n" + "\t\tIf the version numbers do not match, there may be compatibility\n" + "\t\tproblems with further use of the DLL.\n\n" + " Example:\t/* Check the major version number of the DLL code. */\n" + "\t\tUzpVer *pVersion;\n" + "\t\tpVersion = UzpVersion();\n" + "\t\tif (pVersion->unzip.major != UZ_MAJORVER)\n" + "\t\t fprintf(stderr, \"error: using wrong version of DLL\\n\");\n\n" + "\t\tSee unzip.h for details and unzipstb.c for an example.\n" + }, + + { + "UZPMAIN" , "UzpMain" , + "int UzpMain(int argc, char *argv[]);", + "Provide a direct entry point to the command line interface.\n\n" + "\t\tThis is used by the UnZip stub but you can use it in your\n" + "\t\town program as well. Output is sent to stdout.\n" + "\t\t0 on return indicates success.\n\n" + " Example:\t/* Extract 'test.zip' silently, junking paths. */\n" + "\t\tchar *argv[] = { \"-q\", \"-j\", \"test.zip\" };\n" + "\t\tint argc = 3;\n" + "\t\tif (UzpMain(argc,argv))\n" + "\t\t printf(\"error: unzip failed\\n\");\n\n" + "\t\tSee unzip.h for details.\n" + }, + + { + "UZPALTMAIN" , "UzpAltMain" , + "int UzpAltMain(int argc, char *argv[], UzpInit *init);", + "Provide a direct entry point to the command line interface,\n" + "optionally installing replacement I/O handler functions.\n\n" + "\t\tAs with UzpMain(), output is sent to stdout by default.\n" + "\t\t`InputFn *inputfn' is not yet implemented. 0 on return\n" + "\t\tindicates success.\n\n" + " Example:\t/* Replace normal output and `more' functions. */\n" + "\t\tchar *argv[] = { \"-q\", \"-j\", \"test.zip\" };\n" + "\t\tint argc = 3;\n" + "\t\tUzpInit init = { 16, MyMessageFn, NULL, MyPauseFn };\n" + "\t\tif (UzpAltMain(argc,argv,&init))\n" + "\t\t printf(\"error: unzip failed\\n\");\n\n" + "\t\tSee unzip.h for details.\n" + }, + + { + "UZPUNZIPTOMEMORY", "UzpUnzipToMemory", + "int UzpUnzipToMemory(char *zip, char *file, UzpBuffer *retstr);", + "Pass the name of the zip file and the name of the file\n" + "\t\tyou wish to extract. UzpUnzipToMemory will create a\n" + "\t\tbuffer and return it in *retstr; 0 on return indicates\n" + "\t\tfailure.\n\n" + "\t\tSee unzip.h for details.\n" + }, + + { + "UZPFILETREE", "UzpFileTree", + "int UzpFileTree(char *name, cbList(callBack),\n" + "\t\t\tchar *cpInclude[], char *cpExclude[]);", + "Pass the name of the zip file, a callback function, an\n" + "\t\tinclude and exclude file list. UzpFileTree calls the\n" + "\t\tcallback for each valid file found in the zip file.\n" + "\t\t0 on return indicates failure.\n\n" + "\t\tSee unzip.h for details.\n" + }, + + { 0 } +}; + + +static int function_help OF((__GPRO__ APIDocStruct *doc, char *fname)); + + + +static int function_help(__G__ doc, fname) + __GDEF + APIDocStruct *doc; + char *fname; +{ + strcpy(slide, fname); + /* strupr(slide); non-standard */ + while (doc->compare && STRNICMP(doc->compare,slide,strlen(fname))) + doc++; + if (!doc->compare) + return 0; + else + Info(slide, 0, ((char *)slide, + " Function:\t%s\n\n Syntax:\t%s\n\n Purpose:\t%s", + doc->function, doc->syntax, doc->purpose)); + + return 1; +} + + + +void APIhelp(__G__ argc, argv) + __GDEF + int argc; + char **argv; +{ + if (argc > 1) { + struct APIDocStruct *doc; + + if (function_help(__G__ APIDoc, argv[1])) + return; +#ifdef SYSTEM_API_DETAILS + if (function_help(__G__ SYSTEM_API_DETAILS, argv[1])) + return; +#endif + Info(slide, 0, ((char *)slide, + "%s is not a documented command.\n\n", argv[1])); + } + + Info(slide, 0, ((char *)slide, "\ +This API provides a number of external C and REXX functions for handling\n\ +zipfiles in OS/2. Programmers are encouraged to expand this API.\n\ +\n\ +C functions: -- See unzip.h for details\n\ + UzpVer *UzpVersion(void);\n\ + int UzpMain(int argc, char *argv[]);\n\ + int UzpAltMain(int argc, char *argv[], UzpInit *init);\n\ + int UzpUnzipToMemory(char *zip, char *file, UzpBuffer *retstr);\n\ + int UzpFileTree(char *name, cbList(callBack),\n\ + char *cpInclude[], char *cpExclude[]);\n\n")); + +#ifdef SYSTEM_API_BRIEF + Info(slide, 0, ((char *)slide, SYSTEM_API_BRIEF)); +#endif + + Info(slide, 0, ((char *)slide, + "\nFor more information, type 'unzip -A '\n")); +} + +#endif /* API_DOC */ diff --git a/third_party/unzip/consts.h b/third_party/unzip/consts.h new file mode 100644 index 000000000..09eb9cdad --- /dev/null +++ b/third_party/unzip/consts.h @@ -0,0 +1,56 @@ +// clang-format off +/* + Copyright (c) 1990-2001 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 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 +*/ +/*--------------------------------------------------------------------------- + + consts.h + + This file contains global, initialized variables that never change. It is + included by unzip.c and windll/windll.c. + + ---------------------------------------------------------------------------*/ +#include "third_party/unzip/crc32.h" + + +/* And'ing with mask_bits[n] masks the lower n bits */ +ZCONST unsigned near mask_bits[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +ZCONST char Far VersionDate[] = UZ_VERSION_DATE; /* now defined in unzvers.h */ + +#ifndef SFX + ZCONST char Far EndSigMsg[] = + "\nnote: didn't find end-of-central-dir signature at end of central dir.\n"; +#endif + +ZCONST char Far CentSigMsg[] = + "error: expected central file header signature not found (file #%lu).\n"; +ZCONST char Far SeekMsg[] = + "error [%s]: attempt to seek before beginning of zipfile\n%s"; +ZCONST char Far FilenameNotMatched[] = "caution: filename not matched: %s\n"; +ZCONST char Far ExclFilenameNotMatched[] = + "caution: excluded filename not matched: %s\n"; + +#ifdef VMS + ZCONST char Far ReportMsg[] = "\ + (please check that you have transferred or created the zipfile in the\n\ + appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n"; +#else + ZCONST char Far ReportMsg[] = "\ + (please check that you have transferred or created the zipfile in the\n\ + appropriate BINARY mode and that you have compiled UnZip properly)\n"; +#endif + +#ifndef SFX + ZCONST char Far Zipnfo[] = "zipinfo"; + ZCONST char Far CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n"; +#endif diff --git a/third_party/unzip/crc32.c b/third_party/unzip/crc32.c new file mode 100644 index 000000000..e55fbe846 --- /dev/null +++ b/third_party/unzip/crc32.c @@ -0,0 +1,733 @@ +// clang-format off +/* + Copyright (c) 1990-2007 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2005-Feb-10 or later + (the contents of which are also included in zip.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 +*/ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results about a factor + * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* $Id: crc32.c,v 2.0 2007/01/07 05:20:36 spc Exp $ */ + +#define __CRC32_C /* identifies this source module */ + +#include "third_party/unzip/zip.h" + +#if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB)) + +#ifndef ZCONST +# define ZCONST const +#endif + +#include "third_party/unzip/crc32.h" + +/* When only the table of precomputed CRC values is needed, only the basic + system-independent table containing 256 entries is created; any support + for "unfolding" optimization is disabled. + */ +#if (defined(USE_ZLIB) || defined(CRC_TABLE_ONLY)) +# ifdef IZ_CRCOPTIM_UNFOLDTBL +# undef IZ_CRCOPTIM_UNFOLDTBL +# endif +#endif /* (USE_ZLIB || CRC_TABLE_ONLY) */ + +#if defined(IZ_CRCOPTIM_UNFOLDTBL) +# define CRC_TBLS 4 +#else +# define CRC_TBLS 1 +#endif + + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first (or only) table is simply the CRC of all possible eight bit values. + This is all the information needed to generate CRC's on data a byte-at-a-time + for all combinations of CRC register values and incoming bytes. + The remaining 3 tables (if IZ_CRCOPTIM_UNFOLDTBL is enabled) allow for + word-at-a-time CRC calculation, where a word is four bytes. +*/ + +#ifdef DYNAMIC_CRC_TABLE + +/* ========================================================================= + * Make the crc table. This function is needed only if you want to compute + * the table dynamically. + */ + +local void make_crc_table OF((void)); + +#if (defined(DYNALLOC_CRCTAB) && defined(REENTRANT)) + error: Dynamic allocation of CRC table not safe with reentrant code. +#endif /* DYNALLOC_CRCTAB && REENTRANT */ + +#ifdef DYNALLOC_CRCTAB + local ulg near *crc_table = NULL; +# if 0 /* not used, since sizeof("near *") <= sizeof(int) */ + /* Use this section when access to a "local int" is faster than access to + a "local pointer" (e.g.: i86 16bit code with far pointers). */ + local int crc_table_empty = 1; +# define CRC_TABLE_IS_EMPTY (crc_table_empty != 0) +# define MARK_CRCTAB_FILLED crc_table_empty = 0 +# define MARK_CRCTAB_EMPTY crc_table_empty = 1 +# else + /* Use this section on systems where the size of pointers and ints is + equal (e.g.: all 32bit systems). */ +# define CRC_TABLE_IS_EMPTY (crc_table == NULL) +# define MARK_CRCTAB_FILLED crc_table = crctab_p +# define MARK_CRCTAB_EMPTY crc_table = NULL +# endif +#else /* !DYNALLOC_CRCTAB */ + local ulg near crc_table[CRC_TBLS*256]; + local int crc_table_empty = 1; +# define CRC_TABLE_IS_EMPTY (crc_table_empty != 0) +# define MARK_CRCTAB_FILLED crc_table_empty = 0 +#endif /* ?DYNALLOC_CRCTAB */ + + +local void make_crc_table() +{ + ulg c; /* crc shift register */ + int n; /* counter for all possible eight bit values */ + int k; /* byte being shifted into crc apparatus */ +#ifdef DYNALLOC_CRCTAB + ulg near *crctab_p; /* temporary pointer to allocated crc_table area */ +#else /* !DYNALLOC_CRCTAB */ +# define crctab_p crc_table +#endif /* DYNALLOC_CRCTAB */ + +#ifdef COMPUTE_XOR_PATTERN + /* This piece of code has been left here to explain how the XOR pattern + * used in the creation of the crc_table values can be recomputed. + * For production versions of this function, it is more efficient to + * supply the resultant pattern at compile time. + */ + ulg xor; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static ZCONST uch p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + xor = 0L; + for (n = 0; n < sizeof(p)/sizeof(uch); n++) + xor |= 1L << (31 - p[n]); +#else +# define xor 0xedb88320L +#endif + +#ifdef DYNALLOC_CRCTAB + crctab_p = (ulg near *) nearmalloc (CRC_TBLS*256*sizeof(ulg)); + if (crctab_p == NULL) { + ziperr(ZE_MEM, "crc_table allocation"); + } +#endif /* DYNALLOC_CRCTAB */ + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (ulg)n; + for (k = 8; k; k--) + c = c & 1 ? xor ^ (c >> 1) : c >> 1; + crctab_p[n] = REV_BE(c); + } + +#ifdef IZ_CRCOPTIM_UNFOLDTBL + /* generate crc for each value followed by one, two, and three zeros */ + for (n = 0; n < 256; n++) { + c = crctab_p[n]; + for (k = 1; k < 4; k++) { + c = CRC32(c, 0, crctab_p); + crctab_p[k*256+n] = c; + } + } +#endif /* IZ_CRCOPTIM_UNFOLDTBL */ + + MARK_CRCTAB_FILLED; +} + +#else /* !DYNAMIC_CRC_TABLE */ + +#ifdef DYNALLOC_CRCTAB + error: Inconsistent flags, DYNALLOC_CRCTAB without DYNAMIC_CRC_TABLE. +#endif + +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +local ZCONST ulg near crc_table[CRC_TBLS*256] = { +# ifdef IZ_CRC_BE_OPTIMIZ + 0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L, + 0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L, + 0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L, + 0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L, + 0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L, + 0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L, + 0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L, + 0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L, + 0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L, + 0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L, + 0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL, + 0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L, + 0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L, + 0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L, + 0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L, + 0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L, + 0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL, + 0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L, + 0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL, + 0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L, + 0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L, + 0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L, + 0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL, + 0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL, + 0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L, + 0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL, + 0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L, + 0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL, + 0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L, + 0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L, + 0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L, + 0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L, + 0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L, + 0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL, + 0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L, + 0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L, + 0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L, + 0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L, + 0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L, + 0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L, + 0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L, + 0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L, + 0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL, + 0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L, + 0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L, + 0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L, + 0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L, + 0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L, + 0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL, + 0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L, + 0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL, + 0x8def022dL +# ifdef IZ_CRCOPTIM_UNFOLDTBL + , + 0x00000000L, 0x41311b19L, 0x82623632L, 0xc3532d2bL, 0x04c56c64L, + 0x45f4777dL, 0x86a75a56L, 0xc796414fL, 0x088ad9c8L, 0x49bbc2d1L, + 0x8ae8effaL, 0xcbd9f4e3L, 0x0c4fb5acL, 0x4d7eaeb5L, 0x8e2d839eL, + 0xcf1c9887L, 0x5112c24aL, 0x1023d953L, 0xd370f478L, 0x9241ef61L, + 0x55d7ae2eL, 0x14e6b537L, 0xd7b5981cL, 0x96848305L, 0x59981b82L, + 0x18a9009bL, 0xdbfa2db0L, 0x9acb36a9L, 0x5d5d77e6L, 0x1c6c6cffL, + 0xdf3f41d4L, 0x9e0e5acdL, 0xa2248495L, 0xe3159f8cL, 0x2046b2a7L, + 0x6177a9beL, 0xa6e1e8f1L, 0xe7d0f3e8L, 0x2483dec3L, 0x65b2c5daL, + 0xaaae5d5dL, 0xeb9f4644L, 0x28cc6b6fL, 0x69fd7076L, 0xae6b3139L, + 0xef5a2a20L, 0x2c09070bL, 0x6d381c12L, 0xf33646dfL, 0xb2075dc6L, + 0x715470edL, 0x30656bf4L, 0xf7f32abbL, 0xb6c231a2L, 0x75911c89L, + 0x34a00790L, 0xfbbc9f17L, 0xba8d840eL, 0x79dea925L, 0x38efb23cL, + 0xff79f373L, 0xbe48e86aL, 0x7d1bc541L, 0x3c2ade58L, 0x054f79f0L, + 0x447e62e9L, 0x872d4fc2L, 0xc61c54dbL, 0x018a1594L, 0x40bb0e8dL, + 0x83e823a6L, 0xc2d938bfL, 0x0dc5a038L, 0x4cf4bb21L, 0x8fa7960aL, + 0xce968d13L, 0x0900cc5cL, 0x4831d745L, 0x8b62fa6eL, 0xca53e177L, + 0x545dbbbaL, 0x156ca0a3L, 0xd63f8d88L, 0x970e9691L, 0x5098d7deL, + 0x11a9ccc7L, 0xd2fae1ecL, 0x93cbfaf5L, 0x5cd76272L, 0x1de6796bL, + 0xdeb55440L, 0x9f844f59L, 0x58120e16L, 0x1923150fL, 0xda703824L, + 0x9b41233dL, 0xa76bfd65L, 0xe65ae67cL, 0x2509cb57L, 0x6438d04eL, + 0xa3ae9101L, 0xe29f8a18L, 0x21cca733L, 0x60fdbc2aL, 0xafe124adL, + 0xeed03fb4L, 0x2d83129fL, 0x6cb20986L, 0xab2448c9L, 0xea1553d0L, + 0x29467efbL, 0x687765e2L, 0xf6793f2fL, 0xb7482436L, 0x741b091dL, + 0x352a1204L, 0xf2bc534bL, 0xb38d4852L, 0x70de6579L, 0x31ef7e60L, + 0xfef3e6e7L, 0xbfc2fdfeL, 0x7c91d0d5L, 0x3da0cbccL, 0xfa368a83L, + 0xbb07919aL, 0x7854bcb1L, 0x3965a7a8L, 0x4b98833bL, 0x0aa99822L, + 0xc9fab509L, 0x88cbae10L, 0x4f5def5fL, 0x0e6cf446L, 0xcd3fd96dL, + 0x8c0ec274L, 0x43125af3L, 0x022341eaL, 0xc1706cc1L, 0x804177d8L, + 0x47d73697L, 0x06e62d8eL, 0xc5b500a5L, 0x84841bbcL, 0x1a8a4171L, + 0x5bbb5a68L, 0x98e87743L, 0xd9d96c5aL, 0x1e4f2d15L, 0x5f7e360cL, + 0x9c2d1b27L, 0xdd1c003eL, 0x120098b9L, 0x533183a0L, 0x9062ae8bL, + 0xd153b592L, 0x16c5f4ddL, 0x57f4efc4L, 0x94a7c2efL, 0xd596d9f6L, + 0xe9bc07aeL, 0xa88d1cb7L, 0x6bde319cL, 0x2aef2a85L, 0xed796bcaL, + 0xac4870d3L, 0x6f1b5df8L, 0x2e2a46e1L, 0xe136de66L, 0xa007c57fL, + 0x6354e854L, 0x2265f34dL, 0xe5f3b202L, 0xa4c2a91bL, 0x67918430L, + 0x26a09f29L, 0xb8aec5e4L, 0xf99fdefdL, 0x3accf3d6L, 0x7bfde8cfL, + 0xbc6ba980L, 0xfd5ab299L, 0x3e099fb2L, 0x7f3884abL, 0xb0241c2cL, + 0xf1150735L, 0x32462a1eL, 0x73773107L, 0xb4e17048L, 0xf5d06b51L, + 0x3683467aL, 0x77b25d63L, 0x4ed7facbL, 0x0fe6e1d2L, 0xccb5ccf9L, + 0x8d84d7e0L, 0x4a1296afL, 0x0b238db6L, 0xc870a09dL, 0x8941bb84L, + 0x465d2303L, 0x076c381aL, 0xc43f1531L, 0x850e0e28L, 0x42984f67L, + 0x03a9547eL, 0xc0fa7955L, 0x81cb624cL, 0x1fc53881L, 0x5ef42398L, + 0x9da70eb3L, 0xdc9615aaL, 0x1b0054e5L, 0x5a314ffcL, 0x996262d7L, + 0xd85379ceL, 0x174fe149L, 0x567efa50L, 0x952dd77bL, 0xd41ccc62L, + 0x138a8d2dL, 0x52bb9634L, 0x91e8bb1fL, 0xd0d9a006L, 0xecf37e5eL, + 0xadc26547L, 0x6e91486cL, 0x2fa05375L, 0xe836123aL, 0xa9070923L, + 0x6a542408L, 0x2b653f11L, 0xe479a796L, 0xa548bc8fL, 0x661b91a4L, + 0x272a8abdL, 0xe0bccbf2L, 0xa18dd0ebL, 0x62defdc0L, 0x23efe6d9L, + 0xbde1bc14L, 0xfcd0a70dL, 0x3f838a26L, 0x7eb2913fL, 0xb924d070L, + 0xf815cb69L, 0x3b46e642L, 0x7a77fd5bL, 0xb56b65dcL, 0xf45a7ec5L, + 0x370953eeL, 0x763848f7L, 0xb1ae09b8L, 0xf09f12a1L, 0x33cc3f8aL, + 0x72fd2493L + , + 0x00000000L, 0x376ac201L, 0x6ed48403L, 0x59be4602L, 0xdca80907L, + 0xebc2cb06L, 0xb27c8d04L, 0x85164f05L, 0xb851130eL, 0x8f3bd10fL, + 0xd685970dL, 0xe1ef550cL, 0x64f91a09L, 0x5393d808L, 0x0a2d9e0aL, + 0x3d475c0bL, 0x70a3261cL, 0x47c9e41dL, 0x1e77a21fL, 0x291d601eL, + 0xac0b2f1bL, 0x9b61ed1aL, 0xc2dfab18L, 0xf5b56919L, 0xc8f23512L, + 0xff98f713L, 0xa626b111L, 0x914c7310L, 0x145a3c15L, 0x2330fe14L, + 0x7a8eb816L, 0x4de47a17L, 0xe0464d38L, 0xd72c8f39L, 0x8e92c93bL, + 0xb9f80b3aL, 0x3cee443fL, 0x0b84863eL, 0x523ac03cL, 0x6550023dL, + 0x58175e36L, 0x6f7d9c37L, 0x36c3da35L, 0x01a91834L, 0x84bf5731L, + 0xb3d59530L, 0xea6bd332L, 0xdd011133L, 0x90e56b24L, 0xa78fa925L, + 0xfe31ef27L, 0xc95b2d26L, 0x4c4d6223L, 0x7b27a022L, 0x2299e620L, + 0x15f32421L, 0x28b4782aL, 0x1fdeba2bL, 0x4660fc29L, 0x710a3e28L, + 0xf41c712dL, 0xc376b32cL, 0x9ac8f52eL, 0xada2372fL, 0xc08d9a70L, + 0xf7e75871L, 0xae591e73L, 0x9933dc72L, 0x1c259377L, 0x2b4f5176L, + 0x72f11774L, 0x459bd575L, 0x78dc897eL, 0x4fb64b7fL, 0x16080d7dL, + 0x2162cf7cL, 0xa4748079L, 0x931e4278L, 0xcaa0047aL, 0xfdcac67bL, + 0xb02ebc6cL, 0x87447e6dL, 0xdefa386fL, 0xe990fa6eL, 0x6c86b56bL, + 0x5bec776aL, 0x02523168L, 0x3538f369L, 0x087faf62L, 0x3f156d63L, + 0x66ab2b61L, 0x51c1e960L, 0xd4d7a665L, 0xe3bd6464L, 0xba032266L, + 0x8d69e067L, 0x20cbd748L, 0x17a11549L, 0x4e1f534bL, 0x7975914aL, + 0xfc63de4fL, 0xcb091c4eL, 0x92b75a4cL, 0xa5dd984dL, 0x989ac446L, + 0xaff00647L, 0xf64e4045L, 0xc1248244L, 0x4432cd41L, 0x73580f40L, + 0x2ae64942L, 0x1d8c8b43L, 0x5068f154L, 0x67023355L, 0x3ebc7557L, + 0x09d6b756L, 0x8cc0f853L, 0xbbaa3a52L, 0xe2147c50L, 0xd57ebe51L, + 0xe839e25aL, 0xdf53205bL, 0x86ed6659L, 0xb187a458L, 0x3491eb5dL, + 0x03fb295cL, 0x5a456f5eL, 0x6d2fad5fL, 0x801b35e1L, 0xb771f7e0L, + 0xeecfb1e2L, 0xd9a573e3L, 0x5cb33ce6L, 0x6bd9fee7L, 0x3267b8e5L, + 0x050d7ae4L, 0x384a26efL, 0x0f20e4eeL, 0x569ea2ecL, 0x61f460edL, + 0xe4e22fe8L, 0xd388ede9L, 0x8a36abebL, 0xbd5c69eaL, 0xf0b813fdL, + 0xc7d2d1fcL, 0x9e6c97feL, 0xa90655ffL, 0x2c101afaL, 0x1b7ad8fbL, + 0x42c49ef9L, 0x75ae5cf8L, 0x48e900f3L, 0x7f83c2f2L, 0x263d84f0L, + 0x115746f1L, 0x944109f4L, 0xa32bcbf5L, 0xfa958df7L, 0xcdff4ff6L, + 0x605d78d9L, 0x5737bad8L, 0x0e89fcdaL, 0x39e33edbL, 0xbcf571deL, + 0x8b9fb3dfL, 0xd221f5ddL, 0xe54b37dcL, 0xd80c6bd7L, 0xef66a9d6L, + 0xb6d8efd4L, 0x81b22dd5L, 0x04a462d0L, 0x33cea0d1L, 0x6a70e6d3L, + 0x5d1a24d2L, 0x10fe5ec5L, 0x27949cc4L, 0x7e2adac6L, 0x494018c7L, + 0xcc5657c2L, 0xfb3c95c3L, 0xa282d3c1L, 0x95e811c0L, 0xa8af4dcbL, + 0x9fc58fcaL, 0xc67bc9c8L, 0xf1110bc9L, 0x740744ccL, 0x436d86cdL, + 0x1ad3c0cfL, 0x2db902ceL, 0x4096af91L, 0x77fc6d90L, 0x2e422b92L, + 0x1928e993L, 0x9c3ea696L, 0xab546497L, 0xf2ea2295L, 0xc580e094L, + 0xf8c7bc9fL, 0xcfad7e9eL, 0x9613389cL, 0xa179fa9dL, 0x246fb598L, + 0x13057799L, 0x4abb319bL, 0x7dd1f39aL, 0x3035898dL, 0x075f4b8cL, + 0x5ee10d8eL, 0x698bcf8fL, 0xec9d808aL, 0xdbf7428bL, 0x82490489L, + 0xb523c688L, 0x88649a83L, 0xbf0e5882L, 0xe6b01e80L, 0xd1dadc81L, + 0x54cc9384L, 0x63a65185L, 0x3a181787L, 0x0d72d586L, 0xa0d0e2a9L, + 0x97ba20a8L, 0xce0466aaL, 0xf96ea4abL, 0x7c78ebaeL, 0x4b1229afL, + 0x12ac6fadL, 0x25c6adacL, 0x1881f1a7L, 0x2feb33a6L, 0x765575a4L, + 0x413fb7a5L, 0xc429f8a0L, 0xf3433aa1L, 0xaafd7ca3L, 0x9d97bea2L, + 0xd073c4b5L, 0xe71906b4L, 0xbea740b6L, 0x89cd82b7L, 0x0cdbcdb2L, + 0x3bb10fb3L, 0x620f49b1L, 0x55658bb0L, 0x6822d7bbL, 0x5f4815baL, + 0x06f653b8L, 0x319c91b9L, 0xb48adebcL, 0x83e01cbdL, 0xda5e5abfL, + 0xed3498beL + , + 0x00000000L, 0x6567bcb8L, 0x8bc809aaL, 0xeeafb512L, 0x5797628fL, + 0x32f0de37L, 0xdc5f6b25L, 0xb938d79dL, 0xef28b4c5L, 0x8a4f087dL, + 0x64e0bd6fL, 0x018701d7L, 0xb8bfd64aL, 0xddd86af2L, 0x3377dfe0L, + 0x56106358L, 0x9f571950L, 0xfa30a5e8L, 0x149f10faL, 0x71f8ac42L, + 0xc8c07bdfL, 0xada7c767L, 0x43087275L, 0x266fcecdL, 0x707fad95L, + 0x1518112dL, 0xfbb7a43fL, 0x9ed01887L, 0x27e8cf1aL, 0x428f73a2L, + 0xac20c6b0L, 0xc9477a08L, 0x3eaf32a0L, 0x5bc88e18L, 0xb5673b0aL, + 0xd00087b2L, 0x6938502fL, 0x0c5fec97L, 0xe2f05985L, 0x8797e53dL, + 0xd1878665L, 0xb4e03addL, 0x5a4f8fcfL, 0x3f283377L, 0x8610e4eaL, + 0xe3775852L, 0x0dd8ed40L, 0x68bf51f8L, 0xa1f82bf0L, 0xc49f9748L, + 0x2a30225aL, 0x4f579ee2L, 0xf66f497fL, 0x9308f5c7L, 0x7da740d5L, + 0x18c0fc6dL, 0x4ed09f35L, 0x2bb7238dL, 0xc518969fL, 0xa07f2a27L, + 0x1947fdbaL, 0x7c204102L, 0x928ff410L, 0xf7e848a8L, 0x3d58149bL, + 0x583fa823L, 0xb6901d31L, 0xd3f7a189L, 0x6acf7614L, 0x0fa8caacL, + 0xe1077fbeL, 0x8460c306L, 0xd270a05eL, 0xb7171ce6L, 0x59b8a9f4L, + 0x3cdf154cL, 0x85e7c2d1L, 0xe0807e69L, 0x0e2fcb7bL, 0x6b4877c3L, + 0xa20f0dcbL, 0xc768b173L, 0x29c70461L, 0x4ca0b8d9L, 0xf5986f44L, + 0x90ffd3fcL, 0x7e5066eeL, 0x1b37da56L, 0x4d27b90eL, 0x284005b6L, + 0xc6efb0a4L, 0xa3880c1cL, 0x1ab0db81L, 0x7fd76739L, 0x9178d22bL, + 0xf41f6e93L, 0x03f7263bL, 0x66909a83L, 0x883f2f91L, 0xed589329L, + 0x546044b4L, 0x3107f80cL, 0xdfa84d1eL, 0xbacff1a6L, 0xecdf92feL, + 0x89b82e46L, 0x67179b54L, 0x027027ecL, 0xbb48f071L, 0xde2f4cc9L, + 0x3080f9dbL, 0x55e74563L, 0x9ca03f6bL, 0xf9c783d3L, 0x176836c1L, + 0x720f8a79L, 0xcb375de4L, 0xae50e15cL, 0x40ff544eL, 0x2598e8f6L, + 0x73888baeL, 0x16ef3716L, 0xf8408204L, 0x9d273ebcL, 0x241fe921L, + 0x41785599L, 0xafd7e08bL, 0xcab05c33L, 0x3bb659edL, 0x5ed1e555L, + 0xb07e5047L, 0xd519ecffL, 0x6c213b62L, 0x094687daL, 0xe7e932c8L, + 0x828e8e70L, 0xd49eed28L, 0xb1f95190L, 0x5f56e482L, 0x3a31583aL, + 0x83098fa7L, 0xe66e331fL, 0x08c1860dL, 0x6da63ab5L, 0xa4e140bdL, + 0xc186fc05L, 0x2f294917L, 0x4a4ef5afL, 0xf3762232L, 0x96119e8aL, + 0x78be2b98L, 0x1dd99720L, 0x4bc9f478L, 0x2eae48c0L, 0xc001fdd2L, + 0xa566416aL, 0x1c5e96f7L, 0x79392a4fL, 0x97969f5dL, 0xf2f123e5L, + 0x05196b4dL, 0x607ed7f5L, 0x8ed162e7L, 0xebb6de5fL, 0x528e09c2L, + 0x37e9b57aL, 0xd9460068L, 0xbc21bcd0L, 0xea31df88L, 0x8f566330L, + 0x61f9d622L, 0x049e6a9aL, 0xbda6bd07L, 0xd8c101bfL, 0x366eb4adL, + 0x53090815L, 0x9a4e721dL, 0xff29cea5L, 0x11867bb7L, 0x74e1c70fL, + 0xcdd91092L, 0xa8beac2aL, 0x46111938L, 0x2376a580L, 0x7566c6d8L, + 0x10017a60L, 0xfeaecf72L, 0x9bc973caL, 0x22f1a457L, 0x479618efL, + 0xa939adfdL, 0xcc5e1145L, 0x06ee4d76L, 0x6389f1ceL, 0x8d2644dcL, + 0xe841f864L, 0x51792ff9L, 0x341e9341L, 0xdab12653L, 0xbfd69aebL, + 0xe9c6f9b3L, 0x8ca1450bL, 0x620ef019L, 0x07694ca1L, 0xbe519b3cL, + 0xdb362784L, 0x35999296L, 0x50fe2e2eL, 0x99b95426L, 0xfcdee89eL, + 0x12715d8cL, 0x7716e134L, 0xce2e36a9L, 0xab498a11L, 0x45e63f03L, + 0x208183bbL, 0x7691e0e3L, 0x13f65c5bL, 0xfd59e949L, 0x983e55f1L, + 0x2106826cL, 0x44613ed4L, 0xaace8bc6L, 0xcfa9377eL, 0x38417fd6L, + 0x5d26c36eL, 0xb389767cL, 0xd6eecac4L, 0x6fd61d59L, 0x0ab1a1e1L, + 0xe41e14f3L, 0x8179a84bL, 0xd769cb13L, 0xb20e77abL, 0x5ca1c2b9L, + 0x39c67e01L, 0x80fea99cL, 0xe5991524L, 0x0b36a036L, 0x6e511c8eL, + 0xa7166686L, 0xc271da3eL, 0x2cde6f2cL, 0x49b9d394L, 0xf0810409L, + 0x95e6b8b1L, 0x7b490da3L, 0x1e2eb11bL, 0x483ed243L, 0x2d596efbL, + 0xc3f6dbe9L, 0xa6916751L, 0x1fa9b0ccL, 0x7ace0c74L, 0x9461b966L, + 0xf10605deL +# endif /* IZ_CRCOPTIM_UNFOLDTBL */ +# else /* !IZ_CRC_BE_OPTIMIZ */ + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +# ifdef IZ_CRCOPTIM_UNFOLDTBL + , + 0x00000000L, 0x191b3141L, 0x32366282L, 0x2b2d53c3L, 0x646cc504L, + 0x7d77f445L, 0x565aa786L, 0x4f4196c7L, 0xc8d98a08L, 0xd1c2bb49L, + 0xfaefe88aL, 0xe3f4d9cbL, 0xacb54f0cL, 0xb5ae7e4dL, 0x9e832d8eL, + 0x87981ccfL, 0x4ac21251L, 0x53d92310L, 0x78f470d3L, 0x61ef4192L, + 0x2eaed755L, 0x37b5e614L, 0x1c98b5d7L, 0x05838496L, 0x821b9859L, + 0x9b00a918L, 0xb02dfadbL, 0xa936cb9aL, 0xe6775d5dL, 0xff6c6c1cL, + 0xd4413fdfL, 0xcd5a0e9eL, 0x958424a2L, 0x8c9f15e3L, 0xa7b24620L, + 0xbea97761L, 0xf1e8e1a6L, 0xe8f3d0e7L, 0xc3de8324L, 0xdac5b265L, + 0x5d5daeaaL, 0x44469febL, 0x6f6bcc28L, 0x7670fd69L, 0x39316baeL, + 0x202a5aefL, 0x0b07092cL, 0x121c386dL, 0xdf4636f3L, 0xc65d07b2L, + 0xed705471L, 0xf46b6530L, 0xbb2af3f7L, 0xa231c2b6L, 0x891c9175L, + 0x9007a034L, 0x179fbcfbL, 0x0e848dbaL, 0x25a9de79L, 0x3cb2ef38L, + 0x73f379ffL, 0x6ae848beL, 0x41c51b7dL, 0x58de2a3cL, 0xf0794f05L, + 0xe9627e44L, 0xc24f2d87L, 0xdb541cc6L, 0x94158a01L, 0x8d0ebb40L, + 0xa623e883L, 0xbf38d9c2L, 0x38a0c50dL, 0x21bbf44cL, 0x0a96a78fL, + 0x138d96ceL, 0x5ccc0009L, 0x45d73148L, 0x6efa628bL, 0x77e153caL, + 0xbabb5d54L, 0xa3a06c15L, 0x888d3fd6L, 0x91960e97L, 0xded79850L, + 0xc7cca911L, 0xece1fad2L, 0xf5facb93L, 0x7262d75cL, 0x6b79e61dL, + 0x4054b5deL, 0x594f849fL, 0x160e1258L, 0x0f152319L, 0x243870daL, + 0x3d23419bL, 0x65fd6ba7L, 0x7ce65ae6L, 0x57cb0925L, 0x4ed03864L, + 0x0191aea3L, 0x188a9fe2L, 0x33a7cc21L, 0x2abcfd60L, 0xad24e1afL, + 0xb43fd0eeL, 0x9f12832dL, 0x8609b26cL, 0xc94824abL, 0xd05315eaL, + 0xfb7e4629L, 0xe2657768L, 0x2f3f79f6L, 0x362448b7L, 0x1d091b74L, + 0x04122a35L, 0x4b53bcf2L, 0x52488db3L, 0x7965de70L, 0x607eef31L, + 0xe7e6f3feL, 0xfefdc2bfL, 0xd5d0917cL, 0xcccba03dL, 0x838a36faL, + 0x9a9107bbL, 0xb1bc5478L, 0xa8a76539L, 0x3b83984bL, 0x2298a90aL, + 0x09b5fac9L, 0x10aecb88L, 0x5fef5d4fL, 0x46f46c0eL, 0x6dd93fcdL, + 0x74c20e8cL, 0xf35a1243L, 0xea412302L, 0xc16c70c1L, 0xd8774180L, + 0x9736d747L, 0x8e2de606L, 0xa500b5c5L, 0xbc1b8484L, 0x71418a1aL, + 0x685abb5bL, 0x4377e898L, 0x5a6cd9d9L, 0x152d4f1eL, 0x0c367e5fL, + 0x271b2d9cL, 0x3e001cddL, 0xb9980012L, 0xa0833153L, 0x8bae6290L, + 0x92b553d1L, 0xddf4c516L, 0xc4eff457L, 0xefc2a794L, 0xf6d996d5L, + 0xae07bce9L, 0xb71c8da8L, 0x9c31de6bL, 0x852aef2aL, 0xca6b79edL, + 0xd37048acL, 0xf85d1b6fL, 0xe1462a2eL, 0x66de36e1L, 0x7fc507a0L, + 0x54e85463L, 0x4df36522L, 0x02b2f3e5L, 0x1ba9c2a4L, 0x30849167L, + 0x299fa026L, 0xe4c5aeb8L, 0xfdde9ff9L, 0xd6f3cc3aL, 0xcfe8fd7bL, + 0x80a96bbcL, 0x99b25afdL, 0xb29f093eL, 0xab84387fL, 0x2c1c24b0L, + 0x350715f1L, 0x1e2a4632L, 0x07317773L, 0x4870e1b4L, 0x516bd0f5L, + 0x7a468336L, 0x635db277L, 0xcbfad74eL, 0xd2e1e60fL, 0xf9ccb5ccL, + 0xe0d7848dL, 0xaf96124aL, 0xb68d230bL, 0x9da070c8L, 0x84bb4189L, + 0x03235d46L, 0x1a386c07L, 0x31153fc4L, 0x280e0e85L, 0x674f9842L, + 0x7e54a903L, 0x5579fac0L, 0x4c62cb81L, 0x8138c51fL, 0x9823f45eL, + 0xb30ea79dL, 0xaa1596dcL, 0xe554001bL, 0xfc4f315aL, 0xd7626299L, + 0xce7953d8L, 0x49e14f17L, 0x50fa7e56L, 0x7bd72d95L, 0x62cc1cd4L, + 0x2d8d8a13L, 0x3496bb52L, 0x1fbbe891L, 0x06a0d9d0L, 0x5e7ef3ecL, + 0x4765c2adL, 0x6c48916eL, 0x7553a02fL, 0x3a1236e8L, 0x230907a9L, + 0x0824546aL, 0x113f652bL, 0x96a779e4L, 0x8fbc48a5L, 0xa4911b66L, + 0xbd8a2a27L, 0xf2cbbce0L, 0xebd08da1L, 0xc0fdde62L, 0xd9e6ef23L, + 0x14bce1bdL, 0x0da7d0fcL, 0x268a833fL, 0x3f91b27eL, 0x70d024b9L, + 0x69cb15f8L, 0x42e6463bL, 0x5bfd777aL, 0xdc656bb5L, 0xc57e5af4L, + 0xee530937L, 0xf7483876L, 0xb809aeb1L, 0xa1129ff0L, 0x8a3fcc33L, + 0x9324fd72L + , + 0x00000000L, 0x01c26a37L, 0x0384d46eL, 0x0246be59L, 0x0709a8dcL, + 0x06cbc2ebL, 0x048d7cb2L, 0x054f1685L, 0x0e1351b8L, 0x0fd13b8fL, + 0x0d9785d6L, 0x0c55efe1L, 0x091af964L, 0x08d89353L, 0x0a9e2d0aL, + 0x0b5c473dL, 0x1c26a370L, 0x1de4c947L, 0x1fa2771eL, 0x1e601d29L, + 0x1b2f0bacL, 0x1aed619bL, 0x18abdfc2L, 0x1969b5f5L, 0x1235f2c8L, + 0x13f798ffL, 0x11b126a6L, 0x10734c91L, 0x153c5a14L, 0x14fe3023L, + 0x16b88e7aL, 0x177ae44dL, 0x384d46e0L, 0x398f2cd7L, 0x3bc9928eL, + 0x3a0bf8b9L, 0x3f44ee3cL, 0x3e86840bL, 0x3cc03a52L, 0x3d025065L, + 0x365e1758L, 0x379c7d6fL, 0x35dac336L, 0x3418a901L, 0x3157bf84L, + 0x3095d5b3L, 0x32d36beaL, 0x331101ddL, 0x246be590L, 0x25a98fa7L, + 0x27ef31feL, 0x262d5bc9L, 0x23624d4cL, 0x22a0277bL, 0x20e69922L, + 0x2124f315L, 0x2a78b428L, 0x2bbade1fL, 0x29fc6046L, 0x283e0a71L, + 0x2d711cf4L, 0x2cb376c3L, 0x2ef5c89aL, 0x2f37a2adL, 0x709a8dc0L, + 0x7158e7f7L, 0x731e59aeL, 0x72dc3399L, 0x7793251cL, 0x76514f2bL, + 0x7417f172L, 0x75d59b45L, 0x7e89dc78L, 0x7f4bb64fL, 0x7d0d0816L, + 0x7ccf6221L, 0x798074a4L, 0x78421e93L, 0x7a04a0caL, 0x7bc6cafdL, + 0x6cbc2eb0L, 0x6d7e4487L, 0x6f38fadeL, 0x6efa90e9L, 0x6bb5866cL, + 0x6a77ec5bL, 0x68315202L, 0x69f33835L, 0x62af7f08L, 0x636d153fL, + 0x612bab66L, 0x60e9c151L, 0x65a6d7d4L, 0x6464bde3L, 0x662203baL, + 0x67e0698dL, 0x48d7cb20L, 0x4915a117L, 0x4b531f4eL, 0x4a917579L, + 0x4fde63fcL, 0x4e1c09cbL, 0x4c5ab792L, 0x4d98dda5L, 0x46c49a98L, + 0x4706f0afL, 0x45404ef6L, 0x448224c1L, 0x41cd3244L, 0x400f5873L, + 0x4249e62aL, 0x438b8c1dL, 0x54f16850L, 0x55330267L, 0x5775bc3eL, + 0x56b7d609L, 0x53f8c08cL, 0x523aaabbL, 0x507c14e2L, 0x51be7ed5L, + 0x5ae239e8L, 0x5b2053dfL, 0x5966ed86L, 0x58a487b1L, 0x5deb9134L, + 0x5c29fb03L, 0x5e6f455aL, 0x5fad2f6dL, 0xe1351b80L, 0xe0f771b7L, + 0xe2b1cfeeL, 0xe373a5d9L, 0xe63cb35cL, 0xe7fed96bL, 0xe5b86732L, + 0xe47a0d05L, 0xef264a38L, 0xeee4200fL, 0xeca29e56L, 0xed60f461L, + 0xe82fe2e4L, 0xe9ed88d3L, 0xebab368aL, 0xea695cbdL, 0xfd13b8f0L, + 0xfcd1d2c7L, 0xfe976c9eL, 0xff5506a9L, 0xfa1a102cL, 0xfbd87a1bL, + 0xf99ec442L, 0xf85cae75L, 0xf300e948L, 0xf2c2837fL, 0xf0843d26L, + 0xf1465711L, 0xf4094194L, 0xf5cb2ba3L, 0xf78d95faL, 0xf64fffcdL, + 0xd9785d60L, 0xd8ba3757L, 0xdafc890eL, 0xdb3ee339L, 0xde71f5bcL, + 0xdfb39f8bL, 0xddf521d2L, 0xdc374be5L, 0xd76b0cd8L, 0xd6a966efL, + 0xd4efd8b6L, 0xd52db281L, 0xd062a404L, 0xd1a0ce33L, 0xd3e6706aL, + 0xd2241a5dL, 0xc55efe10L, 0xc49c9427L, 0xc6da2a7eL, 0xc7184049L, + 0xc25756ccL, 0xc3953cfbL, 0xc1d382a2L, 0xc011e895L, 0xcb4dafa8L, + 0xca8fc59fL, 0xc8c97bc6L, 0xc90b11f1L, 0xcc440774L, 0xcd866d43L, + 0xcfc0d31aL, 0xce02b92dL, 0x91af9640L, 0x906dfc77L, 0x922b422eL, + 0x93e92819L, 0x96a63e9cL, 0x976454abL, 0x9522eaf2L, 0x94e080c5L, + 0x9fbcc7f8L, 0x9e7eadcfL, 0x9c381396L, 0x9dfa79a1L, 0x98b56f24L, + 0x99770513L, 0x9b31bb4aL, 0x9af3d17dL, 0x8d893530L, 0x8c4b5f07L, + 0x8e0de15eL, 0x8fcf8b69L, 0x8a809decL, 0x8b42f7dbL, 0x89044982L, + 0x88c623b5L, 0x839a6488L, 0x82580ebfL, 0x801eb0e6L, 0x81dcdad1L, + 0x8493cc54L, 0x8551a663L, 0x8717183aL, 0x86d5720dL, 0xa9e2d0a0L, + 0xa820ba97L, 0xaa6604ceL, 0xaba46ef9L, 0xaeeb787cL, 0xaf29124bL, + 0xad6fac12L, 0xacadc625L, 0xa7f18118L, 0xa633eb2fL, 0xa4755576L, + 0xa5b73f41L, 0xa0f829c4L, 0xa13a43f3L, 0xa37cfdaaL, 0xa2be979dL, + 0xb5c473d0L, 0xb40619e7L, 0xb640a7beL, 0xb782cd89L, 0xb2cddb0cL, + 0xb30fb13bL, 0xb1490f62L, 0xb08b6555L, 0xbbd72268L, 0xba15485fL, + 0xb853f606L, 0xb9919c31L, 0xbcde8ab4L, 0xbd1ce083L, 0xbf5a5edaL, + 0xbe9834edL + , + 0x00000000L, 0xb8bc6765L, 0xaa09c88bL, 0x12b5afeeL, 0x8f629757L, + 0x37def032L, 0x256b5fdcL, 0x9dd738b9L, 0xc5b428efL, 0x7d084f8aL, + 0x6fbde064L, 0xd7018701L, 0x4ad6bfb8L, 0xf26ad8ddL, 0xe0df7733L, + 0x58631056L, 0x5019579fL, 0xe8a530faL, 0xfa109f14L, 0x42acf871L, + 0xdf7bc0c8L, 0x67c7a7adL, 0x75720843L, 0xcdce6f26L, 0x95ad7f70L, + 0x2d111815L, 0x3fa4b7fbL, 0x8718d09eL, 0x1acfe827L, 0xa2738f42L, + 0xb0c620acL, 0x087a47c9L, 0xa032af3eL, 0x188ec85bL, 0x0a3b67b5L, + 0xb28700d0L, 0x2f503869L, 0x97ec5f0cL, 0x8559f0e2L, 0x3de59787L, + 0x658687d1L, 0xdd3ae0b4L, 0xcf8f4f5aL, 0x7733283fL, 0xeae41086L, + 0x525877e3L, 0x40edd80dL, 0xf851bf68L, 0xf02bf8a1L, 0x48979fc4L, + 0x5a22302aL, 0xe29e574fL, 0x7f496ff6L, 0xc7f50893L, 0xd540a77dL, + 0x6dfcc018L, 0x359fd04eL, 0x8d23b72bL, 0x9f9618c5L, 0x272a7fa0L, + 0xbafd4719L, 0x0241207cL, 0x10f48f92L, 0xa848e8f7L, 0x9b14583dL, + 0x23a83f58L, 0x311d90b6L, 0x89a1f7d3L, 0x1476cf6aL, 0xaccaa80fL, + 0xbe7f07e1L, 0x06c36084L, 0x5ea070d2L, 0xe61c17b7L, 0xf4a9b859L, + 0x4c15df3cL, 0xd1c2e785L, 0x697e80e0L, 0x7bcb2f0eL, 0xc377486bL, + 0xcb0d0fa2L, 0x73b168c7L, 0x6104c729L, 0xd9b8a04cL, 0x446f98f5L, + 0xfcd3ff90L, 0xee66507eL, 0x56da371bL, 0x0eb9274dL, 0xb6054028L, + 0xa4b0efc6L, 0x1c0c88a3L, 0x81dbb01aL, 0x3967d77fL, 0x2bd27891L, + 0x936e1ff4L, 0x3b26f703L, 0x839a9066L, 0x912f3f88L, 0x299358edL, + 0xb4446054L, 0x0cf80731L, 0x1e4da8dfL, 0xa6f1cfbaL, 0xfe92dfecL, + 0x462eb889L, 0x549b1767L, 0xec277002L, 0x71f048bbL, 0xc94c2fdeL, + 0xdbf98030L, 0x6345e755L, 0x6b3fa09cL, 0xd383c7f9L, 0xc1366817L, + 0x798a0f72L, 0xe45d37cbL, 0x5ce150aeL, 0x4e54ff40L, 0xf6e89825L, + 0xae8b8873L, 0x1637ef16L, 0x048240f8L, 0xbc3e279dL, 0x21e91f24L, + 0x99557841L, 0x8be0d7afL, 0x335cb0caL, 0xed59b63bL, 0x55e5d15eL, + 0x47507eb0L, 0xffec19d5L, 0x623b216cL, 0xda874609L, 0xc832e9e7L, + 0x708e8e82L, 0x28ed9ed4L, 0x9051f9b1L, 0x82e4565fL, 0x3a58313aL, + 0xa78f0983L, 0x1f336ee6L, 0x0d86c108L, 0xb53aa66dL, 0xbd40e1a4L, + 0x05fc86c1L, 0x1749292fL, 0xaff54e4aL, 0x322276f3L, 0x8a9e1196L, + 0x982bbe78L, 0x2097d91dL, 0x78f4c94bL, 0xc048ae2eL, 0xd2fd01c0L, + 0x6a4166a5L, 0xf7965e1cL, 0x4f2a3979L, 0x5d9f9697L, 0xe523f1f2L, + 0x4d6b1905L, 0xf5d77e60L, 0xe762d18eL, 0x5fdeb6ebL, 0xc2098e52L, + 0x7ab5e937L, 0x680046d9L, 0xd0bc21bcL, 0x88df31eaL, 0x3063568fL, + 0x22d6f961L, 0x9a6a9e04L, 0x07bda6bdL, 0xbf01c1d8L, 0xadb46e36L, + 0x15080953L, 0x1d724e9aL, 0xa5ce29ffL, 0xb77b8611L, 0x0fc7e174L, + 0x9210d9cdL, 0x2aacbea8L, 0x38191146L, 0x80a57623L, 0xd8c66675L, + 0x607a0110L, 0x72cfaefeL, 0xca73c99bL, 0x57a4f122L, 0xef189647L, + 0xfdad39a9L, 0x45115eccL, 0x764dee06L, 0xcef18963L, 0xdc44268dL, + 0x64f841e8L, 0xf92f7951L, 0x41931e34L, 0x5326b1daL, 0xeb9ad6bfL, + 0xb3f9c6e9L, 0x0b45a18cL, 0x19f00e62L, 0xa14c6907L, 0x3c9b51beL, + 0x842736dbL, 0x96929935L, 0x2e2efe50L, 0x2654b999L, 0x9ee8defcL, + 0x8c5d7112L, 0x34e11677L, 0xa9362eceL, 0x118a49abL, 0x033fe645L, + 0xbb838120L, 0xe3e09176L, 0x5b5cf613L, 0x49e959fdL, 0xf1553e98L, + 0x6c820621L, 0xd43e6144L, 0xc68bceaaL, 0x7e37a9cfL, 0xd67f4138L, + 0x6ec3265dL, 0x7c7689b3L, 0xc4caeed6L, 0x591dd66fL, 0xe1a1b10aL, + 0xf3141ee4L, 0x4ba87981L, 0x13cb69d7L, 0xab770eb2L, 0xb9c2a15cL, + 0x017ec639L, 0x9ca9fe80L, 0x241599e5L, 0x36a0360bL, 0x8e1c516eL, + 0x866616a7L, 0x3eda71c2L, 0x2c6fde2cL, 0x94d3b949L, 0x090481f0L, + 0xb1b8e695L, 0xa30d497bL, 0x1bb12e1eL, 0x43d23e48L, 0xfb6e592dL, + 0xe9dbf6c3L, 0x516791a6L, 0xccb0a91fL, 0x740cce7aL, 0x66b96194L, + 0xde0506f1L +# endif /* IZ_CRCOPTIM_UNFOLDTBL */ +# endif /* ? IZ_CRC_BE_OPTIMIZ */ +}; +#endif /* ?DYNAMIC_CRC_TABLE */ + +/* use "OF((void))" here to work around a Borland TC++ 1.0 problem */ +#ifdef USE_ZLIB +ZCONST uLongf *get_crc_table OF((void)) +#else +ZCONST ulg near *get_crc_table OF((void)) +#endif +{ +#ifdef DYNAMIC_CRC_TABLE + if (CRC_TABLE_IS_EMPTY) + make_crc_table(); +#endif +#ifdef USE_ZLIB + return (ZCONST uLongf *)crc_table; +#else + return crc_table; +#endif +} + +#ifdef DYNALLOC_CRCTAB +void free_crc_table() +{ + if (!CRC_TABLE_IS_EMPTY) + { + nearfree((ulg near *)crc_table); + MARK_CRCTAB_EMPTY; + } +} +#endif + +#ifndef USE_ZLIB +#ifndef CRC_TABLE_ONLY +#ifndef ASM_CRC + +#define DO1(crc, buf) crc = CRC32(crc, *buf++, crc_32_tab) +#define DO2(crc, buf) DO1(crc, buf); DO1(crc, buf) +#define DO4(crc, buf) DO2(crc, buf); DO2(crc, buf) +#define DO8(crc, buf) DO4(crc, buf); DO4(crc, buf) + +#if (defined(IZ_CRC_BE_OPTIMIZ) || defined(IZ_CRC_LE_OPTIMIZ)) + +# ifdef IZ_CRCOPTIM_UNFOLDTBL +# ifdef IZ_CRC_BE_OPTIMIZ +# define DO_OPT4(c, buf4) c ^= *(buf4)++; \ + c = crc_32_tab[c & 0xff] ^ crc_32_tab[256+((c>>8) & 0xff)] ^ \ + crc_32_tab[2*256+((c>>16) & 0xff)] ^ crc_32_tab[3*256+(c>>24)] +# else /* !IZ_CRC_BE_OPTIMIZ */ +# define DO_OPT4(c, buf4) c ^= *(buf4)++; \ + c = crc_32_tab[3*256+(c & 0xff)] ^ crc_32_tab[2*256+((c>>8) & 0xff)] \ + ^ crc_32_tab[256+((c>>16) & 0xff)] ^ crc_32_tab[c>>24] +# endif /* ?IZ_CRC_BE_OPTIMIZ */ +# else /* !IZ_CRCOPTIM_UNFOLDTBL */ +# define DO_OPT4(c, buf4) c ^= *(buf4)++; \ + c = CRC32UPD(c, crc_32_tab); \ + c = CRC32UPD(c, crc_32_tab); \ + c = CRC32UPD(c, crc_32_tab); \ + c = CRC32UPD(c, crc_32_tab) +# endif /* ?IZ_CRCOPTIM_UNFOLDTBL */ + +# define DO_OPT16(crc, buf4) DO_OPT4(crc, buf4); DO_OPT4(crc, buf4); \ + DO_OPT4(crc, buf4); DO_OPT4(crc, buf4); + +#endif /* (IZ_CRC_BE_OPTIMIZ || IZ_CRC_LE_OPTIMIZ) */ + + +/* ========================================================================= */ +ulg crc32(crc, buf, len) + ulg crc; /* crc shift register */ + register ZCONST uch *buf; /* pointer to bytes to pump through */ + extent len; /* number of bytes in buf[] */ +/* Run a set of bytes through the crc shift register. If buf is a NULL + pointer, then initialize the crc shift register contents instead. + Return the current crc in either case. */ +{ + register z_uint4 c; + register ZCONST ulg near *crc_32_tab; + + if (buf == NULL) return 0L; + + crc_32_tab = get_crc_table(); + + c = (REV_BE((z_uint4)crc) ^ 0xffffffffL); + +#if (defined(IZ_CRC_BE_OPTIMIZ) || defined(IZ_CRC_LE_OPTIMIZ)) + /* Align buf pointer to next DWORD boundary. */ + while (len && ((ptrdiff_t)buf & 3)) { + DO1(c, buf); + len--; + } + { + ZCONST z_uint4 *buf4 = (ZCONST z_uint4 *)buf; + while (len >= 16) { + DO_OPT16(c, buf4); + len -= 16; + } + while (len >= 4) { + DO_OPT4(c, buf4); + len -= 4; + } + buf = (ZCONST uch *)buf4; + } +#else /* !(IZ_CRC_BE_OPTIMIZ || IZ_CRC_LE_OPTIMIZ) */ +#ifndef NO_UNROLLED_LOOPS + while (len >= 8) { + DO8(c, buf); + len -= 8; + } +#endif /* !NO_UNROLLED_LOOPS */ +#endif /* ?(IZ_CRC_BE_OPTIMIZ || IZ_CRC_LE_OPTIMIZ) */ + if (len) do { + DO1(c, buf); + } while (--len); + + return REV_BE(c) ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ +} +#endif /* !ASM_CRC */ +#endif /* !CRC_TABLE_ONLY */ +#endif /* !USE_ZLIB */ +#endif /* !USE_ZLIB || USE_OWN_CRCTAB */ diff --git a/third_party/unzip/crc32.h b/third_party/unzip/crc32.h new file mode 100644 index 000000000..1d99d6f58 --- /dev/null +++ b/third_party/unzip/crc32.h @@ -0,0 +1,65 @@ +// clang-format off +/* + Copyright (c) 1990-2008 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.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 +*/ +/* crc32.h -- compute the CRC-32 of a data stream + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef __crc32_h +#define __crc32_h /* identifies this source module */ +#include "third_party/unzip/unzip.h" +#include "third_party/unzip/unzip.h" +#include "third_party/unzip/unzpriv.h" +#include "third_party/zip/crc32.h" + +/* This header should be read AFTER zip.h resp. unzip.h + * (the latter with UNZIP_INTERNAL defined...). + */ + +#ifndef OF +# define OF(a) a +#endif +#ifndef ZCONST +# define ZCONST const +#endif + +#ifdef DYNALLOC_CRCTAB + void free_crc_table OF((void)); +#endif +#ifndef USE_ZLIB + ZCONST ulg near *get_crc_table OF((void)); +#endif +#if (defined(USE_ZLIB) || defined(CRC_TABLE_ONLY)) +# ifdef IZ_CRC_BE_OPTIMIZ +# undef IZ_CRC_BE_OPTIMIZ +# endif +#else /* !(USE_ZLIB || CRC_TABLE_ONLY) */ + ulg crc32 OF((ulg crc, ZCONST uch *buf, extent len)); +#endif /* ?(USE_ZLIB || CRC_TABLE_ONLY) */ + +#ifndef CRC_32_TAB +# define CRC_32_TAB crc_32_tab +#endif + +#ifdef CRC32 +# undef CRC32 +#endif +#ifdef IZ_CRC_BE_OPTIMIZ +# define CRC32UPD(c, crctab) (crctab[((c) >> 24)] ^ ((c) << 8)) +# define CRC32(c, b, crctab) (crctab[(((int)(c) >> 24) ^ (b))] ^ ((c) << 8)) +# define REV_BE(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) +#else +# define CRC32UPD(c, crctab) (crctab[((int)(c)) & 0xff] ^ ((c) >> 8)) +# define CRC32(c, b, crctab) (crctab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) +# define REV_BE(w) w +#endif + +#endif /* !__crc32_h */ diff --git a/third_party/unzip/crypt.c b/third_party/unzip/crypt.c new file mode 100644 index 000000000..aa5711f83 --- /dev/null +++ b/third_party/unzip/crypt.c @@ -0,0 +1,653 @@ +// clang-format off +/* + Copyright (c) 1990-2007 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2005-Feb-10 or later + (the contents of which are also included in (un)zip.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 +*/ +/* + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The main encryption/decryption source code for Info-Zip software was + originally written in Europe. To the best of our knowledge, it can + be freely distributed in both source and object forms from any country, + including the USA under License Exception TSU of the U.S. Export + Administration Regulations (section 740.13(e)) of 6 June 2002. + + NOTE on copyright history: + Previous versions of this source package (up to version 2.8) were + not copyrighted and put in the public domain. If you cannot comply + with the Info-Zip LICENSE, you may want to look for one of those + public domain versions. + */ + +/* + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + */ + +#define ZCRYPT_INTERNAL +#include "third_party/unzip/zip.h" +#include "third_party/unzip/crypt.h" +#include "third_party/unzip/ttyio.h" + +#if CRYPT + +#ifndef FALSE +# define FALSE 0 +#endif + +#ifdef ZIP + /* For the encoding task used in Zip (and ZipCloak), we want to initialize + the crypt algorithm with some reasonably unpredictable bytes, see + the crypthead() function. The standard rand() library function is + used to supply these `random' bytes, which in turn is initialized by + a srand() call. The srand() function takes an "unsigned" (at least 16bit) + seed value as argument to determine the starting point of the rand() + pseudo-random number generator. + This seed number is constructed as "Seed = Seed1 .XOR. Seed2" with + Seed1 supplied by the current time (= "(unsigned)time()") and Seed2 + as some (hopefully) nondeterministic bitmask. On many (most) systems, + we use some "process specific" number, as the PID or something similar, + but when nothing unpredictable is available, a fixed number may be + sufficient. + NOTE: + 1.) This implementation requires the availability of the following + standard UNIX C runtime library functions: time(), rand(), srand(). + On systems where some of them are missing, the environment that + incorporates the crypt routines must supply suitable replacement + functions. + 2.) It is a very bad idea to use a second call to time() to set the + "Seed2" number! In this case, both "Seed1" and "Seed2" would be + (almost) identical, resulting in a (mostly) "zero" constant seed + number passed to srand(). + + The implementation environment defined in the "zip.h" header should + supply a reasonable definition for ZCR_SEED2 (an unsigned number; for + most implementations of rand() and srand(), only the lower 16 bits are + significant!). An example that works on many systems would be + "#define ZCR_SEED2 (unsigned)getpid()". + The default definition for ZCR_SEED2 supplied below should be regarded + as a fallback to allow successful compilation in "beta state" + environments. + */ + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 (unsigned)3141592654L /* use PI as default pattern */ +# endif +# ifdef GLOBAL /* used in Amiga system headers, maybe others too */ +# undef GLOBAL +# endif +# define GLOBAL(g) g +#else /* !ZIP */ +# define GLOBAL(g) G.g +#endif /* ?ZIP */ + + +#ifdef UNZIP + /* char *key = (char *)NULL; moved to globals.h */ +# ifndef FUNZIP + local int testp OF((__GPRO__ ZCONST uch *h)); + local int testkey OF((__GPRO__ ZCONST uch *h, ZCONST char *key)); +# endif +#endif /* UNZIP */ + +#ifndef UNZIP /* moved to globals.h for UnZip */ +# ifndef Z_UINT4_DEFINED +# if !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 /* !NO_LIMITS_H */ +# endif /* !Z_UINT4_DEFINED */ +# ifndef Z_UINT4_DEFINED + typedef ulg z_uint4; +# define Z_UINT4_DEFINED +# endif + local z_uint4 keys[3]; /* keys defining the pseudo-random sequence */ +#endif /* !UNZIP */ + +#ifndef Trace +# ifdef CRYPT_DEBUG +# define Trace(x) fprintf x +# else +# define Trace(x) +# endif +#endif + +#include "third_party/unzip/crc32.h" + +#ifdef IZ_CRC_BE_OPTIMIZ + local z_uint4 near crycrctab[256]; + local z_uint4 near *cry_crctb_p = NULL; + local z_uint4 near *crytab_init OF((__GPRO)); +# define CRY_CRC_TAB cry_crctb_p +# undef CRC32 +# define CRC32(c, b, crctab) (crctab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) +#else +# define CRY_CRC_TAB CRC_32_TAB +#endif /* ?IZ_CRC_BE_OPTIMIZ */ + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +int decrypt_byte(__G) + __GDEF +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)GLOBAL(keys[2]) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +int update_keys(__G__ c) + __GDEF + int c; /* byte of plain text */ +{ + GLOBAL(keys[0]) = CRC32(GLOBAL(keys[0]), c, CRY_CRC_TAB); + GLOBAL(keys[1]) = (GLOBAL(keys[1]) + + (GLOBAL(keys[0]) & 0xff)) + * 134775813L + 1; + { + register int keyshift = (int)(GLOBAL(keys[1]) >> 24); + GLOBAL(keys[2]) = CRC32(GLOBAL(keys[2]), keyshift, CRY_CRC_TAB); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +void init_keys(__G__ passwd) + __GDEF + ZCONST char *passwd; /* password string with which to modify keys */ +{ +#ifdef IZ_CRC_BE_OPTIMIZ + if (cry_crctb_p == NULL) { + cry_crctb_p = crytab_init(__G); + } +#endif + GLOBAL(keys[0]) = 305419896L; + GLOBAL(keys[1]) = 591751049L; + GLOBAL(keys[2]) = 878082192L; + while (*passwd != '\0') { + update_keys(__G__ (int)*passwd); + passwd++; + } +} + + +/*********************************************************************** + * Initialize the local copy of the table of precomputed crc32 values. + * Whereas the public crc32-table is optimized for crc32 calculations + * on arrays of bytes, the crypt code needs the crc32 values in an + * byte-order-independent form as 32-bit unsigned numbers. On systems + * with Big-Endian byte order using the optimized crc32 code, this + * requires inverting the byte-order of the values in the + * crypt-crc32-table. + */ +#ifdef IZ_CRC_BE_OPTIMIZ +local z_uint4 near *crytab_init(__G) + __GDEF +{ + int i; + + for (i = 0; i < 256; i++) { + crycrctab[i] = REV_BE(CRC_32_TAB[i]); + } + return crycrctab; +} +#endif + + +#ifdef ZIP + +/*********************************************************************** + * Write encryption header to file zfile using the password passwd + * and the cyclic redundancy check crc. + */ +void crypthead(passwd, crc, zfile) + ZCONST char *passwd; /* password string */ + ulg crc; /* crc of file being encrypted */ + FILE *zfile; /* where to write header */ +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + uch header[RAND_HEAD_LEN]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the + * output of rand() to get less predictability, since rand() is + * often poorly implemented. + */ + if (++calls == 1) { + srand((unsigned)time(NULL) ^ ZCR_SEED2); + } + init_keys(passwd); + for (n = 0; n < RAND_HEAD_LEN-2; n++) { + c = (rand() >> 7) & 0xff; + header[n] = (uch)zencode(c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd); + for (n = 0; n < RAND_HEAD_LEN-2; n++) { + header[n] = (uch)zencode(header[n], t); + } + header[RAND_HEAD_LEN-2] = (uch)zencode((int)(crc >> 16) & 0xff, t); + header[RAND_HEAD_LEN-1] = (uch)zencode((int)(crc >> 24) & 0xff, t); + fwrite(header, 1, RAND_HEAD_LEN, f); +} + + +#ifdef UTIL + +/*********************************************************************** + * Encrypt the zip entry described by z from file source to file dest + * using the password passwd. Return an error code in the ZE_ class. + */ +int zipcloak(z, source, dest, passwd) + struct zlist far *z; /* zip entry to encrypt */ + FILE *source, *dest; /* source and destination files */ + ZCONST char *passwd; /* password string */ +{ + int c; /* input byte */ + int res; /* result code */ + ulg n; /* holds offset and counts size */ + ush flag; /* previous flags */ + int t; /* temporary */ + int ztemp; /* temporary storage for zencode value */ + + /* Set encrypted bit, clear extended local header bit and write local + header to output file */ + if ((n = (ulg)ftell(dest)) == (ulg)-1L) return ZE_TEMP; + z->off = n; + flag = z->flg; + z->flg |= 1, z->flg &= ~8; + z->lflg |= 1, z->lflg &= ~8; + z->siz += RAND_HEAD_LEN; + if ((res = putlocal(z, dest)) != ZE_OK) return res; + + /* Initialize keys with password and write random header */ + crypthead(passwd, z->crc, dest); + + /* Skip local header in input file */ + if (fseek(source, (long)((4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext), + SEEK_CUR)) { + return ferror(source) ? ZE_READ : ZE_EOF; + } + + /* Encrypt data */ + for (n = z->siz - RAND_HEAD_LEN; n; n--) { + if ((c = getc(source)) == EOF) { + return ferror(source) ? ZE_READ : ZE_EOF; + } + ztemp = zencode(c, t); + putc(ztemp, dest); + } + /* Skip extended local header in input file if there is one */ + if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) { + return ferror(source) ? ZE_READ : ZE_EOF; + } + if (fflush(dest) == EOF) return ZE_TEMP; + + /* Update number of bytes written to output file */ + tempzn += (4 + LOCHEAD) + z->nam + z->ext + z->siz; + + return ZE_OK; +} + +/*********************************************************************** + * Decrypt the zip entry described by z from file source to file dest + * using the password passwd. Return an error code in the ZE_ class. + */ +int zipbare(z, source, dest, passwd) + struct zlist far *z; /* zip entry to encrypt */ + FILE *source, *dest; /* source and destination files */ + ZCONST char *passwd; /* password string */ +{ +#ifdef ZIP10 + int c0 /* byte preceding the last input byte */ +#endif + int c1; /* last input byte */ + ulg offset; /* used for file offsets */ + ulg size; /* size of input data */ + int r; /* size of encryption header */ + int res; /* return code */ + ush flag; /* previous flags */ + + /* Save position and skip local header in input file */ + if ((offset = (ulg)ftell(source)) == (ulg)-1L || + fseek(source, (long)((4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext), + SEEK_CUR)) { + return ferror(source) ? ZE_READ : ZE_EOF; + } + /* Initialize keys with password */ + init_keys(passwd); + + /* Decrypt encryption header, save last two bytes */ + c1 = 0; + for (r = RAND_HEAD_LEN; r; r--) { +#ifdef ZIP10 + c0 = c1; +#endif + if ((c1 = getc(source)) == EOF) { + return ferror(source) ? ZE_READ : ZE_EOF; + } + Trace((stdout, " (%02x)", c1)); + zdecode(c1); + Trace((stdout, " %02x", c1)); + } + Trace((stdout, "\n")); + + /* If last two bytes of header don't match crc (or file time in the + * case of an extended local header), back up and just copy. For + * pkzip 2.0, the check has been reduced to one byte only. + */ +#ifdef ZIP10 + if ((ush)(c0 | (c1<<8)) != + (z->flg & 8 ? (ush) z->tim & 0xffff : (ush)(z->crc >> 16))) { +#else + if ((ush)c1 != (z->flg & 8 ? (ush) z->tim >> 8 : (ush)(z->crc >> 24))) { +#endif + if (fseek(source, offset, SEEK_SET)) { + return ferror(source) ? ZE_READ : ZE_EOF; + } + if ((res = zipcopy(z, source, dest)) != ZE_OK) return res; + return ZE_MISS; + } + + /* Clear encrypted bit and local header bit, and write local header to + output file */ + if ((offset = (ulg)ftell(dest)) == (ulg)-1L) return ZE_TEMP; + z->off = offset; + flag = z->flg; + z->flg &= ~9; + z->lflg &= ~9; + z->siz -= RAND_HEAD_LEN; + if ((res = putlocal(z, dest)) != ZE_OK) return res; + + /* Decrypt data */ + for (size = z->siz; size; size--) { + if ((c1 = getc(source)) == EOF) { + return ferror(source) ? ZE_READ : ZE_EOF; + } + zdecode(c1); + putc(c1, dest); + } + /* Skip extended local header in input file if there is one */ + if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) { + return ferror(source) ? ZE_READ : ZE_EOF; + } + if (fflush(dest) == EOF) return ZE_TEMP; + + /* Update number of bytes written to output file */ + tempzn += (4 + LOCHEAD) + z->nam + z->ext + z->siz; + + return ZE_OK; +} + + +#else /* !UTIL */ + +/*********************************************************************** + * If requested, encrypt the data in buf, and in any case call fwrite() + * with the arguments to zfwrite(). Return what fwrite() returns. + * + * A bug has been found when encrypting large files. See trees.c + * for details and the fix. + */ +unsigned zfwrite(buf, item_size, nb, f) + zvoid *buf; /* data buffer */ + extent item_size; /* size of each item in bytes */ + extent nb; /* number of items */ + FILE *f; /* file to write to */ +{ + int t; /* temporary */ + + if (key != (char *)NULL) { /* key is the global password pointer */ + ulg size; /* buffer size */ + char *p = (char*)buf; /* steps through buffer */ + + /* Encrypt data in buffer */ + for (size = item_size*(ulg)nb; size != 0; p++, size--) { + *p = (char)zencode(*p, t); + } + } + /* Write the buffer out */ + return fwrite(buf, item_size, nb, f); +} + +#endif /* ?UTIL */ +#endif /* ZIP */ + + +#if (defined(UNZIP) && !defined(FUNZIP)) + +/*********************************************************************** + * Get the password and set up keys for current zipfile member. + * Return PK_ class error. + */ +int decrypt(__G__ passwrd) + __GDEF + ZCONST char *passwrd; +{ + ush b; + int n, r; + uch h[RAND_HEAD_LEN]; + + Trace((stdout, "\n[incnt = %d]: ", GLOBAL(incnt))); + + /* get header once (turn off "encrypted" flag temporarily so we don't + * try to decrypt the same data twice) */ + GLOBAL(pInfo->encrypted) = FALSE; + defer_leftover_input(__G); + for (n = 0; n < RAND_HEAD_LEN; n++) { + b = NEXTBYTE; + h[n] = (uch)b; + Trace((stdout, " (%02x)", h[n])); + } + undefer_input(__G); + GLOBAL(pInfo->encrypted) = TRUE; + + if (GLOBAL(newzip)) { /* this is first encrypted member in this zipfile */ + GLOBAL(newzip) = FALSE; + if (passwrd != (char *)NULL) { /* user gave password on command line */ + if (!GLOBAL(key)) { + if ((GLOBAL(key) = (char *)malloc(strlen(passwrd)+1)) == + (char *)NULL) + return PK_MEM2; + strcpy(GLOBAL(key), passwrd); + GLOBAL(nopwd) = TRUE; /* inhibit password prompting! */ + } + } else if (GLOBAL(key)) { /* get rid of previous zipfile's key */ + free(GLOBAL(key)); + GLOBAL(key) = (char *)NULL; + } + } + + /* if have key already, test it; else allocate memory for it */ + if (GLOBAL(key)) { + if (!testp(__G__ h)) + return PK_COOL; /* existing password OK (else prompt for new) */ + else if (GLOBAL(nopwd)) + return PK_WARN; /* user indicated no more prompting */ + } else if ((GLOBAL(key) = (char *)malloc(IZ_PWLEN+1)) == (char *)NULL) + return PK_MEM2; + + /* try a few keys */ + n = 0; + do { + r = (*G.decr_passwd)((zvoid *)&G, &n, GLOBAL(key), IZ_PWLEN+1, + GLOBAL(zipfn), GLOBAL(filename)); + if (r == IZ_PW_ERROR) { /* internal error in fetch of PW */ + free (GLOBAL(key)); + GLOBAL(key) = NULL; + return PK_MEM2; + } + if (r != IZ_PW_ENTERED) { /* user replied "skip" or "skip all" */ + *GLOBAL(key) = '\0'; /* We try the NIL password, ... */ + n = 0; /* and cancel fetch for this item. */ + } + if (!testp(__G__ h)) + return PK_COOL; + if (r == IZ_PW_CANCELALL) /* User replied "Skip all" */ + GLOBAL(nopwd) = TRUE; /* inhibit any further PW prompt! */ + } while (n > 0); + + return PK_WARN; + +} /* end function decrypt() */ + + + +/*********************************************************************** + * Test the password. Return -1 if bad, 0 if OK. + */ +local int testp(__G__ h) + __GDEF + ZCONST uch *h; +{ + int r; + char *key_translated; + + /* On systems with "obscure" native character coding (e.g., EBCDIC), + * the first test translates the password to the "main standard" + * character coding. */ + +#ifdef STR_TO_CP1 + /* allocate buffer for translated password */ + if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL) + return -1; + /* first try, test password translated "standard" charset */ + r = testkey(__G__ h, STR_TO_CP1(key_translated, GLOBAL(key))); +#else /* !STR_TO_CP1 */ + /* first try, test password as supplied on the extractor's host */ + r = testkey(__G__ h, GLOBAL(key)); +#endif /* ?STR_TO_CP1 */ + +#ifdef STR_TO_CP2 + if (r != 0) { +#ifndef STR_TO_CP1 + /* now prepare for second (and maybe third) test with translated pwd */ + if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL) + return -1; +#endif + /* second try, password translated to alternate ("standard") charset */ + r = testkey(__G__ h, STR_TO_CP2(key_translated, GLOBAL(key))); +#ifdef STR_TO_CP3 + if (r != 0) + /* third try, password translated to another "standard" charset */ + r = testkey(__G__ h, STR_TO_CP3(key_translated, GLOBAL(key))); +#endif +#ifndef STR_TO_CP1 + free(key_translated); +#endif + } +#endif /* STR_TO_CP2 */ + +#ifdef STR_TO_CP1 + free(key_translated); + if (r != 0) { + /* last resort, test password as supplied on the extractor's host */ + r = testkey(__G__ h, GLOBAL(key)); + } +#endif /* STR_TO_CP1 */ + + return r; + +} /* end function testp() */ + + +local int testkey(__G__ h, key) + __GDEF + ZCONST uch *h; /* decrypted header */ + ZCONST char *key; /* decryption password to test */ +{ + ush b; +#ifdef ZIP10 + ush c; +#endif + int n; + uch *p; + uch hh[RAND_HEAD_LEN]; /* decrypted header */ + + /* set keys and save the encrypted header */ + init_keys(__G__ key); + memcpy(hh, h, RAND_HEAD_LEN); + + /* check password */ + for (n = 0; n < RAND_HEAD_LEN; n++) { + zdecode(hh[n]); + Trace((stdout, " %02x", hh[n])); + } + + Trace((stdout, + "\n lrec.crc= %08lx crec.crc= %08lx pInfo->ExtLocHdr= %s\n", + GLOBAL(lrec.crc32), GLOBAL(pInfo->crc), + GLOBAL(pInfo->ExtLocHdr) ? "true":"false")); + Trace((stdout, " incnt = %d unzip offset into zipfile = %ld\n", + GLOBAL(incnt), + GLOBAL(cur_zipfile_bufstart)+(GLOBAL(inptr)-GLOBAL(inbuf)))); + + /* same test as in zipbare(): */ + +#ifdef ZIP10 /* check two bytes */ + c = hh[RAND_HEAD_LEN-2], b = hh[RAND_HEAD_LEN-1]; + Trace((stdout, + " (c | (b<<8)) = %04x (crc >> 16) = %04x lrec.time = %04x\n", + (ush)(c | (b<<8)), (ush)(GLOBAL(lrec.crc32) >> 16), + ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff)))); + if ((ush)(c | (b<<8)) != (GLOBAL(pInfo->ExtLocHdr) ? + ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff) : + (ush)(GLOBAL(lrec.crc32) >> 16))) + return -1; /* bad */ +#else + b = hh[RAND_HEAD_LEN-1]; + Trace((stdout, " b = %02x (crc >> 24) = %02x (lrec.time >> 8) = %02x\n", + b, (ush)(GLOBAL(lrec.crc32) >> 24), + ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff)); + if (b != (GLOBAL(pInfo->ExtLocHdr) ? + ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff : + (ush)(GLOBAL(lrec.crc32) >> 24))) + return -1; /* bad */ +#endif + /* password OK: decrypt current buffer contents before leaving */ + for (n = (long)GLOBAL(incnt) > GLOBAL(csize) ? + (int)GLOBAL(csize) : GLOBAL(incnt), + p = GLOBAL(inptr); n--; p++) + zdecode(*p); + return 0; /* OK */ + +} /* end function testkey() */ + +#endif /* UNZIP && !FUNZIP */ + +#else /* !CRYPT */ + +/* something "externally visible" to shut up compiler/linker warnings */ +int zcr_dummy; + +#endif /* ?CRYPT */ diff --git a/third_party/unzip/crypt.h b/third_party/unzip/crypt.h new file mode 100644 index 000000000..c5caf8fdf --- /dev/null +++ b/third_party/unzip/crypt.h @@ -0,0 +1,171 @@ +// clang-format off +/* + Copyright (c) 1990-2007 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2005-Feb-10 or later + (the contents of which are also included in (un)zip.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 +*/ +/* + crypt.h (full version) by Info-ZIP. Last revised: [see CR_VERSION_DATE] + + The main encryption/decryption source code for Info-Zip software was + originally written in Europe. To the best of our knowledge, it can + be freely distributed in both source and object forms from any country, + including the USA under License Exception TSU of the U.S. Export + Administration Regulations (section 740.13(e)) of 6 June 2002. + + NOTE on copyright history: + Previous versions of this source package (up to version 2.8) were + not copyrighted and put in the public domain. If you cannot comply + with the Info-Zip LICENSE, you may want to look for one of those + public domain versions. + */ + +#ifndef __crypt_h /* don't include more than once */ +#define __crypt_h +#include "third_party/unzip/crc32.h" + +#ifdef CRYPT +# undef CRYPT +#endif +/* + Logic of selecting "full crypt" code: + a) default behaviour: + - dummy crypt code when compiling UnZipSFX stub, to minimize size + - full crypt code when used to compile Zip, UnZip and fUnZip + b) USE_CRYPT defined: + - always full crypt code + c) NO_CRYPT defined: + - never full crypt code + NO_CRYPT takes precedence over USE_CRYPT + */ +#if defined(NO_CRYPT) +# define CRYPT 0 /* dummy version */ +#else +#if defined(USE_CRYPT) +# define CRYPT 1 /* full version */ +#else +#if !defined(SFX) +# define CRYPT 1 /* full version for zip and main unzip */ +#else +# define CRYPT 0 /* dummy version for unzip sfx */ +#endif +#endif /* ?USE_CRYPT */ +#endif /* ?NO_CRYPT */ + +#if CRYPT +/* full version */ + +#ifdef CR_BETA +# undef CR_BETA /* this is not a beta release */ +#endif + +#define CR_MAJORVER 2 +#define CR_MINORVER 11 +#ifdef CR_BETA +# define CR_BETA_VER "c BETA" +# define CR_VERSION_DATE "05 Jan 2007" /* last real code change */ +#else +# define CR_BETA_VER "" +# define CR_VERSION_DATE "05 Jan 2007" /* last public release date */ +# define CR_RELEASE +#endif + +#ifndef __G /* UnZip only, for now (DLL stuff) */ +# define __G +# define __G__ +# define __GDEF +# define __GPRO void +# define __GPRO__ +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) +# ifndef DOS_OS2_W32 +# define DOS_OS2_W32 +# endif +#endif + +#if defined(DOS_OS2_W32) || defined(__human68k__) +# ifndef DOS_H68_OS2_W32 +# define DOS_H68_OS2_W32 +# endif +#endif + +#if defined(VM_CMS) || defined(MVS) +# ifndef CMS_MVS +# define CMS_MVS +# endif +#endif + +/* To allow combining of Zip and UnZip static libraries in a single binary, + * the Zip and UnZip versions of the crypt core functions have to be named + * differently. + */ +#ifdef ZIP +# ifdef REALLY_SHORT_SYMS +# define decrypt_byte zdcrby +# else +# define decrypt_byte zp_decrypt_byte +# endif +# define update_keys zp_update_keys +# define init_keys zp_init_keys +#else /* !ZIP */ +# ifdef REALLY_SHORT_SYMS +# define decrypt_byte dcrbyt +# endif +#endif /* ?ZIP */ + +#define IZ_PWLEN 80 /* input buffer size for reading encryption key */ +#ifndef PWLEN /* for compatibility with previous zcrypt release... */ +# define PWLEN IZ_PWLEN +#endif +#define RAND_HEAD_LEN 12 /* length of encryption random header */ + +/* the crc_32_tab array has to be provided externally for the crypt calculus */ + +/* encode byte c, using temp t. Warning: c must not have side effects. */ +#define zencode(c,t) (t=decrypt_byte(__G), update_keys(c), t^(c)) + +/* decode byte c in place */ +#define zdecode(c) update_keys(__G__ c ^= decrypt_byte(__G)) + +int decrypt_byte OF((__GPRO)); +int update_keys OF((__GPRO__ int c)); +void init_keys OF((__GPRO__ ZCONST char *passwd)); + +#ifdef ZIP + void crypthead OF((ZCONST char *, ulg, FILE *)); +# ifdef UTIL + int zipcloak OF((struct zlist far *, FILE *, FILE *, ZCONST char *)); + int zipbare OF((struct zlist far *, FILE *, FILE *, ZCONST char *)); +# else + unsigned zfwrite OF((zvoid *, extent, extent, FILE *)); + extern char *key; +# endif +#endif /* ZIP */ + +#if (defined(UNZIP) && !defined(FUNZIP)) + int decrypt OF((__GPRO__ ZCONST char *passwrd)); +#endif + +#ifdef FUNZIP + extern int encrypted; +# ifdef NEXTBYTE +# undef NEXTBYTE +# endif +# define NEXTBYTE \ + (encrypted? update_keys(__G__ getc(G.in)^decrypt_byte(__G)) : getc(G.in)) +#endif /* FUNZIP */ + +#else /* !CRYPT */ +/* dummy version */ + +#define zencode +#define zdecode + +#define zfwrite fwrite + +#endif /* ?CRYPT */ +#endif /* !__crypt_h */ diff --git a/third_party/unzip/ebcdic.h b/third_party/unzip/ebcdic.h new file mode 100644 index 000000000..407b0bd08 --- /dev/null +++ b/third_party/unzip/ebcdic.h @@ -0,0 +1,298 @@ +// clang-format off +/* + Copyright (c) 1990-2008 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.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 +*/ +/*--------------------------------------------------------------------------- + + ebcdic.h + + The CECP 1047 (Extended de-facto EBCDIC) <-> ISO 8859-1 conversion tables, + from ftp://aix1.segi.ulg.ac.be/pub/docs/iso8859/iso8859.networking + + NOTES: + (OS/390 port 12/97) + These table no longer represent the standard mappings (for example in the + OS/390 iconv utility). In order to follow current standards I remapped + ebcdic x0a to ascii x15 and + ebcdic x85 to ascii x25 (and vice-versa) + Without these changes, newlines in auto-convert text files appeared + as literal \045. + I'm not sure what effect this remap would have on the MVS and CMS ports, so + I ifdef'd these changes. Hopefully these ifdef's can be removed when the + MVS/CMS folks test the new mappings. + + Christian Spieler , 27-Apr-1998 + The problem mentioned by Paul von Behren was already observed previously + on VM/CMS, during the preparation of the CMS&MVS port of UnZip 5.20 in + 1996. At that point, the ebcdic tables were not changed since they seemed + to be an adopted standard (to my knowledge, these tables are still used + as presented in mainfraime KERMIT). Instead, the "end-of-line" conversion + feature of Zip's and UnZip's "text-translation" mode was used to force + correct mappings between ASCII and EBCDIC newline markers. + Before interchanging the ASCII mappings of the EBCDIC control characters + "NL" 0x25 and "LF" 0x15 according to the OS/390 setting, we have to + make sure that EBCDIC 0x15 is never used as line termination. + + ---------------------------------------------------------------------------*/ + +#ifndef __ebcdic_h /* prevent multiple inclusions */ +#define __ebcdic_h + + +#ifndef ZCONST +# define ZCONST const +#endif + +#ifdef EBCDIC +#ifndef MTS /* MTS uses a slightly "special" EBCDIC code page */ + +ZCONST uch ebcdic[] = { + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, /* 00 - 07 */ +#ifdef OS390 + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */ +#else + 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */ +#endif + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, /* 10 - 17 */ + 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, /* 18 - 1F */ + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 20 - 27 */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, /* 28 - 2F */ + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, /* 30 - 37 */ + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, /* 38 - 3F */ + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 40 - 47 */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, /* 48 - 4F */ + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, /* 50 - 57 */ + 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, /* 58 - 5F */ + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60 - 67 */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* 68 - 6F */ + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, /* 70 - 77 */ + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, /* 78 - 7F */ +#ifdef OS390 + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x06, 0x17, /* 80 - 87 */ +#else + 0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, /* 80 - 87 */ +#endif + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B, /* 88 - 8F */ + 0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, /* 90 - 97 */ + 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF, /* 98 - 9F */ + 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, /* A0 - A7 */ + 0xBB, 0xB4, 0x9A, 0x8A, 0xB0, 0xCA, 0xAF, 0xBC, /* A8 - AF */ + 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, /* B0 - B7 */ + 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, /* B8 - BF */ + 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, /* C0 - C7 */ + 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, /* C8 - CF */ + 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, /* D0 - D7 */ + 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xBA, 0xAE, 0x59, /* D8 - DF */ + 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, /* E0 - E7 */ + 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, /* E8 - EF */ + 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, /* F0 - F7 */ + 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF /* F8 - FF */ +}; + +#if (defined(ZIP) || CRYPT) +ZCONST uch ascii[] = { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, /* 00 - 07 */ + 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */ +#ifdef OS390 + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x0A, 0x08, 0x87, /* 10 - 17 */ +#else + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, /* 10 - 17 */ +#endif + 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, /* 18 - 1F */ +#ifdef OS390 + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1B, /* 20 - 27 */ +#else + 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, /* 20 - 27 */ +#endif + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, /* 28 - 2F */ + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, /* 30 - 37 */ + 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, /* 38 - 3F */ + 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, /* 40 - 47 */ + 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, /* 48 - 4F */ + 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, /* 50 - 57 */ + 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, /* 58 - 5F */ + 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, /* 60 - 67 */ + 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, /* 68 - 6F */ + 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, /* 70 - 77 */ + 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, /* 78 - 7F */ + 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 80 - 87 */ + 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, /* 88 - 8F */ + 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, /* 90 - 97 */ + 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, /* 98 - 9F */ + 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, /* A0 - A7 */ + 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE, /* A8 - AF */ + 0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, /* B0 - B7 */ + 0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7, /* B8 - BF */ + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* C0 - C7 */ + 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, /* C8 - CF */ + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, /* D0 - D7 */ + 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, /* D8 - DF */ + 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* E0 - E7 */ + 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, /* E8 - EF */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* F0 - F7 */ + 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F /* F8 - FF */ +}; +#endif /* ZIP || CRYPT */ + +#else /* MTS */ + +/* + * This is the MTS ASCII->EBCDIC translation table. It provides a 1-1 + * translation from ISO 8859/1 8-bit ASCII to IBM Code Page 37 EBCDIC. + */ + +ZCONST uch ebcdic[] = { + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, /* 00 - 07 */ + 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */ + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, /* 10 - 17 */ + 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, /* 18 - 1F */ + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 20 - 27 */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, /* 28 - 2F */ + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, /* 30 - 37 */ + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, /* 38 - 3F */ + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 40 - 47 */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, /* 48 - 4F */ + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, /* 50 - 57 */ + 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, /* 58 - 5F */ + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60 - 67 */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* 68 - 6F */ + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, /* 70 - 77 */ + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, /* 78 - 7F */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, /* 80 - 87 */ + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B, /* 88 - 8F */ + 0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, /* 90 - 97 */ + 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF, /* 98 - 9F */ + 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, /* A0 - A7 */ + 0xBD, 0xB4, 0x9A, 0x8A, 0x5F, 0xCA, 0xAF, 0xBC, /* A8 - AF */ + 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, /* B0 - B7 */ + 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, /* B8 - BF */ + 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, /* C0 - C7 */ + 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, /* C8 - CF */ + 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, /* D0 - D7 */ + 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xAD, 0xAE, 0x59, /* D8 - DF */ + 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, /* E0 - E7 */ + 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, /* E8 - EF */ + 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, /* F0 - F7 */ + 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF /* F8 - FF */ +}; + +#if (defined(ZIP) || CRYPT) +ZCONST uch ascii[] = { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, /* 00 - 07 */ + 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */ + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, /* 10 - 17 */ + 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, /* 18 - 1F */ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, /* 20 - 27 */ + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, /* 28 - 2F */ + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, /* 30 - 37 */ + 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, /* 38 - 3F */ + 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, /* 40 - 47 */ + 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, /* 48 - 4F */ + 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, /* 50 - 57 */ + 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC, /* 58 - 5F */ + 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, /* 60 - 67 */ + 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, /* 68 - 6F */ + 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, /* 70 - 77 */ + 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, /* 78 - 7F */ + 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 80 - 87 */ + 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, /* 88 - 8F */ + 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, /* 90 - 97 */ + 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, /* 98 - 9F */ + 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, /* A0 - A7 */ + 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE, /* A8 - AF */ + 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, /* B0 - B7 */ + 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7, /* B8 - BF */ + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* C0 - C7 */ + 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, /* C8 - CF */ + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, /* D0 - D7 */ + 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, /* D8 - DF */ + 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* E0 - E7 */ + 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, /* E8 - EF */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* F0 - F7 */ + 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F /* F8 - FF */ +}; +#endif /* ZIP || CRYPT */ + +#endif /* ?MTS */ +#endif /* EBCDIC */ + +/*--------------------------------------------------------------------------- + + The following conversion tables translate between IBM PC CP 850 + (OEM codepage) and the "Western Europe & America" Windows codepage 1252. + The Windows codepage 1252 contains the ISO 8859-1 "Latin 1" codepage, + with some additional printable characters in the range (0x80 - 0x9F), + that is reserved to control codes in the ISO 8859-1 character table. + + The ISO <--> OEM conversion tables were constructed with the help + of the WIN32 (Win16?) API's OemToAnsi() and AnsiToOem() conversion + functions and have been checked against the CP850 and LATIN1 tables + provided in the MS-Kermit 3.14 distribution. + + ---------------------------------------------------------------------------*/ + +#ifdef IZ_ISO2OEM_ARRAY +ZCONST uch Far iso2oem_850[] = { + 0x3F, 0x3F, 0x27, 0x9F, 0x22, 0x2E, 0xC5, 0xCE, /* 80 - 87 */ + 0x5E, 0x25, 0x53, 0x3C, 0x4F, 0x3F, 0x3F, 0x3F, /* 88 - 8F */ + 0x3F, 0x27, 0x27, 0x22, 0x22, 0x07, 0x2D, 0x2D, /* 90 - 97 */ + 0x7E, 0x54, 0x73, 0x3E, 0x6F, 0x3F, 0x3F, 0x59, /* 98 - 9F */ + 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, /* A0 - A7 */ + 0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE, /* A8 - AF */ + 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, /* B0 - B7 */ + 0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8, /* B8 - BF */ + 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, /* C0 - C7 */ + 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, /* C8 - CF */ + 0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, /* D0 - D7 */ + 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, /* D8 - DF */ + 0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, /* E0 - E7 */ + 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, /* E8 - EF */ + 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, /* F0 - F7 */ + 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 /* F8 - FF */ +}; +#endif /* IZ_ISO2OEM_ARRAY */ + +#ifdef IZ_OEM2ISO_ARRAY +ZCONST uch Far oem2iso_850[] = { + 0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7, /* 80 - 87 */ + 0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5, /* 88 - 8F */ + 0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9, /* 90 - 97 */ + 0xFF, 0xD6, 0xDC, 0xF8, 0xA3, 0xD8, 0xD7, 0x83, /* 98 - 9F */ + 0xE1, 0xED, 0xF3, 0xFA, 0xF1, 0xD1, 0xAA, 0xBA, /* A0 - A7 */ + 0xBF, 0xAE, 0xAC, 0xBD, 0xBC, 0xA1, 0xAB, 0xBB, /* A8 - AF */ + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xC1, 0xC2, 0xC0, /* B0 - B7 */ + 0xA9, 0xA6, 0xA6, 0x2B, 0x2B, 0xA2, 0xA5, 0x2B, /* B8 - BF */ + 0x2B, 0x2D, 0x2D, 0x2B, 0x2D, 0x2B, 0xE3, 0xC3, /* C0 - C7 */ + 0x2B, 0x2B, 0x2D, 0x2D, 0xA6, 0x2D, 0x2B, 0xA4, /* C8 - CF */ + 0xF0, 0xD0, 0xCA, 0xCB, 0xC8, 0x69, 0xCD, 0xCE, /* D0 - D7 */ + 0xCF, 0x2B, 0x2B, 0xA6, 0x5F, 0xA6, 0xCC, 0xAF, /* D8 - DF */ + 0xD3, 0xDF, 0xD4, 0xD2, 0xF5, 0xD5, 0xB5, 0xFE, /* E0 - E7 */ + 0xDE, 0xDA, 0xDB, 0xD9, 0xFD, 0xDD, 0xAF, 0xB4, /* E8 - EF */ + 0xAD, 0xB1, 0x3D, 0xBE, 0xB6, 0xA7, 0xF7, 0xB8, /* F0 - F7 */ + 0xB0, 0xA8, 0xB7, 0xB9, 0xB3, 0xB2, 0xA6, 0xA0 /* F8 - FF */ +}; +#endif /* IZ_OEM2ISO_ARRAY */ + +/* The following pointers to the OEM<-->ISO translation tables are used + by the translation code portions. They may get initialized at program + startup to point to the matching static translation tables, or to NULL + to disable OEM-ISO translation. + The compile-time initialization used here provides the backward compatible + setting, as can be found in UnZip 5.52 and earlier. + In case this mechanism will ever get used on a multithreading system that + allows different codepage setups for concurrently running threads, these + pointers should get moved into UnZip's thread-safe global data structure. + */ +#ifdef IZ_ISO2OEM_ARRAY +ZCONST uch Far *iso2oem = iso2oem_850; /* backward compatibility default */ +#endif /* IZ_ISO2OEM_ARRAY */ +#ifdef IZ_OEM2ISO_ARRAY +ZCONST uch Far *oem2iso = oem2iso_850; /* backward compatibility default */ +#endif /* IZ_OEM2ISO_ARRAY */ + +#endif /* __ebcdic_h */ diff --git a/third_party/unzip/envargs.c b/third_party/unzip/envargs.c new file mode 100644 index 000000000..49ff6ace9 --- /dev/null +++ b/third_party/unzip/envargs.c @@ -0,0 +1,318 @@ +// clang-format off +/* + Copyright (c) 1990-2005 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 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 +*/ +/*----------------------------------------------------------------* + | envargs - add default options from environment to command line + |---------------------------------------------------------------- + | Author: Bill Davidsen, original 10/13/91, revised 23 Oct 1991. + | This program is in the public domain. + |---------------------------------------------------------------- + | Minor program notes: + | 1. Yes, the indirection is a tad complex + | 2. Parentheses were added where not needed in some cases + | to make the action of the code less obscure. + |---------------------------------------------------------------- + | UnZip notes: 24 May 92 ("v1.4"): + | 1. #include "third_party/unzip/unzip.h" for prototypes (24 May 92) + | 2. changed ch to type char (24 May 92) + | 3. added an ifdef to avoid Borland warnings (24 May 92) + | 4. included Rich Wales' mksargs() routine (for MS-DOS, maybe + | OS/2? NT?) (4 Dec 93) + | 5. added alternate-variable string envstr2 (21 Apr 94) + | 6. added support for quoted arguments (6 Jul 96) + *----------------------------------------------------------------*/ + + +#define __ENVARGS_C /* identifies this source module */ +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" + +#ifdef __EMX__ /* emx isspace() returns TRUE on extended ASCII !! */ +# define ISspace(c) ((c) & 0x80 ? 0 : isspace((unsigned)c)) +#else +# define ISspace(c) isspace((unsigned)c) +#endif /* ?__EMX__ */ + +#if (!defined(RISCOS) && (!defined(MODERN) || defined(NO_STDLIB_H))) +extern char *getenv(); +#endif +static int count_args OF((ZCONST char *)); + + +/* envargs() returns PK-style error code */ + +int envargs(Pargc, Pargv, envstr, envstr2) + int *Pargc; + char ***Pargv; + ZCONST char *envstr, *envstr2; +{ + char *envptr; /* value returned by getenv */ + char *bufptr; /* copy of env info */ + int argc = 0; /* internal arg count */ + register int ch; /* spare temp value */ + char **argv; /* internal arg vector */ + char **argvect; /* copy of vector address */ + + /* see if anything in the environment */ + if ((envptr = getenv(envstr)) != (char *)NULL) /* usual var */ + while (ISspace(*envptr)) /* must discard leading spaces */ + envptr++; + if (envptr == (char *)NULL || *envptr == '\0') + if ((envptr = getenv(envstr2)) != (char *)NULL) /* alternate var */ + while (ISspace(*envptr)) + envptr++; + if (envptr == (char *)NULL || *envptr == '\0') + return PK_OK; + + bufptr = malloc(1 + strlen(envptr)); + if (bufptr == (char *)NULL) + return PK_MEM; +#if ((defined(WIN32) || defined(WINDLL)) && !defined(_WIN32_WCE)) +# ifdef WIN32 + if (IsWinNT()) { + /* SPC: don't know codepage of 'real' WinNT console */ + strcpy(bufptr, envptr); + } else { + /* Win95 environment is DOS and uses OEM character coding */ + OEM_TO_INTERN(envptr, bufptr); + } +# else /* !WIN32 */ + /* DOS (Win 3.x) environment uses OEM codepage */ + OEM_TO_INTERN(envptr, bufptr); +# endif +#else /* !((WIN32 || WINDLL) && !_WIN32_WCE) */ + strcpy(bufptr, envptr); +#endif /* ?((WIN32 || WINDLL) && !_WIN32_WCE) */ + + /* count the args so we can allocate room for them */ + argc = count_args(bufptr); + /* allocate a vector large enough for all args */ + argv = (char **)malloc((argc + *Pargc + 1) * sizeof(char *)); + if (argv == (char **)NULL) { + free(bufptr); + return PK_MEM; + } + argvect = argv; + + /* copy the program name first, that's always true */ + *(argv++) = *((*Pargv)++); + + /* copy the environment args next, may be changed */ + do { +#if defined(AMIGA) || defined(UNIX) + if (*bufptr == '"') { + char *argstart = ++bufptr; + + *(argv++) = argstart; + for (ch = *bufptr; ch != '\0' && ch != '\"'; + ch = *PREINCSTR(bufptr)) + if (ch == '\\' && bufptr[1] != '\0') + ++bufptr; /* advance to char after backslash */ + if (ch != '\0') + *(bufptr++) = '\0'; /* overwrite trailing " */ + + /* remove escape characters */ + while ((argstart = MBSCHR(argstart, '\\')) != (char *)NULL) { + strcpy(argstart, argstart + 1); + if (*argstart) + ++argstart; + } + } else { + *(argv++) = bufptr; + while ((ch = *bufptr) != '\0' && !ISspace(ch)) + INCSTR(bufptr); + if (ch != '\0') + *(bufptr++) = '\0'; + } +#else +#ifdef DOS_FLX_NLM_OS2_W32 + /* we do not support backslash-quoting of quotes in quoted + * strings under DOS_FLX_NLM_OS2_W32, because backslashes are + * directory separators and double quotes are illegal in filenames */ + if (*bufptr == '"') { + *(argv++) = ++bufptr; + while ((ch = *bufptr) != '\0' && ch != '\"') + INCSTR(bufptr); + if (ch != '\0') + *(bufptr++) = '\0'; + } else { + *(argv++) = bufptr; + while ((ch = *bufptr) != '\0' && !ISspace(ch)) + INCSTR(bufptr); + if (ch != '\0') + *(bufptr++) = '\0'; + } +#else + *(argv++) = bufptr; + while ((ch = *bufptr) != '\0' && !ISspace(ch)) + INCSTR(bufptr); + if (ch != '\0') + *(bufptr++) = '\0'; +#endif /* ?DOS_FLX_NLM_OS2_W32 */ +#endif /* ?(AMIGA || UNIX) */ + while ((ch = *bufptr) != '\0' && ISspace(ch)) + INCSTR(bufptr); + } while (ch); + + /* now save old argc and copy in the old args */ + argc += *Pargc; + while (--(*Pargc)) + *(argv++) = *((*Pargv)++); + + /* finally, add a NULL after the last arg, like Unix */ + *argv = (char *)NULL; + + /* save the values and return, indicating succes */ + *Pargv = argvect; + *Pargc = argc; + + return PK_OK; +} + + + +static int count_args(s) + ZCONST char *s; +{ + int count = 0; + char ch; + + do { + /* count and skip args */ + ++count; +#if defined(AMIGA) || defined(UNIX) + if (*s == '\"') { + for (ch = *PREINCSTR(s); ch != '\0' && ch != '\"'; + ch = *PREINCSTR(s)) + if (ch == '\\' && s[1] != '\0') + ++s; + if (*s) + ++s; /* trailing quote */ + } else +#else +#ifdef DOS_FLX_NLM_OS2_W32 + if (*s == '\"') { + ++s; /* leading quote */ + while ((ch = *s) != '\0' && ch != '\"') + INCSTR(s); + if (*s) + ++s; /* trailing quote */ + } else +#endif /* DOS_FLX_NLM_OS2_W32 */ +#endif /* ?(AMIGA || UNIX) */ + while ((ch = *s) != '\0' && !ISspace(ch)) /* note else-clauses above */ + INCSTR(s); + while ((ch = *s) != '\0' && ISspace(ch)) + INCSTR(s); + } while (ch); + + return count; +} + + + +#ifdef TEST + +int main(argc, argv) + int argc; + char **argv; +{ + int err; + + printf("Orig argv: %p\n", argv); + dump_args(argc, argv); + if ((err = envargs(&argc, &argv, "ENVTEST")) != PK_OK) { + perror("envargs: cannot get memory for arguments"); + EXIT(err); + } + printf(" New argv: %p\n", argv); + dump_args(argc, argv); +} + + + +void dump_args(argc, argv) + int argc; + char *argv[]; +{ + int i; + + printf("\nDump %d args:\n", argc); + for (i = 0; i < argc; ++i) + printf("%3d %s\n", i, argv[i]); +} + +#endif /* TEST */ + + + +#ifdef MSDOS /* DOS_OS2? DOS_OS2_W32? */ + +/* + * void mksargs(int *argcp, char ***argvp) + * + * Substitutes the extended command line argument list produced by + * the MKS Korn Shell in place of the command line info from DOS. + * + * The MKS shell gets around DOS's 128-byte limit on the length of + * a command line by passing the "real" command line in the envi- + * ronment. The "real" arguments are flagged by prepending a tilde + * (~) to each one. + * + * This "mksargs" routine creates a new argument list by scanning + * the environment from the beginning, looking for strings begin- + * ning with a tilde character. The new list replaces the original + * "argv" (pointed to by "argvp"), and the number of arguments + * in the new list replaces the original "argc" (pointed to by + * "argcp"). + * + * Rich Wales + */ +void mksargs(argcp, argvp) + int *argcp; + char ***argvp; +{ +#ifndef MSC /* declared differently in MSC 7.0 headers, at least */ +#ifndef __WATCOMC__ + extern char **environ; /* environment */ +#endif +#endif + char **envp; /* pointer into environment */ + char **newargv; /* new argument list */ + char **argp; /* pointer into new arg list */ + int newargc; /* new argument count */ + + /* sanity check */ + if (environ == NULL || argcp == NULL || argvp == NULL || *argvp == NULL) + return; + + /* find out how many environment arguments there are */ + for (envp = environ, newargc = 0; + *envp != NULL && (*envp)[0] == '~'; + envp++, newargc++) + ; + if (newargc == 0) + return; /* no environment arguments */ + + /* set up new argument list */ + newargv = (char **) malloc(sizeof(char **) * (newargc+1)); + if (newargv == NULL) + return; /* malloc failed */ + + for (argp = newargv, envp = environ; *envp != NULL && (*envp)[0] == '~'; + *argp++ = &(*envp++)[1]) + ; + *argp = NULL; /* null-terminate the list */ + + /* substitute new argument list in place of old one */ + *argcp = newargc; + *argvp = newargv; +} + +#endif /* MSDOS */ diff --git a/third_party/unzip/explode.c b/third_party/unzip/explode.c new file mode 100644 index 000000000..6397f1f79 --- /dev/null +++ b/third_party/unzip/explode.c @@ -0,0 +1,618 @@ +// clang-format off +/* + Copyright (c) 1990-2007 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2007-Mar-04 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 +*/ +/* explode.c -- by Mark Adler + version c17d, 01 December 2007 */ + + +/* Copyright history: + - Starting with UnZip 5.41 of 16-April-2000, this source file + is covered by the Info-Zip LICENSE cited above. + - Prior versions of this source file, found in UnZip source packages + up to UnZip 5.40, were put in the public domain. + The original copyright note by Mark Adler was: + "You can do whatever you like with this source file, + though I would prefer that if you modify it and + redistribute it that you include comments to that effect + with your name and the date. Thank you." + + History: + vers date who what + ---- --------- -------------- ------------------------------------ + c1 30 Mar 92 M. Adler explode that uses huft_build from inflate + (this gives over a 70% speed improvement + over the original unimplode.c, which + decoded a bit at a time) + c2 4 Apr 92 M. Adler fixed bug for file sizes a multiple of 32k. + c3 10 Apr 92 M. Adler added a little memory tracking if DEBUG + c4 11 Apr 92 M. Adler added NOMEMCPY do kill use of memcpy() + c5 21 Apr 92 M. Adler added the WSIZE #define to allow reducing + the 32K window size for specialized + applications. + c6 31 May 92 M. Adler added typecasts to eliminate some warnings + c7 27 Jun 92 G. Roelofs added more typecasts. + c8 17 Oct 92 G. Roelofs changed ULONG/UWORD/byte to ulg/ush/uch. + c9 19 Jul 93 J. Bush added more typecasts (to return values); + made l[256] array static for Amiga. + c10 8 Oct 93 G. Roelofs added used_csize for diagnostics; added + buf and unshrink arguments to flush(); + undef'd various macros at end for Turbo C; + removed NEXTBYTE macro (now in unzip.h) + and bytebuf variable (not used); changed + memset() to memzero(). + c11 9 Jan 94 M. Adler fixed incorrect used_csize calculation. + c12 9 Apr 94 G. Roelofs fixed split comments on preprocessor lines + to avoid bug in Encore compiler. + c13 25 Aug 94 M. Adler fixed distance-length comment (orig c9 fix) + c14 22 Nov 95 S. Maxwell removed unnecessary "static" on auto array + c15 6 Jul 96 W. Haidinger added ulg typecasts to flush() calls. + c16 8 Feb 98 C. Spieler added ZCONST modifiers to const tables + and #ifdef DEBUG around debugging code. + c16b 25 Mar 98 C. Spieler modified DLL code for slide redirection. + c16d 05 Jul 99 C. Spieler take care of flush() return values and + stop processing in case of errors + c17 04 Feb 01 C. Spieler reorganized code to reduce repetitions + of large code parts; adapted huft decoding + to the changes in inflate's huft_build() + due to support of deflate64; fixed memory + leaks (huft tables were not free'd when + get_tree() failed). + c17b 16 Feb 02 C. Spieler changed type of the "extra lengths" array + "extra" from ush into uch (to save space) + c17c 10 Aug 04 NN file sizes use zoff_t. + c17d 01 Dec 07 C. Spieler type for file sizes changed from zoff_t + into zusz_t. + */ + + +/* + Explode imploded (PKZIP method 6 compressed) data. This compression + method searches for as much of the current string of bytes (up to a length + of ~320) in the previous 4K or 8K bytes. If it doesn't find any matches + (of at least length 2 or 3), it codes the next byte. Otherwise, it codes + the length of the matched string and its distance backwards from the + current position. Single bytes ("literals") are preceded by a one (a + single bit) and are either uncoded (the eight bits go directly into the + compressed stream for a total of nine bits) or Huffman coded with a + supplied literal code tree. If literals are coded, then the minimum match + length is three, otherwise it is two. + + There are therefore four kinds of imploded streams: 8K search with coded + literals (min match = 3), 4K search with coded literals (min match = 3), + 8K with uncoded literals (min match = 2), and 4K with uncoded literals + (min match = 2). The kind of stream is identified in two bits of a + general purpose bit flag that is outside of the compressed stream. + + Distance-length pairs for matched strings are preceded by a zero bit (to + distinguish them from literals) and are always coded. The distance comes + first and is either the low six (4K) or low seven (8K) bits of the + distance (uncoded), followed by the high six bits of the distance coded. + Then the length is six bits coded (0..63 + min match length), and if the + maximum such length is coded, then it's followed by another eight bits + (uncoded) to be added to the coded length. This gives a match length + range of 2..320 or 3..321 bytes. + + The literal, length, and distance codes are all represented in a slightly + compressed form themselves. What is sent are the lengths of the codes for + each value, which is sufficient to construct the codes. Each byte of the + code representation is the code length (the low four bits representing + 1..16), and the number of values sequentially with that length (the high + four bits also representing 1..16). There are 256 literal code values (if + literals are coded), 64 length code values, and 64 distance code values, + in that order at the beginning of the compressed stream. Each set of code + values is preceded (redundantly) with a byte indicating how many bytes are + in the code description that follows, in the range 1..256. + + The codes themselves are decoded using tables made by huft_build() from + the bit lengths. That routine and its comments are in the inflate.c + module. + */ + +#define __EXPLODE_C /* identifies this source module */ +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" /* must supply slide[] (uch) array and NEXTBYTE macro */ + +#ifndef WSIZE +# define WSIZE 0x8000 /* window size--must be a power of two, and */ +#endif /* at least 8K for zip's implode method */ + +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) +# define wszimpl (unsigned)(G._wsize) +#else +# if defined(USE_DEFLATE64) && defined(INT_16BIT) +# define wszimpl (unsigned)(WSIZE>>1) +# else /* !(USE_DEFLATE64 && INT_16BIT) */ +# define wszimpl WSIZE +# endif /* !(USE_DEFLATE64 && INT_16BIT) */ +#endif + +/* routines here */ +static int get_tree OF((__GPRO__ unsigned *l, unsigned n)); +static int explode_lit OF((__GPRO__ struct huft *tb, struct huft *tl, + struct huft *td, unsigned bb, unsigned bl, + unsigned bd, unsigned bdl)); +static int explode_nolit OF((__GPRO__ struct huft *tl, struct huft *td, + unsigned bl, unsigned bd, unsigned bdl)); + + +/* The implode algorithm uses a sliding 4K or 8K byte window on the + uncompressed stream to find repeated byte strings. This is implemented + here as a circular buffer. The index is updated simply by incrementing + and then and'ing with 0x0fff (4K-1) or 0x1fff (8K-1). Here, the 32K + buffer of inflate is used, and it works just as well to always have + a 32K circular buffer, so the index is anded with 0x7fff. This is + done to allow the window to also be used as the output buffer. */ +/* This must be supplied in an external module useable like "uch slide[8192];" + or "uch *slide;", where the latter would be malloc'ed. In unzip, slide[] + is actually a 32K area for use by inflate, which uses a 32K sliding window. + */ + + +#define INVALID_CODE 99 +#define IS_INVALID_CODE(c) ((c) == INVALID_CODE) + +/* Tables for length and distance */ +static ZCONST ush cplen2[] = + {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65}; +static ZCONST ush cplen3[] = + {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66}; +static ZCONST uch extra[] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8}; +static ZCONST ush cpdist4[] = + {1, 65, 129, 193, 257, 321, 385, 449, 513, 577, 641, 705, + 769, 833, 897, 961, 1025, 1089, 1153, 1217, 1281, 1345, 1409, 1473, + 1537, 1601, 1665, 1729, 1793, 1857, 1921, 1985, 2049, 2113, 2177, + 2241, 2305, 2369, 2433, 2497, 2561, 2625, 2689, 2753, 2817, 2881, + 2945, 3009, 3073, 3137, 3201, 3265, 3329, 3393, 3457, 3521, 3585, + 3649, 3713, 3777, 3841, 3905, 3969, 4033}; +static ZCONST ush cpdist8[] = + {1, 129, 257, 385, 513, 641, 769, 897, 1025, 1153, 1281, + 1409, 1537, 1665, 1793, 1921, 2049, 2177, 2305, 2433, 2561, 2689, + 2817, 2945, 3073, 3201, 3329, 3457, 3585, 3713, 3841, 3969, 4097, + 4225, 4353, 4481, 4609, 4737, 4865, 4993, 5121, 5249, 5377, 5505, + 5633, 5761, 5889, 6017, 6145, 6273, 6401, 6529, 6657, 6785, 6913, + 7041, 7169, 7297, 7425, 7553, 7681, 7809, 7937, 8065}; + + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed. + */ + +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<>=(n);k-=(n);} + +#define DECODEHUFT(htab, bits, mask) {\ + NEEDBITS((unsigned)(bits))\ + t = (htab) + ((~(unsigned)b)&(mask));\ + while (1) {\ + DUMPBITS(t->b)\ + if ((e=t->e) <= 32) break;\ + if (IS_INVALID_CODE(e)) return 1;\ + e &= 31;\ + NEEDBITS(e)\ + t = t->v.t + ((~(unsigned)b)&mask_bits[e]);\ + }\ +} + + +static int get_tree(__G__ l, n) + __GDEF +unsigned *l; /* bit lengths */ +unsigned n; /* number expected */ +/* Get the bit lengths for a code representation from the compressed + stream. If get_tree() returns 4, then there is an error in the data. + Otherwise zero is returned. */ +{ + unsigned i; /* bytes remaining in list */ + unsigned k; /* lengths entered */ + unsigned j; /* number of codes */ + unsigned b; /* bit length for those codes */ + + + /* get bit lengths */ + i = NEXTBYTE + 1; /* length/count pairs to read */ + k = 0; /* next code */ + do { + b = ((j = NEXTBYTE) & 0xf) + 1; /* bits in code (1..16) */ + j = ((j & 0xf0) >> 4) + 1; /* codes with those bits (1..16) */ + if (k + j > n) + return 4; /* don't overflow l[] */ + do { + l[k++] = b; + } while (--j); + } while (--i); + return k != n ? 4 : 0; /* should have read n of them */ +} + + + +static int explode_lit(__G__ tb, tl, td, bb, bl, bd, bdl) + __GDEF +struct huft *tb, *tl, *td; /* literal, length, and distance tables */ +unsigned bb, bl, bd; /* number of bits decoded by those */ +unsigned bdl; /* number of distance low bits */ +/* Decompress the imploded data using coded literals and a sliding + window (of size 2^(6+bdl) bytes). */ +{ + zusz_t s; /* bytes to decompress */ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned mb, ml, md; /* masks for bb, bl, and bd bits */ + unsigned mdl; /* mask for bdl (distance lower) bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + unsigned u; /* true if unflushed */ + int retval = 0; /* error code returned: initialized to "no error" */ + + + /* explode the coded data */ + b = k = w = 0; /* initialize bit buffer, window */ + u = 1; /* buffer unflushed */ + mb = mask_bits[bb]; /* precompute masks for speed */ + ml = mask_bits[bl]; + md = mask_bits[bd]; + mdl = mask_bits[bdl]; + s = G.lrec.ucsize; + while (s > 0) /* do until ucsize bytes uncompressed */ + { + NEEDBITS(1) + if (b & 1) /* then literal--decode it */ + { + DUMPBITS(1) + s--; + DECODEHUFT(tb, bb, mb) /* get coded literal */ + redirSlide[w++] = (uch)t->v.n; + if (w == wszimpl) + { + if ((retval = flush(__G__ redirSlide, (ulg)w, 0)) != 0) + return retval; + w = u = 0; + } + } + else /* else distance/length */ + { + DUMPBITS(1) + NEEDBITS(bdl) /* get distance low bits */ + d = (unsigned)b & mdl; + DUMPBITS(bdl) + DECODEHUFT(td, bd, md) /* get coded distance high bits */ + d = w - d - t->v.n; /* construct offset */ + DECODEHUFT(tl, bl, ml) /* get coded length */ + n = t->v.n; + if (e) /* get length extra bits */ + { + NEEDBITS(8) + n += (unsigned)b & 0xff; + DUMPBITS(8) + } + + /* do the copy */ + s = (s > (zusz_t)n ? s - (zusz_t)n : 0); + do { +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) { + /* &= w/ wszimpl not needed and wrong if redirect */ + if (d >= wszimpl) + return 1; + e = wszimpl - (d > w ? d : w); + } else +#endif + e = wszimpl - ((d &= wszimpl-1) > w ? d : w); + if (e > n) e = n; + n -= e; + if (u && w <= d) + { + memzero(redirSlide + w, e); + w += e; + d += e; + } + else +#ifndef NOMEMCPY + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(redirSlide + w, redirSlide + d, e); + w += e; + d += e; + } + else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + redirSlide[w++] = redirSlide[d++]; + } while (--e); + if (w == wszimpl) + { + if ((retval = flush(__G__ redirSlide, (ulg)w, 0)) != 0) + return retval; + w = u = 0; + } + } while (n); + } + } + + /* flush out redirSlide */ + if ((retval = flush(__G__ redirSlide, (ulg)w, 0)) != 0) + return retval; + if (G.csize + G.incnt + (k >> 3)) /* should have read csize bytes, but */ + { /* sometimes read one too many: k>>3 compensates */ + G.used_csize = G.lrec.csize - G.csize - G.incnt - (k >> 3); + return 5; + } + return 0; +} + + + +static int explode_nolit(__G__ tl, td, bl, bd, bdl) + __GDEF +struct huft *tl, *td; /* length and distance decoder tables */ +unsigned bl, bd; /* number of bits decoded by tl[] and td[] */ +unsigned bdl; /* number of distance low bits */ +/* Decompress the imploded data using uncoded literals and a sliding + window (of size 2^(6+bdl) bytes). */ +{ + zusz_t s; /* bytes to decompress */ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + unsigned mdl; /* mask for bdl (distance lower) bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + unsigned u; /* true if unflushed */ + int retval = 0; /* error code returned: initialized to "no error" */ + + + /* explode the coded data */ + b = k = w = 0; /* initialize bit buffer, window */ + u = 1; /* buffer unflushed */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + mdl = mask_bits[bdl]; + s = G.lrec.ucsize; + while (s > 0) /* do until ucsize bytes uncompressed */ + { + NEEDBITS(1) + if (b & 1) /* then literal--get eight bits */ + { + DUMPBITS(1) + s--; + NEEDBITS(8) + redirSlide[w++] = (uch)b; + if (w == wszimpl) + { + if ((retval = flush(__G__ redirSlide, (ulg)w, 0)) != 0) + return retval; + w = u = 0; + } + DUMPBITS(8) + } + else /* else distance/length */ + { + DUMPBITS(1) + NEEDBITS(bdl) /* get distance low bits */ + d = (unsigned)b & mdl; + DUMPBITS(bdl) + DECODEHUFT(td, bd, md) /* get coded distance high bits */ + d = w - d - t->v.n; /* construct offset */ + DECODEHUFT(tl, bl, ml) /* get coded length */ + n = t->v.n; + if (e) /* get length extra bits */ + { + NEEDBITS(8) + n += (unsigned)b & 0xff; + DUMPBITS(8) + } + + /* do the copy */ + s = (s > (zusz_t)n ? s - (zusz_t)n : 0); + do { +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) { + /* &= w/ wszimpl not needed and wrong if redirect */ + if (d >= wszimpl) + return 1; + e = wszimpl - (d > w ? d : w); + } else +#endif + e = wszimpl - ((d &= wszimpl-1) > w ? d : w); + if (e > n) e = n; + n -= e; + if (u && w <= d) + { + memzero(redirSlide + w, e); + w += e; + d += e; + } + else +#ifndef NOMEMCPY + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(redirSlide + w, redirSlide + d, e); + w += e; + d += e; + } + else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + redirSlide[w++] = redirSlide[d++]; + } while (--e); + if (w == wszimpl) + { + if ((retval = flush(__G__ redirSlide, (ulg)w, 0)) != 0) + return retval; + w = u = 0; + } + } while (n); + } + } + + /* flush out redirSlide */ + if ((retval = flush(__G__ redirSlide, (ulg)w, 0)) != 0) + return retval; + if (G.csize + G.incnt + (k >> 3)) /* should have read csize bytes, but */ + { /* sometimes read one too many: k>>3 compensates */ + G.used_csize = G.lrec.csize - G.csize - G.incnt - (k >> 3); + return 5; + } + return 0; +} + + + +int explode(__G) + __GDEF +/* Explode an imploded compressed stream. Based on the general purpose + bit flag, decide on coded or uncoded literals, and an 8K or 4K sliding + window. Construct the literal (if any), length, and distance codes and + the tables needed to decode them (using huft_build() from inflate.c), + and call the appropriate routine for the type of data in the remainder + of the stream. The four routines are nearly identical, differing only + in whether the literal is decoded or simply read in, and in how many + bits are read in, uncoded, for the low distance bits. */ +{ + unsigned r; /* return codes */ + struct huft *tb; /* literal code table */ + struct huft *tl; /* length code table */ + struct huft *td; /* distance code table */ + unsigned bb; /* bits for tb */ + unsigned bl; /* bits for tl */ + unsigned bd; /* bits for td */ + unsigned bdl; /* number of uncoded lower distance bits */ + unsigned l[256]; /* bit lengths for codes */ + +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) + /* For 16-bit systems, it has already been checked at DLL entrance that + * the buffer size in G.redirect_size does not exceed unsigned range. + */ + G._wsize = G.redirect_size, redirSlide = G.redirect_buffer; + else +#if defined(USE_DEFLATE64) && defined(INT_16BIT) + /* For systems using 16-bit ints, reduce the used buffer size below + * the limit of "unsigned int" numbers range. + */ + G._wsize = WSIZE>>1, redirSlide = slide; +#else /* !(USE_DEFLATE64 && INT_16BIT) */ + G._wsize = WSIZE, redirSlide = slide; +#endif /* !(USE_DEFLATE64 && INT_16BIT) */ +#endif /* DLL && !NO_SLIDE_REDIR */ + + /* Tune base table sizes. Note: I thought that to truly optimize speed, + I would have to select different bl, bd, and bb values for different + compressed file sizes. I was surprised to find out that the values of + 7, 7, and 9 worked best over a very wide range of sizes, except that + bd = 8 worked marginally better for large compressed sizes. */ + bl = 7; + bd = (G.csize + G.incnt) > 200000L ? 8 : 7; + +#ifdef DEBUG + G.hufts = 0; /* initialize huft's malloc'ed */ +#endif + + if (G.lrec.general_purpose_bit_flag & 4) + /* With literal tree--minimum match length is 3 */ + { + bb = 9; /* base table size for literals */ + if ((r = get_tree(__G__ l, 256)) != 0) + return (int)r; + if ((r = huft_build(__G__ l, 256, 256, NULL, NULL, &tb, &bb)) != 0) + { + if (r == 1) + huft_free(tb); + return (int)r; + } + if ((r = get_tree(__G__ l, 64)) != 0) { + huft_free(tb); + return (int)r; + } + if ((r = huft_build(__G__ l, 64, 0, cplen3, extra, &tl, &bl)) != 0) + { + if (r == 1) + huft_free(tl); + huft_free(tb); + return (int)r; + } + } + else + /* No literal tree--minimum match length is 2 */ + { + tb = (struct huft *)NULL; + if ((r = get_tree(__G__ l, 64)) != 0) + return (int)r; + if ((r = huft_build(__G__ l, 64, 0, cplen2, extra, &tl, &bl)) != 0) + { + if (r == 1) + huft_free(tl); + return (int)r; + } + } + + if ((r = get_tree(__G__ l, 64)) != 0) { + huft_free(tl); + if (tb != (struct huft *)NULL) huft_free(tb); + return (int)r; + } + if (G.lrec.general_purpose_bit_flag & 2) /* true if 8K */ + { + bdl = 7; + r = huft_build(__G__ l, 64, 0, cpdist8, extra, &td, &bd); + } + else /* else 4K */ + { + bdl = 6; + r = huft_build(__G__ l, 64, 0, cpdist4, extra, &td, &bd); + } + if (r != 0) + { + if (r == 1) + huft_free(td); + huft_free(tl); + if (tb != (struct huft *)NULL) huft_free(tb); + return (int)r; + } + + if (tb != NULL) { + r = explode_lit(__G__ tb, tl, td, bb, bl, bd, bdl); + huft_free(tb); + } else { + r = explode_nolit(__G__ tl, td, bl, bd, bdl); + } + + huft_free(td); + huft_free(tl); + Trace((stderr, "<%u > ", G.hufts)); + return (int)r; +} + +/* so explode.c and inflate.c can be compiled together into one object: */ +#undef DECODEHUFT +#undef NEEDBITS +#undef DUMPBITS +#undef wszimpl diff --git a/third_party/unzip/extract.c b/third_party/unzip/extract.c new file mode 100644 index 000000000..39e85383a --- /dev/null +++ b/third_party/unzip/extract.c @@ -0,0 +1,3615 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 "third_party/unzip/unzip.h" +#include "third_party/unzip/crc32.h" +#include "libc/alg/alg.h" +#include "libc/log/log.h" +#include "third_party/unzip/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 +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) +static int extract_or_test_entrylistw OF((__GPRO__ unsigned numchunk, + ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes, + unsigned *pnum_dirs, + direntryw **pdirlistw, + int error_in_archive)); +# endif +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 +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + static int Cdecl dircompw OF((ZCONST zvoid *a, ZCONST zvoid *b)); +# endif + 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"; + +#if defined( UNIX) && defined( __APPLE__) +static ZCONST char Far AplDblNameTooLong[] = + "error: file name too long with AppleDouble suffix: %s\n"; +#endif /* defined( UNIX) && defined( __APPLE__) */ + +#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 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; +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + direntryw *dirlistw=(direntryw *)NULL, **sorted_dirlistw=(direntryw **)NULL; +# endif + 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 defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + if (G.has_win32_wide) { + wchar_t *exdirw = local_to_wchar_string(uO.exdir); + if ((error = checkdirw(__G__ exdirw, ROOT)) > MPN_INF_SKIP) { + /* out of memory, or file in way */ + free(exdirw); + return (error == MPN_NOMEM ? PK_MEM : PK_ERR); + } + free(exdirw); + } else { + 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); + } + } +# else /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ + 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 /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ + } +#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, + 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. + -----------------------------------------------------------------------*/ + +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + if (G.has_win32_wide) + { + error = extract_or_test_entrylistw(__G__ j, + &filnum, &num_bad_pwd, &old_extra_bytes, +# ifdef SET_DIR_ATTRIB + &num_dirs, &dirlistw, +# endif + error_in_archive); + } + else +#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ + { + 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) { +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + if (G.has_win32_wide) { + sorted_dirlistw = (direntryw **)malloc(num_dirs*sizeof(direntryw *)); + if (sorted_dirlistw == (direntryw **)NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(DirlistSortNoMem))); + while (dirlistw != (direntryw *)NULL) { + direntryw *dw = dirlistw; + + dirlistw = dirlistw->next; + free(dw); + } + } else { + ulg ndirs_fail = 0; + + if (num_dirs == 1) + sorted_dirlistw[0] = dirlistw; + else { + for (i = 0; i < num_dirs; ++i) { + sorted_dirlistw[i] = dirlistw; + dirlistw = dirlistw->next; + } + qsort((char *)sorted_dirlistw, num_dirs, sizeof(direntryw *), + dircompw); + } + + Trace((stderr, "setting directory times/perms/attributes\n")); + for (i = 0; i < num_dirs; ++i) { + direntryw *dw = sorted_dirlistw[i]; + + Trace((stderr, "dir = %s\n", dw->fnw)); + if ((error = set_direc_attribsw(__G__ dw)) != PK_OK) { + ndirs_fail++; + Info(slide, 0x201, ((char *)slide, + LoadFarString(DirlistSetAttrFailed), dw->fnw)); + if (!error_in_archive) + error_in_archive = error; + } + free(dw); + } + free(sorted_dirlistw); + if (!uO.tflag && QCOND2) { + if (ndirs_fail > 0) + Info(slide, 0, ((char *)slide, + LoadFarString(DirlistFailAttrSum), ndirs_fail)); + } + } + } + else +# endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ + { + 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, LoadFarString(EndSigMsg))); + Info(slide, 0x401, ((char *)slide, 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) - 1, 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 (strncmp(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 (strncmp(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 ((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) + 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; + } + 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, 9, 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: + 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.\nSkipping %s\n" : + "Target file newer.\nSkipping %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_entrylistw() */ + + + +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + +static int extract_or_test_entrylistw(__G__ numchunk, + pfilnum, pnum_bad_pwd, pold_extra_bytes, +# ifdef SET_DIR_ATTRIB + pnum_dirs, pdirlistw, +# 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; + direntryw **pdirlistw; +# endif + int error_in_archive; +{ + int cfn; + 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 & UTF8_BIT) == UTF8_BIT) + != (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 (G.unipath_filename) { + free(G.unipath_filename); + G.unipath_filename = NULL; + } +# ifdef WIN32_WIDE + if (G.unipath_widefilename) { + free(G.unipath_widefilename); + G.unipath_widefilename = NULL; + } +# endif + 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 */ + } + } +# ifdef WIN32_WIDE + if (G.unipath_widefilename == NULL) { + if (G.unipath_filename) { + /* Get wide path from UTF-8 */ + G.unipath_widefilename = utf8_to_wchar_string(G.unipath_filename); + } + else { + G.unipath_widefilename = utf8_to_wchar_string(G.filename); + } + if (G.pInfo->lcflag) { /* replace with lowercase filename */ + wcslwr(G.unipath_widefilename); + } +# if 0 + if (G.pInfo->vollabel && length > 8 && G.unipath_widefilename[8] == '.') { + wchar_t *p = G.unipath_widefilename+8; + while (*p++) + p[-1] = *p; /* disk label, and 8th char is dot: remove dot */ + } +# endif + } +# endif /* WIN32_WIDE */ + +# ifndef SFX + 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) + 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 = mapnamew(__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 + direntryw *d_entryw; + + error = defer_dir_attribsw(__G__ &d_entryw); + if (d_entryw == (direntryw *)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_entryw->next = (*pdirlistw); + (*pdirlistw) = d_entryw; + ++(*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 */ + } + + cfn = check_for_newerw(__G__ G.unipath_widefilename); + + switch (cfn) { + 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; + } + 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 + 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 + } /* end for-loop (i: files in current block) */ + + return error_in_archive; + +} /* end function extract_or_test_entrylistw() */ + +#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ + + + + +/* 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 */ + close_outfile(__G); +#else +#ifdef DLL + if (!uO.tflag && (!uO.cflag || G.redirect_data)) { + if (G.redirect_data) + FINISH_REDIRECT(); + else + close_outfile(__G); + } +#else + if (!uO.tflag && !uO.cflag) /* don't close NULL file or stdout */ + 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)) + /* 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: + if (makelong(ef+EB_HEADSIZE) != + crc32(CRCVAL_INITIAL, ef+(EB_HEADSIZE+4), + (extent)(ebLen-4))) + 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; + + if (compr_offset < 4) /* field is not compressed: */ + return PK_OK; /* do nothing and signal OK */ + + 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! */ + + 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; +{ + int sts; + extent ucsize = slnk_entry->targetlen; + char *linkfname = slnk_entry->fname; + char *linktarget = (char *)malloc(ucsize+1); + +#ifdef VMS + static int vms_symlink_works = -1; + + if (vms_symlink_works < 0) + { + /* Test symlink() with an invalid file name. If errno comes + * back ENOSYS ("Function not implemented"), then don't try to + * use it below on the symlink placeholder text files. + */ + vms_symlink_works = symlink( "", "?"); + if (errno == ENOSYS) + vms_symlink_works = 0; + else + vms_symlink_works = 1; + } +#endif /* def VMS */ + + 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... */ + +#ifdef VMS + if (vms_symlink_works == 0) + { + /* Should we be using some UnZip error message function instead + * of perror() (or equivalent) for these "symlink error" + * messages? + */ + Info(slide, 0, ((char *)slide, LoadFarString(SymLnkFinish), + FnFilter1(linkfname), FnFilter2(linktarget))); + + fprintf( stderr, "Symlink error: %s\n", strerror( ENOSYS)); + free(linktarget); + return; + } +#endif /* def VMS */ + + unlink(linkfname); /* ...and delete it */ + sts = symlink(linktarget, linkfname); /* create the real link */ + if (QCOND2 || (sts != 0)) + Info(slide, 0, ((char *)slide, LoadFarString(SymLnkFinish), + FnFilter1(linkfname), FnFilter2(linktarget))); + if (sts != 0) + 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 */ +/*************************/ + +/* + If Unicode is supported, assume we have what we need to do this + check using wide characters, avoiding MBCS issues. + */ + +char *fnfilter(raw, space, size) /* convert name to safely printable form */ + ZCONST char *raw; + uch *space; + extent size; +{ +#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 + +#ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */ + +# ifdef UNICODE_SUPPORT +/* If Unicode support is enabled, do the isprint() checks by first + converting to wide characters and checking those. That avoids + issues doing checks on multi-byte characters. After the replacements + 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 *wc; /* pointer to char in wstring */ + wchar_t *wostring; /* wchar_t version of output string */ + size_t woslen; /* length of wostring */ + wchar_t *woc; /* pointer to char in wostring */ + char *newraw; /* new raw */ + ZCONST uch *r; + uch *s=space; + uch *slim=NULL; + uch *se=NULL; + int have_overflow = FALSE; + + wslen = mbstowcs(NULL, raw, 0 ); + if ((wstring = malloc((wslen + 1) * sizeof(wchar_t))) == NULL) { + strcpy( (char *)space, raw); + return (char *)space; + } + if ((wostring = malloc(2 * (wslen + 1) * sizeof(wchar_t))) == NULL) { + free(wstring); + strcpy( (char *)space, raw); + return (char *)space; + } + wslen = mbstowcs(wstring, raw, wslen + 1); + wc = wstring; + woc = wostring; + + while (*wc) { + if (!iswprint(*wc)) { + if (*wc < 32) { + /* ASCII control codes are escaped as "^{letter}". */ + *woc++ = (wchar_t)'^'; + *woc++ = (wchar_t)(64 + *wc); + } else { + /* Other unprintable codes are replaced by the + * placeholder character. */ + *woc++ = (wchar_t)UZ_FNFILTER_REPLACECHAR; + } + } else { + *woc++ = *wc; + } + *wc++; + } + *woc = (wchar_t)0; + + /* convert back to local string to work with output buffer */ + 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; + } + *s++ = *r++; + } + } + if (have_overflow) { + strcpy((char *)se, "..."); + } else { + *s = '\0'; + } + + free(wstring); + free(wostring); + free(newraw); + +# else /* !UNICODE_SUPPORT */ + + 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 + 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'; + } +# endif /* !UNICODE_SUPPORT */ + +# 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); */ +} + +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) +static int Cdecl dircompw(a, b) /* used by qsort(); swiped from Zip */ + ZCONST zvoid *a, *b; +{ + /* order is significant: this sorts in reverse order (deepest first) */ + return wcscmp((*(direntryw **)b)->fnw, (*(direntryw **)a)->fnw); + /* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */ +} +# endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ + +#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 (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 --git a/third_party/unzip/fileio.c b/third_party/unzip/fileio.c new file mode 100644 index 000000000..84576bafc --- /dev/null +++ b/third_party/unzip/fileio.c @@ -0,0 +1,3123 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 +*/ +/*--------------------------------------------------------------------------- + + fileio.c + + This file contains routines for doing direct but relatively generic input/ + output, file-related sorts of things, plus some miscellaneous stuff. Most + of the stuff has to do with opening, closing, reading and/or writing files. + + Contains: open_input_file() + open_outfile() (not: VMS, AOS/VS, CMSMVS, MACOS, TANDEM) + undefer_input() + defer_leftover_input() + readbuf() + readbyte() + fillinbuf() + seek_zipf() + flush() (non-VMS) + is_vms_varlen_txt() (non-VMS, VMS_TEXT_CONV only) + disk_error() (non-VMS) + UzpMessagePrnt() + UzpMessageNull() (DLL only) + UzpInput() + UzpMorePause() + UzpPassword() (non-WINDLL) + handler() + dos_to_unix_time() (non-VMS, non-VM/CMS, non-MVS) + check_for_newer() (non-VMS, non-OS/2, non-VM/CMS, non-MVS) + do_string() + makeword() + makelong() + makeint64() + fzofft() + str2iso() (CRYPT && NEED_STR2ISO, only) + str2oem() (CRYPT && NEED_STR2OEM, only) + memset() (ZMEM only) + memcpy() (ZMEM only) + zstrnicmp() (NO_STRNICMP only) + zstat() (REGULUS only) + plastchar() (_MBCS only) + uzmbclen() (_MBCS && NEED_UZMBCLEN, only) + uzmbschr() (_MBCS && NEED_UZMBSCHR, only) + uzmbsrchr() (_MBCS && NEED_UZMBSRCHR, only) + fLoadFarString() (SMALL_MEM only) + fLoadFarStringSmall() (SMALL_MEM only) + fLoadFarStringSmall2() (SMALL_MEM only) + zfstrcpy() (SMALL_MEM only) + zfstrcmp() (SMALL_MEM && !(SFX || FUNZIP) only) + + ---------------------------------------------------------------------------*/ + + +#define __FILEIO_C /* identifies this source module */ +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" +#include "third_party/unzip/crc32.h" +#include "third_party/unzip/crypt.h" +#include "third_party/unzip/ttyio.h" + +#define st_mtime st_mtim.tv_sec + +#if defined( UNIX) && defined( __APPLE__) +#include "third_party/unzip/unix/macosx.h" +#endif /* defined( UNIX) && defined( __APPLE__) */ + +/* setup of codepage conversion for decryption passwords */ +#if CRYPT +# if (defined(CRYP_USES_ISO2OEM) && !defined(IZ_ISO2OEM_ARRAY)) +# define IZ_ISO2OEM_ARRAY /* pull in iso2oem[] table */ +# endif +# if (defined(CRYP_USES_OEM2ISO) && !defined(IZ_OEM2ISO_ARRAY)) +# define IZ_OEM2ISO_ARRAY /* pull in oem2iso[] table */ +# endif +#endif +#include "third_party/unzip/ebcdic.h" /* definition/initialization of ebcdic[] */ + + +/* + Note: Under Windows, the maximum size of the buffer that can be used + with any of the *printf calls is 16,384, so win_fprintf was used to + feed the fprintf clone no more than 16K chunks at a time. This should + be valid for anything up to 64K (and probably beyond, assuming your + buffers are that big). +*/ +#ifdef WINDLL +# define WriteError(buf,len,strm) \ + (win_fprintf(pG, strm, (extent)len, (char far *)buf) != (int)(len)) +#else /* !WINDLL */ +# ifdef USE_FWRITE +# define WriteError(buf,len,strm) \ + ((extent)fwrite((char *)(buf),1,(extent)(len),strm) != (extent)(len)) +# else +# define WriteError(buf,len,strm) \ + ((extent)write(fileno(strm),(char *)(buf),(extent)(len)) != (extent)(len)) +# endif +#endif /* ?WINDLL */ + +/* + 2005-09-16 SMS. + On VMS, when output is redirected to a file, as in a command like + "PIPE UNZIP -v > X.OUT", the output file is created with VFC record + format, and multiple calls to write() or fwrite() will produce multiple + records, even when there's no newline terminator in the buffer. + The result is unsightly output with spurious newlines. Using fprintf() + instead of write() here, and disabling a fflush(stdout) in UzpMessagePrnt() + below, together seem to solve the problem. + + According to the C RTL manual, "The write and decc$record_write + functions always generate at least one record." Also, "[T]he fwrite + function always generates at least records." So, + "fwrite(buf, len, 1, strm)" is much better ("1" record) than + "fwrite(buf, 1, len, strm)" ("len" (1-character) records, _really_ + ugly), but neither is better than write(). Similarly, "The fflush + function always generates a record if there is unwritten data in the + buffer." Apparently fprintf() buffers the stuff somewhere, and puts + out a record (only) when it sees a newline. +*/ +#ifdef VMS +# define WriteTxtErr(buf,len,strm) \ + ((extent)fprintf(strm, "%.*s", len, buf) != (extent)(len)) +#else +# define WriteTxtErr(buf,len,strm) WriteError(buf,len,strm) +#endif + +#if (defined(USE_DEFLATE64) && defined(__16BIT__)) +static int partflush OF((__GPRO__ uch *rawbuf, ulg size, int unshrink)); +#endif +#ifdef VMS_TEXT_CONV +static int is_vms_varlen_txt OF((__GPRO__ uch *ef_buf, unsigned ef_len)); +#endif +static int disk_error OF((__GPRO)); + + +/****************************/ +/* Strings used in fileio.c */ +/****************************/ + +static ZCONST char Far CannotOpenZipfile[] = + "error: cannot open zipfile [ %s ]\n %s\n"; + +#if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS)) +#if (!defined(TANDEM)) +#if (defined(ATH_BEO_THS_UNX) || defined(DOS_FLX_NLM_OS2_W32)) + static ZCONST char Far CannotDeleteOldFile[] = + "error: cannot delete old %s\n %s\n"; +#ifdef UNIXBACKUP + static ZCONST char Far CannotRenameOldFile[] = + "error: cannot rename old %s\n %s\n"; + static ZCONST char Far BackupSuffix[] = "~"; +#endif +#endif /* ATH_BEO_THS_UNX || DOS_FLX_NLM_OS2_W32 */ +#ifdef NOVELL_BUG_FAILSAFE + static ZCONST char Far NovellBug[] = + "error: %s: stat() says does not exist, but fopen() found anyway\n"; +#endif + static ZCONST char Far CannotCreateFile[] = + "error: cannot create %s\n %s\n"; +#endif /* !TANDEM */ +#endif /* !VMS && !AOS_VS && !CMS_MVS && !MACOS */ + +static ZCONST char Far ReadError[] = "error: zipfile read error\n"; +static ZCONST char Far FilenameTooLongTrunc[] = + "warning: filename too long--truncating.\n"; +#ifdef UNICODE_SUPPORT + static ZCONST char Far UFilenameTooLongTrunc[] = + "warning: Converted unicode filename too long--truncating.\n"; +#endif +static ZCONST char Far ExtraFieldTooLong[] = + "warning: extra field too long (%d). Ignoring...\n"; + +#ifdef WINDLL + static ZCONST char Far DiskFullQuery[] = + "%s: write error (disk full?).\n"; +#else + static ZCONST char Far DiskFullQuery[] = + "%s: write error (disk full?). Continue? (y/n/^C) "; + static ZCONST char Far ZipfileCorrupt[] = + "error: zipfile probably corrupt (%s)\n"; +# ifdef SYMLINKS + static ZCONST char Far FileIsSymLink[] = + "%s exists and is a symbolic link%s.\n"; +# endif +# ifdef MORE + static ZCONST char Far MorePrompt[] = "--More--(%lu)"; +# endif + static ZCONST char Far QuitPrompt[] = + "--- Press `Q' to quit, or any other key to continue ---"; + static ZCONST char Far HidePrompt[] = /* "\r \r"; */ + "\r \r"; +# if CRYPT +# ifdef MACOS + /* SPC: are names on MacOS REALLY so much longer than elsewhere ??? */ + static ZCONST char Far PasswPrompt[] = "[%s]\n %s password: "; +# else + static ZCONST char Far PasswPrompt[] = "[%s] %s password: "; +# endif + static ZCONST char Far PasswPrompt2[] = "Enter password: "; + static ZCONST char Far PasswRetry[] = "password incorrect--reenter: "; +# endif /* CRYPT */ +#endif /* !WINDLL */ + + + + + +/******************************/ +/* Function open_input_file() */ +/******************************/ + +int open_input_file(__G) /* return 1 if open failed */ + __GDEF +{ + /* + * open the zipfile for reading and in BINARY mode to prevent cr/lf + * translation, which would corrupt the bitstreams + */ + +#ifdef VMS + G.zipfd = open(G.zipfn, O_RDONLY, 0, OPNZIP_RMS_ARGS); +#else /* !VMS */ +#ifdef MACOS + G.zipfd = open(G.zipfn, 0); +#else /* !MACOS */ +#ifdef CMS_MVS + G.zipfd = vmmvs_open_infile(__G); +#else /* !CMS_MVS */ +#ifdef USE_STRM_INPUT + G.zipfd = fopen(G.zipfn, FOPR); +#else /* !USE_STRM_INPUT */ + G.zipfd = open(G.zipfn, O_RDONLY | O_BINARY); +#endif /* ?USE_STRM_INPUT */ +#endif /* ?CMS_MVS */ +#endif /* ?MACOS */ +#endif /* ?VMS */ + +#ifdef USE_STRM_INPUT + if (G.zipfd == NULL) +#else + /* if (G.zipfd < 0) */ /* no good for Windows CE port */ + if (G.zipfd == -1) +#endif + { + Info(slide, 0x401, ((char *)slide, LoadFarString(CannotOpenZipfile), + G.zipfn, strerror(errno))); + return 1; + } + return 0; + +} /* end function open_input_file() */ + + + + +#if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS)) +#if (!defined(TANDEM)) + +/***************************/ +/* Function open_outfile() */ +/***************************/ + +int open_outfile(__G) /* return 1 if fail */ + __GDEF +{ + int r; + +#ifdef DLL + if (G.redirect_data) + return (redirect_outfile(__G) == FALSE); +#endif +#ifdef QDOS + QFilename(__G__ G.filename); +#endif + +#if defined( UNIX) && defined( __APPLE__) + if (G.apple_double) + { + /* Set flags and byte counts for the AppleDouble header. */ + G.apl_dbl_hdr_len = 0; + G.apl_dbl_hdr_bytes = APL_DBL_HDR_SIZE; + /* Append "/rsrc" suffix to the AppleDouble file name. */ + strcat( G.ad_filename, APL_DBL_SFX); + + /* Re-aim pointer instead of copying? */ + strcpy( G.filename, G.ad_filename); + } + else + { + /* Set byte count to bypass AppleDouble processing. */ + G.apl_dbl_hdr_bytes = 0; + } +#endif /* defined( UNIX) && defined( __APPLE__) */ + +#if (defined(DOS_FLX_NLM_OS2_W32) || defined(ATH_BEO_THS_UNX)) +#ifdef BORLAND_STAT_BUG + /* Borland 5.0's stat() barfs if the filename has no extension and the + * file doesn't exist. */ + if (access(G.filename, 0) == -1) { + FILE *tmp = fopen(G.filename, "wb+"); + + /* file doesn't exist, so create a dummy file to keep stat() from + * failing (will be over-written anyway) */ + fputc('0', tmp); /* just to have something in the file */ + fclose(tmp); + } +#endif /* BORLAND_STAT_BUG */ + +/* AppleDouble resource fork is expected to exist, so evade the test. */ +#if defined( UNIX) && defined( __APPLE__) +# define TEST_EXIST (G.apple_double == 0) +#else /* defined( UNIX) && defined( __APPLE__) */ +# define TEST_EXIST 1 +#endif /* defined( UNIX) && defined( __APPLE__) [else] */ + +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + r = ((G.has_win32_wide + ? SSTATW(G.unipath_widefilename, &G.statbuf) + : SSTAT(G.filename, &G.statbuf) + ) == 0); +#else + r = (SSTAT(G.filename, &G.statbuf) == 0); +#endif + +#ifdef SYMLINKS + if (TEST_EXIST && (r || lstat(G.filename, &G.statbuf) == 0)) +#else + if (TEST_EXIST && r) +#endif /* ?SYMLINKS */ + { + Trace((stderr, "open_outfile: stat(%s) returns 0: file exists\n", + FnFilter1(G.filename))); +#ifdef UNIXBACKUP + if (uO.B_flag) { /* do backup */ + char *tname; + z_stat tmpstat; + int blen, flen, tlen; + + blen = strlen(BackupSuffix); + flen = strlen(G.filename); + tlen = flen + blen + 6; /* includes space for 5 digits */ + if (tlen >= FILNAMSIZ) { /* in case name is too long, truncate */ + tname = (char *)malloc(FILNAMSIZ); + if (tname == NULL) + return 1; /* in case we run out of space */ + tlen = FILNAMSIZ - 1 - blen; + strcpy(tname, G.filename); /* make backup name */ + tname[tlen] = '\0'; + if (flen > tlen) flen = tlen; + tlen = FILNAMSIZ; + } else { + tname = (char *)malloc(tlen); + if (tname == NULL) + return 1; /* in case we run out of space */ + strcpy(tname, G.filename); /* make backup name */ + } + strcpy(tname+flen, BackupSuffix); + + if (IS_OVERWRT_ALL) { + /* If there is a previous backup file, delete it, + * otherwise the following rename operation may fail. + */ + if (SSTAT(tname, &tmpstat) == 0) + unlink(tname); + } else { + /* Check if backupname exists, and, if it's true, try + * appending numbers of up to 5 digits (or the maximum + * "unsigned int" number on 16-bit systems) to the + * BackupSuffix, until an unused name is found. + */ + unsigned maxtail, i; + char *numtail = tname + flen + blen; + + /* take account of the "unsigned" limit on 16-bit systems: */ + maxtail = ( ((~0) >= 99999L) ? 99999 : (~0) ); + switch (tlen - flen - blen - 1) { + case 4: maxtail = 9999; break; + case 3: maxtail = 999; break; + case 2: maxtail = 99; break; + case 1: maxtail = 9; break; + case 0: maxtail = 0; break; + } + /* while filename exists */ + for (i = 0; (i < maxtail) && (SSTAT(tname, &tmpstat) == 0);) + sprintf(numtail,"%u", ++i); + } + + if (rename(G.filename, tname) != 0) { /* move file */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(CannotRenameOldFile), + FnFilter1(G.filename), strerror(errno))); + free(tname); + return 1; + } + Trace((stderr, "open_outfile: %s now renamed into %s\n", + FnFilter1(G.filename), FnFilter2(tname))); + free(tname); + } else +#endif /* UNIXBACKUP */ + { +#ifdef DOS_FLX_OS2_W32 + if (!(G.statbuf.st_mode & S_IWRITE)) { + Trace((stderr, + "open_outfile: existing file %s is read-only\n", + FnFilter1(G.filename))); + chmod(G.filename, S_IREAD | S_IWRITE); + Trace((stderr, "open_outfile: %s now writable\n", + FnFilter1(G.filename))); + } +#endif /* DOS_FLX_OS2_W32 */ +#ifdef NLM + /* Give the file read/write permission (non-POSIX shortcut) */ + chmod(G.filename, 0); +#endif /* NLM */ +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + if ((G.has_win32_wide + ? _wunlink(G.unipath_widefilename) + : unlink(G.filename) + ) != 0) +#else + if (unlink(G.filename) != 0) +#endif + { + Info(slide, 0x401, ((char *)slide, + LoadFarString(CannotDeleteOldFile), + FnFilter1(G.filename), strerror(errno))); + return 1; + } + Trace((stderr, "open_outfile: %s now deleted\n", + FnFilter1(G.filename))); + } + } +#endif /* DOS_FLX_NLM_OS2_W32 || ATH_BEO_THS_UNX */ +#ifdef RISCOS + if (SWI_OS_File_7(G.filename,0xDEADDEAD,0xDEADDEAD,G.lrec.ucsize)!=NULL) { + Info(slide, 1, ((char *)slide, LoadFarString(CannotCreateFile), + FnFilter1(G.filename), strerror(errno))); + return 1; + } +#endif /* RISCOS */ +#ifdef TOPS20 + char *tfilnam; + + if ((tfilnam = (char *)malloc(2*strlen(G.filename)+1)) == (char *)NULL) + return 1; + strcpy(tfilnam, G.filename); + upper(tfilnam); + enquote(tfilnam); + if ((G.outfile = fopen(tfilnam, FOPW)) == (FILE *)NULL) { + Info(slide, 1, ((char *)slide, LoadFarString(CannotCreateFile), + tfilnam, strerror(errno))); + free(tfilnam); + return 1; + } + free(tfilnam); +#else /* !TOPS20 */ +#ifdef MTS + if (uO.aflag) + G.outfile = zfopen(G.filename, FOPWT); + else + G.outfile = zfopen(G.filename, FOPW); + if (G.outfile == (FILE *)NULL) { + Info(slide, 1, ((char *)slide, LoadFarString(CannotCreateFile), + FnFilter1(G.filename), strerror(errno))); + return 1; + } +#else /* !MTS */ +#ifdef DEBUG + Info(slide, 1, ((char *)slide, + "open_outfile: doing fopen(%s) for reading\n", FnFilter1(G.filename))); + if ((G.outfile = zfopen(G.filename, FOPR)) == (FILE *)NULL) + Info(slide, 1, ((char *)slide, + "open_outfile: fopen(%s) for reading failed: does not exist\n", + FnFilter1(G.filename))); + else { + Info(slide, 1, ((char *)slide, + "open_outfile: fopen(%s) for reading succeeded: file exists\n", + FnFilter1(G.filename))); + fclose(G.outfile); + } +#endif /* DEBUG */ +#ifdef NOVELL_BUG_FAILSAFE + if (G.dne && ((G.outfile = zfopen(G.filename, FOPR)) != (FILE *)NULL)) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NovellBug), + FnFilter1(G.filename))); + fclose(G.outfile); + return 1; /* with "./" fix in checkdir(), should never reach here */ + } +#endif /* NOVELL_BUG_FAILSAFE */ + Trace((stderr, "open_outfile: doing fopen(%s) for writing\n", + FnFilter1(G.filename))); + { +#if defined(ATH_BE_UNX) || defined(AOS_VS) || defined(QDOS) || defined(TANDEM) + mode_t umask_sav = umask(0077); +#endif + +#if defined(SYMLINKS) && defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + G.outfile = (G.has_win32_wide + ? zfopenw(G.unipath_widefilename, L"wbr") + : zfopen(G.filename, FOPWR) + ); +#else +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + G.outfile = (G.has_win32_wide + ? zfopenw(G.unipath_widefilename, L"wb") + : zfopen(G.filename, FOPW) + ); +# else /* (UNICODE_SUPPORT && WIN32_WIDE) */ +# if defined(SYMLINKS) || defined(QLZIP) + /* These features require the ability to re-read extracted data from + the output files. Output files are created with Read&Write access. + */ + G.outfile = zfopen(G.filename, FOPWR); +# else + G.outfile = zfopen(G.filename, FOPW); +# endif +# endif +#endif + +#if defined(ATH_BE_UNX) || defined(AOS_VS) || defined(QDOS) || defined(TANDEM) + umask(umask_sav); +#endif + } + if (G.outfile == (FILE *)NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(CannotCreateFile), + FnFilter1(G.filename), strerror(errno))); + return 1; + } + Trace((stderr, "open_outfile: fopen(%s) for writing succeeded\n", + FnFilter1(G.filename))); +#endif /* !MTS */ +#endif /* !TOPS20 */ + +#ifdef USE_FWRITE +#ifdef DOS_NLM_OS2_W32 + /* 16-bit MSC: buffer size must be strictly LESS than 32K (WSIZE): bogus */ + setbuf(G.outfile, (char *)NULL); /* make output unbuffered */ +#else /* !DOS_NLM_OS2_W32 */ +#ifndef RISCOS +#ifdef _IOFBF /* make output fully buffered (works just about like write()) */ + setvbuf(G.outfile, (char *)slide, _IOFBF, WSIZE); +#else + setbuf(G.outfile, (char *)slide); +#endif +#endif /* !RISCOS */ +#endif /* ?DOS_NLM_OS2_W32 */ +#endif /* USE_FWRITE */ +#ifdef OS2_W32 + /* preallocate the final file size to prevent file fragmentation */ + SetFileSize(G.outfile, G.lrec.ucsize); +#endif + return 0; + +} /* end function open_outfile() */ + +#endif /* !TANDEM */ +#endif /* !VMS && !AOS_VS && !CMS_MVS && !MACOS */ + + + + + +/* + * These functions allow NEXTBYTE to function without needing two bounds + * checks. Call defer_leftover_input() if you ever have filled G.inbuf + * by some means other than readbyte(), and you then want to start using + * NEXTBYTE. When going back to processing bytes without NEXTBYTE, call + * undefer_input(). For example, extract_or_test_member brackets its + * central section that does the decompression with these two functions. + * If you need to check the number of bytes remaining in the current + * file while using NEXTBYTE, check (G.csize + G.incnt), not G.csize. + */ + +/****************************/ +/* function undefer_input() */ +/****************************/ + +void undefer_input(__G) + __GDEF +{ + if (G.incnt > 0) + G.csize += G.incnt; + if (G.incnt_leftover > 0) { + /* We know that "(G.csize < MAXINT)" so we can cast G.csize to int: + * This condition was checked when G.incnt_leftover was set > 0 in + * defer_leftover_input(), and it is NOT allowed to touch G.csize + * before calling undefer_input() when (G.incnt_leftover > 0) + * (single exception: see read_byte()'s "G.csize <= 0" handling) !! + */ + G.incnt = G.incnt_leftover + (int)G.csize; + G.inptr = G.inptr_leftover - (int)G.csize; + G.incnt_leftover = 0; + } else if (G.incnt < 0) + G.incnt = 0; +} /* end function undefer_input() */ + + + + + +/***********************************/ +/* function defer_leftover_input() */ +/***********************************/ + +void defer_leftover_input(__G) + __GDEF +{ + if ((zoff_t)G.incnt > G.csize) { + /* (G.csize < MAXINT), we can safely cast it to int !! */ + if (G.csize < 0L) + G.csize = 0L; + G.inptr_leftover = G.inptr + (int)G.csize; + G.incnt_leftover = G.incnt - (int)G.csize; + G.incnt = (int)G.csize; + } else + G.incnt_leftover = 0; + G.csize -= G.incnt; +} /* end function defer_leftover_input() */ + + + + + +/**********************/ +/* Function readbuf() */ +/**********************/ + +unsigned readbuf(__G__ buf, size) /* return number of bytes read into buf */ + __GDEF + char *buf; + register unsigned size; +{ + register unsigned count; + unsigned n; + + n = size; + while (size) { + if (G.incnt <= 0) { + if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0) + return (n-size); + else if (G.incnt < 0) { + /* another hack, but no real harm copying same thing twice */ + (*G.message)((zvoid *)&G, + (uch *)LoadFarString(ReadError), /* CANNOT use slide */ + (ulg)strlen(LoadFarString(ReadError)), 0x401); + return 0; /* discarding some data; better than lock-up */ + } + /* buffer ALWAYS starts on a block boundary: */ + G.cur_zipfile_bufstart += INBUFSIZ; + G.inptr = G.inbuf; + } + count = MIN(size, (unsigned)G.incnt); + memcpy(buf, G.inptr, count); + buf += count; + G.inptr += count; + G.incnt -= count; + size -= count; + } + return n; + +} /* end function readbuf() */ + + + + + +/***********************/ +/* Function readbyte() */ +/***********************/ + +int readbyte(__G) /* refill inbuf and return a byte if available, else EOF */ + __GDEF +{ + if (G.mem_mode) + return EOF; + if (G.csize <= 0) { + G.csize--; /* for tests done after exploding */ + G.incnt = 0; + return EOF; + } + if (G.incnt <= 0) { + if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0) { + return EOF; + } else if (G.incnt < 0) { /* "fail" (abort, retry, ...) returns this */ + /* another hack, but no real harm copying same thing twice */ + (*G.message)((zvoid *)&G, + (uch *)LoadFarString(ReadError), + (ulg)strlen(LoadFarString(ReadError)), 0x401); + echon(); +#ifdef WINDLL + longjmp(dll_error_return, 1); +#else + DESTROYGLOBALS(); + EXIT(PK_BADERR); /* totally bailing; better than lock-up */ +#endif + } + G.cur_zipfile_bufstart += INBUFSIZ; /* always starts on block bndry */ + G.inptr = G.inbuf; + defer_leftover_input(__G); /* decrements G.csize */ + } + +#if CRYPT + if (G.pInfo->encrypted) { + uch *p; + int n; + + /* This was previously set to decrypt one byte beyond G.csize, when + * incnt reached that far. GRR said, "but it's required: why?" This + * was a bug in fillinbuf() -- was it also a bug here? + */ + for (n = G.incnt, p = G.inptr; n--; p++) + zdecode(*p); + } +#endif /* CRYPT */ + + --G.incnt; + return *G.inptr++; + +} /* end function readbyte() */ + + + + + +#if defined(USE_ZLIB) || defined(USE_BZIP2) + +/************************/ +/* Function fillinbuf() */ +/************************/ + +int fillinbuf(__G) /* like readbyte() except returns number of bytes in inbuf */ + __GDEF +{ + if (G.mem_mode || + (G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0) + return 0; + G.cur_zipfile_bufstart += INBUFSIZ; /* always starts on a block boundary */ + G.inptr = G.inbuf; + defer_leftover_input(__G); /* decrements G.csize */ + +#if CRYPT + if (G.pInfo->encrypted) { + uch *p; + int n; + + for (n = G.incnt, p = G.inptr; n--; p++) + zdecode(*p); + } +#endif /* CRYPT */ + + return G.incnt; + +} /* end function fillinbuf() */ + +#endif /* USE_ZLIB || USE_BZIP2 */ + + + + + +/************************/ +/* Function seek_zipf() */ +/************************/ + +int seek_zipf(__G__ abs_offset) + __GDEF + zoff_t abs_offset; +{ +/* + * Seek to the block boundary of the block which includes abs_offset, + * then read block into input buffer and set pointers appropriately. + * If block is already in the buffer, just set the pointers. This function + * is used by do_seekable (process.c), extract_or_test_entrylist (extract.c) + * and do_string (fileio.c). Also, a slightly modified version is embedded + * within extract_or_test_entrylist (extract.c). readbyte() and readbuf() + * (fileio.c) are compatible. NOTE THAT abs_offset is intended to be the + * "proper offset" (i.e., if there were no extra bytes prepended); + * cur_zipfile_bufstart contains the corrected offset. + * + * Since seek_zipf() is never used during decompression, it is safe to + * use the slide[] buffer for the error message. + * + * returns PK error codes: + * PK_BADERR if effective offset in zipfile is negative + * PK_EOF if seeking past end of zipfile + * PK_OK when seek was successful + */ + zoff_t request = abs_offset + G.extra_bytes; + zoff_t inbuf_offset = request % INBUFSIZ; + zoff_t bufstart = request - inbuf_offset; + + if (request < 0) { + Info(slide, 1, ((char *)slide, LoadFarStringSmall(SeekMsg), + G.zipfn, LoadFarString(ReportMsg))); + return(PK_BADERR); + } else if (bufstart != G.cur_zipfile_bufstart) { + Trace((stderr, + "fpos_zip: abs_offset = %s, G.extra_bytes = %s\n", + FmZofft(abs_offset, NULL, NULL), + FmZofft(G.extra_bytes, NULL, NULL))); +#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 */ + Trace((stderr, + " request = %s, (abs+extra) = %s, inbuf_offset = %s\n", + FmZofft(request, NULL, NULL), + FmZofft((abs_offset+G.extra_bytes), NULL, NULL), + FmZofft(inbuf_offset, NULL, NULL))); + Trace((stderr, " bufstart = %s, cur_zipfile_bufstart = %s\n", + FmZofft(bufstart, NULL, NULL), + FmZofft(G.cur_zipfile_bufstart, NULL, NULL))); + if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0) + return(PK_EOF); + G.incnt -= (int)inbuf_offset; + G.inptr = G.inbuf + (int)inbuf_offset; + } else { + G.incnt += (G.inptr-G.inbuf) - (int)inbuf_offset; + G.inptr = G.inbuf + (int)inbuf_offset; + } + return(PK_OK); +} /* end function seek_zipf() */ + + + + + +#ifndef VMS /* for VMS use code in vms.c */ + +/********************/ +/* Function flush() */ /* returns PK error codes: */ +/********************/ /* if tflag => always 0; PK_DISK if write error */ + +int flush(__G__ rawbuf, size, unshrink) + __GDEF + uch *rawbuf; + ulg size; + int unshrink; +#if (defined(USE_DEFLATE64) && defined(__16BIT__)) +{ + int ret; + + /* On 16-bit systems (MSDOS, OS/2 1.x), the standard C library functions + * cannot handle writes of 64k blocks at once. For these systems, the + * blocks to flush are split into pieces of 32k or less. + */ + while (size > 0x8000L) { + ret = partflush(__G__ rawbuf, 0x8000L, unshrink); + if (ret != PK_OK) + return ret; + size -= 0x8000L; + rawbuf += (extent)0x8000; + } + return partflush(__G__ rawbuf, size, unshrink); +} /* end function flush() */ + + +/************************/ +/* Function partflush() */ /* returns PK error codes: */ +/************************/ /* if tflag => always 0; PK_DISK if write error */ + +static int partflush(__G__ rawbuf, size, unshrink) + __GDEF + uch *rawbuf; /* cannot be ZCONST, gets passed to (*G.message)() */ + ulg size; + int unshrink; +#endif /* USE_DEFLATE64 && __16BIT__ */ +{ + register uch *p; + register uch *q; + uch *transbuf; +#if (defined(SMALL_MEM) || defined(MED_MEM) || defined(VMS_TEXT_CONV)) + ulg transbufsiz; +#endif + /* static int didCRlast = FALSE; moved to globals.h */ + + +/*--------------------------------------------------------------------------- + Compute the CRC first; if testing or if disk is full, that's it. + ---------------------------------------------------------------------------*/ + + G.crc32val = crc32(G.crc32val, rawbuf, (extent)size); + +#ifdef DLL + if ((G.statreportcb != NULL) && + (*G.statreportcb)(__G__ UZ_ST_IN_PROGRESS, G.zipfn, G.filename, NULL)) + return IZ_CTRLC; /* cancel operation by user request */ +#endif + + if (uO.tflag || size == 0L) /* testing or nothing to write: all done */ + return PK_OK; + + if (G.disk_full) + return PK_DISK; /* disk already full: ignore rest of file */ + +/*--------------------------------------------------------------------------- + Write the bytes rawbuf[0..size-1] to the output device, first converting + end-of-lines and ASCII/EBCDIC as needed. If SMALL_MEM or MED_MEM are NOT + defined, outbuf is assumed to be at least as large as rawbuf and is not + necessarily checked for overflow. + ---------------------------------------------------------------------------*/ + + if (!G.pInfo->textmode) { /* write raw binary data */ + /* GRR: note that for standard MS-DOS compilers, size argument to + * fwrite() can never be more than 65534, so WriteError macro will + * have to be rewritten if size can ever be that large. For now, + * never more than 32K. Also note that write() returns an int, which + * doesn't necessarily limit size to 32767 bytes if write() is used + * on 16-bit systems but does make it more of a pain; however, because + * at least MSC 5.1 has a lousy implementation of fwrite() (as does + * DEC Ultrix cc), write() is used anyway. + */ +#ifdef DLL + if (G.redirect_data) { +#ifdef NO_SLIDE_REDIR + if (writeToMemory(__G__ rawbuf, (extent)size)) return PK_ERR; +#else + writeToMemory(__G__ rawbuf, (extent)size); +#endif + } else +#endif + +#if defined( UNIX) && defined( __APPLE__) + /* If expecting AppleDouble header bytes, process them. */ + if (G.apl_dbl_hdr_bytes > 0) + { + if (size < G.apl_dbl_hdr_bytes) + { + /* Fewer bytes than needed to complete the AppleDouble + * header. (Unlikely?) Move them to the AppleDouble + * header buffer, adjust the byte counts, and resume + * extraction. + */ + memcpy( &G.apl_dbl_hdr[ G.apl_dbl_hdr_len], rawbuf, size); + size = 0; + G.apl_dbl_hdr_bytes -= size; + } + else + { + /* Enough bytes to complete the AppleDouble header. Move + * them to the AppleDouble header buffer, adjust the byte + * counts, and set the Finder info attributes (for the + * plain-name) file. + */ + char btrbslash; /* Saved character had better be a slash. */ + int sts; + struct attrlist attr_list_fndr; + + memcpy( &G.apl_dbl_hdr[ G.apl_dbl_hdr_len], rawbuf, + G.apl_dbl_hdr_bytes); + size -= G.apl_dbl_hdr_bytes; + G.apl_dbl_hdr_bytes = 0; + + /* Truncate name at "/rsrc" for setattrlist(). */ + btrbslash = + G.filename[ strlen( G.filename)- strlen( APL_DBL_SFX)]; + G.filename[ strlen( G.filename)- strlen( APL_DBL_SFX)] = '\0'; + + /* Clear attribute list structure. */ + memset( &attr_list_fndr, 0, sizeof( attr_list_fndr)); + /* Set attribute list bits for Finder info. */ + attr_list_fndr.bitmapcount = ATTR_BIT_MAP_COUNT; + attr_list_fndr.commonattr = ATTR_CMN_FNDRINFO; + + /* Set Finder info for main file. */ + sts = setattrlist( G.filename, /* Path. */ + &attr_list_fndr, /* Attrib list. */ + &G.apl_dbl_hdr[ APL_DBL_HDR_FNDR_INFO_OFFS], + /* Src buffer. */ + APL_FNDR_INFO_SIZE, /* Src buffer size. */ + 0); /* Options. */ + + if (sts != 0) + { + Info(slide, 0x12, ((char *)slide, + "\nsetattrlist(fndr) failure: %s", G.filename)); + } + + /* Restore name suffix ("/rsrc"). */ + G.filename[ strlen( G.filename)] = btrbslash; + } + + if (size == 0L) /* No resource fork left to write. */ + return PK_OK; + + rawbuf += APL_DBL_HDR_SIZE; + } +#endif /* defined( UNIX) && defined( __APPLE__) */ + + if (!uO.cflag && WriteError(rawbuf, size, G.outfile)) + return disk_error(__G); + else if (uO.cflag && (*G.message)((zvoid *)&G, rawbuf, size, 0)) + return PK_OK; + } else { /* textmode: aflag is true */ + if (unshrink) { + /* rawbuf = outbuf */ + transbuf = G.outbuf2; +#if (defined(SMALL_MEM) || defined(MED_MEM) || defined(VMS_TEXT_CONV)) + transbufsiz = TRANSBUFSIZ; +#endif + } else { + /* rawbuf = slide */ + transbuf = G.outbuf; +#if (defined(SMALL_MEM) || defined(MED_MEM) || defined(VMS_TEXT_CONV)) + transbufsiz = OUTBUFSIZ; + Trace((stderr, "\ntransbufsiz = OUTBUFSIZ = %u\n", + (unsigned)OUTBUFSIZ)); +#endif + } + if (G.newfile) { +#ifdef VMS_TEXT_CONV + if (G.pInfo->hostnum == VMS_ && G.extra_field && + is_vms_varlen_txt(__G__ G.extra_field, + G.lrec.extra_field_length)) + G.VMS_line_state = 0; /* 0: ready to read line length */ + else + G.VMS_line_state = -1; /* -1: don't treat as VMS text */ +#endif + G.didCRlast = FALSE; /* no previous buffers written */ + G.newfile = FALSE; + } + +#ifdef VMS_TEXT_CONV + if (G.VMS_line_state >= 0) + { + p = rawbuf; + q = transbuf; + while ((extent)(p-rawbuf) < (extent)size) { + switch (G.VMS_line_state) { + + /* 0: ready to read line length */ + case 0: + G.VMS_line_length = 0; + if ((extent)(p-rawbuf) == (extent)size-1) { + /* last char */ + G.VMS_line_length = (unsigned)(*p++); + G.VMS_line_state = 1; + } else { + G.VMS_line_length = makeword(p); + p += 2; + G.VMS_line_state = 2; + } + G.VMS_line_pad = + ((G.VMS_line_length & 1) != 0); /* odd */ + break; + + /* 1: read one byte of length, need second */ + case 1: + G.VMS_line_length += ((unsigned)(*p++) << 8); + G.VMS_line_state = 2; + break; + + /* 2: ready to read VMS_line_length chars */ + case 2: + { + extent remaining = (extent)size+(rawbuf-p); + extent outroom; + + if (G.VMS_line_length < remaining) { + remaining = G.VMS_line_length; + G.VMS_line_state = 3; + } + + outroom = transbuf+(extent)transbufsiz-q; + if (remaining >= outroom) { + remaining -= outroom; + for (;outroom > 0; p++, outroom--) + *q++ = native(*p); +#ifdef DLL + if (G.redirect_data) { + if (writeToMemory(__G__ transbuf, + (extent)(q-transbuf))) return PK_ERR; + } else +#endif + if (!uO.cflag && WriteError(transbuf, + (extent)(q-transbuf), G.outfile)) + return disk_error(__G); + else if (uO.cflag && (*G.message)((zvoid *)&G, + transbuf, (ulg)(q-transbuf), 0)) + return PK_OK; + q = transbuf; + /* fall through to normal case */ + } + G.VMS_line_length -= remaining; + for (;remaining > 0; p++, remaining--) + *q++ = native(*p); + } + break; + + /* 3: ready to PutNativeEOL */ + case 3: + if (q > transbuf+(extent)transbufsiz-lenEOL) { +#ifdef DLL + if (G.redirect_data) { + if (writeToMemory(__G__ transbuf, + (extent)(q-transbuf))) return PK_ERR; + } else +#endif + if (!uO.cflag && + WriteError(transbuf, (extent)(q-transbuf), + G.outfile)) + return disk_error(__G); + else if (uO.cflag && (*G.message)((zvoid *)&G, + transbuf, (ulg)(q-transbuf), 0)) + return PK_OK; + q = transbuf; + } + PutNativeEOL + G.VMS_line_state = G.VMS_line_pad ? 4 : 0; + break; + + /* 4: ready to read pad byte */ + case 4: + ++p; + G.VMS_line_state = 0; + break; + } + } /* end while */ + + } else +#endif /* VMS_TEXT_CONV */ + + /*----------------------------------------------------------------------- + Algorithm: CR/LF => native; lone CR => native; lone LF => native. + This routine is only for non-raw-VMS, non-raw-VM/CMS files (i.e., + stream-oriented files, not record-oriented). + -----------------------------------------------------------------------*/ + + /* else not VMS text */ { + p = rawbuf; + if (*p == LF && G.didCRlast) + ++p; + G.didCRlast = FALSE; + for (q = transbuf; (extent)(p-rawbuf) < (extent)size; ++p) { + if (*p == CR) { /* lone CR or CR/LF: treat as EOL */ + PutNativeEOL + if ((extent)(p-rawbuf) == (extent)size-1) + /* last char in buffer */ + G.didCRlast = TRUE; + else if (p[1] == LF) /* get rid of accompanying LF */ + ++p; + } else if (*p == LF) /* lone LF */ + PutNativeEOL + else +#ifndef DOS_FLX_OS2_W32 + if (*p != CTRLZ) /* lose all ^Z's */ +#endif + *q++ = native(*p); + +#if (defined(SMALL_MEM) || defined(MED_MEM)) +# if (lenEOL == 1) /* don't check unshrink: both buffers small but equal */ + if (!unshrink) +# endif + /* check for danger of buffer overflow and flush */ + if (q > transbuf+(extent)transbufsiz-lenEOL) { + Trace((stderr, + "p - rawbuf = %u q-transbuf = %u size = %lu\n", + (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size)); + if (!uO.cflag && WriteError(transbuf, + (extent)(q-transbuf), G.outfile)) + return disk_error(__G); + else if (uO.cflag && (*G.message)((zvoid *)&G, + transbuf, (ulg)(q-transbuf), 0)) + return PK_OK; + q = transbuf; + continue; + } +#endif /* SMALL_MEM || MED_MEM */ + } + } + + /*----------------------------------------------------------------------- + Done translating: write whatever we've got to file (or screen). + -----------------------------------------------------------------------*/ + + Trace((stderr, "p - rawbuf = %u q-transbuf = %u size = %lu\n", + (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size)); + if (q > transbuf) { +#ifdef DLL + if (G.redirect_data) { + if (writeToMemory(__G__ transbuf, (extent)(q-transbuf))) + return PK_ERR; + } else +#endif + if (!uO.cflag && WriteError(transbuf, (extent)(q-transbuf), + G.outfile)) + return disk_error(__G); + else if (uO.cflag && (*G.message)((zvoid *)&G, transbuf, + (ulg)(q-transbuf), 0)) + return PK_OK; + } + } + + return PK_OK; + +} /* end function flush() [resp. partflush() for 16-bit Deflate64 support] */ + + + + + +#ifdef VMS_TEXT_CONV + +/********************************/ +/* Function is_vms_varlen_txt() */ +/********************************/ + +static int is_vms_varlen_txt(__G__ ef_buf, ef_len) + __GDEF + uch *ef_buf; /* buffer containing extra field */ + unsigned ef_len; /* total length of extra field */ +{ + unsigned eb_id; + unsigned eb_len; + uch *eb_data; + unsigned eb_datlen; +#define VMSREC_C_UNDEF 0 +#define VMSREC_C_VAR 2 + uch vms_rectype = VMSREC_C_UNDEF; + /* uch vms_fileorg = 0; */ /* currently, fileorg is not used... */ + +#define VMSPK_ITEMID 0 +#define VMSPK_ITEMLEN 2 +#define VMSPK_ITEMHEADSZ 4 + +#define VMSATR_C_RECATTR 4 +#define VMS_FABSIG 0x42414656 /* "VFAB" */ +/* offsets of interesting fields in VMS fabdef structure */ +#define VMSFAB_B_RFM 31 /* record format byte */ +#define VMSFAB_B_ORG 29 /* file organization byte */ + + if (ef_len == 0 || ef_buf == NULL) + return FALSE; + + 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, + "is_vms_varlen_txt: block length %u > rest ef_size %u\n", eb_len, + ef_len - EB_HEADSIZE)); + break; + } + + switch (eb_id) { + case EF_PKVMS: + /* The PKVMS e.f. raw data part consists of: + * a) 4 bytes CRC checksum + * b) list of uncompressed variable-length data items + * Each data item is introduced by a fixed header + * - 2 bytes data type ID + * - 2 bytes of data + * - bytes of actual attribute data + */ + + /* get pointer to start of data and its total length */ + eb_data = ef_buf+(EB_HEADSIZE+4); + eb_datlen = eb_len-4; + + /* test the CRC checksum */ + if (makelong(ef_buf+EB_HEADSIZE) != + crc32(CRCVAL_INITIAL, eb_data, (extent)eb_datlen)) + { + Info(slide, 1, ((char *)slide, + "[Warning: CRC error, discarding PKWARE extra field]\n")); + /* skip over the data analysis code */ + break; + } + + /* scan through the attribute data items */ + while (eb_datlen > 4) + { + unsigned fldsize = makeword(&eb_data[VMSPK_ITEMLEN]); + + /* check the item type word */ + switch (makeword(&eb_data[VMSPK_ITEMID])) { + case VMSATR_C_RECATTR: + /* we have found the (currently only) interesting + * data item */ + if (fldsize >= 1) { + vms_rectype = eb_data[VMSPK_ITEMHEADSZ] & 15; + /* vms_fileorg = eb_data[VMSPK_ITEMHEADSZ] >> 4; */ + } + break; + default: + break; + } + /* skip to next data item */ + eb_datlen -= fldsize + VMSPK_ITEMHEADSZ; + eb_data += fldsize + VMSPK_ITEMHEADSZ; + } + break; + + case EF_IZVMS: + if (makelong(ef_buf+EB_HEADSIZE) == VMS_FABSIG) { + if ((eb_data = extract_izvms_block(__G__ + ef_buf+EB_HEADSIZE, eb_len, + &eb_datlen, NULL, 0)) + != NULL) + { + if (eb_datlen >= VMSFAB_B_RFM+1) { + vms_rectype = eb_data[VMSFAB_B_RFM] & 15; + /* vms_fileorg = eb_data[VMSFAB_B_ORG] >> 4; */ + } + free(eb_data); + } + } + break; + + default: + break; + } + + /* Skip this extra field block */ + ef_buf += (eb_len + EB_HEADSIZE); + ef_len -= (eb_len + EB_HEADSIZE); + } + + return (vms_rectype == VMSREC_C_VAR); + +} /* end function is_vms_varlen_txtfile() */ + +#endif /* VMS_TEXT_CONV */ + + + + +/*************************/ +/* Function disk_error() */ +/*************************/ + +static int disk_error(__G) + __GDEF +{ + /* OK to use slide[] here because this file is finished regardless */ + Info(slide, 0x4a1, ((char *)slide, LoadFarString(DiskFullQuery), + FnFilter1(G.filename))); + +#ifndef WINDLL + fgets(G.answerbuf, sizeof(G.answerbuf), stdin); + if (*G.answerbuf == 'y') /* stop writing to this file */ + G.disk_full = 1; /* (outfile bad?), but new OK */ + else +#endif + G.disk_full = 2; /* no: exit program */ + + return PK_DISK; + +} /* end function disk_error() */ + +#endif /* !VMS */ + + + + + +/*****************************/ +/* Function UzpMessagePrnt() */ +/*****************************/ + +int UZ_EXP UzpMessagePrnt(pG, buf, size, flag) + zvoid *pG; /* globals struct: always passed */ + uch *buf; /* preformatted string to be printed */ + ulg size; /* length of string (may include nulls) */ + int flag; /* flag bits */ +{ + /* IMPORTANT NOTE: + * The name of the first parameter of UzpMessagePrnt(), which passes + * the "Uz_Globs" address, >>> MUST <<< be identical to the string + * expansion of the __G__ macro in the REENTRANT case (see globals.h). + * This name identity is mandatory for the LoadFarString() macro + * (in the SMALL_MEM case) !!! + */ + int error; + uch *q=buf, *endbuf=buf+(unsigned)size; +#ifdef MORE + uch *p=buf; +#if (defined(SCREENWIDTH) && defined(SCREENLWRAP)) + int islinefeed = FALSE; +#endif +#endif + FILE *outfp; + + +/*--------------------------------------------------------------------------- + These tests are here to allow fine-tuning of UnZip's output messages, + but none of them will do anything without setting the appropriate bit + in the flag argument of every Info() statement which is to be turned + *off*. That is, all messages are currently turned on for all ports. + To turn off *all* messages, use the UzpMessageNull() function instead + of this one. + ---------------------------------------------------------------------------*/ + +#if (defined(OS2) && defined(DLL)) + if (MSG_NO_DLL2(flag)) /* if OS/2 DLL bit is set, do NOT print this msg */ + return 0; +#endif +#ifdef WINDLL + if (MSG_NO_WDLL(flag)) + return 0; +#endif +#ifdef WINDLL + if (MSG_NO_WGUI(flag)) + return 0; +#endif +/* +#ifdef ACORN_GUI + if (MSG_NO_AGUI(flag)) + return 0; +#endif + */ +#ifdef DLL /* don't display message if data is redirected */ + if (((Uz_Globs *)pG)->redirect_data && + !((Uz_Globs *)pG)->redirect_text) + return 0; +#endif + + if (MSG_STDERR(flag) && !((Uz_Globs *)pG)->UzO.tflag) + outfp = (FILE *)stderr; + else + outfp = (FILE *)stdout; + +#ifdef QUERY_TRNEWLN + /* some systems require termination of query prompts with '\n' to force + * immediate display */ + if (MSG_MNEWLN(flag)) { /* assumes writable buffer (e.g., slide[]) */ + *endbuf++ = '\n'; /* with room for one more char at end of buf */ + ++size; /* (safe assumption: only used for four */ + } /* short queries in extract.c and fileio.c) */ +#endif + + if (MSG_TNEWLN(flag)) { /* again assumes writable buffer: fragile... */ + if ((!size && !((Uz_Globs *)pG)->sol) || + (size && (endbuf[-1] != '\n'))) + { + *endbuf++ = '\n'; + ++size; + } + } + +#ifdef MORE +# ifdef SCREENSIZE + /* room for --More-- and one line of overlap: */ +# if (defined(SCREENWIDTH) && defined(SCREENLWRAP)) + SCREENSIZE(&((Uz_Globs *)pG)->height, &((Uz_Globs *)pG)->width); +# else + SCREENSIZE(&((Uz_Globs *)pG)->height, (int *)NULL); +# endif + ((Uz_Globs *)pG)->height -= 2; +# else + /* room for --More-- and one line of overlap: */ + ((Uz_Globs *)pG)->height = SCREENLINES - 2; +# if (defined(SCREENWIDTH) && defined(SCREENLWRAP)) + ((Uz_Globs *)pG)->width = SCREENWIDTH; +# endif +# endif +#endif /* MORE */ + + if (MSG_LNEWLN(flag) && !((Uz_Globs *)pG)->sol) { + /* not at start of line: want newline */ +#ifdef OS2DLL + if (!((Uz_Globs *)pG)->redirect_text) { +#endif + putc('\n', outfp); + fflush(outfp); +#ifdef MORE + if (((Uz_Globs *)pG)->M_flag) + { +#if (defined(SCREENWIDTH) && defined(SCREENLWRAP)) + ((Uz_Globs *)pG)->chars = 0; +#endif + ++((Uz_Globs *)pG)->numlines; + ++((Uz_Globs *)pG)->lines; + if (((Uz_Globs *)pG)->lines >= ((Uz_Globs *)pG)->height) + (*((Uz_Globs *)pG)->mpause)((zvoid *)pG, + LoadFarString(MorePrompt), 1); + } +#endif /* MORE */ + if (MSG_STDERR(flag) && ((Uz_Globs *)pG)->UzO.tflag && + !isatty(1) && isatty(2)) + { + /* error output from testing redirected: also send to stderr */ + putc('\n', stderr); + fflush(stderr); + } +#ifdef OS2DLL + } else + REDIRECTC('\n'); +#endif + ((Uz_Globs *)pG)->sol = TRUE; + } + + /* put zipfile name, filename and/or error/warning keywords here */ + +#ifdef MORE + if (((Uz_Globs *)pG)->M_flag +#ifdef OS2DLL + && !((Uz_Globs *)pG)->redirect_text +#endif + ) + { + while (p < endbuf) { + if (*p == '\n') { +#if (defined(SCREENWIDTH) && defined(SCREENLWRAP)) + islinefeed = TRUE; + } else if (SCREENLWRAP) { + if (*p == '\r') { + ((Uz_Globs *)pG)->chars = 0; + } else { +# ifdef TABSIZE + if (*p == '\t') + ((Uz_Globs *)pG)->chars += + (TABSIZE - (((Uz_Globs *)pG)->chars % TABSIZE)); + else +# endif + ++((Uz_Globs *)pG)->chars; + + if (((Uz_Globs *)pG)->chars >= ((Uz_Globs *)pG)->width) + islinefeed = TRUE; + } + } + if (islinefeed) { + islinefeed = FALSE; + ((Uz_Globs *)pG)->chars = 0; +#endif /* (SCREENWIDTH && SCREEN_LWRAP) */ + ++((Uz_Globs *)pG)->numlines; + ++((Uz_Globs *)pG)->lines; + if (((Uz_Globs *)pG)->lines >= ((Uz_Globs *)pG)->height) + { + if ((error = WriteTxtErr(q, p-q+1, outfp)) != 0) + return error; + fflush(outfp); + ((Uz_Globs *)pG)->sol = TRUE; + q = p + 1; + (*((Uz_Globs *)pG)->mpause)((zvoid *)pG, + LoadFarString(MorePrompt), 1); + } + } + INCSTR(p); + } /* end while */ + size = (ulg)(p - q); /* remaining text */ + } +#endif /* MORE */ + + if (size) { +#ifdef OS2DLL + if (!((Uz_Globs *)pG)->redirect_text) { +#endif + if ((error = WriteTxtErr(q, size, outfp)) != 0) + return error; +#ifndef VMS /* 2005-09-16 SMS. See note at "WriteTxtErr()", above. */ + fflush(outfp); +#endif + if (MSG_STDERR(flag) && ((Uz_Globs *)pG)->UzO.tflag && + !isatty(1) && isatty(2)) + { + /* error output from testing redirected: also send to stderr */ + if ((error = WriteTxtErr(q, size, stderr)) != 0) + return error; + fflush(stderr); + } +#ifdef OS2DLL + } else { /* GRR: this is ugly: hide with macro */ + if ((error = REDIRECTPRINT(q, size)) != 0) + return error; + } +#endif /* OS2DLL */ + ((Uz_Globs *)pG)->sol = (endbuf[-1] == '\n'); + } + return 0; + +} /* end function UzpMessagePrnt() */ + + + + + +#ifdef DLL + +/*****************************/ +/* Function UzpMessageNull() */ /* convenience routine for no output at all */ +/*****************************/ + +int UZ_EXP UzpMessageNull(pG, buf, size, flag) + zvoid *pG; /* globals struct: always passed */ + uch *buf; /* preformatted string to be printed */ + ulg size; /* length of string (may include nulls) */ + int flag; /* flag bits */ +{ + return 0; + +} /* end function UzpMessageNull() */ + +#endif /* DLL */ + + + + + +/***********************/ +/* Function UzpInput() */ /* GRR: this is a placeholder for now */ +/***********************/ + +int UZ_EXP UzpInput(pG, buf, size, flag) + zvoid *pG; /* globals struct: always passed */ + uch *buf; /* preformatted string to be printed */ + int *size; /* (address of) size of buf and of returned string */ + int flag; /* flag bits (bit 0: no echo) */ +{ + /* tell picky compilers to shut up about "unused variable" warnings */ + pG = pG; buf = buf; flag = flag; + + *size = 0; + return 0; + +} /* end function UzpInput() */ + + + + + +#if (!defined(WINDLL) && !defined(MACOS)) + +/***************************/ +/* Function UzpMorePause() */ +/***************************/ + +void UZ_EXP UzpMorePause(pG, prompt, flag) + zvoid *pG; /* globals struct: always passed */ + ZCONST char *prompt; /* "--More--" prompt */ + int flag; /* 0 = any char OK; 1 = accept only '\n', ' ', q */ +{ + uch c; + +/*--------------------------------------------------------------------------- + Print a prompt and wait for the user to press a key, then erase prompt + if possible. + ---------------------------------------------------------------------------*/ + + if (!((Uz_Globs *)pG)->sol) + fprintf(stderr, "\n"); + /* numlines may or may not be used: */ + fprintf(stderr, prompt, ((Uz_Globs *)pG)->numlines); + fflush(stderr); + if (flag & 1) { + do { + c = (uch)FGETCH(0); + } while ( +#ifdef THEOS + c != 17 && /* standard QUIT key */ +#endif + c != '\r' && c != '\n' && c != ' ' && c != 'q' && c != 'Q'); + } else + c = (uch)FGETCH(0); + + /* newline was not echoed, so cover up prompt line */ + fprintf(stderr, LoadFarString(HidePrompt)); + fflush(stderr); + + if ( +#ifdef THEOS + (c == 17) || /* standard QUIT key */ +#endif + (ToLower(c) == 'q')) { + DESTROYGLOBALS(); + EXIT(PK_COOL); + } + + ((Uz_Globs *)pG)->sol = TRUE; + +#ifdef MORE + /* space for another screen, enter for another line. */ + if ((flag & 1) && c == ' ') + ((Uz_Globs *)pG)->lines = 0; +#endif /* MORE */ + +} /* end function UzpMorePause() */ + +#endif /* !WINDLL && !MACOS */ + + + + +#ifndef WINDLL + +/**************************/ +/* Function UzpPassword() */ +/**************************/ + +int UZ_EXP UzpPassword (pG, rcnt, pwbuf, size, zfn, efn) + zvoid *pG; /* pointer to UnZip's internal global vars */ + int *rcnt; /* retry counter */ + char *pwbuf; /* buffer for password */ + int size; /* size of password buffer */ + ZCONST char *zfn; /* name of zip archive */ + ZCONST char *efn; /* name of archive entry being processed */ +{ +#if CRYPT + int r = IZ_PW_ENTERED; + char *m; + char *prompt; + +#ifndef REENTRANT + /* tell picky compilers to shut up about "unused variable" warnings */ + pG = pG; +#endif + + 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)); + m = prompt; + } else + m = (char *)LoadFarString(PasswPrompt2); + } else { /* Retry call, previous password was wrong */ + (*rcnt)--; + prompt = NULL; + m = (char *)LoadFarString(PasswRetry); + } + + m = getp(__G__ m, pwbuf, size); + if (prompt != (char *)NULL) { + free(prompt); + } + if (m == (char *)NULL) { + r = IZ_PW_ERROR; + } + else if (*pwbuf == '\0') { + r = IZ_PW_CANCELALL; + } + return r; + +#else /* !CRYPT */ + /* tell picky compilers to shut up about "unused variable" warnings */ + pG = pG; rcnt = rcnt; pwbuf = pwbuf; size = size; zfn = zfn; efn = efn; + + return IZ_PW_ERROR; /* internal error; function should never get called */ +#endif /* ?CRYPT */ + +} /* end function UzpPassword() */ + + + + + +/**********************/ +/* Function handler() */ +/**********************/ + +void handler(signal) /* upon interrupt, turn on echo and exit cleanly */ + int signal; +{ + GETGLOBALS(); + +#if !(defined(SIGBUS) || defined(SIGSEGV)) /* add a newline if not at */ + (*G.message)((zvoid *)&G, slide, 0L, 0x41); /* start of line (to stderr; */ +#endif /* slide[] should be safe) */ + + echon(); + +#ifdef SIGBUS + if (signal == SIGBUS) { + Info(slide, 0x421, ((char *)slide, LoadFarString(ZipfileCorrupt), + "bus error")); + DESTROYGLOBALS(); + EXIT(PK_BADERR); + } +#endif /* SIGBUS */ + +#ifdef SIGILL + if (signal == SIGILL) { + Info(slide, 0x421, ((char *)slide, LoadFarString(ZipfileCorrupt), + "illegal instruction")); + DESTROYGLOBALS(); + EXIT(PK_BADERR); + } +#endif /* SIGILL */ + +#ifdef SIGSEGV + if (signal == SIGSEGV) { + Info(slide, 0x421, ((char *)slide, LoadFarString(ZipfileCorrupt), + "segmentation violation")); + DESTROYGLOBALS(); + EXIT(PK_BADERR); + } +#endif /* SIGSEGV */ + + /* probably ctrl-C */ + DESTROYGLOBALS(); +#if defined(AMIGA) && defined(__SASC) + _abort(); +#endif + EXIT(IZ_CTRLC); /* was EXIT(0), then EXIT(PK_ERR) */ +} + +#endif /* !WINDLL */ + + + + +#if (!defined(VMS) && !defined(CMS_MVS)) +#if (!defined(OS2) || defined(TIMESTAMP)) + +#if (!defined(HAVE_MKTIME) || defined(WIN32)) +/* also used in amiga/filedate.c and win32/win32.c */ +ZCONST ush ydays[] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; +#endif + +/*******************************/ +/* Function dos_to_unix_time() */ /* used for freshening/updating/timestamps */ +/*******************************/ + +time_t dos_to_unix_time(dosdatetime) + ulg dosdatetime; +{ + time_t m_time; + +#ifdef HAVE_MKTIME + + ZCONST time_t now = time(NULL); + struct tm *tm; +# define YRBASE 1900 + + tm = localtime(&now); + tm->tm_isdst = -1; /* let mktime determine if DST is in effect */ + + /* dissect date */ + tm->tm_year = ((int)(dosdatetime >> 25) & 0x7f) + (1980 - YRBASE); + tm->tm_mon = ((int)(dosdatetime >> 21) & 0x0f) - 1; + tm->tm_mday = ((int)(dosdatetime >> 16) & 0x1f); + + /* dissect time */ + tm->tm_hour = (int)((unsigned)dosdatetime >> 11) & 0x1f; + tm->tm_min = (int)((unsigned)dosdatetime >> 5) & 0x3f; + tm->tm_sec = (int)((unsigned)dosdatetime << 1) & 0x3e; + + m_time = mktime(tm); + NATIVE_TO_TIMET(m_time) /* NOP unless MSC 7.0 or Macintosh */ + TTrace((stderr, " final m_time = %lu\n", (ulg)m_time)); + +#else /* !HAVE_MKTIME */ + + int yr, mo, dy, hh, mm, ss; +#ifdef TOPS20 +# define YRBASE 1900 + struct tmx *tmx; + char temp[20]; +#else /* !TOPS20 */ +# define YRBASE 1970 + int leap; + unsigned days; + struct tm *tm; +#if (!defined(MACOS) && !defined(RISCOS) && !defined(QDOS) && !defined(TANDEM)) +#ifdef WIN32 + TIME_ZONE_INFORMATION tzinfo; + DWORD res; +#else /* ! WIN32 */ +#ifndef BSD4_4 /* GRR: change to !defined(MODERN) ? */ +#if (defined(BSD) || defined(MTS) || defined(__GO32__)) + struct timeb tbp; +#else /* !(BSD || MTS || __GO32__) */ +#ifdef DECLARE_TIMEZONE + extern time_t timezone; +#endif +#endif /* ?(BSD || MTS || __GO32__) */ +#endif /* !BSD4_4 */ +#endif /* ?WIN32 */ +#endif /* !MACOS && !RISCOS && !QDOS && !TANDEM */ +#endif /* ?TOPS20 */ + + + /* dissect date */ + yr = ((int)(dosdatetime >> 25) & 0x7f) + (1980 - YRBASE); + mo = ((int)(dosdatetime >> 21) & 0x0f) - 1; + dy = ((int)(dosdatetime >> 16) & 0x1f) - 1; + + /* dissect time */ + hh = (int)((unsigned)dosdatetime >> 11) & 0x1f; + mm = (int)((unsigned)dosdatetime >> 5) & 0x3f; + ss = (int)((unsigned)dosdatetime & 0x1f) * 2; + +#ifdef TOPS20 + tmx = (struct tmx *)malloc(sizeof(struct tmx)); + sprintf (temp, "%02d/%02d/%02d %02d:%02d:%02d", mo+1, dy+1, yr, hh, mm, ss); + time_parse(temp, tmx, (char *)0); + m_time = time_make(tmx); + free(tmx); + +#else /* !TOPS20 */ + +/*--------------------------------------------------------------------------- + Calculate the number of seconds since the epoch, usually 1 January 1970. + ---------------------------------------------------------------------------*/ + + /* leap = # of leap yrs from YRBASE up to but not including current year */ + leap = ((yr + YRBASE - 1) / 4); /* leap year base factor */ + + /* calculate days from BASE to this year and add expired days this year */ + days = (yr * 365) + (leap - 492) + ydays[mo]; + + /* if year is a leap year and month is after February, add another day */ + if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100)) + ++days; /* OK through 2199 */ + + /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */ + m_time = (time_t)((unsigned long)(days + dy) * 86400L + + (unsigned long)hh * 3600L + + (unsigned long)(mm * 60 + ss)); + /* - 1; MS-DOS times always rounded up to nearest even second */ + TTrace((stderr, "dos_to_unix_time:\n")); + TTrace((stderr, " m_time before timezone = %lu\n", (ulg)m_time)); + +/*--------------------------------------------------------------------------- + Adjust for local standard timezone offset. + ---------------------------------------------------------------------------*/ + +#if (!defined(MACOS) && !defined(RISCOS) && !defined(QDOS) && !defined(TANDEM)) +#ifdef WIN32 + /* account for timezone differences */ + res = GetTimeZoneInformation(&tzinfo); + if (res != TIME_ZONE_ID_INVALID) + { + m_time += 60*(tzinfo.Bias); +#else /* !WIN32 */ +#if (defined(BSD) || defined(MTS) || defined(__GO32__)) +#ifdef BSD4_4 + if ( (dosdatetime >= DOSTIME_2038_01_18) && + (m_time < (time_t)0x70000000L) ) + m_time = U_TIME_T_MAX; /* saturate in case of (unsigned) overflow */ + if (m_time < (time_t)0L) /* a converted DOS time cannot be negative */ + m_time = S_TIME_T_MAX; /* -> saturate at max signed time_t value */ + if ((tm = localtime(&m_time)) != (struct tm *)NULL) + m_time -= tm->tm_gmtoff; /* sec. EAST of GMT: subtr. */ +#else /* !(BSD4_4 */ + ftime(&tbp); /* get `timezone' */ + m_time += tbp.timezone * 60L; /* seconds WEST of GMT: add */ +#endif /* ?(BSD4_4 || __EMX__) */ +#else /* !(BSD || MTS || __GO32__) */ + /* tzset was already called at start of process_zipfiles() */ + /* tzset(); */ /* set `timezone' variable */ +#ifndef __BEOS__ /* BeOS DR8 has no timezones... */ + m_time += timezone; /* seconds WEST of GMT: add */ +#endif +#endif /* ?(BSD || MTS || __GO32__) */ +#endif /* ?WIN32 */ + TTrace((stderr, " m_time after timezone = %lu\n", (ulg)m_time)); + +/*--------------------------------------------------------------------------- + Adjust for local daylight savings (summer) time. + ---------------------------------------------------------------------------*/ + +#ifndef BSD4_4 /* (DST already added to tm_gmtoff, so skip tm_isdst) */ + if ( (dosdatetime >= DOSTIME_2038_01_18) && + (m_time < (time_t)0x70000000L) ) + m_time = U_TIME_T_MAX; /* saturate in case of (unsigned) overflow */ + if (m_time < (time_t)0L) /* a converted DOS time cannot be negative */ + m_time = S_TIME_T_MAX; /* -> saturate at max signed time_t value */ + TIMET_TO_NATIVE(m_time) /* NOP unless MSC 7.0 or Macintosh */ + if (((tm = localtime((time_t *)&m_time)) != NULL) && tm->tm_isdst) +#ifdef WIN32 + m_time += 60L * tzinfo.DaylightBias; /* adjust with DST bias */ + else + m_time += 60L * tzinfo.StandardBias; /* add StdBias (normally 0) */ +#else + m_time -= 60L * 60L; /* adjust for daylight savings time */ +#endif + NATIVE_TO_TIMET(m_time) /* NOP unless MSC 7.0 or Macintosh */ + TTrace((stderr, " m_time after DST = %lu\n", (ulg)m_time)); +#endif /* !BSD4_4 */ +#ifdef WIN32 + } +#endif +#endif /* !MACOS && !RISCOS && !QDOS && !TANDEM */ +#endif /* ?TOPS20 */ + +#endif /* ?HAVE_MKTIME */ + + if ( (dosdatetime >= DOSTIME_2038_01_18) && + (m_time < (time_t)0x70000000L) ) + m_time = U_TIME_T_MAX; /* saturate in case of (unsigned) overflow */ + if (m_time < (time_t)0L) /* a converted DOS time cannot be negative */ + m_time = S_TIME_T_MAX; /* -> saturate at max signed time_t value */ + + return m_time; + +} /* end function dos_to_unix_time() */ + +#endif /* !OS2 || TIMESTAMP */ +#endif /* !VMS && !CMS_MVS */ + + + +#if (!defined(VMS) && !defined(OS2) && !defined(CMS_MVS)) + +/******************************/ +/* Function check_for_newer() */ /* used for overwriting/freshening/updating */ +/******************************/ + +int check_for_newer(__G__ filename) /* return 1 if existing file is newer */ + __GDEF /* or equal; 0 if older; -1 if doesn't */ + char *filename; /* exist yet */ +{ + time_t existing, archive; +#ifdef USE_EF_UT_TIME + iztimes z_utime; +#endif +#ifdef AOS_VS + long dyy, dmm, ddd, dhh, dmin, dss; + + + dyy = (lrec.last_mod_dos_datetime >> 25) + 1980; + dmm = (lrec.last_mod_dos_datetime >> 21) & 0x0f; + ddd = (lrec.last_mod_dos_datetime >> 16) & 0x1f; + dhh = (lrec.last_mod_dos_datetime >> 11) & 0x1f; + dmin = (lrec.last_mod_dos_datetime >> 5) & 0x3f; + dss = (lrec.last_mod_dos_datetime & 0x1f) * 2; + + /* under AOS/VS, file times can only be set at creation time, + * with the info in a special DG format. Make sure we can create + * it here - we delete it later & re-create it, whether or not + * it exists now. + */ + if (!zvs_create(filename, (((ulg)dgdate(dmm, ddd, dyy)) << 16) | + (dhh*1800L + dmin*30L + dss/2L), -1L, -1L, (char *) -1, -1, -1, -1)) + return DOES_NOT_EXIST; +#endif /* AOS_VS */ + + Trace((stderr, "check_for_newer: doing stat(%s)\n", FnFilter1(filename))); + if (SSTAT(filename, &G.statbuf)) { + Trace((stderr, + "check_for_newer: stat(%s) returns %d: file does not exist\n", + FnFilter1(filename), SSTAT(filename, &G.statbuf))); +#ifdef SYMLINKS + Trace((stderr, "check_for_newer: doing lstat(%s)\n", + FnFilter1(filename))); + /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */ + if (lstat(filename, &G.statbuf) == 0) { + Trace((stderr, + "check_for_newer: lstat(%s) returns 0: symlink does exist\n", + FnFilter1(filename))); + if (QCOND2 && !IS_OVERWRT_ALL) + Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink), + FnFilter1(filename), " with no real file")); + return EXISTS_AND_OLDER; /* symlink dates are meaningless */ + } +#endif /* SYMLINKS */ + return DOES_NOT_EXIST; + } + Trace((stderr, "check_for_newer: stat(%s) returns 0: file exists\n", + FnFilter1(filename))); + +#ifdef SYMLINKS + /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */ + if (lstat(filename, &G.statbuf) == 0 && S_ISLNK(G.statbuf.st_mode)) { + Trace((stderr, "check_for_newer: %s is a symbolic link\n", + FnFilter1(filename))); + if (QCOND2 && !IS_OVERWRT_ALL) + Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink), + FnFilter1(filename), "")); + return EXISTS_AND_OLDER; /* symlink dates are meaningless */ + } +#endif /* SYMLINKS */ + + NATIVE_TO_TIMET(G.statbuf.st_mtime) /* NOP unless MSC 7.0 or Macintosh */ + +#ifdef USE_EF_UT_TIME + /* The `Unix extra field mtime' should be used for comparison with the + * time stamp of the existing file >>>ONLY<<< when the EF info is also + * used to set the modification time of the extracted file. + */ + if (G.extra_field && +#ifdef IZ_CHECK_TZ + G.tz_is_valid && +#endif + (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0, + G.lrec.last_mod_dos_datetime, &z_utime, NULL) + & EB_UT_FL_MTIME)) + { + TTrace((stderr, "check_for_newer: using Unix extra field mtime\n")); + existing = G.statbuf.st_mtime; + archive = z_utime.mtime; + } else { + /* round up existing filetime to nearest 2 seconds for comparison, + * but saturate in case of arithmetic overflow + */ + existing = ((G.statbuf.st_mtime & 1) && + (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ? + G.statbuf.st_mtime + 1 : G.statbuf.st_mtime; + archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime); + } +#else /* !USE_EF_UT_TIME */ + /* round up existing filetime to nearest 2 seconds for comparison, + * but saturate in case of arithmetic overflow + */ + existing = ((G.statbuf.st_mtime & 1) && + (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ? + G.statbuf.st_mtime + 1 : G.statbuf.st_mtime; + archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime); +#endif /* ?USE_EF_UT_TIME */ + + TTrace((stderr, "check_for_newer: existing %lu, archive %lu, e-a %ld\n", + (ulg)existing, (ulg)archive, (long)(existing-archive))); + + return (existing >= archive); + +} /* end function check_for_newer() */ + +#endif /* !VMS && !OS2 && !CMS_MVS */ + +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) +int check_for_newerw(__G__ filenamew) /* return 1 if existing file is newer */ + __GDEF /* or equal; 0 if older; -1 if doesn't */ + wchar_t *filenamew; /* exist yet */ +{ + time_t existing, archive; +#ifdef USE_EF_UT_TIME + iztimes z_utime; +#endif +#ifdef AOS_VS + long dyy, dmm, ddd, dhh, dmin, dss; + + + dyy = (lrec.last_mod_dos_datetime >> 25) + 1980; + dmm = (lrec.last_mod_dos_datetime >> 21) & 0x0f; + ddd = (lrec.last_mod_dos_datetime >> 16) & 0x1f; + dhh = (lrec.last_mod_dos_datetime >> 11) & 0x1f; + dmin = (lrec.last_mod_dos_datetime >> 5) & 0x3f; + dss = (lrec.last_mod_dos_datetime & 0x1f) * 2; + + /* under AOS/VS, file times can only be set at creation time, + * with the info in a special DG format. Make sure we can create + * it here - we delete it later & re-create it, whether or not + * it exists now. + */ + if (!zvs_create(filenamew, (((ulg)dgdate(dmm, ddd, dyy)) << 16) | + (dhh*1800L + dmin*30L + dss/2L), -1L, -1L, (char *) -1, -1, -1, -1)) + return DOES_NOT_EXIST; +#endif /* AOS_VS */ + + Trace((stderr, "check_for_newer: doing stat(%s)\n", FnFilter1(filename))); + if (SSTATW(filenamew, &G.statbuf)) { + Trace((stderr, + "check_for_newer: stat(%s) returns %d: file does not exist\n", + FnFilter1(filename), SSTAT(filename, &G.statbuf))); +#ifdef SYMLINKS + Trace((stderr, "check_for_newer: doing lstat(%s)\n", + FnFilter1(filename))); + /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */ + if (zlstat(filename, &G.statbuf) == 0) { + Trace((stderr, + "check_for_newer: lstat(%s) returns 0: symlink does exist\n", + FnFilter1(filename))); + if (QCOND2 && !IS_OVERWRT_ALL) + Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink), + FnFilter1(filename), " with no real file")); + return EXISTS_AND_OLDER; /* symlink dates are meaningless */ + } +#endif /* SYMLINKS */ + return DOES_NOT_EXIST; + } + Trace((stderr, "check_for_newer: stat(%s) returns 0: file exists\n", + FnFilter1(filename))); + +#ifdef SYMLINKS + /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */ + if (zlstat(filename, &G.statbuf) == 0 && S_ISLNK(G.statbuf.st_mode)) { + Trace((stderr, "check_for_newer: %s is a symbolic link\n", + FnFilter1(filename))); + if (QCOND2 && !IS_OVERWRT_ALL) + Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink), + FnFilter1(filename), "")); + return EXISTS_AND_OLDER; /* symlink dates are meaningless */ + } +#endif /* SYMLINKS */ + + NATIVE_TO_TIMET(G.statbuf.st_mtime) /* NOP unless MSC 7.0 or Macintosh */ + +#ifdef USE_EF_UT_TIME + /* The `Unix extra field mtime' should be used for comparison with the + * time stamp of the existing file >>>ONLY<<< when the EF info is also + * used to set the modification time of the extracted file. + */ + if (G.extra_field && +#ifdef IZ_CHECK_TZ + G.tz_is_valid && +#endif + (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0, + G.lrec.last_mod_dos_datetime, &z_utime, NULL) + & EB_UT_FL_MTIME)) + { + TTrace((stderr, "check_for_newer: using Unix extra field mtime\n")); + existing = G.statbuf.st_mtime; + archive = z_utime.mtime; + } else { + /* round up existing filetime to nearest 2 seconds for comparison, + * but saturate in case of arithmetic overflow + */ + existing = ((G.statbuf.st_mtime & 1) && + (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ? + G.statbuf.st_mtime + 1 : G.statbuf.st_mtime; + archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime); + } +#else /* !USE_EF_UT_TIME */ + /* round up existing filetime to nearest 2 seconds for comparison, + * but saturate in case of arithmetic overflow + */ + existing = ((G.statbuf.st_mtime & 1) && + (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ? + G.statbuf.st_mtime + 1 : G.statbuf.st_mtime; + archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime); +#endif /* ?USE_EF_UT_TIME */ + + TTrace((stderr, "check_for_newer: existing %lu, archive %lu, e-a %ld\n", + (ulg)existing, (ulg)archive, (long)(existing-archive))); + + return (existing >= archive); + +} /* end function check_for_newerw() */ +#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ + + + + +/************************/ +/* Function do_string() */ +/************************/ + +int do_string(__G__ length, option) /* return PK-type error code */ + __GDEF + unsigned int length; /* without prototype, ush converted to this */ + int option; +{ + unsigned comment_bytes_left; + unsigned int block_len; + int error=PK_OK; +#ifdef AMIGA + char tmp_fnote[2 * AMIGA_FILENOTELEN]; /* extra room for squozen chars */ +#endif + ush flag; + + +/*--------------------------------------------------------------------------- + This function processes arbitrary-length (well, usually) strings. Four + major options are allowed: SKIP, wherein the string is skipped (pretty + logical, eh?); DISPLAY, wherein the string is printed to standard output + after undergoing any necessary or unnecessary character conversions; + DS_FN, wherein the string is put into the filename[] array after under- + going appropriate conversions (including case-conversion, if that is + indicated: see the global variable pInfo->lcflag); and EXTRA_FIELD, + wherein the `string' is assumed to be an extra field and is copied to + the (freshly malloced) buffer G.extra_field. The third option should + be OK since filename is dimensioned at 1025, but we check anyway. + + The string, by the way, is assumed to start at the current file-pointer + position; its length is given by 'length'. So start off by checking the + length of the string: if zero, we're already done. + ---------------------------------------------------------------------------*/ + + if (!length) + return PK_COOL; + + switch (option) { + +#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) + /* + * Special case: See if the comment begins with an autorun command line. + * Save that and display (or skip) the remainder. + */ + + case CHECK_AUTORUN: + case CHECK_AUTORUN_Q: + comment_bytes_left = length; + if (length >= 10) + { + block_len = readbuf(__G__ (char *)G.outbuf, 10); + if (block_len == 0) + return PK_EOF; + comment_bytes_left -= block_len; + G.outbuf[block_len] = '\0'; + if (!strcmp((char *)G.outbuf, "$AUTORUN$>")) { + char *eol; + length -= 10; + block_len = readbuf(__G__ G.autorun_command, + MIN(length, sizeof(G.autorun_command)-1)); + if (block_len == 0) + return PK_EOF; + comment_bytes_left -= block_len; + G.autorun_command[block_len] = '\0'; + A_TO_N(G.autorun_command); + eol = strchr(G.autorun_command, '\n'); + if (!eol) + eol = G.autorun_command + strlen(G.autorun_command) - 1; + length -= eol + 1 - G.autorun_command; + while (eol >= G.autorun_command && isspace(*eol)) + *eol-- = '\0'; +#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(G.autorun_command, G.autorun_command); +#endif /* (WIN32 && !_WIN32_WCE) */ + } + } + if (option == CHECK_AUTORUN_Q) /* don't display the remainder */ + length = 0; + /* seek to beginning of remaining part of comment -- rewind if */ + /* displaying entire comment, or skip to end if discarding it */ + seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes + + (G.inptr - G.inbuf) + comment_bytes_left - length); + if (!length) + break; + /* FALL THROUGH... */ +#endif /* SFX && CHEAP_SFX_AUTORUN */ + + /* + * First normal case: print string on standard output. First set loop + * variables, then loop through the comment in chunks of OUTBUFSIZ bytes, + * converting formats and printing as we go. The second half of the + * loop conditional was added because the file might be truncated, in + * which case comment_bytes_left will remain at some non-zero value for + * all time. outbuf and slide are used as scratch buffers because they + * are available (we should be either before or in between any file pro- + * cessing). + */ + + case DISPLAY: + case DISPL_8: + comment_bytes_left = length; + block_len = OUTBUFSIZ; /* for the while statement, first time */ + while (comment_bytes_left > 0 && block_len > 0) { + register uch *p = G.outbuf; + register uch *q = G.outbuf; + + if ((block_len = readbuf(__G__ (char *)G.outbuf, + MIN((unsigned)OUTBUFSIZ, comment_bytes_left))) == 0) + return PK_EOF; + comment_bytes_left -= block_len; + + /* this is why we allocated an extra byte for outbuf: terminate + * with zero (ASCIIZ) */ + G.outbuf[block_len] = '\0'; + + /* remove all ASCII carriage returns from comment before printing + * (since used before A_TO_N(), check for CR instead of '\r') + */ + while (*p) { + while (*p == CR) + ++p; + *q++ = *p++; + } + /* could check whether (p - outbuf) == block_len here */ + *q = '\0'; + + if (option == DISPL_8) { + /* translate the text coded in the entry's host-dependent + "extended ASCII" charset into the compiler's (system's) + internal text code page */ + Ext_ASCII_TO_Native((char *)G.outbuf, G.pInfo->hostnum, + G.pInfo->hostver, G.pInfo->HasUxAtt, + FALSE); +#ifdef WINDLL + /* translate to ANSI (RTL internal codepage may be OEM) */ + INTERN_TO_ISO((char *)G.outbuf, (char *)G.outbuf); +#else /* !WINDLL */ +#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 *)G.outbuf, (char *)G.outbuf); +#endif /* (WIN32 && !_WIN32_WCE) */ +#endif /* ?WINDLL */ + } else { + A_TO_N(G.outbuf); /* translate string to native */ + } + +#ifdef WINDLL + /* ran out of local mem -- had to cheat */ + win_fprintf((zvoid *)&G, stdout, (extent)(q-G.outbuf), + (char *)G.outbuf); + win_fprintf((zvoid *)&G, stdout, 2, (char *)"\n\n"); +#else /* !WINDLL */ +#ifdef NOANSIFILT /* GRR: can ANSI be used with EBCDIC? */ + (*G.message)((zvoid *)&G, G.outbuf, (ulg)(q-G.outbuf), 0); +#else /* ASCII, filter out ANSI escape sequences and handle ^S (pause) */ + p = G.outbuf - 1; + q = slide; + while (*++p) { + int pause = FALSE; + + if (*p == 0x1B) { /* ASCII escape char */ + *q++ = '^'; + *q++ = '['; + } else if (*p == 0x13) { /* ASCII ^S (pause) */ + pause = TRUE; + if (p[1] == LF) /* ASCII LF */ + *q++ = *++p; + else if (p[1] == CR && p[2] == LF) { /* ASCII CR LF */ + *q++ = *++p; + *q++ = *++p; + } + } else + *q++ = *p; + if ((unsigned)(q-slide) > WSIZE-3 || pause) { /* flush */ + (*G.message)((zvoid *)&G, slide, (ulg)(q-slide), 0); + q = slide; + if (pause && G.extract_flag) /* don't pause for list/test */ + (*G.mpause)((zvoid *)&G, LoadFarString(QuitPrompt), 0); + } + } + (*G.message)((zvoid *)&G, slide, (ulg)(q-slide), 0); +#endif /* ?NOANSIFILT */ +#endif /* ?WINDLL */ + } + /* add '\n' if not at start of line */ + (*G.message)((zvoid *)&G, slide, 0L, 0x40); + break; + + /* + * Second case: read string into filename[] array. The filename should + * never ever be longer than FILNAMSIZ-1 (1024), but for now we'll check, + * just to be sure. + */ + + case DS_FN: + case DS_FN_L: +#ifdef UNICODE_SUPPORT + /* get the whole filename as need it for Unicode checksum */ + if (G.fnfull_bufsize <= length) { + extent fnbufsiz = FILNAMSIZ; + + if (fnbufsiz <= length) + fnbufsiz = length + 1; + if (G.filename_full) + free(G.filename_full); + G.filename_full = malloc(fnbufsiz); + if (G.filename_full == NULL) + return PK_MEM; + G.fnfull_bufsize = fnbufsiz; + } + if (readbuf(__G__ G.filename_full, length) == 0) + return PK_EOF; + G.filename_full[length] = '\0'; /* terminate w/zero: ASCIIZ */ + + /* if needed, chop off end so standard filename is a valid length */ + if (length >= FILNAMSIZ) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(FilenameTooLongTrunc))); + error = PK_WARN; + length = FILNAMSIZ - 1; + } + /* no excess size */ + block_len = 0; + strncpy(G.filename, G.filename_full, length); + G.filename[length] = '\0'; /* terminate w/zero: ASCIIZ */ +#else /* !UNICODE_SUPPORT */ + if (length >= FILNAMSIZ) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(FilenameTooLongTrunc))); + error = PK_WARN; + /* remember excess length in block_len */ + block_len = length - (FILNAMSIZ - 1); + length = FILNAMSIZ - 1; + } else + /* no excess size */ + block_len = 0; + if (readbuf(__G__ G.filename, length) == 0) + return PK_EOF; + G.filename[length] = '\0'; /* terminate w/zero: ASCIIZ */ +#endif /* ?UNICODE_SUPPORT */ + + flag = (option==DS_FN_L)?G.lrec.general_purpose_bit_flag:G.crec.general_purpose_bit_flag; + /* skip ISO/OEM translation if stored name is UTF-8 */ + if ((flag & UTF8_BIT) == 0) { + /* translate the Zip entry filename coded in host-dependent "extended + ASCII" into the compiler's (system's) internal text code page */ + Ext_ASCII_TO_Native(G.filename, G.pInfo->hostnum, G.pInfo->hostver, + G.pInfo->HasUxAtt, (option == DS_FN_L)); + } + + if (G.pInfo->lcflag) /* replace with lowercase filename */ + STRLOWER(G.filename, G.filename); + + if (G.pInfo->vollabel && length > 8 && G.filename[8] == '.') { + char *p = G.filename+8; + while (*p++) + p[-1] = *p; /* disk label, and 8th char is dot: remove dot */ + } + + if (!block_len) /* no overflow, we're done here */ + break; + + /* + * We truncated the filename, so print what's left and then fall + * through to the SKIP routine. + */ + Info(slide, 0x401, ((char *)slide, "[ %s ]\n", FnFilter1(G.filename))); + length = block_len; /* SKIP the excess bytes... */ + /* FALL THROUGH... */ + + /* + * Third case: skip string, adjusting readbuf's internal variables + * as necessary (and possibly skipping to and reading a new block of + * data). + */ + + case SKIP: + /* cur_zipfile_bufstart already takes account of extra_bytes, so don't + * correct for it twice: */ + seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes + + (G.inptr-G.inbuf) + length); + break; + + /* + * Fourth case: assume we're at the start of an "extra field"; malloc + * storage for it and read data into the allocated space. + */ + + case EXTRA_FIELD: + if (G.extra_field != (uch *)NULL) + free(G.extra_field); + if ((G.extra_field = (uch *)malloc(length)) == (uch *)NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(ExtraFieldTooLong), + length)); + /* cur_zipfile_bufstart already takes account of extra_bytes, + * so don't correct for it twice: */ + 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) + return PK_EOF; + /* Looks like here is where extra fields are read */ + getZip64Data(__G__ G.extra_field, length); +#ifdef UNICODE_SUPPORT + G.unipath_filename = NULL; + if (G.UzO.U_flag < 2) { + /* check if GPB11 (General Purpuse Bit 11) is set indicating + the standard path and comment are UTF-8 */ + if (G.pInfo->GPFIsUTF8) { + /* if GPB11 set then filename_full is untruncated UTF-8 */ + if (!(G.unipath_filename = malloc(strlen(G.filename_full)+1))) + return PK_MEM; + strcpy(G.unipath_filename, G.filename_full); + } else { + /* Get the Unicode fields if exist */ + getUnicodeData(__G__ G.extra_field, length); + if (G.unipath_filename && strlen(G.unipath_filename) == 0) { + /* the standard filename field is UTF-8 */ + free(G.unipath_filename); + G.unipath_filename = G.filename_full; + } + } + if (G.unipath_filename) { +# ifdef UTF8_MAYBE_NATIVE + if (G.native_is_utf8 +# ifdef UNICODE_WCHAR + && (!G.unicode_escape_all) +# endif + ) { + strncpy(G.filename, G.unipath_filename, FILNAMSIZ - 1); + /* make sure filename is short enough */ + if (strlen(G.unipath_filename) >= FILNAMSIZ) { + G.filename[FILNAMSIZ - 1] = '\0'; + Info(slide, 0x401, ((char *)slide, + LoadFarString(UFilenameTooLongTrunc))); + error = PK_WARN; + } + } +# ifdef UNICODE_WCHAR + else +# endif +# endif /* UTF8_MAYBE_NATIVE */ +# ifdef UNICODE_WCHAR + { + char *fn; + + /* convert UTF-8 to local character set */ + fn = utf8_to_local_string(G.unipath_filename, + G.unicode_escape_all); + /* make sure filename is short enough */ + if (strlen(fn) >= FILNAMSIZ) { + fn[FILNAMSIZ - 1] = '\0'; + Info(slide, 0x401, ((char *)slide, + LoadFarString(UFilenameTooLongTrunc))); + error = PK_WARN; + } + /* replace filename with converted UTF-8 */ + strcpy(G.filename, fn); + free(fn); + } +# endif /* UNICODE_WCHAR */ + /* + if (G.unipath_filename != G.filename_full) + free(G.unipath_full); + G.unipath_full = NULL; + */ + } +# ifdef WIN32_WIDE + G.unipath_widefilename = NULL; + if (G.has_win32_wide) { + if (G.unipath_filename) + /* Get wide path from UTF-8 */ + G.unipath_widefilename = utf8_to_wchar_string(G.unipath_filename); + else + G.unipath_widefilename = utf8_to_wchar_string(G.filename); + + if (G.pInfo->lcflag) /* replace with lowercase filename */ + wcslwr(G.unipath_widefilename); + + if (G.pInfo->vollabel && length > 8 && G.unipath_widefilename[8] == '.') { + wchar_t *p = G.unipath_widefilename+8; + while (*p++) + p[-1] = *p; /* disk label, and 8th char is dot: remove dot */ + } + } +# endif /* WIN32_WIDE */ + } +#endif /* UNICODE_SUPPORT */ + } + break; + +#ifdef AMIGA + /* + * Fifth case, for the Amiga only: take the comment that would ordinarily + * be skipped over, and turn it into a 79 character string that will be + * attached to the file as a "filenote" after it is extracted. + */ + + case FILENOTE: + if ((block_len = readbuf(__G__ tmp_fnote, (unsigned) + MIN(length, 2 * AMIGA_FILENOTELEN - 1))) == 0) + return PK_EOF; + if ((length -= block_len) > 0) /* treat remainder as in case SKIP: */ + seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes + + (G.inptr - G.inbuf) + length); + /* convert multi-line text into single line with no ctl-chars: */ + tmp_fnote[block_len] = '\0'; + while ((short int) --block_len >= 0) + if ((unsigned) tmp_fnote[block_len] < ' ') + if (tmp_fnote[block_len+1] == ' ') /* no excess */ + strcpy(tmp_fnote+block_len, tmp_fnote+block_len+1); + else + tmp_fnote[block_len] = ' '; + tmp_fnote[AMIGA_FILENOTELEN - 1] = '\0'; + if (G.filenotes[G.filenote_slot]) + free(G.filenotes[G.filenote_slot]); /* should not happen */ + G.filenotes[G.filenote_slot] = NULL; + if (tmp_fnote[0]) { + if (!(G.filenotes[G.filenote_slot] = malloc(strlen(tmp_fnote)+1))) + return PK_MEM; + strcpy(G.filenotes[G.filenote_slot], tmp_fnote); + } + break; +#endif /* AMIGA */ + + } /* end switch (option) */ + + return error; + +} /* end function do_string() */ + + + + + +/***********************/ +/* Function makeword() */ +/***********************/ + +ush makeword(b) + ZCONST uch *b; +{ + /* + * Convert Intel style 'short' integer to non-Intel non-16-bit + * host format. This routine also takes care of byte-ordering. + */ + return (ush)((b[1] << 8) | b[0]); +} + + + + + +/***********************/ +/* Function makelong() */ +/***********************/ + +ulg makelong(sig) + ZCONST uch *sig; +{ + /* + * Convert intel style 'long' variable to non-Intel non-16-bit + * host format. This routine also takes care of byte-ordering. + */ + return (((ulg)sig[3]) << 24) + + (((ulg)sig[2]) << 16) + + (ulg)((((unsigned)sig[1]) << 8) + + ((unsigned)sig[0])); +} + + + + + +/************************/ +/* Function makeint64() */ +/************************/ + +zusz_t makeint64(sig) + ZCONST uch *sig; +{ +#ifdef LARGE_FILE_SUPPORT + /* + * Convert intel style 'int64' variable to non-Intel non-16-bit + * host format. This routine also takes care of byte-ordering. + */ + return (((zusz_t)sig[7]) << 56) + + (((zusz_t)sig[6]) << 48) + + (((zusz_t)sig[4]) << 32) + + (zusz_t)((((ulg)sig[3]) << 24) + + (((ulg)sig[2]) << 16) + + (((unsigned)sig[1]) << 8) + + (sig[0])); + +#else /* !LARGE_FILE_SUPPORT */ + + if ((sig[7] | sig[6] | sig[5] | sig[4]) != 0) + return (zusz_t)0xffffffffL; + else + return (zusz_t)((((ulg)sig[3]) << 24) + + (((ulg)sig[2]) << 16) + + (((unsigned)sig[1]) << 8) + + (sig[0])); + +#endif /* ?LARGE_FILE_SUPPORT */ +} + + + + + +/*********************/ +/* Function fzofft() */ +/*********************/ + +/* Format a zoff_t value in a cylindrical buffer set. */ +char *fzofft(__G__ val, pre, post) + __GDEF + zoff_t val; + ZCONST char *pre; + ZCONST char *post; +{ + /* Storage cylinder. (now in globals.h) */ + /*static char fzofft_buf[FZOFFT_NUM][FZOFFT_LEN];*/ + /*static int fzofft_index = 0;*/ + + /* Temporary format string storage. */ + char fmt[16]; + + /* Assemble the format string. */ + fmt[0] = '%'; + fmt[1] = '\0'; /* Start after initial "%". */ + if (pre == FZOFFT_HEX_WID) /* Special hex width. */ + { + strcat(fmt, FZOFFT_HEX_WID_VALUE); + } + else if (pre == FZOFFT_HEX_DOT_WID) /* Special hex ".width". */ + { + strcat(fmt, "."); + strcat(fmt, FZOFFT_HEX_WID_VALUE); + } + else if (pre != NULL) /* Caller's prefix (width). */ + { + strcat(fmt, pre); + } + + strcat(fmt, FZOFFT_FMT); /* Long or long-long or whatever. */ + + if (post == NULL) + strcat(fmt, "d"); /* Default radix = decimal. */ + else + strcat(fmt, post); /* Caller's radix. */ + + /* Advance the cylinder. */ + G.fzofft_index = (G.fzofft_index + 1) % FZOFFT_NUM; + + /* Write into the current chamber. */ + sprintf(G.fzofft_buf[G.fzofft_index], fmt, val); + + /* Return a pointer to this chamber. */ + return G.fzofft_buf[G.fzofft_index]; +} + + + + +#if CRYPT + +#ifdef NEED_STR2ISO +/**********************/ +/* Function str2iso() */ +/**********************/ + +char *str2iso(dst, src) + char *dst; /* destination buffer */ + register ZCONST char *src; /* source string */ +{ +#ifdef INTERN_TO_ISO + INTERN_TO_ISO(src, dst); +#else + register uch c; + register char *dstp = dst; + + do { + c = (uch)foreign(*src++); + *dstp++ = (char)ASCII2ISO(c); + } while (c != '\0'); +#endif + + return dst; +} +#endif /* NEED_STR2ISO */ + + +#ifdef NEED_STR2OEM +/**********************/ +/* Function str2oem() */ +/**********************/ + +char *str2oem(dst, src) + char *dst; /* destination buffer */ + register ZCONST char *src; /* source string */ +{ +#ifdef INTERN_TO_OEM + INTERN_TO_OEM(src, dst); +#else + register uch c; + register char *dstp = dst; + + do { + c = (uch)foreign(*src++); + *dstp++ = (char)ASCII2OEM(c); + } while (c != '\0'); +#endif + + return dst; +} +#endif /* NEED_STR2OEM */ + +#endif /* CRYPT */ + + +#ifdef ZMEM /* memset/memcmp/memcpy for systems without either them or */ + /* bzero/bcmp/bcopy */ + /* (no known systems as of 960211) */ + +/*********************/ +/* Function memset() */ +/*********************/ + +zvoid *memset(buf, init, len) + register zvoid *buf; /* buffer location */ + register int init; /* initializer character */ + register unsigned int len; /* length of the buffer */ +{ + zvoid *start; + + start = buf; + while (len--) + *((char *)buf++) = (char)init; + return start; +} + + + +/*********************/ +/* Function memcmp() */ +/*********************/ + +int memcmp(b1, b2, len) + register ZCONST zvoid *b1; + register ZCONST zvoid *b2; + register unsigned int len; +{ + register int c; + + if (len > 0) do { + if ((c = (int)(*((ZCONST unsigned char *)b1)++) - + (int)(*((ZCONST unsigned char *)b2)++)) != 0) + return c; + } while (--len > 0) + return 0; +} + + + +/*********************/ +/* Function memcpy() */ +/*********************/ + +zvoid *memcpy(dst, src, len) + register zvoid *dst; + register ZCONST zvoid *src; + register unsigned int len; +{ + zvoid *start; + + start = dst; + while (len-- > 0) + *((char *)dst)++ = *((ZCONST char *)src)++; + return start; +} + +#endif /* ZMEM */ + + + + +#ifdef NO_STRNICMP + +/************************/ +/* Function zstrnicmp() */ +/************************/ + +int zstrnicmp(s1, s2, n) + register ZCONST char *s1, *s2; + register unsigned n; +{ + for (; n > 0; --n, ++s1, ++s2) { + + if (ToLower(*s1) != ToLower(*s2)) + /* test includes early termination of one string */ + return ((uch)ToLower(*s1) < (uch)ToLower(*s2))? -1 : 1; + + if (*s1 == '\0') /* both strings terminate early */ + return 0; + } + return 0; +} + +#endif /* NO_STRNICMP */ + + + + +#ifdef REGULUS /* returns the inode number on success(!)...argh argh argh */ +# undef stat + +/********************/ +/* Function zstat() */ +/********************/ + +int zstat(p, s) + ZCONST char *p; + struct stat *s; +{ + return (stat((char *)p,s) >= 0? 0 : (-1)); +} + +#endif /* REGULUS */ + + + + +#ifdef _MBCS + +/* DBCS support for Info-ZIP's zip (mainly for japanese (-: ) + * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp) + * This code is public domain! Date: 1998/12/20 + */ + +/************************/ +/* Function plastchar() */ +/************************/ + +char *plastchar(ptr, len) + ZCONST char *ptr; + extent len; +{ + unsigned clen; + ZCONST char *oldptr = ptr; + while(*ptr != '\0' && len > 0){ + oldptr = ptr; + clen = CLEN(ptr); + ptr += clen; + len -= clen; + } + return (char *)oldptr; +} + + +#ifdef NEED_UZMBCLEN +/***********************/ +/* Function uzmbclen() */ +/***********************/ + +extent uzmbclen(ptr) + ZCONST unsigned char *ptr; +{ + int mbl; + + mbl = mblen((ZCONST char *)ptr, MB_CUR_MAX); + /* For use in code scanning through MBCS strings, we need a strictly + positive "MB char bytes count". For our scanning purpose, it is not + not relevant whether the MB character is valid or not. And, the NUL + char '\0' has a byte count of 1, but mblen() returns 0. So, we make + sure that the uzmbclen() return value is not less than 1. + */ + return (extent)(mbl > 0 ? mbl : 1); +} +#endif /* NEED_UZMBCLEN */ + + +#ifdef NEED_UZMBSCHR +/***********************/ +/* Function uzmbschr() */ +/***********************/ + +unsigned char *uzmbschr(str, c) + ZCONST unsigned char *str; + unsigned int c; +{ + while(*str != '\0'){ + if (*str == c) {return (unsigned char *)str;} + INCSTR(str); + } + return NULL; +} +#endif /* NEED_UZMBSCHR */ + + +#ifdef NEED_UZMBSRCHR +/************************/ +/* Function uzmbsrchr() */ +/************************/ + +unsigned char *uzmbsrchr(str, c) + ZCONST unsigned char *str; + unsigned int c; +{ + unsigned char *match = NULL; + while(*str != '\0'){ + if (*str == c) {match = (unsigned char *)str;} + INCSTR(str); + } + return match; +} +#endif /* NEED_UZMBSRCHR */ +#endif /* _MBCS */ + + + + + +#ifdef SMALL_MEM + +/*******************************/ +/* Function fLoadFarString() */ /* (and friends...) */ +/*******************************/ + +char *fLoadFarString(__GPRO__ const char Far *sz) +{ + (void)zfstrcpy(G.rgchBigBuffer, sz); + return G.rgchBigBuffer; +} + +char *fLoadFarStringSmall(__GPRO__ const char Far *sz) +{ + (void)zfstrcpy(G.rgchSmallBuffer, sz); + return G.rgchSmallBuffer; +} + +char *fLoadFarStringSmall2(__GPRO__ const char Far *sz) +{ + (void)zfstrcpy(G.rgchSmallBuffer2, sz); + return G.rgchSmallBuffer2; +} + + + + +#if (!defined(_MSC_VER) || (_MSC_VER < 600)) +/*************************/ +/* Function zfstrcpy() */ /* portable clone of _fstrcpy() */ +/*************************/ + +char Far * Far zfstrcpy(char Far *s1, const char Far *s2) +{ + char Far *p = s1; + + while ((*s1++ = *s2++) != '\0'); + return p; +} + +#if (!(defined(SFX) || defined(FUNZIP))) +/*************************/ +/* Function zfstrcmp() */ /* portable clone of _fstrcmp() */ +/*************************/ + +int Far zfstrcmp(const char Far *s1, const char Far *s2) +{ + int ret; + + while ((ret = (int)(uch)*s1 - (int)(uch)*s2) == 0 + && *s2 != '\0') { + ++s2; ++s1; + } + return ret; +} +#endif /* !(SFX || FUNZIP) */ +#endif /* !_MSC_VER || (_MSC_VER < 600) */ + +#endif /* SMALL_MEM */ + diff --git a/third_party/unzip/globals.c b/third_party/unzip/globals.c new file mode 100644 index 000000000..80124f0c2 --- /dev/null +++ b/third_party/unzip/globals.c @@ -0,0 +1,223 @@ +// clang-format off +/* + Copyright (c) 1990-2007 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2003-May-08 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 +*/ +/*--------------------------------------------------------------------------- + + globals.c + + Routines to allocate and initialize globals, with or without threads. + + Contents: registerGlobalPointer() + deregisterGlobalPointer() + getGlobalPointer() + globalsCtor() + + ---------------------------------------------------------------------------*/ + + +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" + +#ifndef FUNZIP +/* initialization of sigs is completed at runtime so unzip(sfx) executable + * won't look like a zipfile + */ +char central_hdr_sig[4] = {0, 0, 0x01, 0x02}; +char local_hdr_sig[4] = {0, 0, 0x03, 0x04}; +char end_central_sig[4] = {0, 0, 0x05, 0x06}; +char end_central64_sig[4] = {0, 0, 0x06, 0x06}; +char end_centloc64_sig[4] = {0, 0, 0x06, 0x07}; +/* extern char extd_local_sig[4] = {0, 0, 0x07, 0x08}; NOT USED YET */ + +ZCONST char *fnames[2] = {"*", NULL}; /* default filenames vector */ +#endif + + +#ifndef REENTRANT + Uz_Globs G; +#else /* REENTRANT */ + +# ifndef USETHREADID + Uz_Globs *GG; +# else /* USETHREADID */ +# define THREADID_ENTRIES 0x40 + + int lastScan; + Uz_Globs *threadPtrTable[THREADID_ENTRIES]; + ulg threadIdTable [THREADID_ENTRIES] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* Make sure there are */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* THREADID_ENTRIES 0s */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 + }; + + static ZCONST char Far TooManyThreads[] = + "error: more than %d simultaneous threads.\n\ + Some threads are probably not calling DESTROYTHREAD()\n"; + static ZCONST char Far EntryNotFound[] = + "error: couldn't find global pointer in table.\n\ + Maybe somebody accidentally called DESTROYTHREAD() twice.\n"; + static ZCONST char Far GlobalPointerMismatch[] = + "error: global pointer in table does not match pointer passed as\ + parameter\n"; + +static void registerGlobalPointer OF((__GPRO)); + + + +static void registerGlobalPointer(__G) + __GDEF +{ + int scan=0; + ulg tid = GetThreadId(); + + while (threadIdTable[scan] && scan < THREADID_ENTRIES) + scan++; + + if (scan == THREADID_ENTRIES) { + ZCONST char *tooMany = LoadFarString(TooManyThreads); + Info(slide, 0x421, ((char *)slide, tooMany, THREADID_ENTRIES)); + free(pG); + EXIT(PK_MEM); /* essentially memory error before we've started */ + } + + threadIdTable [scan] = tid; + threadPtrTable[scan] = pG; + lastScan = scan; +} + + + +void deregisterGlobalPointer(__G) + __GDEF +{ + int scan=0; + ulg tid = GetThreadId(); + + + while (threadIdTable[scan] != tid && scan < THREADID_ENTRIES) + scan++; + +/*--------------------------------------------------------------------------- + There are two things we can do if we can't find the entry: ignore it or + scream. The most likely reason for it not to be here is the user calling + this routine twice. Since this could cause BIG problems if any globals + are accessed after the first call, we'd better scream. + ---------------------------------------------------------------------------*/ + + if (scan == THREADID_ENTRIES || threadPtrTable[scan] != pG) { + ZCONST char *noEntry; + if (scan == THREADID_ENTRIES) + noEntry = LoadFarString(EntryNotFound); + else + noEntry = LoadFarString(GlobalPointerMismatch); + Info(slide, 0x421, ((char *)slide, noEntry)); + EXIT(PK_WARN); /* programming error, but after we're all done */ + } + + threadIdTable [scan] = 0; + lastScan = scan; + free(threadPtrTable[scan]); +} + + + +Uz_Globs *getGlobalPointer() +{ + int scan=0; + ulg tid = GetThreadId(); + + while (threadIdTable[scan] != tid && scan < THREADID_ENTRIES) + scan++; + +/*--------------------------------------------------------------------------- + There are two things we can do if we can't find the entry: ignore it or + scream. The most likely reason for it not to be here is the user calling + this routine twice. Since this could cause BIG problems if any globals + are accessed after the first call, we'd better scream. + ---------------------------------------------------------------------------*/ + + if (scan == THREADID_ENTRIES) { + ZCONST char *noEntry = LoadFarString(EntryNotFound); + fprintf(stderr, noEntry); /* can't use Info w/o a global pointer */ + EXIT(PK_ERR); /* programming error while still working */ + } + + return threadPtrTable[scan]; +} + +# endif /* ?USETHREADID */ +#endif /* ?REENTRANT */ + + + +Uz_Globs *globalsCtor() +{ +#ifdef REENTRANT + Uz_Globs *pG = (Uz_Globs *)malloc(sizeof(Uz_Globs)); + + if (!pG) + return (Uz_Globs *)NULL; +#endif /* REENTRANT */ + + /* for REENTRANT version, G is defined as (*pG) */ + + memzero(&G, sizeof(Uz_Globs)); + +#ifndef FUNZIP +#ifdef CMS_MVS + uO.aflag=1; + uO.C_flag=1; +#endif +#ifdef TANDEM + uO.aflag=1; /* default to '-a' auto create Text Files as type 101 */ +#endif +#ifdef VMS +# if (!defined(NO_TIMESTAMPS)) + uO.D_flag=1; /* default to '-D', no restoration of dir timestamps */ +# endif +#endif + + uO.lflag=(-1); + G.wildzipfn = ""; + G.pfnames = (char **)fnames; + G.pxnames = (char **)&fnames[1]; + G.pInfo = G.info; + G.sol = TRUE; /* at start of line */ + + G.message = UzpMessagePrnt; + G.input = UzpInput; /* not used by anyone at the moment... */ +#if defined(WINDLL) || defined(MACOS) + G.mpause = NULL; /* has scrollbars: no need for pausing */ +#else + G.mpause = UzpMorePause; +#endif + G.decr_passwd = UzpPassword; +#endif /* !FUNZIP */ + +#if (!defined(DOS_FLX_H68_NLM_OS2_W32) && !defined(AMIGA) && !defined(RISCOS)) +#if (!defined(MACOS) && !defined(ATARI) && !defined(VMS)) + G.echofd = -1; +#endif /* !(MACOS || ATARI || VMS) */ +#endif /* !(DOS_FLX_H68_NLM_OS2_W32 || AMIGA || RISCOS) */ + +#ifdef SYSTEM_SPECIFIC_CTOR + SYSTEM_SPECIFIC_CTOR(__G); +#endif + +#ifdef REENTRANT +#ifdef USETHREADID + registerGlobalPointer(__G); +#else + GG = &G; +#endif /* ?USETHREADID */ +#endif /* REENTRANT */ + + return &G; +} diff --git a/third_party/unzip/globals.h b/third_party/unzip/globals.h new file mode 100644 index 000000000..841a76b24 --- /dev/null +++ b/third_party/unzip/globals.h @@ -0,0 +1,468 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 +*/ +/*--------------------------------------------------------------------------- + + globals.h + + There is usually no need to include this file since unzip.h includes it. + + This header file is used by all of the UnZip source files. It contains + a struct definition that is used to "house" all of the global variables. + This is done to allow for multithreaded environments (OS/2, NT, Win95, + Unix) to call UnZip through an API without a semaphore. REENTRANT should + be defined for all platforms that require this. + + GLOBAL CONSTRUCTOR AND DESTRUCTOR (API WRITERS READ THIS!!!) + ------------------------------------------------------------ + + No, it's not C++, but it's as close as we can get with K&R. + + The main() of each process that uses these globals must include the + CONSTRUCTGLOBALS; statement. This will malloc enough memory for the + structure and initialize any variables that require it. This must + also be done by any API function that jumps into the middle of the + code. + + The DESTROYGLOBALS(); statement should be inserted before EVERY "EXIT(n)". + Naturally, it also needs to be put before any API returns as well. + In fact, it's much more important in API functions since the process + will NOT end, and therefore the memory WON'T automatically be freed + by the operating system. + + USING VARIABLES FROM THE STRUCTURE + ---------------------------------- + + All global variables must now be prefixed with `G.' which is either a + global struct (in which case it should be the only global variable) or + a macro for the value of a local pointer variable that is passed from + function to function. Yes, this is a pain. But it's the only way to + allow full reentrancy. + + ADDING VARIABLES TO THE STRUCTURE + --------------------------------- + + If you make the inclusion of any variables conditional, be sure to only + check macros that are GUARANTEED to be included in every module. + For instance, newzip and pwdarg are needed only if CRYPT is TRUE, + but this is defined after unzip.h has been read. If you are not careful, + some modules will expect your variable to be part of this struct while + others won't. This will cause BIG problems. (Inexplicable crashes at + strange times, car fires, etc.) When in doubt, always include it! + + Note also that UnZipSFX needs a few variables that UnZip doesn't. However, + it also includes some object files from UnZip. If we were to conditionally + include the extra variables that UnZipSFX needs, the object files from + UnZip would not mesh with the UnZipSFX object files. Result: we just + include the UnZipSFX variables every time. (It's only an extra 4 bytes + so who cares!) + + ADDING FUNCTIONS + ---------------- + + To support this new global struct, all functions must now conditionally + pass the globals pointer (pG) to each other. This is supported by 5 macros: + __GPRO, __GPRO__, __G, __G__ and __GDEF. A function that needs no other + parameters would look like this: + + int extract_or_test_files(__G) + __GDEF + { + ... stuff ... + } + + A function with other parameters would look like: + + int memextract(__G__ tgt, tgtsize, src, srcsize) + __GDEF + uch *tgt, *src; + ulg tgtsize, srcsize; + { + ... stuff ... + } + + In the Function Prototypes section of unzpriv.h, you should use __GPRO and + __GPRO__ instead: + + int uz_opts OF((__GPRO__ int *pargc, char ***pargv)); + int process_zipfiles OF((__GPRO)); + + Note that there is NO comma after __G__ or __GPRO__ and no semi-colon after + __GDEF. I wish there was another way but I don't think there is. + + + TESTING THE CODE + ----------------- + + Whether your platform requires reentrancy or not, you should always try + building with REENTRANT defined if any functions have been added. It is + pretty easy to forget a __G__ or a __GDEF and this mistake will only show + up if REENTRANT is defined. All platforms should run with REENTRANT + defined. Platforms that can't take advantage of it will just be paying + a performance penalty needlessly. + + SIGNAL MADNESS + -------------- + + This whole pointer passing scheme falls apart when it comes to SIGNALs. + I handle this situation 2 ways right now. If you define USETHREADID, + UnZip will include a 64-entry table. Each entry can hold a global + pointer and thread ID for one thread. This should allow up to 64 + threads to access UnZip simultaneously. Calling DESTROYGLOBALS() + will free the global struct and zero the table entry. If somebody + forgets to call DESTROYGLOBALS(), this table will eventually fill up + and UnZip will exit with an error message. A good way to test your + code to make sure you didn't forget a DESTROYGLOBALS() is to change + THREADID_ENTRIES to 3 or 4 in globals.c, making the table real small. + Then make a small test program that calls your API a dozen times. + + Those platforms that don't have threads still need to be able to compile + with REENTRANT defined to test and see if new code is correctly written + to work either way. For these platforms, I simply keep a global pointer + called GG that points to the Globals structure. Good enough for testing. + + I believe that NT has thread level storage. This could probably be used + to store a global pointer for the sake of the signal handler more cleanly + than my table approach. + + ---------------------------------------------------------------------------*/ + +#ifndef __globals_h +#define __globals_h + +#include "third_party/unzip/unxcfg.h" +#include "third_party/unzip/unzip.h" +#include "third_party/unzip/unzpriv.h" +#include "libc/stdio/stdio.h" + +#ifdef USE_ZLIB +#include "third_party/zlib/zlib.h" +# ifdef zlib_version /* This name is used internally in unzip */ +# undef zlib_version /* and must not be defined as a macro. */ +# endif +#endif + +#ifdef USE_BZIP2 +#include "third_party/bzip2/bzlib.h" +#endif + +#if defined( UNIX) && defined( __APPLE__) +#include "third_party/unzip/unix/macosx.h" +#endif /* defined( UNIX) && defined( __APPLE__) */ + + +/*************/ +/* Globals */ +/*************/ + +typedef struct Globals { +#ifdef DLL + zvoid *callerglobs; /* pointer to structure of pass-through global vars */ +#endif + + /* command options of general use */ + UzpOpts UzO; /* command options of general use */ + +#ifndef FUNZIP + /* command options specific to the high level command line interface */ +#ifdef MORE + int M_flag; /* -M: built-in "more" function */ +#endif + + /* internal flags and general globals */ +#ifdef MORE + int height; /* check for SIGWINCH, etc., eventually... */ + int lines; /* count of lines displayed on current screen */ +# if (defined(SCREENWIDTH) && defined(SCREENLWRAP)) + int width; + int chars; /* count of screen characters in current line */ +# endif +#endif /* MORE */ +#if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME)) + int tz_is_valid; /* indicates that timezone info can be used */ +#endif + int noargs; /* did true command line have *any* arguments? */ + unsigned filespecs; /* number of real file specifications to be matched */ + unsigned xfilespecs; /* number of excluded filespecs to be matched */ + int process_all_files; + int overwrite_mode; /* 0 - query, 1 - always, 2 - never */ + int create_dirs; /* used by main(), mapname(), checkdir() */ + int extract_flag; + int newzip; /* reset in extract.c; used in crypt.c */ + zoff_t real_ecrec_offset; + zoff_t expect_ecrec_offset; + zoff_t csize; /* used by decompr. (NEXTBYTE): must be signed */ + zoff_t used_csize; /* used by extract_or_test_member(), explode() */ + +#if defined( UNIX) && defined( __APPLE__) + int apple_double; /* True for an AppleDouble file ("._name"). */ + int apl_dbl_hdr_bytes;/* Non-zero for AplDbl until Finder info is set. */ + int apl_dbl_hdr_len; /* Bytes in apl_dbl_hdr. */ + int exdir_attr_ok; /* True if destination supports setattrlist(). */ + char apl_dbl_hdr[ APL_DBL_HDR_SIZE]; /* AppleDouble header buffer. */ + char ad_filename[ FILNAMSIZ]; /* AppleDouble "/rsrc" file name. */ + char pq_filename[ FILNAMSIZ]; /* Previous query file name. */ + char pr_filename[ FILNAMSIZ]; /* Previous rename file name. */ +#endif /* defined( UNIX) && defined( __APPLE__) */ + +#ifdef DLL + int fValidate; /* true if only validating an archive */ + int filenotfound; + int redirect_data; /* redirect data to memory buffer */ + int redirect_text; /* redirect text output to buffer */ +# ifndef NO_SLIDE_REDIR + int redirect_slide; /* redirect decompression area to mem buffer */ +# if (defined(USE_DEFLATE64) && defined(INT_16BIT)) + ulg _wsize; /* size of sliding window exceeds "unsigned" range */ +# else + unsigned _wsize; /* sliding window size can be hold in unsigned */ +# endif +# endif + ulg redirect_size; /* size of redirected output buffer */ + uch *redirect_buffer; /* pointer to head of allocated buffer */ + uch *redirect_pointer; /* pointer past end of written data */ +# ifndef NO_SLIDE_REDIR + uch *redirect_sldptr; /* head of decompression slide buffer */ +# endif +# ifdef OS2DLL + cbList(processExternally); /* call-back list */ +# endif +#endif /* DLL */ + + char **pfnames; + char **pxnames; + char sig[4]; + char answerbuf[10]; + min_info info[DIR_BLKSIZ]; + min_info *pInfo; +#endif /* !FUNZIP */ + union work area; /* see unzpriv.h for definition of work */ + +#if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB)) + ZCONST ulg near *crc_32_tab; +#else + ZCONST ulg Far *crc_32_tab; +#endif + ulg crc32val; /* CRC shift reg. (was static in funzip) */ + +#ifdef FUNZIP + FILE *in; /* file descriptor of compressed stream */ +#endif + uch *inbuf; /* input buffer (any size is OK) */ + uch *inptr; /* pointer into input buffer */ + int incnt; + +#ifndef FUNZIP + ulg bitbuf; + int bits_left; /* unreduce and unshrink only */ + int zipeof; + char *argv0; /* used for NT and EXE_EXTENSION */ + char *wildzipfn; + char *zipfn; /* GRR: WINDLL: must nuke any malloc'd zipfn... */ +#ifdef USE_STRM_INPUT + FILE *zipfd; /* zipfile file descriptor */ +#else + int zipfd; /* zipfile file handle */ +#endif + zoff_t ziplen; + zoff_t cur_zipfile_bufstart; /* extract_or_test, readbuf, ReadByte */ + zoff_t extra_bytes; /* used in unzip.c, misc.c */ + uch *extra_field; /* Unix, VMS, Mac, OS/2, Acorn, ... */ + uch *hold; + + local_file_hdr lrec; /* used in unzip.c, extract.c */ + cdir_file_hdr crec; /* used in unzip.c, extract.c, misc.c */ + ecdir_rec ecrec; /* used in unzip.c, extract.c */ + z_stat statbuf; /* used by main, mapname, check_for_newer */ + + int mem_mode; + uch *outbufptr; /* extract.c static */ + ulg outsize; /* extract.c static */ + int reported_backslash; /* extract.c static */ + int disk_full; + int newfile; + + int didCRlast; /* fileio static */ + ulg numlines; /* fileio static: number of lines printed */ + int sol; /* fileio static: at start of line */ + int no_ecrec; /* process static */ +#ifdef SYMLINKS + int symlnk; + slinkentry *slink_head; /* pointer to head of symlinks list */ + slinkentry *slink_last; /* pointer to last entry in symlinks list */ +#endif +#ifdef NOVELL_BUG_FAILSAFE + int dne; /* true if stat() says file doesn't exist */ +#endif + + FILE *outfile; + uch *outbuf; + uch *realbuf; + +#ifndef VMS /* if SMALL_MEM, outbuf2 is initialized in */ + uch *outbuf2; /* process_zipfiles() (never changes); */ +#endif /* else malloc'd ONLY if unshrink and -a */ +#endif /* !FUNZIP */ + uch *outptr; + ulg outcnt; /* number of chars stored in outbuf */ +#ifndef FUNZIP + char filename[FILNAMSIZ]; /* also used by NT for temporary SFX path */ +#ifdef UNICODE_SUPPORT + char *filename_full; /* the full path so Unicode checks work */ + extent fnfull_bufsize; /* size of allocated filename buffer */ + int unicode_escape_all; + int unicode_mismatch; +#ifdef UTF8_MAYBE_NATIVE + int native_is_utf8; /* bool, TRUE => native charset == UTF-8 */ +#endif + + int unipath_version; /* version of Unicode field */ + ulg unipath_checksum; /* Unicode field checksum */ + char *unipath_filename; /* UTF-8 path */ +# ifdef WIN32_WIDE + wchar_t *unipath_widefilename; /* wide character filename */ + int has_win32_wide; /* true if Win32 W calls work */ +# endif +#endif /* UNICODE_SUPPORT */ + +#ifdef CMS_MVS + char *tempfn; /* temp file used; erase on close */ +#endif + + char *key; /* crypt static: decryption password or NULL */ + int nopwd; /* crypt static */ +#endif /* !FUNZIP */ + z_uint4 keys[3]; /* crypt static: keys defining pseudo-random sequence */ + +#if (!defined(DOS_FLX_H68_NLM_OS2_W32) && !defined(AMIGA) && !defined(RISCOS)) +#if (!defined(MACOS) && !defined(ATARI) && !defined(VMS)) + int echofd; /* ttyio static: file descriptor whose echo is off */ +#endif /* !(MACOS || ATARI || VMS) */ +#endif /* !(DOS_FLX_H68_NLM_OS2_W32 || AMIGA || RISCOS) */ + + unsigned hufts; /* track memory usage */ + +#ifdef USE_ZLIB + int inflInit; /* inflate static: zlib inflate() initialized */ + z_stream dstrm; /* inflate global: decompression stream */ +#else + struct huft *fixed_tl; /* inflate static */ + struct huft *fixed_td; /* inflate static */ + unsigned fixed_bl, fixed_bd; /* inflate static */ +#ifdef USE_DEFLATE64 + struct huft *fixed_tl64; /* inflate static */ + struct huft *fixed_td64; /* inflate static */ + unsigned fixed_bl64, fixed_bd64; /* inflate static */ + struct huft *fixed_tl32; /* inflate static */ + struct huft *fixed_td32; /* inflate static */ + unsigned fixed_bl32, fixed_bd32; /* inflate static */ + ZCONST ush *cplens; /* inflate static */ + ZCONST uch *cplext; /* inflate static */ + ZCONST uch *cpdext; /* inflate static */ +#endif + unsigned wp; /* inflate static: current position in slide */ + ulg bb; /* inflate static: bit buffer */ + unsigned bk; /* inflate static: bits count in bit buffer */ +#endif /* ?USE_ZLIB */ + +#ifndef FUNZIP + /* cylindric buffer space for formatting zoff_t values (fileio static) */ + char fzofft_buf[FZOFFT_NUM][FZOFFT_LEN]; + int fzofft_index; + +#ifdef SMALL_MEM + char rgchBigBuffer[512]; + char rgchSmallBuffer[96]; + char rgchSmallBuffer2[160]; /* boosted to 160 for local3[] in unzip.c */ +#endif + + MsgFn *message; + InputFn *input; + PauseFn *mpause; + PasswdFn *decr_passwd; + StatCBFn *statreportcb; +#ifdef WINDLL + LPUSERFUNCTIONS lpUserFunctions; +#endif + + int incnt_leftover; /* so improved NEXTBYTE does not waste input */ + uch *inptr_leftover; + +#ifdef VMS_TEXT_CONV + unsigned VMS_line_length; /* so native VMS variable-length text files */ + int VMS_line_state; /* are readable on other platforms */ + int VMS_line_pad; +#endif + +#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) + char autorun_command[FILNAMSIZ]; +#endif +#endif /* !FUNZIP */ + +#ifdef SYSTEM_SPECIFIC_GLOBALS + SYSTEM_SPECIFIC_GLOBALS +#endif + +} Uz_Globs; /* end of struct Globals */ + + +/***************************************************************************/ + + +#define CRC_32_TAB G.crc_32_tab + + +Uz_Globs *globalsCtor OF((void)); + +/* pseudo constant sigs; they are initialized at runtime so unzip executable + * won't look like a zipfile + */ +extern char local_hdr_sig[4]; +extern char central_hdr_sig[4]; +extern char end_central_sig[4]; +extern char end_central32_sig[4]; +extern char end_central64_sig[4]; +extern char end_centloc64_sig[4]; +/* extern char extd_local_sig[4]; NOT USED YET */ + +#ifdef REENTRANT +# define G (*(Uz_Globs *)pG) +# define __G pG +# define __G__ pG, +# define __GPRO Uz_Globs *pG +# define __GPRO__ Uz_Globs *pG, +# define __GDEF Uz_Globs *pG; +# ifdef USETHREADID + extern int lastScan; + void deregisterGlobalPointer OF((__GPRO)); + Uz_Globs *getGlobalPointer OF((void)); +# define GETGLOBALS() Uz_Globs *pG = getGlobalPointer() +# define DESTROYGLOBALS() do {free_G_buffers(pG); \ + deregisterGlobalPointer(pG);} while (0) +# else + extern Uz_Globs *GG; +# define GETGLOBALS() Uz_Globs *pG = GG +# define DESTROYGLOBALS() do {free_G_buffers(pG); free(pG);} while (0) +# endif /* ?USETHREADID */ +# define CONSTRUCTGLOBALS() Uz_Globs *pG = globalsCtor() +#else /* !REENTRANT */ + extern Uz_Globs G; +# define __G +# define __G__ +# define __GPRO void +# define __GPRO__ +# define __GDEF +# define GETGLOBALS() +# define CONSTRUCTGLOBALS() globalsCtor() +# define DESTROYGLOBALS() +#endif /* ?REENTRANT */ + +#define uO G.UzO + +#endif /* __globals_h */ diff --git a/third_party/unzip/inflate.c b/third_party/unzip/inflate.c new file mode 100644 index 000000000..9a0e2d7be --- /dev/null +++ b/third_party/unzip/inflate.c @@ -0,0 +1,1785 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 +*/ +/* inflate.c -- by Mark Adler + version c17e, 30 Mar 2007 */ + + +/* Copyright history: + - Starting with UnZip 5.41 of 16-April-2000, this source file + is covered by the Info-Zip LICENSE cited above. + - Prior versions of this source file, found in UnZip source packages + up to UnZip 5.40, were put in the public domain. + The original copyright note by Mark Adler was: + "You can do whatever you like with this source file, + though I would prefer that if you modify it and + redistribute it that you include comments to that effect + with your name and the date. Thank you." + + History: + vers date who what + ---- --------- -------------- ------------------------------------ + a ~~ Feb 92 M. Adler used full (large, one-step) lookup table + b1 21 Mar 92 M. Adler first version with partial lookup tables + b2 21 Mar 92 M. Adler fixed bug in fixed-code blocks + b3 22 Mar 92 M. Adler sped up match copies, cleaned up some + b4 25 Mar 92 M. Adler added prototypes; removed window[] (now + is the responsibility of unzip.h--also + changed name to slide[]), so needs diffs + for unzip.c and unzip.h (this allows + compiling in the small model on MSDOS); + fixed cast of q in huft_build(); + b5 26 Mar 92 M. Adler got rid of unintended macro recursion. + b6 27 Mar 92 M. Adler got rid of nextbyte() routine. fixed + bug in inflate_fixed(). + c1 30 Mar 92 M. Adler removed lbits, dbits environment variables. + changed BMAX to 16 for explode. Removed + OUTB usage, and replaced it with flush()-- + this was a 20% speed improvement! Added + an explode.c (to replace unimplod.c) that + uses the huft routines here. Removed + register union. + c2 4 Apr 92 M. Adler fixed bug for file sizes a multiple of 32k. + c3 10 Apr 92 M. Adler reduced memory of code tables made by + huft_build significantly (factor of two to + three). + c4 15 Apr 92 M. Adler added NOMEMCPY do kill use of memcpy(). + worked around a Turbo C optimization bug. + c5 21 Apr 92 M. Adler added the WSIZE #define to allow reducing + the 32K window size for specialized + applications. + c6 31 May 92 M. Adler added some typecasts to eliminate warnings + c7 27 Jun 92 G. Roelofs added some more typecasts (444: MSC bug). + c8 5 Oct 92 J-l. Gailly added ifdef'd code to deal with PKZIP bug. + c9 9 Oct 92 M. Adler removed a memory error message (~line 416). + c10 17 Oct 92 G. Roelofs changed ULONG/UWORD/byte to ulg/ush/uch, + removed old inflate, renamed inflate_entry + to inflate, added Mark's fix to a comment. + c10.5 14 Dec 92 M. Adler fix up error messages for incomplete trees. + c11 2 Jan 93 M. Adler fixed bug in detection of incomplete + tables, and removed assumption that EOB is + the longest code (bad assumption). + c12 3 Jan 93 M. Adler make tables for fixed blocks only once. + c13 5 Jan 93 M. Adler allow all zero length codes (pkzip 2.04c + outputs one zero length code for an empty + distance tree). + c14 12 Mar 93 M. Adler made inflate.c standalone with the + introduction of inflate.h. + c14b 16 Jul 93 G. Roelofs added (unsigned) typecast to w at 470. + c14c 19 Jul 93 J. Bush changed v[N_MAX], l[288], ll[28x+3x] arrays + to static for Amiga. + c14d 13 Aug 93 J-l. Gailly de-complicatified Mark's c[*p++]++ thing. + c14e 8 Oct 93 G. Roelofs changed memset() to memzero(). + c14f 22 Oct 93 G. Roelofs renamed quietflg to qflag; made Trace() + conditional; added inflate_free(). + c14g 28 Oct 93 G. Roelofs changed l/(lx+1) macro to pointer (Cray bug) + c14h 7 Dec 93 C. Ghisler huft_build() optimizations. + c14i 9 Jan 94 A. Verheijen set fixed_t{d,l} to NULL after freeing; + G. Roelofs check NEXTBYTE macro for EOF. + c14j 23 Jan 94 G. Roelofs removed Ghisler "optimizations"; ifdef'd + EOF check. + c14k 27 Feb 94 G. Roelofs added some typecasts to avoid warnings. + c14l 9 Apr 94 G. Roelofs fixed split comments on preprocessor lines + to avoid bug in Encore compiler. + c14m 7 Jul 94 P. Kienitz modified to allow assembler version of + inflate_codes() (define ASM_INFLATECODES) + c14n 22 Jul 94 G. Roelofs changed fprintf to macro for DLL versions + c14o 23 Aug 94 C. Spieler added a newline to a debug statement; + G. Roelofs added another typecast to avoid MSC warning + c14p 4 Oct 94 G. Roelofs added (voidp *) cast to free() argument + c14q 30 Oct 94 G. Roelofs changed fprintf macro to MESSAGE() + c14r 1 Nov 94 G. Roelofs fixed possible redefinition of CHECK_EOF + c14s 7 May 95 S. Maxwell OS/2 DLL globals stuff incorporated; + P. Kienitz "fixed" ASM_INFLATECODES macro/prototype + c14t 18 Aug 95 G. Roelofs added UZinflate() to use zlib functions; + changed voidp to zvoid; moved huft_build() + and huft_free() to end of file + c14u 1 Oct 95 G. Roelofs moved G into definition of MESSAGE macro + c14v 8 Nov 95 P. Kienitz changed ASM_INFLATECODES to use a regular + call with __G__ instead of a macro + c15 3 Aug 96 M. Adler fixed bomb-bug on random input data (Adobe) + c15b 24 Aug 96 M. Adler more fixes for random input data + c15c 28 Mar 97 G. Roelofs changed USE_ZLIB fatal exit code from + PK_MEM2 to PK_MEM3 + c16 20 Apr 97 J. Altman added memzero(v[]) in huft_build() + c16b 29 Mar 98 C. Spieler modified DLL code for slide redirection + c16c 04 Apr 99 C. Spieler fixed memory leaks when processing gets + stopped because of input data errors + c16d 05 Jul 99 C. Spieler take care of FLUSH() return values and + stop processing in case of errors + c17 31 Dec 00 C. Spieler added preliminary support for Deflate64 + c17a 04 Feb 01 C. Spieler complete integration of Deflate64 support + c17b 16 Feb 02 C. Spieler changed type of "extra bits" arrays and + corresponding huft_build() parameter e from + ush into uch, to save space + c17c 9 Mar 02 C. Spieler fixed NEEDBITS() "read beyond EOF" problem + with CHECK_EOF enabled + c17d 23 Jul 05 C. Spieler fixed memory leaks in inflate_dynamic() + when processing invalid compressed literal/ + distance table data + c17e 30 Mar 07 C. Spieler in inflate_dynamic(), initialize tl and td + to prevent freeing unallocated huft tables + when processing invalid compressed data and + hitting premature EOF, do not reuse td as + temp work ptr during tables decoding + c17f 13 Jul 10 S. Schweda Added FUNZIP conditionality to uses of + G.disk_full. + */ + + +/* + Inflate deflated (PKZIP's method 8 compressed) data. The compression + method searches for as much of the current string of bytes (up to a + length of 258) in the previous 32K bytes. If it doesn't find any + matches (of at least length 3), it codes the next byte. Otherwise, it + codes the length of the matched string and its distance backwards from + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + code codes the distance information, which follows a length code. Each + length or distance code actually represents a base value and a number + of "extra" (sometimes zero) bits to get to add to the base value. At + the end of each deflated block is a special end-of-block (EOB) literal/ + length code. The decoding process is basically: get a literal/length + code; if EOB then done; if a literal, emit the decoded byte; if a + length then get the distance and emit the referred-to bytes from the + sliding window of previously emitted data. + + There are (currently) three kinds of inflate blocks: stored, fixed, and + dynamic. The compressor outputs a chunk of data at a time and decides + which method to use on a chunk-by-chunk basis. A chunk might typically + be 32K to 64K, uncompressed. If the chunk is uncompressible, then the + "stored" method is used. In this case, the bytes are simply stored as + is, eight bits per byte, with none of the above coding. The bytes are + preceded by a count, since there is no longer an EOB code. + + If the data are compressible, then either the fixed or dynamic methods + are used. In the dynamic method, the compressed data are preceded by + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + coded, and so is preceded by a description of that code. These code + descriptions take up a little space, and so for small blocks, there is + a predefined set of codes, called the fixed codes. The fixed method is + used if the block ends up smaller that way (usually for quite small + chunks); otherwise the dynamic method is used. In the latter case, the + codes are customized to the probabilities in the current block and so + can code it much better than the pre-determined fixed codes can. + + The Huffman codes themselves are decoded using a multi-level table + lookup, in order to maximize the speed of decoding plus the speed of + building the decoding tables. See the comments below that precede the + lbits and dbits tuning parameters. + + GRR: return values(?) + 0 OK + 1 incomplete table + 2 bad input + 3 not enough memory + the following return codes are passed through from FLUSH() errors + 50 (PK_DISK) "overflow of output space" + 80 (IZ_CTRLC) "canceled by user's request" + */ + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + 14. The Deflate64 (PKZIP method 9) variant of the compression algorithm + differs from "classic" deflate in the following 3 aspect: + a) The size of the sliding history window is expanded to 64 kByte. + b) The previously unused distance codes #30 and #31 code distances + from 32769 to 49152 and 49153 to 65536. Both codes take 14 bits + of extra data to determine the exact position in their 16 kByte + range. + c) The last lit/length code #285 gets a different meaning. Instead + of coding a fixed maximum match length of 258, it is used as a + "generic" match length code, capable of coding any length from + 3 (min match length + 0) to 65538 (min match length + 65535). + This means that the length code #285 takes 16 bits (!) of uncoded + extra data, added to a fixed min length of 3. + Changes a) and b) would have been transparent for valid deflated + data, but change c) requires to switch decoder configurations between + Deflate and Deflate64 modes. + */ + + +#define PKZIP_BUG_WORKAROUND /* PKZIP 1.93a problem--live with it */ + +/* + inflate.h must supply the uch slide[WSIZE] array, the zvoid typedef + (void if (void *) is accepted, else char) and the NEXTBYTE, + FLUSH() and memzero macros. If the window size is not 32K, it + should also define WSIZE. If INFMOD is defined, it can include + compiled functions to support the NEXTBYTE and/or FLUSH() macros. + There are defaults for NEXTBYTE and FLUSH() below for use as + examples of what those functions need to do. Normally, you would + also want FLUSH() to compute a crc on the data. inflate.h also + needs to provide these typedefs: + + typedef unsigned char uch; + typedef unsigned short ush; + typedef unsigned long ulg; + + This module uses the external functions malloc() and free() (and + probably memset() or bzero() in the memzero() macro). Their + prototypes are normally found in and . + */ + +#define __INFLATE_C /* identifies this source module */ + +/* #define DEBUG */ +#define INFMOD /* tell inflate.h to include code to be compiled */ +#include "third_party/unzip/inflate.h" + + +/* marker for "unused" huft code, and corresponding check macro */ +#define INVALID_CODE 99 +#define IS_INVALID_CODE(c) ((c) == INVALID_CODE) + +#ifndef WSIZE /* default is 32K resp. 64K */ +# 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 + +/* some buffer counters must be capable of holding 64k for Deflate64 */ +#if (defined(USE_DEFLATE64) && defined(INT_16BIT)) +# define UINT_D64 ulg +#else +# define UINT_D64 unsigned +#endif + +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) +# define wsize G._wsize /* wsize is a variable */ +#else +# define wsize WSIZE /* wsize is a constant */ +#endif + + +#ifndef NEXTBYTE /* default is to simply get a byte from stdin */ +# define NEXTBYTE getchar() +#endif + +#ifndef MESSAGE /* only used twice, for fixed strings--NOT general-purpose */ +# define MESSAGE(str,len,flag) fprintf(stderr,(char *)(str)) +#endif + +#ifndef FLUSH /* default is to simply write the buffer to stdout */ +# define FLUSH(n) \ + (((extent)fwrite(redirSlide, 1, (extent)(n), stdout) == (extent)(n)) ? \ + 0 : PKDISK) +#endif +/* Warning: the fwrite above might not work on 16-bit compilers, since + 0x8000 might be interpreted as -32,768 by the library function. When + support for Deflate64 is enabled, the window size is 64K and the + simple fwrite statement is definitely broken for 16-bit compilers. */ + +#ifndef Trace +# ifdef DEBUG +# define Trace(x) fprintf x +# else +# define Trace(x) +# endif +#endif + + +/*---------------------------------------------------------------------------*/ +#ifdef USE_ZLIB + +/* Beginning with zlib version 1.2.0, a new inflate callback interface is + provided that allows tighter integration of the zlib inflate service + into unzip's extraction framework. + The advantages are: + - uses the windows buffer supplied by the unzip code; this saves one + copy process between zlib's internal decompression buffer and unzip's + post-decompression output buffer and improves performance. + - does not pull in unused checksum code (adler32). + The preprocessor flag NO_ZLIBCALLBCK can be set to force usage of the + old zlib 1.1.x interface, for testing purpose. + */ +#ifdef USE_ZLIB_INFLATCB +# undef USE_ZLIB_INFLATCB +#endif +#if (defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1200 && !defined(NO_ZLIBCALLBCK)) +# define USE_ZLIB_INFLATCB 1 +#else +# define USE_ZLIB_INFLATCB 0 +#endif + +/* Check for incompatible combinations of zlib and Deflate64 support. */ +#if defined(USE_DEFLATE64) +# if !USE_ZLIB_INFLATCB + #error Deflate64 is incompatible with traditional (pre-1.2.x) zlib interface! +# else + /* The Deflate64 callback function in the framework of zlib 1.2.x requires + the inclusion of the unsupported infback9 header file: + */ +# endif +#endif /* USE_DEFLATE64 */ + + +#if USE_ZLIB_INFLATCB + +static unsigned zlib_inCB OF((void FAR *pG, unsigned char FAR * FAR * pInbuf)); +static int zlib_outCB OF((void FAR *pG, unsigned char FAR *outbuf, + unsigned outcnt)); + +static unsigned zlib_inCB(pG, pInbuf) + void FAR *pG; + unsigned char FAR * FAR * pInbuf; +{ + *pInbuf = G.inbuf; + return fillinbuf(__G); +} + +static int zlib_outCB(pG, outbuf, outcnt) + void FAR *pG; + unsigned char FAR *outbuf; + unsigned outcnt; +{ +#ifdef FUNZIP + return flush(__G__ (ulg)(outcnt)); +#else + return ((G.mem_mode) ? memflush(__G__ outbuf, (ulg)(outcnt)) + : flush(__G__ outbuf, (ulg)(outcnt), 0)); +#endif +} +#endif /* USE_ZLIB_INFLATCB */ + + +/* + GRR: return values for both original inflate() and UZinflate() + 0 OK + 1 incomplete table(?) + 2 bad input + 3 not enough memory + */ + +/**************************/ +/* Function UZinflate() */ +/**************************/ + +int UZinflate(__G__ is_defl64) + __GDEF + int is_defl64; +/* decompress an inflated entry using the zlib routines */ +{ + int retval = 0; /* return code: 0 = "no error" */ + int err=Z_OK; +#if USE_ZLIB_INFLATCB + +#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 + + if (!G.inflInit) { + /* local buffer for efficiency */ + ZCONST char *zlib_RtVersion = zlibVersion(); + + /* only need to test this stuff once */ + if ((zlib_RtVersion[0] != ZLIB_VERSION[0]) || + (zlib_RtVersion[2] != ZLIB_VERSION[2])) { + Info(slide, 0x21, ((char *)slide, + "error: incompatible zlib version (expected %s, found %s)\n", + ZLIB_VERSION, zlib_RtVersion)); + return 3; + } else if (strcmp(zlib_RtVersion, ZLIB_VERSION) != 0) + Info(slide, 0x21, ((char *)slide, + "warning: different zlib version (expected %s, using %s)\n", + ZLIB_VERSION, zlib_RtVersion)); + + G.dstrm.zalloc = (alloc_func)Z_NULL; + G.dstrm.zfree = (free_func)Z_NULL; + + G.inflInit = 1; + } + +#ifdef USE_DEFLATE64 + if (is_defl64) + { + Trace((stderr, "initializing inflate9()\n")); + err = inflateBack9Init(&G.dstrm, redirSlide); + + if (err == Z_MEM_ERROR) + return 3; + else if (err != Z_OK) { + Trace((stderr, "oops! (inflateBack9Init() err = %d)\n", err)); + return 2; + } + + G.dstrm.next_in = G.inptr; + G.dstrm.avail_in = G.incnt; + + err = inflateBack9(&G.dstrm, zlib_inCB, &G, zlib_outCB, &G); + if (err != Z_STREAM_END) { + if (err == Z_DATA_ERROR || err == Z_STREAM_ERROR) { + Trace((stderr, "oops! (inflateBack9() err = %d)\n", err)); + retval = 2; + } else if (err == Z_MEM_ERROR) { + retval = 3; + } else if (err == Z_BUF_ERROR) { + Trace((stderr, "oops! (inflateBack9() err = %d)\n", err)); + if (G.dstrm.next_in == Z_NULL) { + /* input failure */ + Trace((stderr, " inflateBack9() input failure\n")); + retval = 2; + } else { + /* output write failure */ +#ifdef FUNZIP + retval = PK_DISK; +#else /* def FUNZIP */ + retval = (G.disk_full != 0 ? PK_DISK : IZ_CTRLC); +#endif /* def FUNZIP [else] */ + } + } else { + Trace((stderr, "oops! (inflateBack9() err = %d)\n", err)); + retval = 2; + } + } + if (G.dstrm.next_in != NULL) { + G.inptr = (uch *)G.dstrm.next_in; + G.incnt = G.dstrm.avail_in; + } + + err = inflateBack9End(&G.dstrm); + if (err != Z_OK) { + Trace((stderr, "oops! (inflateBack9End() err = %d)\n", err)); + if (retval == 0) + retval = 2; + } + } + else +#endif /* USE_DEFLATE64 */ + { + /* For the callback interface, inflate initialization has to + be called before each decompression call. + */ + { + unsigned i; + int windowBits; + /* windowBits = log2(wsize) */ + for (i = (unsigned)wsize, windowBits = 0; + !(i & 1); i >>= 1, ++windowBits); + if ((unsigned)windowBits > (unsigned)15) + windowBits = 15; + else if (windowBits < 8) + windowBits = 8; + + Trace((stderr, "initializing inflate()\n")); + err = inflateBackInit(&G.dstrm, windowBits, redirSlide); + + if (err == Z_MEM_ERROR) + return 3; + else if (err != Z_OK) { + Trace((stderr, "oops! (inflateBackInit() err = %d)\n", err)); + return 2; + } + } + + G.dstrm.next_in = G.inptr; + G.dstrm.avail_in = G.incnt; + + err = inflateBack(&G.dstrm, zlib_inCB, &G, zlib_outCB, &G); + if (err != Z_STREAM_END) { + if (err == Z_DATA_ERROR || err == Z_STREAM_ERROR) { + Trace((stderr, "oops! (inflateBack() err = %d)\n", err)); + retval = 2; + } else if (err == Z_MEM_ERROR) { + retval = 3; + } else if (err == Z_BUF_ERROR) { + Trace((stderr, "oops! (inflateBack() err = %d)\n", err)); + if (G.dstrm.next_in == Z_NULL) { + /* input failure */ + Trace((stderr, " inflateBack() input failure\n")); + retval = 2; + } else { + /* output write failure */ +#ifdef FUNZIP + retval = PK_DISK; +#else /* def FUNZIP */ + retval = (G.disk_full != 0 ? PK_DISK : IZ_CTRLC); +#endif /* def FUNZIP [else] */ + } + } else { + Trace((stderr, "oops! (inflateBack() err = %d)\n", err)); + retval = 2; + } + } + if (G.dstrm.next_in != NULL) { + G.inptr = (uch *)G.dstrm.next_in; + G.incnt = G.dstrm.avail_in; + } + + err = inflateBackEnd(&G.dstrm); + if (err != Z_OK) { + Trace((stderr, "oops! (inflateBackEnd() err = %d)\n", err)); + if (retval == 0) + retval = 2; + } + } + +#else /* !USE_ZLIB_INFLATCB */ + int repeated_buf_err; + +#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.dstrm.next_out = redirSlide; + G.dstrm.avail_out = wsize; + + G.dstrm.next_in = G.inptr; + G.dstrm.avail_in = G.incnt; + + if (!G.inflInit) { + unsigned i; + int windowBits; + /* local buffer for efficiency */ + ZCONST char *zlib_RtVersion = zlibVersion(); + + /* only need to test this stuff once */ + if (zlib_RtVersion[0] != ZLIB_VERSION[0]) { + Info(slide, 0x21, ((char *)slide, + "error: incompatible zlib version (expected %s, found %s)\n", + ZLIB_VERSION, zlib_RtVersion)); + return 3; + } else if (strcmp(zlib_RtVersion, ZLIB_VERSION) != 0) + Info(slide, 0x21, ((char *)slide, + "warning: different zlib version (expected %s, using %s)\n", + ZLIB_VERSION, zlib_RtVersion)); + + /* windowBits = log2(wsize) */ + for (i = (unsigned)wsize, windowBits = 0; + !(i & 1); i >>= 1, ++windowBits); + if ((unsigned)windowBits > (unsigned)15) + windowBits = 15; + else if (windowBits < 8) + windowBits = 8; + + G.dstrm.zalloc = (alloc_func)Z_NULL; + G.dstrm.zfree = (free_func)Z_NULL; + + Trace((stderr, "initializing inflate()\n")); + err = inflateInit2(&G.dstrm, -windowBits); + + if (err == Z_MEM_ERROR) + return 3; + else if (err != Z_OK) + Trace((stderr, "oops! (inflateInit2() err = %d)\n", err)); + G.inflInit = 1; + } + +#ifdef FUNZIP + while (err != Z_STREAM_END) { +#else /* !FUNZIP */ + while (G.csize > 0) { + Trace((stderr, "first loop: G.csize = %ld\n", G.csize)); +#endif /* ?FUNZIP */ + while (G.dstrm.avail_out > 0) { + err = inflate(&G.dstrm, Z_PARTIAL_FLUSH); + + if (err == Z_DATA_ERROR) { + retval = 2; goto uzinflate_cleanup_exit; + } else if (err == Z_MEM_ERROR) { + retval = 3; goto uzinflate_cleanup_exit; + } else if (err != Z_OK && err != Z_STREAM_END) + Trace((stderr, "oops! (inflate(first loop) err = %d)\n", err)); + +#ifdef FUNZIP + if (err == Z_STREAM_END) /* "END-of-entry-condition" ? */ +#else /* !FUNZIP */ + if (G.csize <= 0L) /* "END-of-entry-condition" ? */ +#endif /* ?FUNZIP */ + break; + + if (G.dstrm.avail_in == 0) { + if (fillinbuf(__G) == 0) { + /* no "END-condition" yet, but no more data */ + retval = 2; goto uzinflate_cleanup_exit; + } + + G.dstrm.next_in = G.inptr; + G.dstrm.avail_in = G.incnt; + } + Trace((stderr, " avail_in = %u\n", G.dstrm.avail_in)); + } + /* flush slide[] */ + if ((retval = FLUSH(wsize - G.dstrm.avail_out)) != 0) + goto uzinflate_cleanup_exit; + Trace((stderr, "inside loop: flushing %ld bytes (ptr diff = %ld)\n", + (long)(wsize - G.dstrm.avail_out), + (long)(G.dstrm.next_out-(Bytef *)redirSlide))); + G.dstrm.next_out = redirSlide; + G.dstrm.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 != Z_STREAM_END) { + err = inflate(&G.dstrm, Z_PARTIAL_FLUSH); + if (err == Z_DATA_ERROR) { + retval = 2; goto uzinflate_cleanup_exit; + } else if (err == Z_MEM_ERROR) { + retval = 3; goto uzinflate_cleanup_exit; + } else if (err == Z_BUF_ERROR) { /* DEBUG */ +#ifdef FUNZIP + Trace((stderr, + "zlib inflate() did not detect stream end\n")); +#else + Trace((stderr, + "zlib inflate() did not detect stream end (%s, %s)\n", + G.zipfn, G.filename)); +#endif + if ((!repeated_buf_err) && (G.dstrm.avail_in == 0)) { + /* when detecting this problem for the first time, + try to provide one fake byte beyond "EOF"... */ + G.dstrm.next_in = ""; + G.dstrm.avail_in = 1; + repeated_buf_err = TRUE; + } else + break; + } else if (err != Z_OK && err != Z_STREAM_END) { + Trace((stderr, "oops! (inflate(final loop) err = %d)\n", err)); + DESTROYGLOBALS(); + EXIT(PK_MEM3); + } + /* final flush of slide[] */ + if ((retval = FLUSH(wsize - G.dstrm.avail_out)) != 0) + goto uzinflate_cleanup_exit; + Trace((stderr, "final loop: flushing %ld bytes (ptr diff = %ld)\n", + (long)(wsize - G.dstrm.avail_out), + (long)(G.dstrm.next_out-(Bytef *)redirSlide))); + G.dstrm.next_out = redirSlide; + G.dstrm.avail_out = wsize; + } + Trace((stderr, "total in = %lu, total out = %lu\n", G.dstrm.total_in, + G.dstrm.total_out)); + + G.inptr = (uch *)G.dstrm.next_in; + G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */ + +uzinflate_cleanup_exit: + err = inflateReset(&G.dstrm); + if (err != Z_OK) + Trace((stderr, "oops! (inflateReset() err = %d)\n", err)); + +#endif /* ?USE_ZLIB_INFLATCB */ + return retval; +} + + +/*---------------------------------------------------------------------------*/ +#else /* !USE_ZLIB */ + + +/* Function prototypes */ +#ifndef OF +# ifdef __STDC__ +# define OF(a) a +# else +# define OF(a) () +# endif +#endif /* !OF */ +int inflate_codes OF((__GPRO__ struct huft *tl, struct huft *td, + unsigned bl, unsigned bd)); +static int inflate_stored OF((__GPRO)); +static int inflate_fixed OF((__GPRO)); +static int inflate_dynamic OF((__GPRO)); +static int inflate_block OF((__GPRO__ int *e)); + + +/* The inflate algorithm uses a sliding 32K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + and'ing with 0x7fff (32K-1). */ +/* It is left to other modules to supply the 32K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ + + +/* unsigned wp; moved to globals.h */ /* current position in slide */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +/* - Order of the bit length code lengths */ +static ZCONST unsigned border[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* - Copy lengths for literal codes 257..285 */ +#ifdef USE_DEFLATE64 +static ZCONST ush cplens64[] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 3, 0, 0}; + /* For Deflate64, the code 285 is defined differently. */ +#else +# define cplens32 cplens +#endif +static ZCONST ush cplens32[] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +/* - Extra bits for literal codes 257..285 */ +#ifdef USE_DEFLATE64 +static ZCONST uch cplext64[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 16, INVALID_CODE, INVALID_CODE}; +#else +# define cplext32 cplext +#endif +static ZCONST uch cplext32[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, INVALID_CODE, INVALID_CODE}; + +/* - Copy offsets for distance codes 0..29 (0..31 for Deflate64) */ +static ZCONST ush cpdist[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, +#if (defined(USE_DEFLATE64) || defined(PKZIP_BUG_WORKAROUND)) + 8193, 12289, 16385, 24577, 32769, 49153}; +#else + 8193, 12289, 16385, 24577}; +#endif + +/* - Extra bits for distance codes 0..29 (0..31 for Deflate64) */ +#ifdef USE_DEFLATE64 +static ZCONST uch cpdext64[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13, 14, 14}; +#else +# define cpdext32 cpdext +#endif +static ZCONST uch cpdext32[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, +#ifdef PKZIP_BUG_WORKAROUND + 12, 12, 13, 13, INVALID_CODE, INVALID_CODE}; +#else + 12, 12, 13, 13}; +#endif + +#ifdef PKZIP_BUG_WORKAROUND +# define MAXLITLENS 288 +#else +# define MAXLITLENS 286 +#endif +#if (defined(USE_DEFLATE64) || defined(PKZIP_BUG_WORKAROUND)) +# define MAXDISTS 32 +#else +# define MAXDISTS 30 +#endif + + +/* moved to consts.h (included in unzip.c), resp. funzip.c */ +#if 0 +/* And'ing with mask_bits[n] masks the lower n bits */ +ZCONST unsigned near mask_bits[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; +#endif /* 0 */ + + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed and are initialized at the beginning of a + routine that uses these macros from a global bit buffer and count. + + In order to not ask for more bits than there are in the compressed + stream, the Huffman tables are constructed to only ask for just + enough bits to make up the end-of-block code (value 256). Then no + bytes need to be "returned" to the buffer at the end of the last + block. See the huft_build() routine. + + Actually, the precautions mentioned above are not sufficient to + prevent fetches of bits beyound the end of the last block in every + case. When the last code fetched before the end-of-block code was + a very short distance code (shorter than "distance-prefetch-bits" - + "end-of-block code bits"), this last distance code fetch already + exausts the available data. To prevent failure of extraction in this + case, the "read beyond EOF" check delays the raise of the "invalid + data" error until an actual overflow of "used data" is detected. + This error condition is only fulfilled when the "number of available + bits" counter k is found to be negative in the NEEDBITS() macro. + + An alternate fix for that problem adjusts the size of the distance code + base table so that it does not exceed the length of the end-of-block code + plus the minimum length of a distance code. This alternate fix can be + enabled by defining the preprocessor symbol FIX_PAST_EOB_BY_TABLEADJUST. + */ + +/* These have been moved to globals.h */ +#if 0 +ulg bb; /* bit buffer */ +unsigned bk; /* bits in bit buffer */ +#endif + +#ifndef CHECK_EOF +# define CHECK_EOF /* default as of 5.13/5.2 */ +#endif + +#ifndef CHECK_EOF +# define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<=0)break;retval=1;goto cleanup_and_exit;}\ + b|=((ulg)c)<>=(n);k-=(n);} + + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + are not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* bits in base literal/length lookup table */ +static ZCONST unsigned lbits = 9; +/* bits in base distance lookup table */ +static ZCONST unsigned dbits = 6; + + +#ifndef ASM_INFLATECODES + +int inflate_codes(__G__ tl, td, bl, bd) + __GDEF +struct huft *tl, *td; /* literal/length and distance decoder tables */ +unsigned bl, bd; /* number of bits decoded by tl[] and td[] */ +/* inflate (decompress) the codes in a deflated (compressed) block. + Return an error code or zero if it all goes ok. */ +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned d; /* index for copy */ + UINT_D64 n; /* length for copy (deflate64: might be 64k+2) */ + UINT_D64 w; /* current window position (deflate64: up to 64k) */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + int retval = 0; /* error code returned: initialized to "no error" */ + + + /* make local copies of globals */ + b = G.bb; /* initialize bit buffer */ + k = G.bk; + w = G.wp; /* initialize window position */ + + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + while (1) /* do until end of block */ + { + NEEDBITS(bl) + t = tl + ((unsigned)b & ml); + while (1) { + DUMPBITS(t->b) + + if ((e = t->e) == 32) /* then it's a literal */ + { + redirSlide[w++] = (uch)t->v.n; + if (w == wsize) + { + if ((retval = FLUSH(w)) != 0) goto cleanup_and_exit; + w = 0; + } + break; + } + + if (e < 31) /* then it's a length */ + { + /* get length of block to copy */ + NEEDBITS(e) + n = t->v.n + ((unsigned)b & mask_bits[e]); + DUMPBITS(e) + + /* decode distance of block to copy */ + NEEDBITS(bd) + t = td + ((unsigned)b & md); + while (1) { + DUMPBITS(t->b) + if ((e = t->e) < 32) + break; + if (IS_INVALID_CODE(e)) + return 1; + e &= 31; + NEEDBITS(e) + t = t->v.t + ((unsigned)b & mask_bits[e]); + } + NEEDBITS(e) + d = (unsigned)w - t->v.n - ((unsigned)b & mask_bits[e]); + DUMPBITS(e) + + /* do the copy */ + do { +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) { + /* &= w/ wsize unnecessary & wrong if redirect */ + if ((UINT_D64)d >= wsize) + return 1; /* invalid compressed data */ + e = (unsigned)(wsize - (d > (unsigned)w ? (UINT_D64)d : w)); + } + else +#endif + e = (unsigned)(wsize - + ((d &= (unsigned)(wsize-1)) > (unsigned)w ? + (UINT_D64)d : w)); + if ((UINT_D64)e > n) e = (unsigned)n; + n -= e; +#ifndef NOMEMCPY + if ((unsigned)w - d >= e) + /* (this test assumes unsigned comparison) */ + { + memcpy(redirSlide + (unsigned)w, redirSlide + d, e); + w += e; + d += e; + } + else /* do it slowly to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + redirSlide[w++] = redirSlide[d++]; + } while (--e); + if (w == wsize) + { + if ((retval = FLUSH(w)) != 0) goto cleanup_and_exit; + w = 0; + } + } while (n); + break; + } + + if (e == 31) /* it's the EOB signal */ + { + /* sorry for this goto, but we have to exit two loops at once */ + goto cleanup_decode; + } + + if (IS_INVALID_CODE(e)) + return 1; + + e &= 31; + NEEDBITS(e) + t = t->v.t + ((unsigned)b & mask_bits[e]); + } + } +cleanup_decode: + + /* restore the globals from the locals */ + G.wp = (unsigned)w; /* restore global window pointer */ + G.bb = b; /* restore global bit buffer */ + G.bk = k; + + +cleanup_and_exit: + /* done */ + return retval; +} + +#endif /* ASM_INFLATECODES */ + + + +static int inflate_stored(__G) + __GDEF +/* "decompress" an inflated type 0 (stored) block. */ +{ + UINT_D64 w; /* current window position (deflate64: up to 64k!) */ + unsigned n; /* number of bytes in block */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + int retval = 0; /* error code returned: initialized to "no error" */ + + + /* make local copies of globals */ + Trace((stderr, "\nstored block")); + b = G.bb; /* initialize bit buffer */ + k = G.bk; + w = G.wp; /* initialize window position */ + + + /* go to byte boundary */ + n = k & 7; + DUMPBITS(n); + + + /* get the length and its complement */ + NEEDBITS(16) + n = ((unsigned)b & 0xffff); + DUMPBITS(16) + NEEDBITS(16) + if (n != (unsigned)((~b) & 0xffff)) + return 1; /* error in compressed data */ + DUMPBITS(16) + + + /* read and output the compressed data */ + while (n--) + { + NEEDBITS(8) + redirSlide[w++] = (uch)b; + if (w == wsize) + { + if ((retval = FLUSH(w)) != 0) goto cleanup_and_exit; + w = 0; + } + DUMPBITS(8) + } + + + /* restore the globals from the locals */ + G.wp = (unsigned)w; /* restore global window pointer */ + G.bb = b; /* restore global bit buffer */ + G.bk = k; + +cleanup_and_exit: + return retval; +} + + +/* Globals for literal tables (built once) */ +/* Moved to globals.h */ +#if 0 +struct huft *fixed_tl = (struct huft *)NULL; +struct huft *fixed_td; +int fixed_bl, fixed_bd; +#endif + +static int inflate_fixed(__G) + __GDEF +/* decompress an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ +{ + /* if first time, set up tables for fixed blocks */ + Trace((stderr, "\nliteral block")); + if (G.fixed_tl == (struct huft *)NULL) + { + int i; /* temporary variable */ + unsigned l[288]; /* length list for huft_build */ + + /* literal table */ + for (i = 0; i < 144; i++) + l[i] = 8; + for (; i < 256; i++) + l[i] = 9; + for (; i < 280; i++) + l[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + G.fixed_bl = 7; +#ifdef USE_DEFLATE64 + if ((i = huft_build(__G__ l, 288, 257, G.cplens, G.cplext, + &G.fixed_tl, &G.fixed_bl)) != 0) +#else + if ((i = huft_build(__G__ l, 288, 257, cplens, cplext, + &G.fixed_tl, &G.fixed_bl)) != 0) +#endif + { + G.fixed_tl = (struct huft *)NULL; + return i; + } + + /* distance table */ + for (i = 0; i < MAXDISTS; i++) /* make an incomplete code set */ + l[i] = 5; + G.fixed_bd = 5; +#ifdef USE_DEFLATE64 + if ((i = huft_build(__G__ l, MAXDISTS, 0, cpdist, G.cpdext, + &G.fixed_td, &G.fixed_bd)) > 1) +#else + if ((i = huft_build(__G__ l, MAXDISTS, 0, cpdist, cpdext, + &G.fixed_td, &G.fixed_bd)) > 1) +#endif + { + huft_free(G.fixed_tl); + G.fixed_td = G.fixed_tl = (struct huft *)NULL; + return i; + } + } + + /* decompress until an end-of-block code */ + return inflate_codes(__G__ G.fixed_tl, G.fixed_td, + G.fixed_bl, G.fixed_bd); +} + + + +static int inflate_dynamic(__G) + __GDEF +/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + unsigned i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + struct huft *tl = (struct huft *)NULL; /* literal/length code table */ + struct huft *td = (struct huft *)NULL; /* distance code table */ + struct huft *th; /* temp huft table pointer used in tables decoding */ + unsigned bl; /* lookup bits for tl */ + unsigned bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ + unsigned ll[MAXLITLENS+MAXDISTS]; /* lit./length and distance code lengths */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + int retval = 0; /* error code returned: initialized to "no error" */ + + + /* make local bit buffer */ + Trace((stderr, "\ndynamic block")); + b = G.bb; + k = G.bk; + + + /* read in table lengths */ + NEEDBITS(5) + nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */ + DUMPBITS(5) + NEEDBITS(5) + nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */ + DUMPBITS(5) + NEEDBITS(4) + nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */ + DUMPBITS(4) + if (nl > MAXLITLENS || nd > MAXDISTS) + return 1; /* bad lengths */ + + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3) + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3) + } + for (; j < 19; j++) + ll[border[j]] = 0; + + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + retval = huft_build(__G__ ll, 19, 19, NULL, NULL, &tl, &bl); + if (bl == 0) /* no bit lengths */ + retval = 1; + if (retval) + { + if (retval == 1) + huft_free(tl); + return retval; /* incomplete code set */ + } + + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while (i < n) + { + NEEDBITS(bl) + j = (th = tl + ((unsigned)b & m))->b; + DUMPBITS(j) + j = th->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2) + j = 3 + ((unsigned)b & 3); + DUMPBITS(2) + if ((unsigned)i + j > n) { + huft_free(tl); + return 1; + } + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3) + j = 3 + ((unsigned)b & 7); + DUMPBITS(3) + if ((unsigned)i + j > n) { + huft_free(tl); + return 1; + } + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7) + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7) + if ((unsigned)i + j > n) { + huft_free(tl); + return 1; + } + while (j--) + ll[i++] = 0; + l = 0; + } + } + + + /* free decoding table for trees */ + huft_free(tl); + + + /* restore the global bit buffer */ + G.bb = b; + G.bk = k; + + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; +#ifdef USE_DEFLATE64 + retval = huft_build(__G__ ll, nl, 257, G.cplens, G.cplext, &tl, &bl); +#else + retval = huft_build(__G__ ll, nl, 257, cplens, cplext, &tl, &bl); +#endif + if (bl == 0) /* no literals or lengths */ + retval = 1; + if (retval) + { + if (retval == 1) { + if (!uO.qflag) + MESSAGE((uch *)"(incomplete l-tree) ", 21L, 1); + huft_free(tl); + } + return retval; /* incomplete code set */ + } +#ifdef FIX_PAST_EOB_BY_TABLEADJUST + /* Adjust the requested distance base table size so that a distance code + fetch never tries to get bits behind an immediatly following end-of-block + code. */ + bd = (dbits <= bl+1 ? dbits : bl+1); +#else + bd = dbits; +#endif +#ifdef USE_DEFLATE64 + retval = huft_build(__G__ ll + nl, nd, 0, cpdist, G.cpdext, &td, &bd); +#else + retval = huft_build(__G__ ll + nl, nd, 0, cpdist, cpdext, &td, &bd); +#endif +#ifdef PKZIP_BUG_WORKAROUND + if (retval == 1) + retval = 0; +#endif + if (bd == 0 && nl > 257) /* lengths but no distances */ + retval = 1; + if (retval) + { + if (retval == 1) { + if (!uO.qflag) + MESSAGE((uch *)"(incomplete d-tree) ", 21L, 1); + huft_free(td); + } + huft_free(tl); + return retval; + } + + /* decompress until an end-of-block code */ + retval = inflate_codes(__G__ tl, td, bl, bd); + +cleanup_and_exit: + /* free the decoding tables, return */ + if (tl != (struct huft *)NULL) + huft_free(tl); + if (td != (struct huft *)NULL) + huft_free(td); + return retval; +} + + + +static int inflate_block(__G__ e) + __GDEF + int *e; /* last block flag */ +/* decompress an inflated block */ +{ + unsigned t; /* block type */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + int retval = 0; /* error code returned: initialized to "no error" */ + + + /* make local bit buffer */ + b = G.bb; + k = G.bk; + + + /* read in last block bit */ + NEEDBITS(1) + *e = (int)b & 1; + DUMPBITS(1) + + + /* read in block type */ + NEEDBITS(2) + t = (unsigned)b & 3; + DUMPBITS(2) + + + /* restore the global bit buffer */ + G.bb = b; + G.bk = k; + + + /* inflate that block type */ + if (t == 2) + return inflate_dynamic(__G); + if (t == 0) + return inflate_stored(__G); + if (t == 1) + return inflate_fixed(__G); + + + /* bad block type */ + retval = 2; + +cleanup_and_exit: + return retval; +} + + + +int inflate(__G__ is_defl64) + __GDEF + int is_defl64; +/* decompress an inflated entry */ +{ + int e; /* last block flag */ + int r; /* result code */ +#ifdef DEBUG + unsigned h = 0; /* maximum struct huft's malloc'ed */ +#endif + +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) + wsize = G.redirect_size, redirSlide = G.redirect_buffer; + else + wsize = WSIZE, redirSlide = slide; /* how they're #defined if !DLL */ +#endif + + /* initialize window, bit buffer */ + G.wp = 0; + G.bk = 0; + G.bb = 0; + +#ifdef USE_DEFLATE64 + if (is_defl64) { + G.cplens = cplens64; + G.cplext = cplext64; + G.cpdext = cpdext64; + G.fixed_tl = G.fixed_tl64; + G.fixed_bl = G.fixed_bl64; + G.fixed_td = G.fixed_td64; + G.fixed_bd = G.fixed_bd64; + } else { + G.cplens = cplens32; + G.cplext = cplext32; + G.cpdext = cpdext32; + G.fixed_tl = G.fixed_tl32; + G.fixed_bl = G.fixed_bl32; + G.fixed_td = G.fixed_td32; + G.fixed_bd = G.fixed_bd32; + } +#else /* !USE_DEFLATE64 */ + if (is_defl64) { + /* This should not happen unless UnZip is built from object files + * compiled with inconsistent option setting. Handle this by + * returning with "bad input" error code. + */ + Trace((stderr, "\nThis inflate() cannot handle Deflate64!\n")); + return 2; + } +#endif /* ?USE_DEFLATE64 */ + + /* decompress until the last block */ + do { +#ifdef DEBUG + G.hufts = 0; +#endif + if ((r = inflate_block(__G__ &e)) != 0) + return r; +#ifdef DEBUG + if (G.hufts > h) + h = G.hufts; +#endif + } while (!e); + + Trace((stderr, "\n%u bytes in Huffman tables (%u/entry)\n", + h * (unsigned)sizeof(struct huft), (unsigned)sizeof(struct huft))); + +#ifdef USE_DEFLATE64 + if (is_defl64) { + G.fixed_tl64 = G.fixed_tl; + G.fixed_bl64 = G.fixed_bl; + G.fixed_td64 = G.fixed_td; + G.fixed_bd64 = G.fixed_bd; + } else { + G.fixed_tl32 = G.fixed_tl; + G.fixed_bl32 = G.fixed_bl; + G.fixed_td32 = G.fixed_td; + G.fixed_bd32 = G.fixed_bd; + } +#endif + + /* flush out redirSlide and return (success, unless final FLUSH failed) */ + return (FLUSH(G.wp)); +} + + + +int inflate_free(__G) + __GDEF +{ + if (G.fixed_tl != (struct huft *)NULL) + { + huft_free(G.fixed_td); + huft_free(G.fixed_tl); + G.fixed_td = G.fixed_tl = (struct huft *)NULL; + } + return 0; +} + +#endif /* ?USE_ZLIB */ + + +/* + * GRR: moved huft_build() and huft_free() down here; used by explode() + * and fUnZip regardless of whether USE_ZLIB defined or not + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +int huft_build(__G__ b, n, s, d, e, t, m) + __GDEF + ZCONST unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ + unsigned n; /* number of codes (assumed <= N_MAX) */ + unsigned s; /* number of simple-valued codes (0..s-1) */ + ZCONST ush *d; /* list of base values for non-simple codes */ + ZCONST uch *e; /* list of extra bits for non-simple codes */ + struct huft **t; /* result: starting table */ + unsigned *m; /* maximum lookup bits, returns actual */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. + The code with value 256 is special, and the tables are constructed + so that no bits beyond that code are fetched when that code is + decoded. */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned el; /* length of EOB code (value 256) */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int lx[BMAX+1]; /* memory for l[-1..BMAX-1] */ + int *l = lx+1; /* stack of bits per table */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + el = n > 256 ? b[256] : BMAX; /* set length of EOB code, if any */ + memzero((char *)c, sizeof(c)); + p = (unsigned *)b; i = n; + do { + c[*p]++; p++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *)NULL; + *m = 0; + return 0; + } + + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if (*m < j) + *m = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if (*m > i) + *m = i; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + memzero((char *)v, sizeof(v)); + p = (unsigned *)b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = l[-1] = 0; /* no bits decoded yet */ + u[0] = (struct huft *)NULL; /* just to keep compilers happy */ + q = (struct huft *)NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l[h]) + { + w += l[h++]; /* add bits already decoded */ + + /* compute minimum size table less than or equal to *m bits */ + z = (z = g - w) > *m ? *m : z; /* upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + if ((unsigned)w + j > el && (unsigned)w < el) + j = el - w; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + l[h] = j; /* set table size in stack */ + + /* allocate and link in new table */ + if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) == + (struct huft *)NULL) + { + if (h) + huft_free(u[0]); + return 3; /* not enough memory */ + } +#ifdef DEBUG + G.hufts += z + 1; /* track memory usage */ +#endif + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *)NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l[h-1]; /* bits to dump before this table */ + r.e = (uch)(32 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = (i & ((1 << w) - 1)) >> (w - l[h-1]); + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = INVALID_CODE; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 32 : 31); /* 256 is end-of-block code */ + r.v.n = (ush)*p++; /* simple code is just the value */ + } + else + { + r.e = e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + w -= l[--h]; /* don't need to update q */ + } + } + + + /* return actual size of base table */ + *m = l[0]; + + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + + +int huft_free(t) +struct huft *t; /* table to free */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (struct huft *)NULL) + { + q = (--p)->v.t; + free((zvoid *)p); + p = q; + } + return 0; +} diff --git a/third_party/unzip/inflate.h b/third_party/unzip/inflate.h new file mode 100644 index 000000000..a9ec2ddae --- /dev/null +++ b/third_party/unzip/inflate.h @@ -0,0 +1,40 @@ +// clang-format off +/* + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 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 +*/ +/* inflate.h for UnZip -- by Mark Adler + version c14f, 23 November 1995 */ + + +/* Copyright history: + - Starting with UnZip 5.41 of 16-April-2000, this source file + is covered by the Info-Zip LICENSE cited above. + - Prior versions of this source file, found in UnZip source packages + up to UnZip 5.40, were put in the public domain. + The original copyright note by Mark Adler was: + "You can do whatever you like with this source file, + though I would prefer that if you modify it and + redistribute it that you include comments to that effect + with your name and the date. Thank you." + + History: + vers date who what + ---- --------- -------------- ------------------------------------ + c14 12 Mar 93 M. Adler made inflate.c standalone with the + introduction of inflate.h. + c14d 28 Aug 93 G. Roelofs replaced flush/FlushOutput with new version + c14e 29 Sep 93 G. Roelofs moved everything into unzip.h; added crypt.h + c14f 23 Nov 95 G. Roelofs added UNZIP_INTERNAL to accommodate newly + split unzip.h + */ + +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" /* provides slide[], typedefs and macros */ +#ifdef FUNZIP +#include "third_party/unzip/crypt.h" /* provides NEXTBYTE macro for crypt version of funzip */ +#endif diff --git a/third_party/unzip/list.c b/third_party/unzip/list.c new file mode 100644 index 000000000..e32a99946 --- /dev/null +++ b/third_party/unzip/list.c @@ -0,0 +1,728 @@ +// clang-format off +/* + 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 "third_party/unzip/unzip.h" + + +#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[16]; /* [jart] increased buffer size */ + 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, 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) { + /* [jart] fix problematic use of sprintf */ + sprintf(&methbuf[4], "%03u", G.crec.compression_method & 127); + } + +#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, 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, 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, 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 --git a/third_party/unzip/match.c b/third_party/unzip/match.c new file mode 100644 index 000000000..f8abfee0e --- /dev/null +++ b/third_party/unzip/match.c @@ -0,0 +1,456 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 +*/ +/*--------------------------------------------------------------------------- + + match.c + + The match() routine recursively compares a string to a "pattern" (regular + expression), returning TRUE if a match is found or FALSE if not. This + version is specifically for use with unzip.c: as did the previous match() + routines from SEA and J. Kercheval, it leaves the case (upper, lower, or + mixed) of the string alone, but converts any uppercase characters in the + pattern to lowercase if indicated by the global var pInfo->lcflag (which + is to say, string is assumed to have been converted to lowercase already, + if such was necessary). + + GRR: reversed order of text, pattern in matche() (now same as match()); + added ignore_case/ic flags, Case() macro. + + PaulK: replaced matche() with recmatch() from Zip, modified to have an + ignore_case argument; replaced test frame with simpler one. + + --------------------------------------------------------------------------- + + Copyright on recmatch() from Zip's util.c (although recmatch() was almost + certainly written by Mark Adler...ask me how I can tell :-) ): + + Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly, + Kai Uwe Rommel and Igor Mandrichenko. + + 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. + + --------------------------------------------------------------------------- + + Match the pattern (wildcard) against the string (fixed): + + match(string, pattern, ignore_case, sepc); + + returns TRUE if string matches pattern, FALSE otherwise. In the pattern: + + `*' matches any sequence of characters (zero or more) + `?' matches any single character + [SET] matches any character in the specified set, + [!SET] or [^SET] matches any character not in the specified set. + + 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 + allowed (i.e., 8-bit characters) if your system will support them. + + To suppress the special syntactic significance of any of ``[]*?!^-\'', in- + side or outside a [..] construct, and match the character exactly, precede + it with a ``\'' (backslash). + + Note that "*.*" and "*." are treated specially under MS-DOS if DOSWILD is + defined. See the DOSWILD section below for an explanation. Note also + that with VMSWILD defined, '%' is used instead of '?', and sets (ranges) + are delimited by () instead of []. + + ---------------------------------------------------------------------------*/ + + +#define __MATCH_C /* identifies this source module */ + +/* define ToLower() in here (for Unix, define ToLower to be macro (using + * isupper()); otherwise just use tolower() */ +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" + +#ifndef THEOS /* the Theos port defines its own variant of match() */ + +#if 0 /* this is not useful until it matches Amiga names insensitively */ +#ifdef AMIGA /* some other platforms might also want to use this */ +# define ANSI_CHARSET /* MOVE INTO UNZIP.H EVENTUALLY */ +#endif +#endif /* 0 */ + +#ifdef ANSI_CHARSET +# ifdef ToLower +# undef ToLower +# endif + /* uppercase letters are values 41 thru 5A, C0 thru D6, and D8 thru DE */ +# define IsUpper(c) (c>=0xC0 ? c<=0xDE && c!=0xD7 : c>=0x41 && c<=0x5A) +# define ToLower(c) (IsUpper((uch) c) ? (unsigned) c | 0x20 : (unsigned) c) +#endif +#define Case(x) (ic? ToLower(x) : (x)) + +#ifdef VMSWILD +# define WILDCHAR '%' +# define BEG_RANGE '(' +# define END_RANGE ')' +#else +# define WILDCHAR '?' +# define BEG_RANGE '[' +# define END_RANGE ']' +#endif + +#if 0 /* GRR: add this to unzip.h someday... */ +#if !(defined(MSDOS) && defined(DOSWILD)) +#ifdef WILD_STOP_AT_DIR +#define match(s,p,ic,sc) (recmatch((ZCONST uch *)p,(ZCONST uch *)s,ic,sc) == 1) +#else +#define match(s,p,ic) (recmatch((ZCONST uch *)p,(ZCONST uch *)s,ic) == 1) +#endif +int recmatch OF((ZCONST uch *pattern, ZCONST uch *string, + int ignore_case __WDLPRO)); +#endif +#endif /* 0 */ +static int recmatch OF((ZCONST uch *pattern, ZCONST uch *string, + int ignore_case __WDLPRO)); +static char *isshexp OF((ZCONST char *p)); +static int namecmp OF((ZCONST char *s1, ZCONST char *s2)); + + +/* match() is a shell to recmatch() to return only Boolean values. */ + +int match(string, pattern, ignore_case __WDL) + ZCONST char *string, *pattern; + int ignore_case; + __WDLDEF +{ +#if (defined(MSDOS) && defined(DOSWILD)) + char *dospattern; + int j = strlen(pattern); + +/*--------------------------------------------------------------------------- + Optional MS-DOS preprocessing section: compare last three chars of the + wildcard to "*.*" and translate to "*" if found; else compare the last + two characters to "*." and, if found, scan the non-wild string for dots. + If in the latter case a dot is found, return failure; else translate the + "*." to "*". In either case, continue with the normal (Unix-like) match + procedure after translation. (If not enough memory, default to normal + match.) This causes "a*.*" and "a*." to behave as MS-DOS users expect. + ---------------------------------------------------------------------------*/ + + if ((dospattern = (char *)malloc(j+1)) != NULL) { + strcpy(dospattern, pattern); + if (!strcmp(dospattern+j-3, "*.*")) { + dospattern[j-2] = '\0'; /* nuke the ".*" */ + } else if (!strcmp(dospattern+j-2, "*.")) { + char *p = MBSCHR(string, '.'); + + if (p) { /* found a dot: match fails */ + free(dospattern); + return 0; + } + dospattern[j-1] = '\0'; /* nuke the end "." */ + } + j = recmatch((uch *)dospattern, (uch *)string, ignore_case __WDL); + free(dospattern); + return j == 1; + } else +#endif /* MSDOS && DOSWILD */ + return recmatch((uch *)pattern, (uch *)string, ignore_case __WDL) == 1; +} + + + +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 */ +/* 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. */ +{ + unsigned int c; /* pattern char or start of range in [-] loop */ + + /* Get first character, the pattern for new recmatch calls follows */ + c = *p; INCSTR(p); + + /* If that was the end of the pattern, match if string empty too */ + if (c == 0) + return *s == 0; + + /* '?' (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 + + /* '*' matches any number of characters, including zero */ +#ifdef AMIGA + if (c == '#' && *p == '?') /* "#?" is Amiga-ese for "*" */ + c = '*', 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 (*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 + */ +#ifdef _MBCS + { + ZCONST uch *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); + } +#else /* !_MBCS */ + return ((ic + ? namecmp((ZCONST char *)p, (ZCONST char *)srest) + : strcmp((ZCONST char *)p, (ZCONST char *)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 */ + } + + /* if escape ('\\'), just compare next character */ + if (c == '\\' && (c = *p++) == 0) /* if \ at end, then syntax error */ + return 0; + + /* 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 + +} /* end function recmatch() */ + + + +static char *isshexp(p) +ZCONST char *p; +/* If p is a sh expression, a pointer to the first special character is + returned. Otherwise, NULL is returned. */ +{ + for (; *p; INCSTR(p)) + if (*p == '\\' && *(p+1)) + p++; + else if (*p == WILDCHAR || *p == '*' || *p == BEG_RANGE) + return (char *)p; + return NULL; +} /* end function isshexp() */ + + + +static int namecmp(s1, s2) + ZCONST char *s1, *s2; +{ + int d; + + for (;;) { + d = (int)ToLower((uch)*s1) + - (int)ToLower((uch)*s2); + + if (d || *s1 == 0 || *s2 == 0) + return d; + + s1++; + s2++; + } +} /* end function namecmp() */ + +#endif /* !THEOS */ + + + + +int iswild(p) /* originally only used for stat()-bug workaround in */ + ZCONST char *p; /* VAX C, Turbo/Borland C, Watcom C, Atari MiNT libs; */ +{ /* now used in process_zipfiles() as well */ + for (; *p; INCSTR(p)) + if (*p == '\\' && *(p+1)) + ++p; +#ifdef THEOS + else if (*p == '?' || *p == '*' || *p=='#'|| *p == '@') +#else /* !THEOS */ +#ifdef VMS + else if (*p == '%' || *p == '*') +#else /* !VMS */ +#ifdef AMIGA + else if (*p == '?' || *p == '*' || (*p=='#' && p[1]=='?') || *p == '[') +#else /* !AMIGA */ + else if (*p == '?' || *p == '*' || *p == '[') +#endif /* ?AMIGA */ +#endif /* ?VMS */ +#endif /* ?THEOS */ +#ifdef QDOS + return (int)p; +#else + return TRUE; +#endif + + return FALSE; + +} /* end function iswild() */ + +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) +int iswildw(pw) /* originally only used for stat()-bug workaround in */ + ZCONST wchar_t *pw; /* VAX C, Turbo/Borland C, Watcom C, Atari MiNT libs; */ +{ /* now used in process_zipfiles() as well */ + for (; *pw; pw++) + if (*pw == '\\' && *(pw+1)) + ++pw; + else if (*pw == '?' || *pw == '*' || *pw == '[') + return TRUE; + + return FALSE; + +} /* end function iswildw() */ +#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ + + + +#ifdef TEST_MATCH + +#define put(s) {fputs(s,stdout); fflush(stdout);} +#ifdef main +# undef main +#endif + +int main(int argc, char **argv) +{ + char pat[256], str[256]; + + for (;;) { + put("Pattern (return to exit): "); + gets(pat); + if (!pat[0]) + break; + for (;;) { + put("String (return for new pattern): "); + gets(str); + if (!str[0]) + break; + printf("Case sensitive: %s insensitive: %s\n", + match(str, pat, 0) ? "YES" : "NO", + match(str, pat, 1) ? "YES" : "NO"); + } + } + EXIT(0); +} + +#endif /* TEST_MATCH */ diff --git a/third_party/unzip/process.c b/third_party/unzip/process.c new file mode 100644 index 000000000..c66b5bbe7 --- /dev/null +++ b/third_party/unzip/process.c @@ -0,0 +1,3178 @@ +// clang-format off +/* + Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2009-Jan-02 or later + (the contents of which are also included in unzip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html +*/ +/*--------------------------------------------------------------------------- + + process.c + + This file contains the top-level routines for processing multiple zipfiles. + + Contains: process_zipfiles() + free_G_buffers() + do_seekable() + file_size() + rec_find() + find_ecrec64() + find_ecrec() + process_zip_cmmnt() + process_cdir_file_hdr() + get_cdir_ent() + process_local_file_hdr() + getZip64Data() + ef_scan_for_izux() + getRISCOSexfield() + + ---------------------------------------------------------------------------*/ + + +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" +#if defined(DYNALLOC_CRCTAB) || defined(UNICODE_SUPPORT) +#include "third_party/unzip/crc32.h" +#endif +#ifdef UNICODE_SUPPORT +#endif /* def UNICODE_SUPPORT */ + +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 */ +#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); +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + if (G.has_win32_wide) + checkdirw(__G__ (wchar_t *)NULL, END); + else + checkdir(__G__ (char *)NULL, END); +#else + checkdir(__G__ (char *)NULL, END); +#endif + +#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)) { +# if defined(VMS) || defined(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; + + /* Handle the PKWare verification bit, bit 2 (0x0004) of internal + attributes. If this is set, then a verification checksum is in the + first 3 bytes of the external attributes. In this case all we can use + for setting file attributes is the last external attributes byte. */ + if (G.crec.internal_file_attributes & 0x0004) + G.crec.external_file_attributes &= (ulg)0xff; + + /* 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 Purpose Bit 11) which indicates + that the standard path and comment are UTF-8. */ + G.pInfo->GPFIsUTF8 + = (G.crec.general_purpose_bit_flag & UTF8_BIT) == UTF8_BIT; +#endif + + return PK_COOL; + +} /* end function process_cdir_file_hdr() */ + + + + + +/***************************/ +/* Function get_cdir_ent() */ +/***************************/ + +static int get_cdir_ent(__G) /* return PK-type error code */ + __GDEF +{ + cdir_byte_hdr byterec; + + +/*--------------------------------------------------------------------------- + Read the next central directory entry and do any necessary machine-type + conversions (byte ordering, structure padding compensation--do so by + copying the data from the array into which it was read (byterec) to the + usable struct (crec)). + ---------------------------------------------------------------------------*/ + + if (readbuf(__G__ (char *)byterec, CREC_SIZE) == 0) + return PK_EOF; + + G.crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0]; + G.crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1]; + G.crec.version_needed_to_extract[0] = + byterec[C_VERSION_NEEDED_TO_EXTRACT_0]; + G.crec.version_needed_to_extract[1] = + byterec[C_VERSION_NEEDED_TO_EXTRACT_1]; + + G.crec.general_purpose_bit_flag = + makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]); + G.crec.compression_method = + makeword(&byterec[C_COMPRESSION_METHOD]); + G.crec.last_mod_dos_datetime = + makelong(&byterec[C_LAST_MOD_DOS_DATETIME]); + G.crec.crc32 = + makelong(&byterec[C_CRC32]); + G.crec.csize = + makelong(&byterec[C_COMPRESSED_SIZE]); + G.crec.ucsize = + makelong(&byterec[C_UNCOMPRESSED_SIZE]); + G.crec.filename_length = + makeword(&byterec[C_FILENAME_LENGTH]); + G.crec.extra_field_length = + makeword(&byterec[C_EXTRA_FIELD_LENGTH]); + G.crec.file_comment_length = + makeword(&byterec[C_FILE_COMMENT_LENGTH]); + G.crec.disk_number_start = + makeword(&byterec[C_DISK_NUMBER_START]); + G.crec.internal_file_attributes = + makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]); + G.crec.external_file_attributes = + makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */ + G.crec.relative_offset_local_header = + makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]); + + return PK_COOL; + +} /* end function get_cdir_ent() */ + + + + + +/*************************************/ +/* Function process_local_file_hdr() */ +/*************************************/ + +int process_local_file_hdr(__G) /* return PK-type error code */ + __GDEF +{ + local_byte_hdr byterec; + + +/*--------------------------------------------------------------------------- + Read the next local file header and do any necessary machine-type con- + versions (byte ordering, structure padding compensation--do so by copy- + ing the data from the array into which it was read (byterec) to the + usable struct (lrec)). + ---------------------------------------------------------------------------*/ + + if (readbuf(__G__ (char *)byterec, LREC_SIZE) == 0) + return PK_EOF; + + G.lrec.version_needed_to_extract[0] = + byterec[L_VERSION_NEEDED_TO_EXTRACT_0]; + G.lrec.version_needed_to_extract[1] = + byterec[L_VERSION_NEEDED_TO_EXTRACT_1]; + + G.lrec.general_purpose_bit_flag = + makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]); + G.lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]); + G.lrec.last_mod_dos_datetime = makelong(&byterec[L_LAST_MOD_DOS_DATETIME]); + G.lrec.crc32 = makelong(&byterec[L_CRC32]); + G.lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]); + G.lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]); + G.lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]); + G.lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]); + + if ((G.lrec.general_purpose_bit_flag & 8) != 0) { + /* can't trust local header, use central directory: */ + G.lrec.crc32 = G.pInfo->crc; + G.lrec.csize = G.pInfo->compr_size; + G.lrec.ucsize = G.pInfo->uncompr_size; + } + + G.csize = G.lrec.csize; + + return PK_COOL; + +} /* end function process_local_file_hdr() */ + + +/*******************************/ +/* Function getZip64Data() */ +/*******************************/ + +int getZip64Data(__G__ ef_buf, ef_len) + __GDEF + ZCONST uch *ef_buf; /* buffer containing extra field */ + unsigned ef_len; /* total length of extra field */ +{ + unsigned eb_id; + unsigned eb_len; + +/*--------------------------------------------------------------------------- + This function scans the extra field for zip64 information, ie 8-byte + versions of compressed file size, uncompressed file size, relative offset + and a 4-byte version of disk start number. + Sets both local header and central header fields. Not terribly clever, + but it means that this procedure is only called in one place. + ---------------------------------------------------------------------------*/ + + if (ef_len == 0 || ef_buf == NULL) + return PK_COOL; + + Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n", + ef_len)); + + while (ef_len >= EB_HEADSIZE) { + eb_id = makeword(EB_ID + ef_buf); + eb_len = makeword(EB_LEN + ef_buf); + + if (eb_len > (ef_len - EB_HEADSIZE)) { + /* discovered some extra field inconsistency! */ + Trace((stderr, + "getZip64Data: block length %u > rest ef_size %u\n", eb_len, + ef_len - EB_HEADSIZE)); + break; + } + if (eb_id == EF_PKSZ64) { + + int offset = EB_HEADSIZE; + + if (G.crec.ucsize == 0xffffffff || G.lrec.ucsize == 0xffffffff){ + G.lrec.ucsize = G.crec.ucsize = makeint64(offset + ef_buf); + offset += sizeof(G.crec.ucsize); + } + if (G.crec.csize == 0xffffffff || G.lrec.csize == 0xffffffff){ + G.csize = G.lrec.csize = G.crec.csize = makeint64(offset + ef_buf); + offset += sizeof(G.crec.csize); + } + if (G.crec.relative_offset_local_header == 0xffffffff){ + G.crec.relative_offset_local_header = makeint64(offset + ef_buf); + offset += sizeof(G.crec.relative_offset_local_header); + } + if (G.crec.disk_number_start == 0xffff){ + G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf); + offset += sizeof(G.crec.disk_number_start); + } + } + + /* Skip this extra field block */ + ef_buf += (eb_len + EB_HEADSIZE); + ef_len -= (eb_len + EB_HEADSIZE); + } + + return PK_COOL; +} /* end function getZip64Data() */ + + +#ifdef UNICODE_SUPPORT + +/*******************************/ +/* Function getUnicodeData() */ +/*******************************/ + +int getUnicodeData(__G__ ef_buf, ef_len) + __GDEF + ZCONST uch *ef_buf; /* buffer containing extra field */ + unsigned ef_len; /* total length of extra field */ +{ + unsigned eb_id; + unsigned eb_len; + +/*--------------------------------------------------------------------------- + This function scans the extra field for Unicode information, ie UTF-8 + path extra fields. + + On return, G.unipath_filename = + NULL, if no Unicode path extra field or error + "", if the standard path is UTF-8 (free when done) + null-terminated UTF-8 path (free when done) + Return PK_COOL if no error. + ---------------------------------------------------------------------------*/ + + G.unipath_filename = NULL; + + if (ef_len == 0 || ef_buf == NULL) + return PK_COOL; + + Trace((stderr,"\ngetUnicodeData: scanning extra field of length %u\n", + ef_len)); + + while (ef_len >= EB_HEADSIZE) { + eb_id = makeword(EB_ID + ef_buf); + eb_len = makeword(EB_LEN + ef_buf); + + if (eb_len > (ef_len - EB_HEADSIZE)) { + /* discovered some extra field inconsistency! */ + Trace((stderr, + "getUnicodeData: block length %u > rest ef_size %u\n", eb_len, + ef_len - EB_HEADSIZE)); + break; + } + if (eb_id == EF_UNIPATH) { + + int offset = EB_HEADSIZE; + ush ULen = eb_len - 5; + ulg chksum = CRCVAL_INITIAL; + + /* version */ + G.unipath_version = (uch) *(offset + ef_buf); + offset += 1; + if (G.unipath_version > 1) { + /* can do only version 1 */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(UnicodeVersionError))); + return PK_ERR; + } + + /* filename CRC */ + G.unipath_checksum = makelong(offset + ef_buf); + offset += 4; + + /* + * Compute 32-bit crc + */ + + chksum = crc32(chksum, (uch *)(G.filename_full), + strlen(G.filename_full)); + + /* If the checksums's don't match then likely filename has been + * modified and the Unicode Path is no longer valid. + */ + if (chksum != G.unipath_checksum) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(UnicodeMismatchError))); + if (G.unicode_mismatch == 1) { + /* warn and continue */ + } else if (G.unicode_mismatch == 2) { + /* ignore and continue */ + } else if (G.unicode_mismatch == 0) { + } + return PK_ERR; + } + + /* UTF-8 Path */ + if ((G.unipath_filename = malloc(ULen + 1)) == NULL) { + return PK_ERR; + } + if (ULen == 0) { + /* standard path is UTF-8 so use that */ + G.unipath_filename[0] = '\0'; + } else { + /* UTF-8 path */ + strncpy(G.unipath_filename, + (ZCONST char *)(offset + ef_buf), ULen); + G.unipath_filename[ULen] = '\0'; + } + } + + /* Skip this extra field block */ + ef_buf += (eb_len + EB_HEADSIZE); + ef_len -= (eb_len + EB_HEADSIZE); + } + + return PK_COOL; +} /* end function getUnicodeData() */ + + + + +#ifdef UNICODE_WCHAR + /*--------------------------------------------- + * Unicode conversion functions + * + * Based on functions provided by Paul Kienitz + * + *--------------------------------------------- + */ + +/* + NOTES APPLICABLE TO ALL STRING FUNCTIONS: + + All of the x_to_y functions take parameters for an output buffer and + its available length, and return an int. The value returned is the + length of the string that the input produces, which may be larger than + the provided buffer length. If the returned value is less than the + buffer length, then the contents of the buffer will be null-terminated; + otherwise, it will not be terminated and may be invalid, possibly + stopping in the middle of a multibyte sequence. + + In all cases you may pass NULL as the buffer and/or 0 as the length, if + you just want to learn how much space the string is going to require. + + The functions will return -1 if the input is invalid UTF-8 or cannot be + encoded as UTF-8. +*/ + +static int utf8_char_bytes OF((ZCONST char *utf8)); +static ulg ucs4_char_from_utf8 OF((ZCONST char **utf8)); +static int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *ucs4buf, + int buflen)); + +/* utility functions for managing UTF-8 and UCS-4 strings */ + + +/* utf8_char_bytes + * + * Returns the number of bytes used by the first character in a UTF-8 + * string, or -1 if the UTF-8 is invalid or null. + */ +static int utf8_char_bytes(utf8) + ZCONST char *utf8; +{ + int t, r; + unsigned lead; + + if (!utf8) + return -1; /* no input */ + lead = (unsigned char) *utf8; + if (lead < 0x80) + r = 1; /* an ascii-7 character */ + else if (lead < 0xC0) + return -1; /* error: trailing byte without lead byte */ + else if (lead < 0xE0) + r = 2; /* an 11 bit character */ + else if (lead < 0xF0) + r = 3; /* a 16 bit character */ + else if (lead < 0xF8) + r = 4; /* a 21 bit character (the most currently used) */ + else if (lead < 0xFC) + r = 5; /* a 26 bit character (shouldn't happen) */ + else if (lead < 0xFE) + r = 6; /* a 31 bit character (shouldn't happen) */ + else + return -1; /* error: invalid lead byte */ + for (t = 1; t < r; t++) + if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0) + return -1; /* error: not enough valid trailing bytes */ + return r; +} + + +/* ucs4_char_from_utf8 + * + * Given a reference to a pointer into a UTF-8 string, returns the next + * UCS-4 character and advances the pointer to the next character sequence. + * Returns ~0 (= -1 in twos-complement notation) and does not advance the + * pointer when input is ill-formed. + */ +static ulg ucs4_char_from_utf8(utf8) + ZCONST char **utf8; +{ + ulg ret; + int t, bytes; + + if (!utf8) + return ~0L; /* no input */ + bytes = utf8_char_bytes(*utf8); + if (bytes <= 0) + return ~0L; /* invalid input */ + if (bytes == 1) + ret = **utf8; /* ascii-7 */ + else + ret = **utf8 & (0x7F >> bytes); /* lead byte of a multibyte sequence */ + (*utf8)++; + for (t = 1; t < bytes; t++) /* consume trailing bytes */ + ret = (ret << 6) | (*((*utf8)++) & 0x3F); + return (zwchar) ret; +} + + +#if 0 /* currently unused */ +/* utf8_from_ucs4_char - Convert UCS char to UTF-8 + * + * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6, + * or -1 if ch is too large to represent. utf8buf must have room for 6 bytes. + */ +static int utf8_from_ucs4_char(utf8buf, ch) + char *utf8buf; + ulg ch; +{ + int trailing = 0; + int leadmask = 0x80; + int leadbits = 0x3F; + int tch = ch; + int ret; + + if (ch > 0x7FFFFFFFL) + return -1; /* UTF-8 can represent 31 bits */ + if (ch < 0x7F) + { + *utf8buf++ = (char) ch; /* ascii-7 */ + return 1; + } + do { + trailing++; + leadmask = (leadmask >> 1) | 0x80; + leadbits >>= 1; + tch >>= 6; + } while (tch & ~leadbits); + ret = trailing + 1; + /* produce lead byte */ + *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing))); + while (--trailing >= 0) + /* produce trailing bytes */ + *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F)); + return ret; +} +#endif /* unused */ + + +/*===================================================================*/ + +/* utf8_to_ucs4_string - convert UTF-8 string to UCS string + * + * Return UCS count. Now returns int so can return -1. + */ +static int utf8_to_ucs4_string(utf8, ucs4buf, buflen) + ZCONST char *utf8; + ulg *ucs4buf; + int buflen; +{ + int count = 0; + + for (;;) + { + ulg ch = ucs4_char_from_utf8(&utf8); + if (ch == (ulg)~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; +} + +wchar_t *wide_to_wchar_string(wide_string) + zwchar *wide_string; +{ + wchar_t *wstring; + int i; + int zwlen; + + for (zwlen = 0; wide_string[zwlen]; zwlen++) ; + + if ((wstring = malloc((zwlen + 1) * sizeof(wchar_t))) == NULL) { + return NULL; + } + + for (i = 0; wide_string[i]; i++) { + wstring[i] = (wchar_t)wide_string[i]; + } + wstring[i] = (wchar_t)0; + + return wstring; +} + +zwchar *wchar_to_wide_string(wchar_string) + wchar_t *wchar_string; +{ + zwchar *zwstring; + int i; + int wlen; + + for (wlen = 0; wchar_string[wlen]; wlen++) ; + + if ((zwstring = malloc((wlen + 1) * sizeof(zwchar))) == NULL) { + return NULL; + } + + for (i = 0; wchar_string[i]; i++) { + zwstring[i] = (zwchar)wchar_string[i]; + } + zwstring[i] = (zwchar)0; + + return zwstring; +} + + +/* 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; +} + +#if 0 /* currently unused */ + +/* 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; +} + +zwchar *wchar_to_wide_string(wchar_string) + wchar_t *wchar_string; +{ + int i; + int wchar_len; + zwchar *wide_string; + + wchar_len = wcslen(wchar_string); + + if ((wide_string = malloc((wchar_len + 1) * sizeof(zwchar))) == NULL) { + return NULL; + } + for (i = 0; i <= wchar_len; i++) { + wide_string[i] = wchar_string[i]; + } + + return wide_string; +} + +#endif /* unused */ + + +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + +char *wchar_to_local_string(wchar_string, escape_all) + wchar_t *wchar_string; + int escape_all; +{ + zwchar *wide_string = wchar_to_wide_string(wchar_string); + char *local_string = wide_to_local_string(wide_string, escape_all); + + free(wide_string); + + return local_string; +} + +#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ + + +/* 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 --git a/third_party/unzip/timezone.c b/third_party/unzip/timezone.c new file mode 100644 index 000000000..e21a5955b --- /dev/null +++ b/third_party/unzip/timezone.c @@ -0,0 +1,813 @@ +// clang-format off +/* + Copyright (c) 1990-2001 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.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 +*/ +/* Replacement time library functions, based on platform independent public + * domain timezone code from ftp://elsie.nci.nih.gov/pub, with mktime and + * mkgmtime from our own mktime.c in Zip. + * + * Contains: tzset() + * __tzset() + * gmtime() + * localtime() + * mktime() + * mkgmtime() + * GetPlatformLocalTimezone() [different versions] + */ + +/* HISTORY/CHANGES + * 17 Jun 00, Paul Kienitz, added the PD-based tzset(), localtime(), and so on + * to amiga/filedate.c, replacing GNU-based functions which had + * replaced time_lib.c, both having been rejected for licensing + * reasons. Support for timezone files and leap seconds was removed. + * + * 23 Aug 00, Paul Kienitz, split into separate timezone.c file, made platform + * independent, copied in mktime() and mkgmtime() from Zip, renamed + * locale_TZ as GetPlatformLocalTimezone(), for use as a generic + * hook by other platforms. + */ + +#ifndef __timezone_c +#define __timezone_c + + +#include "third_party/unzip/zip.h" +#include "libc/time/struct/tm.h" +#include "third_party/unzip/timezone.h" + +#ifdef IZTZ_DEFINESTDGLOBALS +long timezone = 0; +int daylight = 0; +char *tzname[2]; +#endif + +#ifndef IZTZ_GETLOCALETZINFO +# define IZTZ_GETLOCALETZINFO(ptzstruct, pgenrulefunct) (FALSE) +#endif + +int real_timezone_is_set = FALSE; /* set by tzset() */ + + +#define TZDEFRULESTRING ",M4.1.0,M10.5.0" +#define TZDEFAULT "EST5EDT" + +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define DAYSPERWEEK 7 +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) +#define MONSPERYEAR 12 + +#define EPOCH_WDAY 4 /* Jan 1, 1970 was thursday */ +#define EPOCH_YEAR 1970 +#define TM_YEAR_BASE 1900 +#define FIRST_GOOD_YEAR ((time_t) -1 < (time_t) 1 ? EPOCH_YEAR-68 : EPOCH_YEAR) +#define LAST_GOOD_YEAR (EPOCH_YEAR + ((time_t) -1 < (time_t) 1 ? 67 : 135)) + +#define YDAYS(month, year) yr_days[leap(year)][month] + +/* Nonzero if `y' is a leap year, else zero. */ +#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) + +/* Number of leap years from EPOCH_YEAR to `y' (not including `y' itself). */ +#define _P4 ((EPOCH_YEAR / 4) * 4 + 1) +#define _P100 ((EPOCH_YEAR / 100) * 100 + 1) +#define _P400 ((EPOCH_YEAR / 400) * 400 + 1) +#define nleap(y) (((y) - _P4) / 4 - ((y) - _P100) / 100 + ((y) - _P400) / 400) + +/* Length of month `m' (0 .. 11) */ +#define monthlen(m, y) (yr_days[0][(m)+1] - yr_days[0][m] + \ + ((m) == 1 && leap(y))) + +/* internal module-level constants */ +#ifndef IZ_MKTIME_ONLY +static ZCONST char gmt[] = "GMT"; +static ZCONST int mon_lengths[2][MONSPERYEAR] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; +#endif /* !IZ_MKTIME_ONLY */ +static ZCONST int yr_days[2][MONSPERYEAR+1] = { + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } +}; +#ifndef IZ_MKTIME_ONLY +static ZCONST int year_lengths[2] = { + DAYSPERNYEAR, DAYSPERLYEAR +}; + +/* internal variables */ +static struct state statism; + + +/* prototypes of static functions */ +static time_t transtime OF((ZCONST time_t janfirst, ZCONST int year, + ZCONST struct rule * ZCONST rulep, + ZCONST long offset)); +static void generate_transitions OF((register struct state * ZCONST sp, + ZCONST struct rule * ZCONST start, + ZCONST struct rule * ZCONST end)); +static ZCONST char *getzname OF((ZCONST char *strp)); +static ZCONST char *getnum OF((ZCONST char *strp, int * ZCONST nump, + ZCONST int min, ZCONST int max)); +static ZCONST char *getsecs OF((ZCONST char *strp, long * ZCONST secsp)); +static ZCONST char *getoffset OF((ZCONST char *strp, long * ZCONST offsetp)); +static ZCONST char *getrule OF((ZCONST char *strp, struct rule * ZCONST rulep)); +static int Parse_TZ OF((ZCONST char *name, register struct state * ZCONST sp)); + + +static time_t transtime(janfirst, year, rulep, offset) + ZCONST time_t janfirst; + ZCONST int year; + ZCONST struct rule * ZCONST rulep; + ZCONST long offset; +{ + register int leapyear; + register time_t value; + register int i; + int d, m1, yy0, yy1, yy2, dow; + + value = 0; + leapyear = leap(year); + switch (rulep->r_type) { + + case JULIAN_DAY: + /* + ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap + ** years. + ** In non-leap years, or if the day number is 59 or less, just + ** add SECSPERDAY times the day number-1 to the time of + ** January 1, midnight, to get the day. + */ + value = janfirst + (rulep->r_day - 1) * SECSPERDAY; + if (leapyear && rulep->r_day >= 60) + value += SECSPERDAY; + break; + + case DAY_OF_YEAR: + /* + ** n - day of year. + ** Just add SECSPERDAY times the day number to the time of + ** January 1, midnight, to get the day. + */ + value = janfirst + rulep->r_day * SECSPERDAY; + break; + + case MONTH_NTH_DAY_OF_WEEK: + /* + ** Mm.n.d - nth "dth day" of month m. + */ + value = janfirst; +/* + for (i = 0; i < rulep->r_mon - 1; ++i) + value += mon_lengths[leapyear][i] * SECSPERDAY; +*/ + value += yr_days[leapyear][rulep->r_mon - 1] * SECSPERDAY; + + /* + ** Use Zeller's Congruence to get day-of-week of first day of + ** month. + */ + m1 = (rulep->r_mon + 9) % 12 + 1; + yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; + yy1 = yy0 / 100; + yy2 = yy0 % 100; + dow = ((26 * m1 - 2) / 10 + + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; + if (dow < 0) + dow += DAYSPERWEEK; + + /* + ** "dow" is the day-of-week of the first day of the month. Get + ** the day-of-month (zero-origin) of the first "dow" day of the + ** month. + */ + d = rulep->r_day - dow; + if (d < 0) + d += DAYSPERWEEK; + for (i = 1; i < rulep->r_week; ++i) { + if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1]) + break; + d += DAYSPERWEEK; + } + + /* + ** "d" is the day-of-month (zero-origin) of the day we want. + */ + value += d * SECSPERDAY; + break; + } + + /* + ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in + ** question. To get the Epoch-relative time of the specified local + ** time on that day, add the transition time and the current offset + ** from UTC. + */ + return value + rulep->r_time + offset; +} + +static void generate_transitions(sp, start, end) + register struct state * ZCONST sp; + ZCONST struct rule * ZCONST start; + ZCONST struct rule * ZCONST end; +{ + register int year; + register time_t janfirst; + time_t starttime; + time_t endtime; + long stdoffset = -sp->ttis[0].tt_gmtoff; + long dstoffset = -sp->ttis[1].tt_gmtoff; + register time_t * atp; + register unsigned char * typep; + + /* + ** Two transitions per year, from EPOCH_YEAR to LAST_GOOD_YEAR. + */ + sp->timecnt = 2 * (LAST_GOOD_YEAR - EPOCH_YEAR + 1); + atp = sp->ats; + typep = sp->types; + janfirst = 0; + for (year = EPOCH_YEAR; year <= LAST_GOOD_YEAR; ++year) { + starttime = transtime(janfirst, year, start, stdoffset); + endtime = transtime(janfirst, year, end, dstoffset); + if (starttime > endtime) { + *atp++ = endtime; + *typep++ = 0; /* DST ends */ + *atp++ = starttime; + *typep++ = 1; /* DST begins */ + } else { + *atp++ = starttime; + *typep++ = 1; /* DST begins */ + *atp++ = endtime; + *typep++ = 0; /* DST ends */ + } + janfirst += year_lengths[leap(year)] * SECSPERDAY; + } +} + +static ZCONST char *getzname(strp) + ZCONST char *strp; +{ + register char c; + + while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && + c != '+') + ++strp; + return strp; +} + +static ZCONST char *getnum(strp, nump, min, max) + ZCONST char *strp; + int * ZCONST nump; + ZCONST int min; + ZCONST int max; +{ + register char c; + register int num; + + if (strp == NULL || !isdigit(c = *strp)) + return NULL; + num = 0; + do { + num = num * 10 + (c - '0'); + if (num > max) + return NULL; /* illegal value */ + c = *++strp; + } while (isdigit(c)); + if (num < min) + return NULL; /* illegal value */ + *nump = num; + return strp; +} + +static ZCONST char *getsecs(strp, secsp) + ZCONST char *strp; + long * ZCONST secsp; +{ + int num; + + /* + ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like + ** "M10.4.6/26", which does not conform to Posix, + ** but which specifies the equivalent of + ** ``02:00 on the first Sunday on or after 23 Oct''. + */ + strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); + if (strp == NULL) + return NULL; + *secsp = num * (long) SECSPERHOUR; + if (*strp == ':') { + ++strp; + strp = getnum(strp, &num, 0, MINSPERHOUR - 1); + if (strp == NULL) + return NULL; + *secsp += num * SECSPERMIN; + if (*strp == ':') { + ++strp; + /* `SECSPERMIN' allows for leap seconds. */ + strp = getnum(strp, &num, 0, SECSPERMIN); + if (strp == NULL) + return NULL; + *secsp += num; + } + } + return strp; +} + +static ZCONST char *getoffset(strp, offsetp) + ZCONST char *strp; + long * ZCONST offsetp; +{ + register int neg = 0; + + if (*strp == '-') { + neg = 1; + ++strp; + } else if (*strp == '+') + ++strp; + strp = getsecs(strp, offsetp); + if (strp == NULL) + return NULL; /* illegal time */ + if (neg) + *offsetp = -*offsetp; + return strp; +} + +static ZCONST char *getrule(strp, rulep) + ZCONST char *strp; + struct rule * ZCONST rulep; +{ + if (*strp == 'J') { + /* + ** Julian day. + */ + rulep->r_type = JULIAN_DAY; + ++strp; + strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); + } else if (*strp == 'M') { + /* + ** Month, week, day. + */ + rulep->r_type = MONTH_NTH_DAY_OF_WEEK; + ++strp; + strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); + if (strp == NULL) + return NULL; + if (*strp++ != '.') + return NULL; + strp = getnum(strp, &rulep->r_week, 1, 5); + if (strp == NULL) + return NULL; + if (*strp++ != '.') + return NULL; + strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); + } else if (isdigit(*strp)) { + /* + ** Day of year. + */ + rulep->r_type = DAY_OF_YEAR; + strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); + } else return NULL; /* invalid format */ + if (strp == NULL) + return NULL; + if (*strp == '/') { + /* + ** Time specified. + */ + ++strp; + strp = getsecs(strp, &rulep->r_time); + } else + rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ + return strp; +} + +static int Parse_TZ(name, sp) + ZCONST char *name; + register struct state * ZCONST sp; +{ + ZCONST char * stdname; + ZCONST char * dstname; + size_t stdlen; + size_t dstlen; + long stdoffset; + long dstoffset; + register char * cp; + + dstname = NULL; + stdname = name; + name = getzname(name); + stdlen = name - stdname; + if (stdlen < 3) + return -1; + if (*name == '\0') + return -1; + name = getoffset(name, &stdoffset); + if (name == NULL) + return -1; + if (*name != '\0') { + dstname = name; + name = getzname(name); + dstlen = name - dstname; /* length of DST zone name */ + if (dstlen < 3) + return -1; + if (*name != '\0' && *name != ',' && *name != ';') { + name = getoffset(name, &dstoffset); + if (name == NULL) + return -1; + } else + dstoffset = stdoffset - SECSPERHOUR; + if (*name == '\0') + name = TZDEFRULESTRING; + if (*name == ',' || *name == ';') { + struct rule start; + struct rule end; + + ++name; + if ((name = getrule(name, &start)) == NULL) + return -1; + if (*name++ != ',') + return -1; + if ((name = getrule(name, &end)) == NULL) + return -1; + if (*name != '\0') + return -1; + sp->typecnt = 2; /* standard time and DST */ + sp->ttis[0].tt_gmtoff = -stdoffset; + sp->ttis[0].tt_isdst = 0; + sp->ttis[0].tt_abbrind = 0; + sp->ttis[1].tt_gmtoff = -dstoffset; + sp->ttis[1].tt_isdst = 1; + sp->ttis[1].tt_abbrind = stdlen + 1; + generate_transitions(sp, &start, &end); + } + } else { + dstlen = 0; + sp->typecnt = 1; /* only standard time */ + sp->timecnt = 0; + sp->ttis[0].tt_gmtoff = -stdoffset; + sp->ttis[0].tt_isdst = 0; + sp->ttis[0].tt_abbrind = 0; + } + sp->charcnt = stdlen + 1; + if (dstlen != 0) + sp->charcnt += dstlen + 1; + if ((size_t) sp->charcnt > sizeof(sp->chars)) + return -1; + cp = sp->chars; + (void) strncpy(cp, stdname, stdlen); + cp += stdlen; + *cp++ = '\0'; + if (dstlen != 0) { + (void) strncpy(cp, dstname, dstlen); + *(cp + dstlen) = '\0'; + } + return 0; +} + +void tzset() +{ + char *TZstring; + int dstfirst; + static char *old_TZstring = NULL; + + TZstring = getenv("TZ"); /* read TZ envvar */ + if (old_TZstring && TZstring && !strcmp(old_TZstring, TZstring)) + /* do not repeatedly parse an unchanged TZ specification */ + return; + if ((TZstring && TZstring[0] && Parse_TZ(TZstring, &statism) == 0) + || IZTZ_GETLOCALETZINFO(&statism, generate_transitions) + || Parse_TZ(gmt, &statism) == 0) { + daylight = statism.typecnt > 1; + dstfirst = daylight && statism.ttis[0].tt_isdst && !statism.ttis[1].tt_isdst; + timezone = -statism.ttis[dstfirst].tt_gmtoff; + tzname[0] = statism.chars + statism.ttis[dstfirst].tt_abbrind; + tzname[1] = statism.chars + statism.ttis[!dstfirst].tt_abbrind; + real_timezone_is_set = TRUE; + if (TZstring) { + if (old_TZstring) + old_TZstring = realloc(old_TZstring, strlen(TZstring) + 1); + else + old_TZstring = malloc(strlen(TZstring) + 1); + if (old_TZstring) + strcpy(old_TZstring, TZstring); + } + } else { + timezone = 0; /* default is GMT0 which means no offsets */ + daylight = 0; /* from local system time */ + real_timezone_is_set = FALSE; + if (old_TZstring) { + free(old_TZstring); + old_TZstring = NULL; + } + } +#ifdef IZTZ_SETLOCALTZINFO + /* Some SAS/C library functions, e.g. stat(), call library */ + /* __tzset() themselves. So envvar TZ *must* exist in order to */ + /* to get the right offset from GMT. XXX TRY HARD to fix this! */ + set_TZ(timezone, daylight); +#endif /* IZTZ_SETLOCALTZINFO */ +} + +/* XXX Does this also help SAS/C library work? */ +void __tzset() +{ + if (!real_timezone_is_set) tzset(); +} + +static struct tm _tmbuf; + +struct tm *gmtime(when) + ZCONST time_t *when; +{ + long days = *when / SECSPERDAY; + long secs = *when % SECSPERDAY; + int isleap; + + memset(&_tmbuf, 0, sizeof(_tmbuf)); /* get any nonstandard fields */ + _tmbuf.tm_wday = (days + EPOCH_WDAY) % 7; + _tmbuf.tm_year = EPOCH_YEAR - TM_YEAR_BASE; + isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE); + while (days >= year_lengths[isleap]) { + days -= year_lengths[isleap]; + _tmbuf.tm_year++; + isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE); + } + _tmbuf.tm_mon = 0; + _tmbuf.tm_yday = days; + while (days >= mon_lengths[isleap][_tmbuf.tm_mon]) + days -= mon_lengths[isleap][_tmbuf.tm_mon++]; + _tmbuf.tm_mday = days + 1; + _tmbuf.tm_isdst = 0; + _tmbuf.tm_sec = secs % SECSPERMIN; + _tmbuf.tm_min = (secs / SECSPERMIN) % SECSPERMIN; + _tmbuf.tm_hour = secs / SECSPERHOUR; + return &_tmbuf; +} + +struct tm *localtime(when) + ZCONST time_t *when; +{ + time_t localwhen = *when; + int timetype; + struct tm *ret; + + __tzset(); + if (statism.timecnt == 0 || localwhen < statism.ats[0]) + timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 && + !statism.ttis[1].tt_isdst; + else { + for (timetype = 1; timetype < statism.timecnt; ++timetype) + if (localwhen < statism.ats[timetype]) + break; + timetype = statism.types[timetype - 1]; + } + localwhen += statism.ttis[timetype].tt_gmtoff; + ret = gmtime(&localwhen); + ret->tm_isdst = statism.ttis[timetype].tt_isdst; + return ret; +} + +#ifdef NEED__ISINDST +int _isindst(tb) + struct tm *tb; +{ + time_t localt; /* time_t equivalent of given tm struct */ + time_t univt; /* assumed UTC value of given time */ + long tzoffset_adj; /* timezone-adjustment `remainder' */ + int bailout_cnt; /* counter of tries for tz correction */ + int timetype; + + __tzset(); + + /* when DST is unsupported in current timezone, DST is always off */ + if (statism.typecnt <= 1) return FALSE; + + localt = mkgmtime(tb); + if (localt == (time_t)-1) + /* specified time is out-of-range, default to FALSE */ + return FALSE; + + univt = localt - statism.ttis[0].tt_gmtoff; + bailout_cnt = 3; + do { + if (statism.timecnt == 0 || univt < statism.ats[0]) + timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 && + !statism.ttis[1].tt_isdst; + else { + for (timetype = 1; timetype < statism.timecnt; ++timetype) + if (univt < statism.ats[timetype]) + break; + timetype = statism.types[timetype - 1]; + } + if ((tzoffset_adj = localt - univt - statism.ttis[timetype].tt_gmtoff) + == 0L) + break; + univt += tzoffset_adj; + } while (--bailout_cnt > 0); + + /* return TRUE when DST is active at given time */ + return (statism.ttis[timetype].tt_isdst); +} +#endif /* NEED__ISINDST */ +#endif /* !IZ_MKTIME_ONLY */ + +/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT + of the local time and date in the exploded time structure `tm', + adjust out of range fields in `tm' and set `tm->tm_yday', `tm->tm_wday'. + If `tm->tm_isdst < 0' was passed to mktime(), the correct setting of + tm_isdst is determined and returned. Otherwise, mktime() assumes this + field as valid; its information is used when converting local time + to UTC. + Return -1 if time in `tm' cannot be represented as time_t value. */ + +time_t mktime(tm) + struct tm *tm; +{ + struct tm *ltm; /* Local time. */ + time_t loctime; /* The time_t value of local time. */ + time_t then; /* The time to return. */ + long tzoffset_adj = 0; /* timezone-adjustment `remainder' */ + int bailout_cnt; /* counter of tries for tz correction */ + int save_isdst; /* Copy of the tm->isdst input value */ + + save_isdst = tm->tm_isdst; + loctime = mkgmtime(tm); + if (loctime == -1) { + tm->tm_isdst = save_isdst; + return (time_t)-1; + } + + /* Correct for the timezone and any daylight savings time. + The correction is verified and repeated when not correct, to + take into account the rare case that a change to or from daylight + savings time occurs between when it is the time in `tm' locally + and when it is that time in Greenwich. After the second correction, + the "timezone & daylight" offset should be correct in all cases. To + be sure, we allow a third try, but then the loop is stopped. */ + bailout_cnt = 3; + then = loctime; + do { + ltm = localtime(&then); + if (ltm == (struct tm *)NULL || + (tzoffset_adj = loctime - mkgmtime(ltm)) == 0L) + break; + then += tzoffset_adj; + } while (--bailout_cnt > 0); + + if (ltm == (struct tm *)NULL || tzoffset_adj != 0L) { + /* Signal failure if timezone adjustment did not converge. */ + tm->tm_isdst = save_isdst; + return (time_t)-1; + } + + if (save_isdst >= 0) { + if (ltm->tm_isdst && !save_isdst) + { + if (then + 3600 < then) + then = (time_t)-1; + else + then += 3600; + } + else if (!ltm->tm_isdst && save_isdst) + { + if (then - 3600 > then) + then = (time_t)-1; + else + then -= 3600; + } + ltm->tm_isdst = save_isdst; + } + + if (tm != ltm) /* `tm' may already point to localtime's internal storage */ + *tm = *ltm; + + return then; +} + + +#ifndef NO_TIME_T_MAX + /* Provide default values for the upper limit of the time_t range. + These are the result of the decomposition into a `struct tm' for + the time value 0xFFFFFFFEL ( = (time_t)-2 ). + Note: `(time_t)-1' is reserved for "invalid time"! */ +# ifndef TM_YEAR_MAX +# define TM_YEAR_MAX 2106 +# endif +# ifndef TM_MON_MAX +# define TM_MON_MAX 1 /* February */ +# endif +# ifndef TM_MDAY_MAX +# define TM_MDAY_MAX 7 +# endif +# ifndef TM_HOUR_MAX +# define TM_HOUR_MAX 6 +# endif +# ifndef TM_MIN_MAX +# define TM_MIN_MAX 28 +# endif +# ifndef TM_SEC_MAX +# define TM_SEC_MAX 14 +# endif +#endif /* NO_TIME_T_MAX */ + +/* Adjusts out-of-range values for `tm' field `tm_member'. */ +#define ADJUST_TM(tm_member, tm_carry, modulus) \ + if ((tm_member) < 0) { \ + tm_carry -= (1 - ((tm_member)+1) / (modulus)); \ + tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \ + } else if ((tm_member) >= (modulus)) { \ + tm_carry += (tm_member) / (modulus); \ + tm_member = (tm_member) % (modulus); \ + } + +/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT + of the Greenwich Mean time and date in the exploded time structure `tm'. + This function does always put back normalized values into the `tm' struct, + parameter, including the calculated numbers for `tm->tm_yday', + `tm->tm_wday', and `tm->tm_isdst'. + Returns -1 if the time in the `tm' parameter cannot be represented + as valid `time_t' number. */ + +time_t mkgmtime(tm) + struct tm *tm; +{ + int years, months, days, hours, minutes, seconds; + + years = tm->tm_year + TM_YEAR_BASE; /* year - 1900 -> year */ + months = tm->tm_mon; /* 0..11 */ + days = tm->tm_mday - 1; /* 1..31 -> 0..30 */ + hours = tm->tm_hour; /* 0..23 */ + minutes = tm->tm_min; /* 0..59 */ + seconds = tm->tm_sec; /* 0..61 in ANSI C. */ + + ADJUST_TM(seconds, minutes, 60) + ADJUST_TM(minutes, hours, 60) + ADJUST_TM(hours, days, 24) + ADJUST_TM(months, years, 12) + if (days < 0) + do { + if (--months < 0) { + --years; + months = 11; + } + days += monthlen(months, years); + } while (days < 0); + else + while (days >= monthlen(months, years)) { + days -= monthlen(months, years); + if (++months >= 12) { + ++years; + months = 0; + } + } + + /* Restore adjusted values in tm structure */ + tm->tm_year = years - TM_YEAR_BASE; + tm->tm_mon = months; + tm->tm_mday = days + 1; + tm->tm_hour = hours; + tm->tm_min = minutes; + tm->tm_sec = seconds; + + /* Set `days' to the number of days into the year. */ + days += YDAYS(months, years); + tm->tm_yday = days; + + /* Now calculate `days' to the number of days since Jan 1, 1970. */ + days = (unsigned)days + 365 * (unsigned)(years - EPOCH_YEAR) + + (unsigned)(nleap (years)); + tm->tm_wday = ((unsigned)days + EPOCH_WDAY) % 7; + tm->tm_isdst = 0; + + if (years < EPOCH_YEAR) + return (time_t)-1; + +#if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX)) +#if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX)) + if (years > TM_YEAR_MAX || + (years == TM_YEAR_MAX && + (tm->tm_yday > (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) || + (tm->tm_yday == (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) && + (hours > TM_HOUR_MAX || + (hours == TM_HOUR_MAX && + (minutes > TM_MIN_MAX || + (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) ))))))) + return (time_t)-1; +#endif +#endif + + return (time_t)(SECSPERDAY * (unsigned long)(unsigned)days + + SECSPERHOUR * (unsigned long)hours + + (unsigned long)(SECSPERMIN * minutes + seconds)); +} + +#endif /* __timezone_c */ diff --git a/third_party/unzip/timezone.h b/third_party/unzip/timezone.h new file mode 100644 index 000000000..9e822c481 --- /dev/null +++ b/third_party/unzip/timezone.h @@ -0,0 +1,84 @@ +// clang-format off +/* + Copyright (c) 1990-2001 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.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 +*/ +#ifndef __timezone_h +#define __timezone_h +#include "third_party/unzip/crc32.h" +#include "libc/calls/weirdtypes.h" + +#ifndef IZ_MKTIME_ONLY + +/* limits for our timezone info data: + * we support only basic standard and daylight time, with max 2 transitions + * per year, but for the maximum range of years a 32-bit second counter + * can cover (these are 136 years plus a bit more than one month) + */ +#define TZ_MAX_TIMES 272 /* (=2*(LastGoodYr + 1 - FirstGoodYr) */ +#define TZ_MAX_TYPES 2 /* We only support basic standard and daylight */ +#ifdef WIN32 /* Win32 tzinfo supplies at max (2 * 32) chars of tz names */ +#define TZ_MAX_CHARS 64 /* Maximum number of abbreviation characters */ +#else +#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ +#endif + +/* supported types of transition rules */ +#define JULIAN_DAY 0 /* Jn - Julian day */ +#define DAY_OF_YEAR 1 /* n - day of year */ +#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ + + +struct ttinfo { + long tt_gmtoff; /* UTC offset in seconds */ + int tt_isdst; /* used to set tm_isdst */ + int tt_abbrind; /* abbreviation list index */ +}; + +struct state { + int timecnt; + int typecnt; + int charcnt; + time_t ats[TZ_MAX_TIMES]; + unsigned char types[TZ_MAX_TIMES]; + struct ttinfo ttis[TZ_MAX_TYPES]; + char chars[TZ_MAX_CHARS]; +}; + +struct rule { + int r_type; /* type of rule--JULIAN_DAY etc */ + int r_day; /* day number of rule */ + int r_week; /* week number of rule */ + int r_mon; /* month number of rule */ + long r_time; /* transition time of rule */ +}; + +extern int real_timezone_is_set; /* set by tzset() */ + + +/* prototypes of functions not in time.h */ + +void __tzset OF((void)); + +#ifdef NEED__ISINDST +int _isindst OF((struct tm *tb)); +#endif + +/* callback function to be supplied by the program that uses this library */ +int GetPlatformLocalTimezone OF((register struct state * ZCONST sp, + void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res, + ZCONST struct rule * ZCONST start, + ZCONST struct rule * ZCONST end))); +#ifdef IZTZ_SETLOCALTZINFO +void set_TZ OF((long time_zone, int day_light)); +#endif + +#endif /* !IZ_MKTIME_ONLY */ + +time_t mkgmtime OF((struct tm *tm)); + +#endif diff --git a/third_party/unzip/ttyio.c b/third_party/unzip/ttyio.c new file mode 100644 index 000000000..d85bb99c9 --- /dev/null +++ b/third_party/unzip/ttyio.c @@ -0,0 +1,694 @@ +// clang-format off +/* + Copyright (c) 1990-2008 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.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 +*/ +/*--------------------------------------------------------------------------- + + ttyio.c + + This file contains routines for doing console input/output, including code + for non-echoing input. It is used by the encryption/decryption code but + does not contain any restricted code itself. This file is shared between + Info-ZIP's Zip and UnZip. + + Contains: echo() (VMS only) + Echon() (Unix only) + Echoff() (Unix only) + screensize() (Unix only) + zgetch() (Unix, VMS, and non-Unix/VMS versions) + getp() ("PC," Unix/Atari/Be, VMS/VMCMS/MVS) + + ---------------------------------------------------------------------------*/ + +#define __TTYIO_C /* identifies this source module */ + +#include "third_party/unzip/zip.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/termios.h" +#include "libc/calls/termios.h" +#include "third_party/unzip/crypt.h" + +#if (CRYPT || (defined(UNZIP) && !defined(FUNZIP))) +/* Non-echo console/keyboard input is needed for (en/de)cryption's password + * entry, and for UnZip(SFX)'s MORE and Pause features. + * (The corresponding #endif is found at the end of this module.) + */ + +#include "third_party/unzip/ttyio.h" + +#ifndef PUTC +# define PUTC putc +#endif + +#ifdef ZIP +# ifdef GLOBAL /* used in Amiga system headers, maybe others too */ +# undef GLOBAL +# endif +# define GLOBAL(g) g +#else +# define GLOBAL(g) G.g +#endif + +#if (defined(__ATHEOS__) || defined(__BEOS__)) /* why yes, we do */ +# define HAVE_TERMIOS_H +#endif + +#ifdef _POSIX_VERSION +# ifndef USE_POSIX_TERMIOS +# define USE_POSIX_TERMIOS /* use POSIX style termio (termios) */ +# endif +# ifndef HAVE_TERMIOS_H +# define HAVE_TERMIOS_H /* POSIX termios.h */ +# endif +#endif /* _POSIX_VERSION */ + +#ifdef UNZIP /* Zip handles this with the unix/configure script */ +# ifndef _POSIX_VERSION +# if (defined(SYSV) || defined(CRAY)) && !defined(__MINT__) +# ifndef USE_SYSV_TERMIO +# define USE_SYSV_TERMIO +# endif +# ifdef COHERENT +# ifndef HAVE_TERMIO_H +# define HAVE_TERMIO_H +# endif +# ifdef HAVE_SYS_TERMIO_H +# undef HAVE_SYS_TERMIO_H +# endif +# else /* !COHERENT */ +# ifdef HAVE_TERMIO_H +# undef HAVE_TERMIO_H +# endif +# ifndef HAVE_SYS_TERMIO_H +# define HAVE_SYS_TERMIO_H +# endif +# endif /* ?COHERENT */ +# endif /* (SYSV || CRAY) && !__MINT__ */ +# endif /* !_POSIX_VERSION */ +# if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__)) +# ifndef NO_FCNTL_H +# define NO_FCNTL_H +# endif +# endif /* !(BSD4_4 || SYSV || __convexc__) */ +#endif /* UNZIP */ + +#ifdef HAVE_TERMIOS_H +# ifndef USE_POSIX_TERMIOS +# define USE_POSIX_TERMIOS +# endif +#endif + +#if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H)) +# ifndef USE_SYSV_TERMIO +# define USE_SYSV_TERMIO +# endif +#endif + +#if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE)) +# define GOT_IOCTL_H + /* int ioctl OF((int, int, zvoid *)); GRR: may need for some systems */ +#endif + +#ifndef HAVE_WORKING_GETCH + /* include system support for switching of console echo */ +# ifdef VMS + /* Workaround for broken header files of older DECC distributions + * that are incompatible with the /NAMES=AS_IS qualifier. */ +# define sys$assign SYS$ASSIGN +# define sys$dassgn SYS$DASSGN +# define sys$qiow SYS$QIOW +# else /* !VMS */ +# ifdef HAVE_TERMIOS_H +# define sgttyb termios +# define sg_flags c_lflag +# define GTTY(f, s) tcgetattr(f, (zvoid *) s) +# define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s) +# else /* !HAVE_TERMIOS_H */ +# ifdef USE_SYSV_TERMIO /* Amdahl, Cray, all SysV? */ +# ifdef HAVE_TERMIO_H +# endif +# ifdef HAVE_SYS_TERMIO_H +# endif +# ifdef NEED_PTEM +# endif +# define sgttyb termio +# define sg_flags c_lflag +# define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s) +# define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s) +# else /* !USE_SYSV_TERMIO */ +# ifndef CMS_MVS +# if (!defined(MINIX) && !defined(GOT_IOCTL_H)) +# endif +# define GTTY gtty +# define STTY stty +# ifdef UNZIP + /* + * XXX : Are these declarations needed at all ???? + */ + /* + * GRR: let's find out... Hmmm, appears not... + int gtty OF((int, struct sgttyb *)); + int stty OF((int, struct sgttyb *)); + */ +# endif +# endif /* !CMS_MVS */ +# endif /* ?USE_SYSV_TERMIO */ +# endif /* ?HAVE_TERMIOS_H */ +# ifndef NO_FCNTL_H +# ifndef UNZIP +# endif +# else +# endif +# endif /* ?VMS */ +#endif /* !HAVE_WORKING_GETCH */ + + + +#ifndef HAVE_WORKING_GETCH +#ifdef VMS + +static struct dsc$descriptor_s DevDesc = + {11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"}; + /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */ + +/* + * Turn keyboard echoing on or off (VMS). Loosely based on VMSmunch.c + * and hence on Joe Meadows' file.c code. + */ +int echo(opt) + int opt; +{ + /* + * For VMS v5.x: + * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming, + * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6 + * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services, + * System Services Reference Manual, pp. sys-23, sys-379 + * fixed-length descriptor info: Programming, Vol. 3, System Services, + * Intro to System Routines, sec. 2.9.2 + * Greg Roelofs, 15 Aug 91 + */ + + short DevChan, iosb[4]; + long status; + unsigned long ttmode[2]; /* space for 8 bytes */ + + + /* assign a channel to standard input */ + status = sys$assign(&DevDesc, &DevChan, 0, 0); + if (!(status & 1)) + return status; + + /* use sys$qio and the IO$_SENSEMODE function to determine the current + * tty status (for password reading, could use IO$_READVBLK function + * instead, but echo on/off will be more general) + */ + status = sys$qiow(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0, + ttmode, 8, 0, 0, 0, 0); + if (!(status & 1)) + return status; + status = iosb[0]; + if (!(status & 1)) + return status; + + /* modify mode buffer to be either NOECHO or ECHO + * (depending on function argument opt) + */ + if (opt == 0) /* off */ + ttmode[1] |= TT$M_NOECHO; /* set NOECHO bit */ + else + ttmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */ + + /* use the IO$_SETMODE function to change the tty status */ + status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0, + ttmode, 8, 0, 0, 0, 0); + if (!(status & 1)) + return status; + status = iosb[0]; + if (!(status & 1)) + return status; + + /* deassign the sys$input channel by way of clean-up */ + status = sys$dassgn(DevChan); + if (!(status & 1)) + return status; + + return SS$_NORMAL; /* we be happy */ + +} /* end function echo() */ + + +/* + * Read a single character from keyboard in non-echoing mode (VMS). + * (returns EOF in case of errors) + */ +int tt_getch() +{ + short DevChan, iosb[4]; + long status; + char kbbuf[16]; /* input buffer with - some - excess length */ + + /* assign a channel to standard input */ + status = sys$assign(&DevDesc, &DevChan, 0, 0); + if (!(status & 1)) + return EOF; + + /* read a single character from SYS$COMMAND (no-echo) and + * wait for completion + */ + status = sys$qiow(0,DevChan, + IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR, + &iosb, 0, 0, + &kbbuf, 1, 0, 0, 0, 0); + if ((status&1) == 1) + status = iosb[0]; + + /* deassign the sys$input channel by way of clean-up + * (for this step, we do not need to check the completion status) + */ + sys$dassgn(DevChan); + + /* return the first char read, or EOF in case the read request failed */ + return (int)(((status&1) == 1) ? (uch)kbbuf[0] : EOF); + +} /* end function tt_getch() */ + + +#else /* !VMS: basically Unix */ + + +/* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */ +#ifndef CMS_MVS + +#ifdef ZIP /* moved to globals.h for UnZip */ + static int echofd=(-1); /* file descriptor whose echo is off */ +#endif + +/* + * Turn echo off for file descriptor f. Assumes that f is a tty device. + */ +void Echoff(__G__ f) + __GDEF + int f; /* file descriptor for which to turn echo off */ +{ + struct sgttyb sg; /* tty device structure */ + + GLOBAL(echofd) = f; + GTTY(f, &sg); /* get settings */ + sg.sg_flags &= ~ECHO; /* turn echo off */ + STTY(f, &sg); +} + +/* + * Turn echo back on for file descriptor echofd. + */ +void Echon(__G) + __GDEF +{ + struct sgttyb sg; /* tty device structure */ + + if (GLOBAL(echofd) != -1) { + GTTY(GLOBAL(echofd), &sg); /* get settings */ + sg.sg_flags |= ECHO; /* turn echo on */ + STTY(GLOBAL(echofd), &sg); + GLOBAL(echofd) = -1; + } +} + +#endif /* !CMS_MVS */ +#endif /* ?VMS */ + + +#if (defined(UNZIP) && !defined(FUNZIP)) + +#ifdef ATH_BEO_UNX +#ifdef MORE + +/* + * Get the number of lines on the output terminal. SCO Unix apparently + * defines TIOCGWINSZ but doesn't support it (!M_UNIX). + * + * GRR: will need to know width of terminal someday, too, to account for + * line-wrapping. + */ + +#if (defined(TIOCGWINSZ) && !defined(M_UNIX)) + +int screensize(tt_rows, tt_cols) + int *tt_rows; + int *tt_cols; +{ + struct winsize wsz; +#ifdef DEBUG_WINSZ + static int firsttime = TRUE; +#endif + + /* see termio(4) under, e.g., SunOS */ + if (ioctl(1, TIOCGWINSZ, &wsz) == 0) { +#ifdef DEBUG_WINSZ + if (firsttime) { + firsttime = FALSE; + fprintf(stderr, "ttyio.c screensize(): ws_row = %d\n", + wsz.ws_row); + fprintf(stderr, "ttyio.c screensize(): ws_col = %d\n", + wsz.ws_col); + } +#endif + /* number of rows */ + if (tt_rows != NULL) + *tt_rows = (int)((wsz.ws_row > 0) ? wsz.ws_row : 24); + /* number of columns */ + if (tt_cols != NULL) + *tt_cols = (int)((wsz.ws_col > 0) ? wsz.ws_col : 80); + return 0; /* signal success */ + } else { /* this happens when piping to more(1), for example */ +#ifdef DEBUG_WINSZ + if (firsttime) { + firsttime = FALSE; + fprintf(stderr, + "ttyio.c screensize(): ioctl(TIOCGWINSZ) failed\n")); + } +#endif + /* VT-100 assumed to be minimal hardware */ + if (tt_rows != NULL) + *tt_rows = 24; + if (tt_cols != NULL) + *tt_cols = 80; + return 1; /* signal failure */ + } +} + +#else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */ + +int screensize(tt_rows, tt_cols) + int *tt_rows; + int *tt_cols; +{ + char *envptr, *getenv(); + int n; + int errstat = 0; + + /* GRR: this is overly simplistic, but don't have access to stty/gtty + * system anymore + */ + if (tt_rows != NULL) { + envptr = getenv("LINES"); + if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) { + /* VT-100 assumed to be minimal hardware */ + *tt_rows = 24; + errstat = 1; /* signal failure */ + } else { + *tt_rows = n; + } + } + if (tt_cols != NULL) { + envptr = getenv("COLUMNS"); + if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) { + *tt_cols = 80; + errstat = 1; /* signal failure */ + } else { + *tt_cols = n; + } + } + return errstat; +} + +#endif /* ?(TIOCGWINSZ && !M_UNIX) */ +#endif /* MORE */ + + +/* + * Get a character from the given file descriptor without echo or newline. + */ +int zgetch(__G__ f) + __GDEF + int f; /* file descriptor from which to read */ +{ +#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)) + char oldmin, oldtim; +#endif + char c; + struct sgttyb sg; /* tty device structure */ + + GTTY(f, &sg); /* get settings */ +#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)) + oldmin = sg.c_cc[VMIN]; /* save old values */ + oldtim = sg.c_cc[VTIME]; + sg.c_cc[VMIN] = 1; /* need only one char to return read() */ + sg.c_cc[VTIME] = 0; /* no timeout */ + sg.sg_flags &= ~ICANON; /* canonical mode off */ +#else + sg.sg_flags |= CBREAK; /* cbreak mode on */ +#endif + sg.sg_flags &= ~ECHO; /* turn echo off, too */ + STTY(f, &sg); /* set cbreak mode */ + GLOBAL(echofd) = f; /* in case ^C hit (not perfect: still CBREAK) */ + + read(f, &c, 1); /* read our character */ + +#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)) + sg.c_cc[VMIN] = oldmin; /* restore old values */ + sg.c_cc[VTIME] = oldtim; + sg.sg_flags |= ICANON; /* canonical mode on */ +#else + sg.sg_flags &= ~CBREAK; /* cbreak mode off */ +#endif + sg.sg_flags |= ECHO; /* turn echo on */ + STTY(f, &sg); /* restore canonical mode */ + GLOBAL(echofd) = -1; + + return (int)(uch)c; +} + + +#else /* !ATH_BEO_UNX */ +#ifndef VMS /* VMS supplies its own variant of getch() */ + + +int zgetch(__G__ f) + __GDEF + int f; /* file descriptor from which to read (must be open already) */ +{ + char c, c2; + +/*--------------------------------------------------------------------------- + Get a character from the given file descriptor without echo; can't fake + CBREAK mode (i.e., newline required), but can get rid of all chars up to + and including newline. + ---------------------------------------------------------------------------*/ + + echoff(f); + read(f, &c, 1); + if (c != '\n') + do { + read(f, &c2, 1); /* throw away all other chars up thru newline */ + } while (c2 != '\n'); + echon(); + return (int)c; +} + +#endif /* !VMS */ +#endif /* ?ATH_BEO_UNX */ + +#endif /* UNZIP && !FUNZIP */ +#endif /* !HAVE_WORKING_GETCH */ + + +#if CRYPT /* getp() is only used with full encryption */ + +/* + * Simple compile-time check for source compatibility between + * zcrypt and ttyio: + */ +#if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7)) + error: This Info-ZIP tool requires zcrypt 2.7 or later. +#endif + +/* + * Get a password of length n-1 or less into *p using the prompt *m. + * The entered password is not echoed. + */ + +#ifdef HAVE_WORKING_GETCH +/* + * For the AMIGA, getch() is defined as Agetch(), which is in + * amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch() + * uses the infrastructure that is already in place in filedate.c, it is + * smaller. With this function, echoff() and echon() are not needed. + * + * For the MAC, a non-echo macgetch() function is defined in the MacOS + * specific sources which uses the event handling mechanism of the + * desktop window manager to get a character from the keyboard. + * + * For the other systems in this section, a non-echo getch() function + * is either contained the C runtime library (conio package), or getch() + * is defined as an alias for a similar system specific RTL function. + */ + +#ifndef WINDLL /* WINDLL does not support a console interface */ +#ifndef QDOS /* QDOS supplies a variant of this function */ + +/* This is the getp() function for all systems (with TTY type user interface) + * that supply a working `non-echo' getch() function for "raw" console input. + */ +char *getp(__G__ m, p, n) + __GDEF + ZCONST char *m; /* prompt for password */ + char *p; /* return value: line input */ + int n; /* bytes available in p[] */ +{ + char c; /* one-byte buffer for read() to use */ + int i; /* number of characters input */ + char *w; /* warning on retry */ + + /* get password */ + w = ""; + do { + fputs(w, stderr); /* warning if back again */ + fputs(m, stderr); /* display prompt and flush */ + fflush(stderr); + i = 0; + do { /* read line, keeping first n characters */ + if ((c = (char)getch()) == '\r') + c = '\n'; /* until user hits CR */ + if (c == 8 || c == 127) { + if (i > 0) i--; /* the `backspace' and `del' keys works */ + } + else if (i < n) + p[i++] = c; /* truncate past n */ + } while (c != '\n'); + PUTC('\n', stderr); fflush(stderr); + w = "(line too long--try again)\n"; + } while (p[i-1] != '\n'); + p[i-1] = 0; /* terminate at newline */ + + return p; /* return pointer to password */ + +} /* end function getp() */ + +#endif /* !QDOS */ +#endif /* !WINDLL */ + + +#else /* !HAVE_WORKING_GETCH */ + + +#if (defined(ATH_BEO_UNX) || defined(__MINT__)) + +#ifndef _PATH_TTY +# ifdef __MINT__ +# define _PATH_TTY ttyname(2) +# else +# define _PATH_TTY "/dev/tty" +# endif +#endif + +char *getp(__G__ m, p, n) + __GDEF + ZCONST char *m; /* prompt for password */ + char *p; /* return value: line input */ + int n; /* bytes available in p[] */ +{ + char c; /* one-byte buffer for read() to use */ + int i; /* number of characters input */ + char *w; /* warning on retry */ + int f; /* file descriptor for tty device */ + +#ifdef PASSWD_FROM_STDIN + /* Read from stdin. This is unsafe if the password is stored on disk. */ + f = 0; +#else + /* turn off echo on tty */ + + if ((f = open(_PATH_TTY, 0)) == -1) + return NULL; +#endif + /* get password */ + w = ""; + do { + fputs(w, stderr); /* warning if back again */ + fputs(m, stderr); /* prompt */ + fflush(stderr); + i = 0; + echoff(f); + do { /* read line, keeping n */ + read(f, &c, 1); + if (i < n) + p[i++] = c; + } while (c != '\n'); + echon(); + PUTC('\n', stderr); fflush(stderr); + w = "(line too long--try again)\n"; + } while (p[i-1] != '\n'); + p[i-1] = 0; /* terminate at newline */ + +#ifndef PASSWD_FROM_STDIN + close(f); +#endif + + return p; /* return pointer to password */ + +} /* end function getp() */ + +#endif /* ATH_BEO_UNX || __MINT__ */ + + + +#if (defined(VMS) || defined(CMS_MVS)) + +char *getp(__G__ m, p, n) + __GDEF + ZCONST char *m; /* prompt for password */ + char *p; /* return value: line input */ + int n; /* bytes available in p[] */ +{ + char c; /* one-byte buffer for read() to use */ + int i; /* number of characters input */ + char *w; /* warning on retry */ + FILE *f; /* file structure for SYS$COMMAND device */ + +#ifdef PASSWD_FROM_STDIN + f = stdin; +#else + if ((f = fopen(ctermid(NULL), "r")) == NULL) + return NULL; +#endif + + /* get password */ + fflush(stdout); + w = ""; + do { + if (*w) /* bug: VMS apparently adds \n to NULL fputs */ + fputs(w, stderr); /* warning if back again */ + fputs(m, stderr); /* prompt */ + fflush(stderr); + i = 0; + echoff(f); + do { /* read line, keeping n */ + if ((c = (char)getc(f)) == '\r') + c = '\n'; + if (i < n) + p[i++] = c; + } while (c != '\n'); + echon(); + PUTC('\n', stderr); fflush(stderr); + w = "(line too long--try again)\n"; + } while (p[i-1] != '\n'); + p[i-1] = 0; /* terminate at newline */ +#ifndef PASSWD_FROM_STDIN + fclose(f); +#endif + + return p; /* return pointer to password */ + +} /* end function getp() */ + +#endif /* VMS || CMS_MVS */ +#endif /* ?HAVE_WORKING_GETCH */ +#endif /* CRYPT */ +#endif /* CRYPT || (UNZIP && !FUNZIP) */ diff --git a/third_party/unzip/ttyio.h b/third_party/unzip/ttyio.h new file mode 100644 index 000000000..fd0076dfe --- /dev/null +++ b/third_party/unzip/ttyio.h @@ -0,0 +1,225 @@ +// clang-format off +/* + Copyright (c) 1990-2004 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.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 +*/ +/* + ttyio.h + */ + +#ifndef __ttyio_h /* don't include more than once */ +#define __ttyio_h + +#ifndef __crypt_h +#include "third_party/unzip/crypt.h" /* ensure that encryption header file has been seen */ +#endif + +#if (CRYPT || (defined(UNZIP) && !defined(FUNZIP))) +/* + * Non-echo keyboard/console input support is needed and enabled. + */ + +#ifndef __G /* UnZip only, for now (DLL stuff) */ +# define __G +# define __G__ +# define __GDEF +# define __GPRO void +# define __GPRO__ +#endif + +#ifndef ZCONST /* UnZip only (until have configure script like Zip) */ +# define ZCONST const +#endif + +#if (defined(MSDOS) || defined(OS2) || defined(WIN32)) +# ifndef DOS_OS2_W32 +# define DOS_OS2_W32 +# endif +#endif + +#if (defined(DOS_OS2_W32) || defined(__human68k__)) +# ifndef DOS_H68_OS2_W32 +# define DOS_H68_OS2_W32 +# endif +#endif + +#if (defined(DOS_OS2_W32) || defined(FLEXOS)) +# ifndef DOS_FLX_OS2_W32 +# define DOS_FLX_OS2_W32 +# endif +#endif + +#if (defined(DOS_H68_OS2_W32) || defined(FLEXOS)) +# ifndef DOS_FLX_H68_OS2_W32 +# define DOS_FLX_H68_OS2_W32 +# endif +#endif + +#if (defined(__ATHEOS__) || defined(__BEOS__) || defined(UNIX)) +# ifndef ATH_BEO_UNX +# define ATH_BEO_UNX +# endif +#endif + +#if (defined(VM_CMS) || defined(MVS)) +# ifndef CMS_MVS +# define CMS_MVS +# endif +#endif + + +/* Function prototypes */ + +/* The following systems supply a `non-echo' character input function "getch()" + * (or an alias) and do not need the echoff() / echon() function pair. + */ +#ifdef AMIGA +# define echoff(f) +# define echon() +# define getch() Agetch() +# define HAVE_WORKING_GETCH +#endif /* AMIGA */ + +#ifdef ATARI +# define echoff(f) +# define echon() +# define getch() (Cnecin() & 0x000000ff) +# define HAVE_WORKING_GETCH +#endif + +#ifdef MACOS +# define echoff(f) +# define echon() +# define getch() macgetch() +# define HAVE_WORKING_GETCH +#endif + +#ifdef NLM +# define echoff(f) +# define echon() +# define HAVE_WORKING_GETCH +#endif + +#ifdef QDOS +# define echoff(f) +# define echon() +# define HAVE_WORKING_GETCH +#endif + +#ifdef RISCOS +# define echoff(f) +# define echon() +# define getch() SWI_OS_ReadC() +# define HAVE_WORKING_GETCH +#endif + +#ifdef DOS_H68_OS2_W32 +# define echoff(f) +# define echon() +# ifdef WIN32 +# ifndef getch +# define getch() getch_win32() +# endif +# else /* !WIN32 */ +# ifdef __EMX__ +# ifndef getch +# define getch() _read_kbd(0, 1, 0) +# endif +# else /* !__EMX__ */ +# ifdef __GO32__ +# define getch() getkey() +# else /* !__GO32__ */ +# endif /* ?__GO32__ */ +# endif /* ?__EMX__ */ +# endif /* ?WIN32 */ +# define HAVE_WORKING_GETCH +#endif /* DOS_H68_OS2_W32 */ + +#ifdef FLEXOS +# define echoff(f) +# define echon() +# define getch() getchar() /* not correct, but may not be on a console */ +# define HAVE_WORKING_GETCH +#endif + +/* For VM/CMS and MVS, we do not (yet) have any support to switch terminal + * input echo on and off. The following "fake" definitions allow inclusion + * of crypt support and UnZip's "pause prompting" features, but without + * any echo suppression. + */ +#ifdef CMS_MVS +# define echoff(f) +# define echon() +#endif + +#ifdef TANDEM +# define echoff(f) +# define echon() +# define getch() zgetch() /* defined in TANDEMC */ +# define HAVE_WORKING_GETCH +#endif + +/* The THEOS C runtime library supplies the function conmask() to toggle + * terminal input echo on (conmask("e")) and off (conmask("n")). But, + * since THEOS C RTL also contains a working non-echo getch() function, + * the echo toggles are not needed. + */ +#ifdef THEOS +# define echoff(f) +# define echon() +# define HAVE_WORKING_GETCH +#endif + +/* VMS has a single echo() function in ttyio.c to toggle terminal + * input echo on and off. + */ +#ifdef VMS +# define echoff(f) echo(0) +# define echon() echo(1) +# define getch() tt_getch() +# define FGETCH(f) tt_getch() + int echo OF((int)); + int tt_getch OF((void)); +#endif + +/* For all other systems, ttyio.c supplies the two functions Echoff() and + * Echon() for suppressing and (re)enabling console input echo. + */ +#ifndef echoff +# define echoff(f) Echoff(__G__ f) +# define echon() Echon(__G) + void Echoff OF((__GPRO__ int f)); + void Echon OF((__GPRO)); +#endif + +/* this stuff is used by MORE and also now by the ctrl-S code; fileio.c only */ +#if (defined(UNZIP) && !defined(FUNZIP)) +# ifdef HAVE_WORKING_GETCH +# define FGETCH(f) getch() +# endif +# ifndef FGETCH + /* default for all systems where no getch()-like function is available */ + int zgetch OF((__GPRO__ int f)); +# define FGETCH(f) zgetch(__G__ f) +# endif +#endif /* UNZIP && !FUNZIP */ + +#if (CRYPT && !defined(WINDLL)) + char *getp OF((__GPRO__ ZCONST char *m, char *p, int n)); +#endif + +#else /* !(CRYPT || (UNZIP && !FUNZIP)) */ + +/* + * No need for non-echo keyboard/console input; provide dummy definitions. + */ +#define echoff(f) +#define echon() + +#endif /* ?(CRYPT || (UNZIP && !FUNZIP)) */ + +#endif /* !__ttyio_h */ diff --git a/third_party/unzip/ubz2err.c b/third_party/unzip/ubz2err.c new file mode 100644 index 000000000..23f4bb9ad --- /dev/null +++ b/third_party/unzip/ubz2err.c @@ -0,0 +1,57 @@ +// clang-format off +/* + Copyright (c) 1990-2008 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2007-Mar-04 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 +*/ +/*--------------------------------------------------------------------------- + + ubz2err.c + + This file contains the "fatal error" callback routine required by the + "minimal" (silent, non-stdio) setup of the bzip2 compression library. + + The fatal bzip2 error bail-out routine is provided in a separate code + module, so that it can be easily overridden when the UnZip package is + used as a static link library. One example is the WinDLL static library + usage for building a monolythic binary of the Windows application "WiZ" + that supports bzip2 both in compression and decompression operations. + + Contains: bz_internal_error() (USE_BZIP2 only) + + ---------------------------------------------------------------------------*/ + + +#define __UBZ2ERR_C /* identifies this source module */ +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" + +#ifdef USE_BZIP2 + +/**********************************/ +/* Function bz_internal_error() */ +/**********************************/ + +/* Call-back function for the bzip2 decompression code (compiled with + * BZ_NO_STDIO), required to handle fatal internal bug-type errors of + * the bzip2 library. + */ +void bz_internal_error(bzerrcode) + int bzerrcode; +{ + GETGLOBALS(); + + Info(slide, 0x421, ((char *)slide, + "error: internal fatal libbzip2 error number %d\n", bzerrcode)); +#ifdef WINDLL + longjmp(dll_error_return, 1); +#else + DESTROYGLOBALS(); + EXIT(PK_BADERR); +#endif +} /* end function bz_internal_error() */ + +#endif /* USE_BZIP2 */ diff --git a/third_party/unzip/unix.c b/third_party/unzip/unix.c new file mode 100644 index 000000000..b5927c378 --- /dev/null +++ b/third_party/unzip/unix.c @@ -0,0 +1,2125 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 "libc/calls/struct/dirent.h" +#include "libc/log/log.h" +#include "libc/time/time.h" +#include "third_party/unzip/unzip.h" + +#ifdef USE_ICONV_MAPPING +#endif /* USE_ICONV_MAPPING */ + +#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 +#else +# ifdef SYSV +# ifdef SYSNDIR +# else +# endif +# else /* !SYSV */ +# ifndef NO_SYSDIR +# endif +# endif /* ?SYSV */ +# ifndef dirent +# define dirent direct +# endif +#endif /* ?DIRENT */ + +#if defined( UNIX) && defined( __APPLE__) +#endif /* defined( UNIX) && defined( __APPLE__) */ + +#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 + if (uO.X_flag >= 0) + { + /* 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 > 0) || 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; + if (*pp != '\0') { /* At least one digit is required. */ + 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 > 0) && (eb_izux_flg & EB_UX2_VALID)); +#else + 0; +#endif + return have_uidgid_flg; +} +#endif /* !MTS || SET_DIR_ATTRIB */ + + + +#ifndef MTS + +/****************************/ +/* Function close_outfile() */ +/****************************/ + +void close_outfile(__G) /* GRR: change to return PK-style warning level */ + __GDEF +{ + union { + iztimes t3; /* mtime, atime, ctime */ + ztimbuf t2; /* modtime, actime */ + } zt; + ulg z_uidgid[2]; + int have_uidgid_flg; + + 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))); + fclose(G.outfile); + return; + } + + 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; + } + 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); + fclose(G.outfile); + return; + } + fclose(G.outfile); /* 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; + } +#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)) + fclose(G.outfile); +#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)) + fclose(G.outfile); +#endif + +#if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD)) +/*--------------------------------------------------------------------------- + Change the file permissions from default ones to those stored in the + zipfile. + ---------------------------------------------------------------------------*/ + +# if defined( UNIX) && defined( __APPLE__) + /* 2009-04-19 SMS. + * Skip fchmod() for an AppleDouble file. (Doing the normal file + * is enough, and fchmod() will fail on a "/rsrc" pseudo-file.) + */ + if (!G.apple_double) + { +# endif /* defined( UNIX) && defined( __APPLE__) */ + + if (uO.X_flag >= 0) + { + if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr))) + perror("fchmod (file attributes) error"); + } + +# if defined( UNIX) && defined( __APPLE__) + } +# endif /* defined( UNIX) && defined( __APPLE__) */ + + fclose(G.outfile); +#endif /* !NO_FCHOWN && !NO_FCHMOD */ + +# if defined( UNIX) && defined( __APPLE__) + /* 2009-04-19 SMS. + * Skip utime() for an AppleDouble file. (Doing the normal file + * is enough, and utime() will fail on a "/rsrc" pseudo-file.) + */ + if (!G.apple_double) + { +# endif /* defined( UNIX) && defined( __APPLE__) */ + + /* 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, (void *)&(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( UNIX) && defined( __APPLE__) + } +# endif /* defined( UNIX) && defined( __APPLE__) */ + +#if (defined(NO_FCHOWN) || defined(NO_FCHMOD)) +/*--------------------------------------------------------------------------- + Change the file permissions from default ones to those stored in the + zipfile. + ---------------------------------------------------------------------------*/ + +#ifndef NO_CHMOD + if (uO.X_flag >= 0) + { + if (chmod(G.filename, filtattr(__G__ G.pInfo->file_attr))) + perror("chmod (file attributes) error"); + } +#endif /* ndef NO_CHMOD */ +#endif /* NO_FCHOWN || NO_FCHMOD */ + +} /* end function close_outfile() */ + +#endif /* !MTS */ + + +#if (defined(SYMLINKS) && defined(SET_SYMLINK_ATTRIBS)) +int set_symlnk_attribs(__G__ slnk_entry) + __GDEF + slinkentry *slnk_entry; +{ + ulg z_uidgid[2]; + + 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)) + if (uO.X_flag >= 0) + { + 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, (void *)&UxAtt(d)->u.t2)) { + Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps, + FnFilter1(d->fn), strerror(errno))); + if (!errval) + errval = PK_WARN; + } + } +#ifndef NO_CHMOD + if (uO.X_flag >= 0) + { + 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, (void *)&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 +# if defined(UNAME_P) && defined(UNAME_R) && defined(UNAME_S) + " ("UNAME_S" "UNAME_R" "UNAME_P")", +# else +# 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 +# endif +#else /* def sun */ +#ifdef __hpux +# if defined(UNAME_M) && defined(UNAME_R) && defined(UNAME_S) + " ("UNAME_S" "UNAME_R" "UNAME_M")", +# else + " (HP-UX)", +# endif +#else +#ifdef __osf__ +# if defined( SIZER_V) + " (Tru64 "SIZER_V")" +# else /* defined( SIZER_V) */ + " (Tru64)", +# endif /* defined( SIZER_V) [else] */ +#else +#ifdef _AIX +# if defined( UNAME_R) && defined( UNAME_S) && defined( UNAME_V) + " ("UNAME_S" "UNAME_V"."UNAME_R")", +# else /* */ + " (IBM AIX)", +# endif /* [else] */ +#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 +# if defined( UNAME_M) && defined( UNAME_O) + " ("UNAME_O" "UNAME_M")", +# else +# ifdef __ELF__ + " (Linux ELF)", +# else + " (Linux a.out)", +# endif +# 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__ +# if defined(UNAME_P) && defined(UNAME_R) && defined(UNAME_S) + " ("UNAME_S" "UNAME_R" "UNAME_P")", +# else +# 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__ */ +# endif +#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 */ + + +#ifdef USE_ICONV_MAPPING +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, + sizeof(OEM_CP)); + break; + } + } +} + +/* Convert a string from one encoding to the current locale using iconv(). + * Be as non-intrusive as possible. If error is encountered during + * convertion 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; + dlen = buflen = 2 * slen; + d = buf = malloc(buflen + 1); + if (d) { + bzero(buf, buflen); + if(iconv(cd, &s, &slen, &d, &dlen) != (size_t)-1) + strncpy(string, buf, buflen); + 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); +} +#endif /* USE_ICONV_MAPPING */ + + +#if defined( UNIX) && defined( __APPLE__) + +/* Determine if the volume where "path" resides supports getattrlist() + * and setattrlist(), that is, if we can do the special AppleDouble + * file processing using setattrlist(). Otherwise, we should pretend + * that "-J" is in effect, to bypass the special AppleDouble processing, + * and leave the separate file elements separate. + * + * Return value Meaning + * -1 Error. See errno. + * 0 Volume does not support getattrlist() and setattrlist(). + * 1 Volume does support getattrlist() and setattrlist(). + */ +int vol_attr_ok( const char *path) +{ + + int sts; + struct statfs statfs_buf; + struct attrlist attr_list_volattr; + struct attr_bufr_volattr { + unsigned int ret_length; + vol_capabilities_attr_t vol_caps; + } attr_bufr_volattr; + + /* Get file system info (in particular, the mounted volume name) for + * the specified path. + */ + sts = statfs( path, &statfs_buf); + + /* If that worked, get the interesting volume capability attributes. */ + if (sts == 0) + { + /* Clear attribute list structure. */ + memset( &attr_list_volattr, 0, sizeof( attr_list_volattr)); + /* Set attribute list bits for volume capabilities. */ + attr_list_volattr.bitmapcount = ATTR_BIT_MAP_COUNT; + attr_list_volattr.volattr = ATTR_VOL_INFO| ATTR_VOL_CAPABILITIES; + + sts = getattrlist( statfs_buf.f_mntonname, /* Path. */ + &attr_list_volattr, /* Attrib list. */ + &attr_bufr_volattr, /* Dest buffer. */ + sizeof( attr_bufr_volattr), /* Dest buffer size. */ + 0); + + if (sts == 0) + { + /* Set a valid return value. */ + sts = ((attr_bufr_volattr.vol_caps.capabilities[ + VOL_CAPABILITIES_INTERFACES]& + VOL_CAP_INT_ATTRLIST) != 0); + } + } + return sts; +} +#endif /* defined( UNIX) && defined( __APPLE__) */ + + +/* 2006-03-23 SMS. + * Emergency replacement for strerror(). (Useful on SunOS 4.*.) + * Enable by specifying "LOCAL_UNZIP=-DNEED_STRERROR=1" on the "make" + * command line. + */ + +#ifdef NEED_STRERROR + +char *strerror( err) + int err; +{ + extern char *sys_errlist[]; + extern int sys_nerr; + + static char no_msg[ 64]; + + if ((err >= 0) && (err < sys_nerr)) + { + return sys_errlist[ err]; + } + else + { + sprintf( no_msg, "(no message, code = %d.)", err); + return no_msg; + } +} + +#endif /* def NEED_STRERROR */ diff --git a/third_party/unzip/unix/Contents b/third_party/unzip/unix/Contents new file mode 100644 index 000000000..968accb9c --- /dev/null +++ b/third_party/unzip/unix/Contents @@ -0,0 +1,14 @@ +Contents of the "unix" subdirectory for UnZip 6.0 and later: + + Contents this file + Makefile makefile for UnZip for various architectures and OS's + configure automatic build configuration script + unix.c Unix-specific support routines + unxcfg.h Unix-specific configuration settings + zipgrep script to scan zip archive entries for lines matching a pattern + Packaging/ subdirectory containing SysV.4 (e.g., Solaris 2.x) package info + +Type "make" or "make help" to get general compile instructions (beyond +those in the INSTALL file), or "make list" for a list of makefile targets. +Note that there are some MS-DOS and cross-compilation targets thrown in +just to make things more exciting. diff --git a/third_party/unzip/unix/Makefile b/third_party/unzip/unix/Makefile new file mode 100644 index 000000000..9f5d99676 --- /dev/null +++ b/third_party/unzip/unix/Makefile @@ -0,0 +1,1038 @@ +#============================================================================== +# Makefile for UnZip, UnZipSFX and fUnZip: Unix and MS-DOS ("real" makes only) +# Version: 6.1 25 Jul 2010 +#============================================================================== + + +# INSTRUCTIONS (such as they are): +# +# "make generic" Makes UnZip on most systems using "cc". +# "make generic_gcc" Makes UnZip on most systems using "gcc". +# "make list" Lists all supported targets. +# "make help" Advice on which targets to try if problems occur. +# +# CF are flags for the C compiler. LF are flags for the loader. LF2 are more +# flags for the loader, if they need to be at the end of the line instead of at +# the beginning (for example, some libraries). FL and FL2 are corresponding +# flags for fUnZip. LOCAL_UNZIP is a "make" macro that can be used to add +# default C flags to your compile without editing the Makefile (e.g., +# -DDEBUG_STRUC, or -FPi87 on PCs using Microsoft C). +# +# The "generic" and "generic_gcc" targets use the "unix/configure" script to +# probe the compiler and other parts of the environment to adjust the build +# procedure, and to enable or disable some program features. Other (older) +# targets are less well tested, and may need considerable help from the user +# to get optimal results (or any success at all). +# +# The "generic" and "generic_gcc" targets should find bzip2 source code in the +# local ./bzip2 subdirectory, or the user can set the "make" macro IZ_BZIP2 to +# a directory containing suitable bzip2 header and object/shared library files. +# Similarly, to use zlib compress-expand code instead of UnZip's built-in code, +# set the "make" macro IZ_ZLIB to a directory containing suitable zlib header +# and object/shared library files. For example: +# make -f unix/Makefile IZ_BZIP2=../../bzip2/bzip2-1.0.5 \ +# IZ_ZLIB=../../zlib/zlib-1.2.5 generic +# +# Some versions of make do not define the macro "MAKE"; this is rare, but if +# things don't work, try using "make" instead of "$(MAKE)" in your system's +# makerule. Or try adding the following line to your .login file: +# setenv MAKE "make" +# (That never works--makes that are too stupid to define MAKE are also too +# stupid to look in the environment--but try it anyway for kicks. :-) ) +# +# Memcpy and memset are provided for those systems that don't have them; they +# are in fileio.c and will be used if -DZMEM is included in CF. These days +# almost all systems have them. +# +# Be sure to test your new UnZip (and UnZipSFX and fUnZip); successful +# compilation does not always imply a working program. + + +##################### +# MACRO DEFINITIONS # +##################### + +# Defaults most systems use (use "make" macro LOCAL_UNZIP to add compiler +# flags, such as -DDOSWILD). + +# UnZip flags +CC = cc# try using "gcc" target rather than changing this (CC and LD +LD = $(CC)# must match, else "unresolved symbol: ___main" is possible) +AS = as +LOC = $(D_USE_BZ2) $(D_USE_ZLIB) $(LOCAL_UNZIP) +AF = $(LOC) +CFLAGS = -O +CF_NOOPT = -I. -DUNIX $(LOC) +CF = $(CFLAGS) $(CF_NOOPT) +LFLAGS1 = +LF = -o unzip$E $(LFLAGS1) +LF2 = -s + +# UnZipSFX flags +SL = -o unzipsfx$E $(LFLAGS1) +SL2 = $(LF2) + +# fUnZip flags +FL = -o funzip$E $(LFLAGS1) +FL2 = $(LF2) + +# general-purpose stuff +#CP = cp +CP = ln +LN = ln +RM = rm -f +CHMOD = chmod +BINPERMS = 755 +MANPERMS = 644 +STRIP = strip +E = +O = .o +M = unix +SHELL = /bin/sh +MAKEF = -f unix/Makefile + +# Version info for unix/unix.c +HOST_VERSINFO=-DIZ_CC_NAME='\"\$$(CC) \"' -DIZ_OS_NAME='\"`uname -a`\"' + +# defaults for crc32 stuff and system dependent headers +CRCA_O = +OSDEP_H = unix/unxcfg.h +# default for dependency on auto-configure result, is an empty symbol +# so that the static non-autoconfigure targets continue to work +ACONF_DEP = + +# optional inclusion of bzip2 decompression +IZ_OUR_BZIP2_DIR = bzip2 +IZ_BZIP2 = $(IZ_OUR_BZIP2_DIR) +## The following symbols definitions need to be set to activate bzip2 support: +#D_USE_BZ2 = -DUSE_BZIP2 +#L_BZ2 = -lbz2 +#LIBBZ2 = $(IZ_BZIP2)/libbz2.a + +# defaults for unzip's "built-in" bzip2 library compilation +CC_BZ = $(CC) +CFLAGS_BZ = $(CFLAGS) + +# object files +OBJS1 = unzip$O crc32$O $(CRCA_O) crypt$O envargs$O explode$O +OBJS2 = extract$O fileio$O globals$O inflate$O list$O match$O +OBJS3 = process$O ttyio$O ubz2err$O unreduce$O unshrink$O zipinfo$O +OBJS = $(OBJS1) $(OBJS2) $(OBJS3) $M$O +LOBJS = $(OBJS) +OBJSDLL = $(OBJS:.o=.pic.o) api.pic.o +OBJX = unzipsfx$O crc32_$O $(CRCA_O) crypt_$O extract_$O fileio_$O \ + globals_$O inflate_$O match_$O process_$O ttyio_$O ubz2err_$O $M_$O +LOBJX = $(OBJX) +OBJF = funzip$O crc32$O $(CRCA_O) cryptf$O globalsf$O inflatef$O ttyiof$O +#OBJS_OS2 = $(OBJS1:.o=.obj) $(OBJS2:.o=.obj) os2.obj +#OBJF_OS2 = $(OBJF:.o=.obj) +UNZIP_H = unzip.h unzpriv.h globals.h $(OSDEP_H) $(ACONF_DEP) + +# installation +# (probably can change next two to `install' and `install -d' if you have it) +INSTALL = cp +INSTALL_PROGRAM = $(INSTALL) +INSTALL_D = mkdir -p +# on some systems, manext=l and MANDIR=/usr/man/man$(manext) may be appropriate +manext = 1 +prefix = /usr/local +BINDIR = $(prefix)/bin# where to install executables +MANDIR = $(prefix)/man/man$(manext)# where to install man pages +INSTALLEDBIN = $(BINDIR)/funzip$E $(BINDIR)/unzip$E $(BINDIR)/unzipsfx$E \ + $(BINDIR)/zipgrep$E $(BINDIR)/zipinfo$E +INSTALLEDMAN = $(MANDIR)/funzip.$(manext) $(MANDIR)/unzip.$(manext) \ + $(MANDIR)/unzipsfx.$(manext) $(MANDIR)/zipgrep.$(manext) \ + $(MANDIR)/zipinfo.$(manext) + +# Solaris 2.x package stuff: +PKGDIR = IZunzip +VERSION = Version 6.1 + +UNZIPS = unzip$E funzip$E unzipsfx$E +# this is a little ugly...well, OK, it's a lot ugly: +MANS = man/funzip.1 man/unzip.1 man/unzipsfx.1 man/zipgrep.1 man/zipinfo.1 +DOCS = funzip.txt unzip.txt unzipsfx.txt zipgrep.txt zipinfo.txt + +# list of supported systems/targets in this version +SYSTEMG1 = generic generic_gcc generic_pkg generic_gccpkg +SYSTEMG2 = generic1 generic2 generic3 generic_bz2 generic_zlib generic_shlib +SYSTEMS1 = 386i 3Bx 7300 7300_gcc aix aix_rt amdahl amdahl_eft apollo aviion +SYSTEMS2 = bsd bsdi bsdi_noasm bull coherent convex cray cray_opt cyber_sgi +SYSTEMS3 = cygwin dec dnix encore eta freebsd gcc gould hk68 hp hpux +SYSTEMS4 = isc isc_gcc isi linux linux_dos linux_noasm linux_shlib linux_shlibz +SYSTEMS5 = lynx macosx macosx_gcc minix mips mpeix next next10 next2x next3x +SYSTEMS6 = nextfat osf1 pixel ptx pyramid qnxnto realix regulus rs6000 sco +SYSTEMS7 = sco_dos sco_sl sco_x286 sequent sgi solaris solaris_pkg stardent +SYSTEMS8 = stellar sunos3 sunos4 sysv sysv_gcc sysv6300 tahoe ti_sysv ultrix +SYSTEMS9 = vax v7 xenix xos + + +#################### +# DEFAULT HANDLING # +#################### + +# By default, print help on which makefile targets to try. (The SYSTEM +# variable is no longer supported; use "make " instead.) + +help: + @echo "" + @echo " For most users, the best build method is to use the \"make\" target \"generic\"" + @echo " or \"generic_gcc\". (To use "cc", type \"make generic\" or, to use gcc," + @echo " \"make generic_gcc\".) These use the \"unix/configure\" script to probe the" + @echo " compiler and other parts of the environment to adjust the build procedure," + @echo " and to enable or disable some program features. Problems with these targets" + @echo " should be reported to the developers. Other (older) targets are less well" + @echo " tested, and may need considerable help from the user to get optimal results" + @echo " (or any success at all)." + @echo "" + @echo " If \"generic[_gcc]\" fails, then you might try the original generic which is" + @echo " now \"generic1\". Always do \"make clean\" before trying a different target." + @echo "" + @echo " If the compiler complains about \"timezone redefined\", then the \"generic2\"" + @echo " target may work better. If the linker complains about an undefined symbol," + @echo " \"_ftime\", then the \"generic3\" target may work better." + @echo "" + @echo " One of these actions should produce working UnZip programs on most" + @echo " UNIX(-like) systems. If you know a bit more about the system on which you" + @echo " work, then you might try \"make list\" for a list of the system-specific" + @echo " targets supported herein. (Many of them do exactly the same thing, so don't" + @echo " agonize too much over which to pick if two or more sound equally likely.)" + @echo " Also check out the INSTALL file for notes on compiling various targets. As" + @echo " a last resort, feel free to read the numerous comments within the Makefile" + @echo " itself." + @echo "" + +list: + @echo "" + @echo\ + 'Type "make ", where is one of the following:' + @echo "" + @echo " $(SYSTEMG1)" + @echo " $(SYSTEMG2)" + @echo "" + @echo " $(SYSTEMS1)" + @echo " $(SYSTEMS2)" + @echo " $(SYSTEMS3)" + @echo " $(SYSTEMS4)" + @echo " $(SYSTEMS5)" + @echo " $(SYSTEMS6)" + @echo " $(SYSTEMS7)" + @echo " $(SYSTEMS8)" + @echo " $(SYSTEMS9)" +# @echo "" +# @echo\ +# 'Targets for related utilities (ZipInfo and fUnZip) include:' +# @echo "" +# @echo " $(SYS_UTIL1)" +# @echo " $(SYS_UTIL2)" + @echo "" + @echo\ + 'For further (very useful) information, please read the comments in Makefile.' + @echo "" + +generic_msg: + @echo "" + @echo\ + ' Attempting "make generic" now. If this fails for some reason, type' + @echo\ + ' "make help" and/or "make list" for suggestions.' + @echo "" + + +############################################### +# BASIC COMPILE INSTRUCTIONS AND DEPENDENCIES # +############################################### + +# this is for GNU make; comment out and notify zip-bugs if it causes errors +.SUFFIXES: .c .o .obj .pic.o + +# yes, we should be able to use the $O macro to combine these two, but it +# fails on some brain-damaged makes (e.g., AIX's)...no big deal +.c.o: + $(CC) -c $(CF) $*.c + +.c.obj: + $(CC) -c $(CF) $*.c + +.c.pic.o: + $(CC) -c $(CF) -o $@ $*.c + +# this doesn't work...directories are always a pain with implicit rules +#.1.txt: man/$< +# nroff -Tman -man $< | col -b | uniq | \ +# sed 's/Sun Release ..../Info-ZIP /' > $@ + + +# these rules may be specific to Linux (or at least the GNU groff package) +# and are really intended only for the authors' use in creating non-Unix +# documentation files (which are provided with both source and binary +# distributions). We should probably add a ".1.txt" rule for more generic +# systems... + +funzip.txt: man/funzip.1 + nroff -Tascii -man man/funzip.1 | col -bx | uniq | expand > $@ + +unzip.txt: man/unzip.1 + nroff -Tascii -man man/unzip.1 | col -bx | uniq | expand > $@ + +unzipsfx.txt: man/unzipsfx.1 + nroff -Tascii -man man/unzipsfx.1 | col -bx | uniq | expand > $@ + +zipgrep.txt: man/zipgrep.1 + nroff -Tascii -man man/zipgrep.1 | col -bx | uniq | expand > $@ + +zipinfo.txt: man/zipinfo.1 + nroff -Tascii -man man/zipinfo.1 | col -bx | uniq | expand > $@ + + +all: generic_msg generic +unzips: $(UNZIPS) +objs: $(OBJS) +objsdll: $(OBJSDLL) +docs: $(DOCS) +unzipsman: unzips docs +unzipsdocs: unzips docs + + +# EDIT HERE FOR PARALLEL MAKES on Sequent (and others?)--screws up MS-DOS +# make utilities if default: change "unzip$E:" to "unzip$E:&" + +unzip$E: $(OBJS) $(LIBBZ2) # add `&' for parallel makes + $(LD) $(LF) $(LOBJS) $(LF2) + +unzipsfx$E: $(OBJX) # add `&' for parallel makes + $(LD) $(SL) $(LOBJX) $(SL2) + +funzip$E: $(OBJF) # add `&' for parallel makes + $(LD) $(FL) $(OBJF) $(FL2) + +zipinfo$E: unzip$E # `&' is pointless here... + @echo\ + ' This is a Unix-specific target. ZipInfo is not enabled in some MS-DOS' + @echo\ + ' versions of UnZip; if it is in yours, copy unzip.exe to zipinfo.exe' + @echo\ + ' or else invoke as "unzip -Z" (in a batch file, for example).' + $(LN) unzip$E zipinfo$E + +# when the optional bzip2 support is provided (as recommended) by sources +# in the 'bzip2' subdirectory, create/update the library: +$(IZ_OUR_BZIP2_DIR)/libbz2.a: + @echo "Building/updating bzip2 object library..." + ( cd $(IZ_OUR_BZIP2_DIR) ; $(MAKE) -f Makebz2.iz CC="$(CC_BZ)"\ + CFLAGS="$(CFLAGS_BZ)" RM="rm -f" ) + + +crc32$O: crc32.c $(UNZIP_H) zip.h crc32.h +crypt$O: crypt.c $(UNZIP_H) zip.h crypt.h crc32.h ttyio.h +envargs$O: envargs.c $(UNZIP_H) +explode$O: explode.c $(UNZIP_H) +extract$O: extract.c $(UNZIP_H) crc32.h crypt.h +fileio$O: fileio.c $(UNZIP_H) crc32.h crypt.h ttyio.h ebcdic.h +funzip$O: funzip.c $(UNZIP_H) crc32.h crypt.h ttyio.h +globals$O: globals.c $(UNZIP_H) +inflate$O: inflate.c inflate.h $(UNZIP_H) +list$O: list.c $(UNZIP_H) +match$O: match.c $(UNZIP_H) +process$O: process.c $(UNZIP_H) crc32.h +ttyio$O: ttyio.c $(UNZIP_H) zip.h crypt.h ttyio.h +ubz2err$O: ubz2err.c $(UNZIP_H) +unreduce$O: unreduce.c $(UNZIP_H) +unshrink$O: unshrink.c $(UNZIP_H) +unzip$O: unzip.c $(UNZIP_H) crypt.h unzvers.h consts.h +zipinfo$O: zipinfo.c $(UNZIP_H) + +# unzipsfx compilation section +unzipsfx$O: unzip.c $(UNZIP_H) crypt.h unzvers.h consts.h + $(CC) -c $(CF) -DSFX -o $@ unzip.c + +crc32_$O: crc32.c $(UNZIP_H) zip.h crc32.h + $(CC) -c $(CF) -DSFX -o $@ crc32.c + +crypt_$O: crypt.c $(UNZIP_H) zip.h crypt.h crc32.h ttyio.h + $(CC) -c $(CF) -DSFX -o $@ crypt.c + +extract_$O: extract.c $(UNZIP_H) crc32.h crypt.h + $(CC) -c $(CF) -DSFX -o $@ extract.c + +fileio_$O: fileio.c $(UNZIP_H) crc32.h crypt.h ttyio.h ebcdic.h + $(CC) -c $(CF) -DSFX -o $@ fileio.c + +globals_$O: globals.c $(UNZIP_H) + $(CC) -c $(CF) -DSFX -o $@ globals.c + +inflate_$O: inflate.c inflate.h $(UNZIP_H) crypt.h + $(CC) -c $(CF) -DSFX -o $@ inflate.c + +match_$O: match.c $(UNZIP_H) + $(CC) -c $(CF) -DSFX -o $@ match.c + +process_$O: process.c $(UNZIP_H) crc32.h + $(CC) -c $(CF) -DSFX -o $@ process.c + +ttyio_$O: ttyio.c $(UNZIP_H) zip.h crypt.h ttyio.h + $(CC) -c $(CF) -DSFX -o $@ ttyio.c + +ubz2err_$O: ubz2err.c $(UNZIP_H) + $(CC) -c $(CF) -DSFX -o $@ ubz2err.c + + +# funzip compilation section +cryptf$O: crypt.c $(UNZIP_H) zip.h crypt.h crc32.h ttyio.h + $(CC) -c $(CF) -DFUNZIP -o $@ crypt.c + +globalsf$O: globals.c $(UNZIP_H) + $(CC) -c $(CF) -DFUNZIP -o $@ globals.c + +inflatef$O: inflate.c inflate.h $(UNZIP_H) crypt.h + $(CC) -c $(CF) -DFUNZIP -o $@ inflate.c + +ttyiof$O: ttyio.c $(UNZIP_H) zip.h crypt.h ttyio.h + $(CC) -c $(CF) -DFUNZIP -o $@ ttyio.c + + +# optional assembler replacements +crc_i86$O: msdos/crc_i86.asm # 16bit only + $(AS) $(AF) msdos/crc_i86.asm $(ASEOL) + +crc_gcc$O: crc_i386.S $(ACONF_DEP) # 32bit, GNU AS + $(AS) $(AF) -x assembler-with-cpp -c -o $@ crc_i386.S + +crc_gcc.pic.o: crc_i386.S $(ACONF_DEP) # 32bit, GNU AS + $(AS) $(AF) -x assembler-with-cpp -c -o $@ crc_i386.S + +crc_sysv$O: crc_i386.S $(ACONF_DEP) # 32bit, SysV AS + $(CC) -E $(AF) crc_i386.S > crc_i386s.s + $(AS) -o $@ crc_i386s.s + $(RM) crc_i386s.s + +msdos$O: msdos/msdos.c $(UNZIP_H) unzvers.h # DOS only + $(CC) -c $(CF) msdos/msdos.c + +msdos_$O: msdos/msdos.c $(UNZIP_H) # DOS unzipsfx + -$(CP) msdos/msdos.c msdos_.c > nul + $(CC) -c $(CF) -DSFX msdos_.c + $(RM) msdos_.c + +#os2$O: os2/os2.c $(UNZIP_H) # OS/2 only +# $(CC) -c $(CF) os2/os2.c + +unix$O: unix/unix.c $(UNZIP_H) unzvers.h # Unix only + $(CC) -c $(CF) unix/unix.c + +unix_$O: unix/unix.c $(UNZIP_H) # Unix unzipsfx + $(CC) -c $(CF) -DSFX -o $@ unix/unix.c + +unix.pic.o: unix/unix.c $(UNZIP_H) unzvers.h # Unix shlib + $(CC) -c $(CF) -o $@ unix/unix.c + + +unix_make: +# @echo\ +# '(Ignore any errors from `make'"' due to the following command; it's harmless.)" + -@2>&1 $(LN) unix/Makefile . > /dev/null || echo > /dev/null + +# this really only works for Unix targets, unless E and O specified on cmd line +clean: + @echo "" + @echo ' This is a Unix-specific target. (Just so you know.)' + @echo "" + -( cd $(IZ_OUR_BZIP2_DIR); $(MAKE) -f Makebz2.iz RM="rm -f" clean ) + rm -f $(UNZIPS) $(OBJS) $(OBJF) $(OBJX) api$O apihelp$O crc_gcc$O \ + crc_sysv$O unzipstb$O crypt_.c extract_.c globals_.c inflate_.c \ + ttyio_.c crc_i386s.s msdos_.c process_.c unix_.c unzipsfx.c + rm -f flags + rm -rf ./$(PKGDIR) + +# Package generation interface (by J.Bush). Originally tested under Sun +# Solaris 2.x. Other SVr4s may be very similar and could possibly use this. +# Note: expects version info to be stored in VERSION macro variable. +# See "README" under ./unix/Packaging +# +svr4package: unzips + @echo "Creating SVR4 package for Unix ..." + -@rm -rf ./$(PKGDIR) ./$(PKGDIR)_`uname -p`.pkg + -@sed -e "s/.VERSION./$(VERSION)/g" \ + -e "s/.PSTAMP./$(LOGNAME)_`date | tr ' ' '_'`/g" \ + -e "s/.ARCH./Solaris_`uname -rp | tr ' ' ','`/g" \ + ./unix/Packaging/pkginfo.in > ./unix/Packaging/pkginfo + -@sed -e "s/.ARCH./`uname -p`/g" \ + ./unix/Packaging/preinstall.in > ./unix/Packaging/preinstall + /usr/bin/pkgmk -d . -b . -r . -f ./unix/Packaging/prototype $(PKGDIR) + /usr/bin/pkgtrans -o -s . $(PKGDIR)_`uname -p`.pkg $(PKGDIR) + @echo " " + @echo "To install, copy $(PKGDIR)_`uname -p`.pkg to the target system, and" + @echo "issue the command (as root): pkgadd -d $(PKGDIR)_`uname -p`.pkg" + @echo " " + +install: $(MANS) + -$(INSTALL_D) $(BINDIR) + $(INSTALL_PROGRAM) $(UNZIPS) $(BINDIR) + $(INSTALL) unix/zipgrep $(BINDIR) + $(RM) $(BINDIR)/zipinfo$E + $(LN) $(BINDIR)/unzip$E $(BINDIR)/zipinfo$E + -$(INSTALL_D) $(MANDIR) + $(INSTALL) man/funzip.1 $(MANDIR)/funzip.$(manext) + $(INSTALL) man/unzip.1 $(MANDIR)/unzip.$(manext) + $(INSTALL) man/unzipsfx.1 $(MANDIR)/unzipsfx.$(manext) + $(INSTALL) man/zipgrep.1 $(MANDIR)/zipgrep.$(manext) + $(INSTALL) man/zipinfo.1 $(MANDIR)/zipinfo.$(manext) + $(CHMOD) $(BINPERMS) $(INSTALLEDBIN) + $(CHMOD) $(MANPERMS) $(INSTALLEDMAN) + +uninstall: + $(RM) $(INSTALLEDBIN) $(INSTALLEDMAN) + +# added 10/28/04 EG +flags: unix/configure + sh unix/configure "${CC}" "${CF_NOOPT}" "${IZ_BZIP2}" "${IZ_ZLIB}" + +# the test zipfile +TESTZIP = testmake.zip + +# test some basic features of the build +test: check + +check: + @echo '##### This is a Unix-specific target. (Just so you know.)' + @echo '##### Make sure unzip, funzip and unzipsfx are compiled and' + @echo '##### in this directory.' + @if test ! -f ./unzip; then \ + echo "##### ERROR: can't find ./unzip"; exit 1; fi + @if test ! -f ./funzip; then \ + echo "##### ERROR: can't find ./funzip"; exit 1; fi + @if test ! -f ./unzipsfx; then \ + echo "##### ERROR: can't find ./unzipsfx"; exit 1; fi +# + @if test ! -f $(TESTZIP); then \ + echo "##### ERROR: can't find test file $(TESTZIP)"; exit 1; fi +# + @echo "##### testing extraction" + @./unzip -bo $(TESTZIP) testmake.zipinfo + @if test ! -f testmake.zipinfo ; then \ + echo "##### ERROR: file extraction from $(TESTZIP) failed"; \ + exit 1; fi +# + @echo '##### testing zipinfo (unzip -Z)' + @./unzip -Z $(TESTZIP) > testmake.unzip-Z + @if diff testmake.unzip-Z testmake.zipinfo; then echo "OK."; else \ + echo "##### WARNING: zipinfo output doesn't match stored version"; \ + echo '##### (If the only difference is the file times, compare your'; \ + echo '##### timezone with the Central European timezone, which is one'; \ + echo '##### hour east of Greenwich but effectively 2 hours east'; \ + echo '##### during summer Daylight Savings Time. The upper two'; \ + echo '##### lines should correspond to your local time when the'; \ + echo '##### files were created, on 19 November 1998 at 10:46pm CET.'; \ + echo '##### If the times are consistent, please ignore this warning.)'; \ + fi + @$(RM) testmake.unzip-Z testmake.zipinfo +# + @echo '##### testing unzip -d exdir option' + @./unzip -bo $(TESTZIP) -d testun notes + @cat testun/notes +# + @echo '##### testing unzip -o and funzip (ignore funzip warning)' + @./unzip -boq $(TESTZIP) notes -d testun + @./funzip < $(TESTZIP) > testun/notes2 + @if diff testun/notes testun/notes2; then true; else \ + echo '##### ERROR: funzip output disagrees with unzip'; fi +# + @echo '##### testing unzipsfx (self-extractor)' + @cat unzipsfx $(TESTZIP) > testsfx + @$(CHMOD) 0700 testsfx + @./testsfx -bo notes + @if diff notes testun/notes; then true; else \ + echo '##### ERROR: unzipsfx file disagrees with unzip'; fi + @$(RM) testsfx notes testun/notes testun/notes2 + @rmdir testun +# + @echo '##### testing complete.' + + +################################ +# INDIVIDUAL MACHINE MAKERULES # +################################ + +#---------------------------------------------------------------------------- +# Generic targets using the configure script to determine configuration. +#---------------------------------------------------------------------------- + +# Well, try MAKE and see. By now everyone may be happy. 10/28/04 EG +generic: flags # now try autoconfigure first + eval $(MAKE) $(MAKEF) unzips ACONF_DEP=flags `cat flags` +# make $(MAKEF) unzips CF="${CF} `cat flags`" + +generic_gcc: + $(MAKE) $(MAKEF) generic CC=gcc IZ_BZIP2="$(IZ_BZIP2)" + +# extensions to perform SVR4 package-creation after compilation +generic_pkg: generic svr4package +generic_gccpkg: generic_gcc svr4package + +#---------------------------------------------------------------------------- +# Old static generic targets (can't assume make utility groks "$(MAKE)") +#---------------------------------------------------------------------------- + +generic1: unzips # first try if unknown + +generic2: unix_make # second try if unknown: hope make is called "make" + make $(MAKEF) unzips CF="$(CF) -DBSD" + +generic3: unix_make # third try if unknown: hope make is called "make" + make $(MAKEF) unzips CF="$(CF) -DSYSV" + +# Generic build including bzip2 decompression support for unzip. +# Requires presence of the bzip2 sources in subdirectory bzip2. + +generic_bz2: unix_make + @echo\ + "This target assumes bzip2 sources are available in subfolder bzip2/." + $(MAKE) $(MAKEF) unzips D_USE_BZ2="-DUSE_BZIP2"\ + L_BZ2="-lbz2" LIBBZ2="$(IZ_OUR_BZIP2_DIR)/libbz2.a" \ + CC_BZ="$(CC)" CFLAGS_BZ="$(CFLAGS)" + +# Generic unzip and funzip target using either shared or static zlib for +# inflate rather than the original UnZip version. (libz was libgz prior +# to 0.94) Need to figure out how to force unzipsfx to use static libz. + +generic_zlib: unix_make + @echo\ + "This target assumes zlib (libz.a or libz.so.*) is already installed." + $(MAKE) unzip funzip CF="$(CF) -DUSE_ZLIB" LF2="-lz $(LF2)" + +# Generic GNU C shared library. This is an example of how to compile UnZip as +# a shared library. (Doing so as a static library would be similar.) See also +# the linux_shlib target. + +generic_shlib: unix_make + @echo\ + 'This target requires GNU C. When done, do "setenv LD_LIBRARY_PATH `pwd`"' + @echo\ + 'or similar in order to test the shared library in place (with ./unzip_shlib ,' + @echo\ + 'which is UnZip linked with the DLL). This target is an example only.' + @echo "" + $(MAKE) objsdll CC=gcc CFLAGS="-O3 -Wall -fPIC -DDLL" + gcc -shared -Wl,-soname,libunzip.so.0 -o libunzip.so.0.4 $(OBJSDLL) + $(RM) libunzip.so.0 libunzip.so + $(LN) -s libunzip.so.0.4 libunzip.so.0 + $(LN) -s libunzip.so.0 libunzip.so + gcc -c -O unzipstb.c + gcc -o unzip_shlib unzipstb.o -L. -lunzip + +#---------------------------------------------------------------------------- +# "Autoconfig" group, aliases for the generic targets using configure: +#---------------------------------------------------------------------------- + +# Solaris: generic, plus generation of installable package. +solaris_pkg: generic_pkg + +# Solaris: forcing usage of GCC, plus generation of installable package. +solaris_gccpkg: generic_gcc_pkg + +#---------------------------------------------------------------------------- +# "Normal" group (BSD vs. SysV may be set in unzip.h via predefined macros): +#---------------------------------------------------------------------------- + +386i: unzips # sun386i, SunOS 4.0.2 +#3Bx: unzips # AT&T 3B2/1000-80; should work on any WE32XXX machine +#aix_rt: unzips # IBM RT 6150 under AIX 2.2.1 +bull: unzips # Bull DPX/2, BOS 2.00.45 (doesn't require -Xk switch) +convex: unzips # Convex C-120 and C-210 (-O is enough; -ext is default) +cray: unzips # Cray-2 and Y-MP, using default (possibly old) compiler +dec: unzips # DEC 5820 (MIPS RISC), test version of Ultrix v4.0 +encore: unzips # Multimax +eta: unzips # ETA-10P*, hybrid SysV with BSD 4.3 enhancements +gould: unzips # Gould PN9000 running UTX/32 2.1Bu01 +hp: unzips # HP 9000 series (68020), 4.3BSD or HP-UX A.B3.10 Ver D +hpux: unzips # (to match zip's makefile entry) +mips: unzips # MIPS M120-5(?), SysV.3 [error in sys/param.h file?] +next10: unzips # NeXT (generic; use next2x or next3x for better opt.) +osf1: unzips # DECstation, including Alpha-based; DEC OSF/1 v1.x +pyr_: unzips # [failsafe target for pyramid target below] +pyr_ucb: unzips # Pyramids running BSD universe by default (see below) +realix: unzips # Modcomp Real/IX (SysV.3); note "gcc" = GLS C, not GNU +sco: unzips # Xenix/386 (tested on 2.3.1); SCO Unix 3.2.0. +sgi: unzips # Silicon Graphics; Irix 3.3.2, 4.0.x, 5.2, etc. +stellar: unzips # gs-2000 +sun: unzips # old target; no good with solaris...use "sunos" now +sunos: unzips # no good with SunOS 3.x...use "sunos3" or "sunos4" now +sunos4: unzips # Sun 3, 4; SunOS 4.x (SOME SYSTEMS ARE SYSTEM V!) +tahoe: unzips # tahoe (CCI Power6/32), 4.3BSD +ultrix: unzips # VAXen, DEC 58x0 (MIPS guts), DECstation 2100; v4.x +vax: unzips # general-purpose VAX target (not counting VMS) + +#---------------------------------------------------------------------------- +# BSD group (for timezone structs [struct timeb]): +#---------------------------------------------------------------------------- + +bsd: _bsd # generic BSD (BSD 4.2 & Ultrix handled in unzip.h) + +_bsd: unix_make + $(MAKE) unzips CF="$(CF) -DBSD" + +#---------------------------------------------------------------------------- +# SysV group (for extern long timezone and ioctl.h instead of sgtty.h): +#---------------------------------------------------------------------------- + +aix_rt: _sysv # IBM RT 6150 under AIX 2.2.1 +aviion: _sysv # Data General AViiONs, DG/UX 4.3x +pyr_att: _sysv # Pyramids running AT&T (SysV) universe by default +stardent: _sysv # Stardent ... +sysv: _sysv # generic System V Unix (Xenix handled in unzip.h) +xos: _sysv # Olivetti LSX-3005..3045, X/OS 2.3 and 2.4 + +_sysv: unix_make + $(MAKE) unzips CF="$(CF) -DSYSV" + +# extension to perform SVR4 package-creation after compilation +_sysvp: _sysv svr4package + +#---------------------------------------------------------------------------- +# Version 7 group (old/obsolescent): +#---------------------------------------------------------------------------- + +pixel: _v7 # Pixel 80, 100 (68000-based, V7/mostly BSD4.1 compat.) +v7: _v7 # generic Unix Version 7 box (prob. only Pixel...) + +_v7: + make $(MAKEF) unzips \ + CF="$(CF) -DV7 -DNO_PARAM_H -DSHORT_NAMES -DBSD -DZMEM -DNO_LCHOWN -DNO_LCHMOD" + +#---------------------------------------------------------------------------- +# "Unique" group (require non-standard options): +#---------------------------------------------------------------------------- + +# AT&T 3B2/1000-80; should work on any WE32XXX machine +3Bx: unix_make + $(MAKE) unzips CF="$(CF) -DCBREAK=2" + +# AT&T 7300 (M68000/SysV.3) (add -DSYSV? -DNO_LIMITS?) +7300: unix_make + $(MAKE) unzips CF="$(CF) -DNO_DIR -DNO_MKDIR -DNO_STRNICMP -DNO_UID_GID -DNO_FCHMOD -DNO_LCHOWN -DNO_LCHMOD -DCBREAK=2" + +7300_gcc: unix_make + $(MAKE) unzips CC=gcc LD=gcc LF2="" CFLAGS="-O2" \ + LOC="-DNO_DIR -DNO_MKDIR -DNO_STDLIB_H -DNO_STRNICMP -DNO_UID_GID -DNO_FCHMOD -DNO_LCHOWN -DNO_LCHMOD -DCBREAK=2 $(LOC)" + $(STRIP) $(UNZIPS) + +# IBM AIX 3.x on an RS/6000: see rs6000 target below +aix: rs6000 + +# Amdahl (IBMish) mainframe, UTS (SysV) 1.2.4, 2.0.1, 3.x +amdahl: unix_make + $(MAKE) unzips CF="$(CF) -DSYSV -DNO_UID_GID -DNO_LCHOWN -DNO_LCHMOD" + +# Amdahl UTS 2.1.4 with "extended file types" filesystem (aarrrggghhhh...) +amdahl_eft: unix_make + $(MAKE) unzips CF="$(CF) -eft -DSYSV -DNO_UID_GID -DNO_LCHOWN -DNO_LCHMOD" + +# Apollo Domain/OS machines (added -D...SOURCE options) [Gordon Fox, 960810] +apollo: unix_make + $(MAKE) unzips CF="$(CF) -D_INCLUDE_BSD_SOURCE -D_INCLUDE_XOPEN_SOURCE -DNO_LCHOWN -DNO_LCHMOD" + +# BSDI BSD/OS on 386 platform, using the assembler replacement for crc32.c +bsdi: unix_make + @echo 'NOTE: use bsdi_noasm target for non-Intel BSD/OS compiles.' + $(MAKE) unzips CC=gcc2 LD=shlicc2 AS=gcc2\ + CFLAGS="-O3 -Wall -DASM_CRC -DBSD" CRCA_O=crc_gcc$O + +# BSDI BSD/OS +bsdi_noasm: unix_make +# @echo 'NOTE: use bsd target for non-Intel BSD/OS compiles.' + $(MAKE) unzips CC=gcc2 LD=shlicc2 AS=gcc2\ + CFLAGS="-O3 -Wall -DBSD" + +# Coherent 3.x/4.x, Mark Williams C. ``For Coherent's CC, it needs either +# -T0 or -T150000 (or bigger) added to the CFLAGS, otherwise the compiler +# runs out of memory and dies in zipinfo.c.'' [Fred "Fredex" Smith, 940719] +coherent: unix_make + $(MAKE) unzips CFLAGS="$(CFLAGS) -T0 -DNO_LCHOWN -DNO_LCHMOD" + +# Cray-2, Y-MP or C90, running Unicos 5.x to 8.x (SysV + BSD enhancements) +# and Standard (ANSI) C compiler 3.0 or later. +cray_opt: unix_make + $(MAKE) unzips CFLAGS="$(CFLAGS) -h scalar3 -h vector3 -DNO_LCHOWN -DNO_LCHMOD" + +# The unzip41 build on a Cyber 910/SGI running Irix v3.3.3 was successful +# with the following change to Makefile: +cyber_sgi: unix_make + $(MAKE) unzips CFLAGS="$(CFLAGS) -I/usr/include/bsd -DNO_LCHOWN -DNO_LCHMOD"\ + LF="-lbsd $(LF)" SL="-lbsd $(SL)" + +# The Cygwin environment on a Win32 system, treated as an UNIX emulator. +# This port does not offer full access to the Windows file system. +# Info-ZIP recommends using "win32/Makefile.gcc" instead. +cygwin: unix_make + $(MAKE) unzips CC=gcc LD=gcc AS=gcc\ + CFLAGS="-O3 -DASM_CRC -DNO_LCHOWN -DNO_LCHMOD"\ + AF="-Di386 $(AF)" CRCA_O=crc_gcc$O\ + E=".exe" CP="cp" LN="ln -s" + +# 680x0, DIAB dnix 5.2/5.3 (a Swedish System V clone) +# +# Options for the dnix cc: +# -X7 = cc is strict ANSI C +# -X9 = warnings if a function is used without a declaration +# +dnix: unix_make + $(MAKE) unzips CFLAGS="$(CFLAGS) -X7 -X9 -DDNIX" + +# FreeBSD on Intel: +freebsd: unix_make + @echo 'NOTE: use bsd target for non-Intel FreeBSD compiles (if any).' + $(MAKE) unzips CC=gcc LD=gcc AS=gcc\ + CFLAGS="-O3 -Wall -DASM_CRC -DBSD"\ + AF="-Di386 $(AF)" CRCA_O=crc_gcc$O + +# Generic BSDish Unix gcc. ``The -O3 only works with later versions of gcc; +# you may have to use -O2 or -O for earlier versions. I have no idea why +# -s causes this bug in gcc.'' [Bug: "nm: unzip: no name list", "collect: +# /usr/bin/nm returned 1 exit status".] If you don't have strip, don't +# worry about it (it just makes the executable smaller and can be replaced +# with "echo" instead). +# +gcc: unix_make + $(MAKE) unzips CC=gcc LD=gcc CFLAGS="-O3" LF2="" + $(STRIP) $(UNZIPS) + +# Heurikon HK68 (68010), UniPlus+ System V 5.0, Green Hills C-68000 +hk68: unix_make + $(MAKE) unzips CC="gcc" LD="gcc"\ + LF="-n $(LF)" SL="-n $(SL)" FL="-n $(FL)"\ + CFLAGS="-ga -X138 -Dlocaltime=localti -Dtimezone=timezon" + +# ISC Unix on 386 platform +isc: unix_make + $(MAKE) unzips LF2="-lc_s $(LF2)" CRCA_O=crc_sysv$O \ + CFLAGS="-O" LOC="-DASM_CRC -DSYSV -DNO_UID_GID -DNEED_PTEM -DNO_LCHOWN -DNO_LCHMOD $(LOC)" \ + AF="-DNO_UNDERLINE -Djecxz=jcxz -DALIGNMENT='.align 16' $(AF)" + +isc_gcc: unix_make + $(MAKE) unzips AS=gcc CC=gcc LD=gcc CRCA_O=crc_gcc$O \ + LF="-shlib $(LF)" SL="-shlib $(SL)" FL="-shlib $(FL)" LF2="" \ + CFLAGS="-O3" LOC="-DSYSV -DASM_CRC -DNO_UID_GID -DNEED_PTEM -DNO_LCHOWN -DNO_LCHMOD $(LOC)" \ + AF="-DNO_UNDERLINE -Djecxz=jcxz -DALIGNMENT='.align 16' $(AF)" + $(STRIP) $(UNZIPS) + +# "ISI machine (68025 CPU)" (based on e-mail from Rob White ; +# no further information). May also need DIRENT defined. +isi: unix_make + $(MAKE) unzips CF="$(CF) -DDECLARE_ERRNO -DNO_LCHOWN -DNO_LCHMOD" + +# Linux on 386 platform, using the assembler replacement for crc32.c. (-O4 and +# -fno-strength-reduce have virtually no effect beyond -O3. Add "-m486 +# -malign-functions=2 -malign-jumps=2 -malign-loops=2" for Pentium [Pro] +# systems.) +linux: unix_make + @echo 'NOTE: use linux_noasm target for non-Intel Linux compiles.' + $(MAKE) unzips CC=gcc LD=gcc AS=gcc\ + CFLAGS="-O3 -Wall -DASM_CRC"\ + AF="-Di386 $(AF)" CRCA_O=crc_gcc$O +# GRR: this echo is pointless; if user gets this far, no difference to install +# @echo 'Be sure to use the install_asm target rather than the install target' + +linux_asm: linux + +# Linux (Posix, approximately SysV): virtually any version since before 0.96, +# for any platform. Change "-O" to "-O3" or whatever, as desired... +linux_noasm: unix_make + $(MAKE) unzips CC=gcc LD=gcc CFLAGS="-O -Wall" + +# Linux with lcc compiler: __inline__ (stat.h) not recognized, and must edit +# /usr/include/gnu/types.h to get rid of "long long" if __LCC__ defined. -O3 +# (or -O2 or -O) is ignored. [GRR 960828: test target only] +# +linux_lcc: unix_make + $(MAKE) unzips CC=lcc LD=lcc CFLAGS="-O3 -Wall -D__inline__= " + +# Linux host with go32 (djgpp) cross-compiler (go32crs.tgz) for 32-bit DOS. +linux_dos: unix_make + $(MAKE) unzips CC=go32gcc LD=go32gcc M=msdos OSDEP_H="msdos/doscfg.h" \ + CFLAGS="-O2 -Wall" +# go32-strip unzip +# Due to limitations of the cross-compiling package, this has to be +# done manually: + @echo Copy $(UNZIPS) to your DOS partition and use coff2exe. + +# Linux ELF shared library (ooo, it's so easy). This is a test target for +# now, and it only makes the UnZip/ZipInfo stuff (not fUnZip or UnZipSFX). +# The version number may eventually change to match the UnZip version. Or +# not. Whatever. Also do "setenv LD_LIBRARY_PATH `pwd`" or similar to test +# the DLL in place (with unzip_shlib, which is UnZip linked with the shared +# library). +# +linux_shlib: unix_make + $(MAKE) objsdll CC=gcc CFLAGS="-O3 -Wall -fPIC"\ + LOC="-DDLL -DASM_CRC $(LOC)"\ + AS=gcc AF="-fPIC -Di386 $(AF)" CRCA_O=crc_gcc$O + gcc -shared -Wl,-soname,libunzip.so.0 -o libunzip.so.0.4 $(OBJSDLL)\ + crc_gcc.pic.o + ln -sf libunzip.so.0.4 libunzip.so.0 + ln -sf libunzip.so.0 libunzip.so + gcc -c -O unzipstb.c + gcc -o unzip_shlib unzipstb.o -L. -lunzip + +# Linux ELF shared library, as above, but using inflate() from zlib (libz.so) +# instead of the original UnZip version. (libz was libgz prior to 0.94) +linux_shlibz: unix_make + $(MAKE) objsdll CC=gcc AS=gcc AF="-fPIC -Di386 $(AF)" CRCA_O=crc_gcc$O\ + CFLAGS="-O3 -Wall -fPIC" LOC="-DDLL -DUSE_ZLIB -DASM_CRC $(LOC)" + gcc -shared -Wl,-soname,libunzip.so.0 -o libunzip.so.0.4 $(OBJSDLL)\ + crc_gcc.pic.o + ln -sf libunzip.so.0.4 libunzip.so.0 + gcc -c -O unzipstb.c + gcc -o unzip unzipstb.o -L. -lunzip -lz + +# LynxOS-x86 2.3.0 and newer, a real-time BSD-like OS; uses gcc. +lynx: unix_make + $(MAKE) unzips CC=gcc CF="$(CF) -DLynx -DLYNX -DBSD -DUNIX" + +# Macintosh MacOS X (Unix-compatible enviroment), using standard compiler +macosx: unix_make + $(MAKE) unzips CFLAGS="-O3 -Wall -DBSD" LF2="" + $(STRIP) $(UNZIPS) + +# Macintosh MacOS X (Unix-compatible enviroment), using gcc +macosx_gcc: unix_make + $(MAKE) unzips CC=gcc CFLAGS="-O3 -Wall -DBSD" LF2="" + $(STRIP) $(UNZIPS) + +# Minix 1.5 PC for the 386. Invoke as is to use default cc, or as "make +# minix CC=gcc" to use gcc. Try "make linux" if you have a working termios.h. +minix: unix_make + $(MAKE) unzips CF="$(CF) -DMINIX -DSHORT_NAMES -DNO_LCHOWN -DNO_LCHMOD" CC=$(CC) LD=$(CC) + +# MPE/iX, the Unix variant for HP 3000 systems. +mpeix: unix_make + $(MAKE) unzips CC=c89\ + CF="$(CF) -DUNIX -D_POSIX_SOURCE -DHAVE_TERMIOS_H -DPASSWD_FROM_STDIN -DNO_PARAM_H -DNO_LCHOWN -DNO_LCHMOD"\ + LF2=-lbsd CP=cp LN="ln -s" + +# NeXT info. +next: + @echo + @echo\ + ' Please pick a specific NeXT target: "make next10" will create a generic' + @echo\ + ' NeXT executable; "make next2x" will create a smaller executable (for' + @echo\ + ' NeXTstep 2.0 and higher); "make next3x" will create a small executable' + @echo\ + ' with significantly better optimization (NeXTstep 3.0 and higher only);' + @echo\ + ' "make nextfat" will create a fat, multi-architecture (NeXT plus Intel)' + @echo\ + ' executable (NeXTstep 3.1 and higher only).' + @echo + +# 68030 BSD 4.3+Mach. NeXT 2.x: make the executable smaller. +next2x: unix_make + $(MAKE) unzips LF2="-object -s" + +# NeXT 3.x: as above, plus better optimization. +next3x: unix_make + $(MAKE) unzips CFLAGS="-O2" LF2="-object -s" + +# NeXT 3.1+: make the executable fat (multi-architecture binary [MAB], +# for "black" [NeXT] and "white" [x86] hardware, so far). +nextfat: unix_make + $(MAKE) unzips CFLAGS="-O2 -arch i386 -arch m68k" \ + LF2="-arch i386 -arch m68k -object -s" + +# IBM OS/390 (formerly MVS) compiled under "OpenEdition" shell +os390: unix_make + set -x; \ + $(MAKE) $(MAKEF) unzips \ + CC=c89 LD="\$$(CC) -Wl,EDIT=NO" \ + CF="$(CF) -DSYSV -DUNIX -DOS390 -DEBCDIC -DNO_PARAM_H \ + -DNO_LCHOWN -DNO_LCHMOD \ + -D_ALL_SOURCE $(HOST_VERSINFO)" LF2="" + +# Sequent Symmetry running Dynix/ptx (sort of SysV.3): needs to link +# with libseq to get symlink(). +ptx: unix_make + $(MAKE) unzips CF="$(CF) -DSYSV -DTERMIO -DPTX -DNO_LCHOWN -DNO_LCHMOD" LF2="$(LF2) -lseq" + +# Pyramid 90X (probably all) under >= OSx4.1, either universe. (This is an +# experimental target! If it fails, use either pyr_ucb or pyr_att instead.) +# The make in the BSD half is too stupid to understand $(MAKE), sigh... +pyramid: unix_make + -make $(MAKEF) pyr_`universe` + +# QNX/Neutrino is "special" because you don't have any native development +# tools yet. Set ARCH to "x86", "ppcbe", "ppcle", "mipsbe", or "mipsle" +# to produce x86, PowerPC (big- or little-endian) and MIPS (big- +# or little-endian) using gcc. [cjh] +qnxnto: unix_make + @if [ "$(ARCH)" = "" ] ; then \ + echo "You didn't set ARCH; I'll assume you meant ARCH=x86..." ; \ + echo "" ; \ + $(MAKE) $(MAKEF) CC="qcc -Vgcc_ntox86" unzips ; \ + else \ + echo "Making unzip for $(ARCH)..." ; \ + echo "" ; \ + $(MAKE) $(MAKEF) CC="qcc -Vgcc_nto$(ARCH)" unzips ; \ + fi + +# REGULUS: 68040-based, "real-time" SysV.3 mutant; uses gcc, with "REGULUS" +# predefined. +regulus: unix_make + $(MAKE) unzips CF="$(CF) -traditional -DSYSV -DNO_MKDIR -DNO_LCHOWN -DNO_LCHMOD" + +# IBM RS/6000 under AIX 3.2 +rs6000: unix_make + $(MAKE) unzips CF="$(CF) -DBSD -D_BSD -DUNIX" LF2="-lbsd" + +# SCO cross compile from Unix to DOS. Tested with Xenix/386 and OpenDeskTop. +# Should work with Xenix/286 as well. (davidsen) Note that you *must* remove +# the Unix objects and executable before doing this! (Piet Plomp: gcc won't +# recognize the -M0 flag that forces 8086 code.) (GRR: may need to reduce +# stack to 0c00h if using 286/small-model code...?) +sco_dos: unix_make + $(MAKE) unzips CFLAGS="-O -dos -M0" M=msdos OSDEP_H="msdos/doscfg.h" \ + LF="-dos -F 2000" LF2="-o unzip.exe" \ + FL="-dos" FL2="-o funzip.exe" SL="-dos" SL2="-o unzipsfx.exe" + +# SCO UNIX with shared libraries and no international support. If you are +# not using a USA-style keyboard and display, you may want to remove -nointl +# to get support. It adds quite a bit to the size of the executable. +sco_sl: unix_make + $(MAKE) unzips LF="$(LF) -nointl" LF2="$(LF2) -lc_s"\ + SL="$(SL) -nointl" FL="$(FL) -nointl" + +# SCO Xenix/286 2.2.3 or later with development system 2.2.1 or later +sco_x286: unix_make + $(MAKE) unzips CF="$(CF) -Mel2 -LARGE -DNO_MKDIR -DNO_LCHOWN -DNO_LCHMOD" \ + LF="$(LF) -Mel2 -LARGE -lx" SL="$(SL) -Mel2 -LARGE" \ + FL="$(FL) -Mel2 -LARGE" + +# Sequent Symmetry with Dynix. (386, but needs -DZMEM) +# This should also work on Balance but I can't test it just yet. +sequent: unix_make + $(MAKE) unzips CF="$(CF) -DBSD -DZMEM -DNO_LCHOWN -DNO_LCHMOD" + +# Sun 2, 3, 4 running SunOS 3.x +sunos3: unix_make + $(MAKE) unzips CF="$(CF) -DNO_UID_GID -DUID_USHORT -DNO_LCHOWN -DNO_LCHMOD" + +# Generic System V + GNU C +sysv_gcc: unix_make + $(MAKE) unzips CC=gcc LD=gcc CFLAGS="-O2 -DSYSV" LF2="" + $(STRIP) $(UNZIPS) + +# AT&T 6300+, System V.2 Unix: run-time out-of-memory error if don't use -Ml; +# also compile-time error if work arrays dimensioned at HSIZE+2 (>32K) +sysv6300: unix_make + $(MAKE) unzips CF="$(CF) -Ml -DSYSV -DNO_LCHOWN -DNO_LCHMOD" LF="$(LF) -Ml"\ + SL="$(SL) -Ml" FL="$(FL) -Ml" + +# Texas Instruments System V.3 (running on HP 9000-1500) +ti_sysv: unix_make + $(MAKE) unzips CF="$(CF) -DSYSV -DNO_UID_GID -DUID_USHORT -DNO_LCHOWN -DNO_LCHMOD" + +# SCO Xenix (Joe Foster 950508: "unzip needs to be linked with -lx [for the +# opendir(), readdir(), telldir(), rewinddir(), and closedir() calls]") +xenix: unix_make + $(MAKE) unzips LF2="$(LF2) -lx" + diff --git a/third_party/unzip/unix/Packaging/README b/third_party/unzip/unix/Packaging/README new file mode 100644 index 000000000..63d6b9ff9 --- /dev/null +++ b/third_party/unzip/unix/Packaging/README @@ -0,0 +1,44 @@ +Solaris packaging +----------------- + +To generate a Solaris package for Info-ZIP UnZip utilities, +first see the top level INSTALL and README files. Do a +"make solaris", which will automatically build two Solaris +installable package files for the package, IZunzip. + + IZunzip -- Solaris installable package in directory format. + IZunzip_$(arch).pkg -- Solaris installable package in "stream" format. + + Where: $(arch) := system architecture, currently i386, sparc, or ppc. + (use "uname -p" to determine) + +The ".pkg" file is a single file datastream that can be compressed +and/or ftp'd. This is the recommended form, because all required +files are resident in the archive, and it is easily distributed. + +To install, simply: + + 1) copy the package to the target system's /tmp directory. + 2) login or su to root + 3) pkgadd -d /tmp/IZunzip_$(arch).pkg + 4) add /opt/Info-ZIP/IZunzip/bin to PATH + 5) add /opt/Info-ZIP/IZunzip/man to MANPATH + +This works for both SPARC and x86. + +Ongoing maintenance: + + Keep the files, "prototype" and "pkginfo.in" up to date. + Observe variable substitutions made by "Makefile". + See manpages for pkginfo(1), pkginfo(4), pkgmk(1), pkgproto(1) + +Variations: + + If you wish the base directory to be set to something other than + /opt/Info-ZIP, change the setting BASEDIR in pkginfo.in and + re-run the make. + + +-John Bush (John.Bush@East.Sun.COM) + July 20, 1996 + diff --git a/third_party/unzip/unix/Packaging/pkginfo.in b/third_party/unzip/unix/Packaging/pkginfo.in new file mode 100644 index 000000000..fe6c11b4d --- /dev/null +++ b/third_party/unzip/unix/Packaging/pkginfo.in @@ -0,0 +1,13 @@ +PKG=IZunzip +NAME=Info-ZIP UnZip Utilities +CATEGORY=application +VENDOR=Info-ZIP +EMAIL=Zip-Bugs@lists.wku.edu +HOTLINE=Zip-Bugs@lists.wku.edu +DESC=Copyrighted FREEWARE. See README, WHERE, and LICENSE docs in pkg's doc dir. +CLASSES=none +BASEDIR=/opt/Info-ZIP +#BASEDIR=/usr/local +VERSION=".VERSION." +PSTAMP=".PSTAMP." +ARCH=".ARCH." diff --git a/third_party/unzip/unix/Packaging/postinstall b/third_party/unzip/unix/Packaging/postinstall new file mode 100644 index 000000000..030067d50 --- /dev/null +++ b/third_party/unzip/unix/Packaging/postinstall @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Post installation script (simply inform installer about PATH etc) +# +echo " " +echo " " +echo "Installation is complete. Now, you should add the following" +echo "(or equivalnet) commands to the appropriate initial user shell" +echo "scripts (such as .profile, .login, etc) -- " +echo " " +echo " For korn or bourne shell:" +echo " PATH=\${PATH}:${BASEDIR}/${PKG}/bin" +echo " MANPATH=\${MANPATH}:${BASEDIR}/${PKG}/man" +echo " export PATH MANPATH" +echo " " +echo " For C shell:" +echo " set path=(\$path ${BASEDIR}/${PKG}/bin)" +echo " setenv MANPATH \$MANPATH:${BASEDIR}/${PKG}/man" +echo " " +echo " See the files under ${BASEDIR}/${PKG}/doc for more information." +echo " " +exit 0 diff --git a/third_party/unzip/unix/Packaging/preinstall.in b/third_party/unzip/unix/Packaging/preinstall.in new file mode 100644 index 000000000..86c4b931a --- /dev/null +++ b/third_party/unzip/unix/Packaging/preinstall.in @@ -0,0 +1,26 @@ +#!/bin/sh +echo " " +echo "REPORT ALL BUGS, PROBLEMS, AND ACCOLADES TO:" +echo " " +echo " Zip-Bugs@lists.wku.edu" +echo " " +echo "Checking architecture platform for .ARCH. ..." +arch=`uname -p` +if [ "arch_${arch}" != "arch_.ARCH." ]; then + echo " " + echo "This product MUST be installed on a Solaris .ARCH. platform." + echo "Your machine looks like it is a ${arch} platform." + echo "Please install the version for the .ARCH. architecture." + echo "Aborting the installation because of this. " + echo " " + returncode=1 + else + echo " " + echo "This product works on .ARCH., which you happen to have!" + echo " " + returncode=0 +fi +echo " " +/usr/bin/sleep 4 +exit ${returncode:-1} +# diff --git a/third_party/unzip/unix/Packaging/prototype b/third_party/unzip/unix/Packaging/prototype new file mode 100644 index 000000000..ecec67438 --- /dev/null +++ b/third_party/unzip/unix/Packaging/prototype @@ -0,0 +1,33 @@ +d none $BASEDIR 0755 root bin +d none $BASEDIR/$PKG 0755 root bin +d none $PKG/bin 0755 root bin +f none $PKG/bin/unzip=unzip 0755 root bin +f none $PKG/bin/funzip=funzip 0755 root bin +f none $PKG/bin/unzipsfx=unzipsfx 0755 root bin +f none $PKG/bin/zipgrep=unix/zipgrep 0755 root bin +s none $PKG/bin/zipinfo=unzip +d none $PKG/doc 0755 root bin +f none $PKG/doc/ZipPorts=proginfo/ZipPorts 0644 root bin +f none $PKG/doc/CONTRIBS=proginfo/CONTRIBS 0644 root bin +f none $PKG/doc/COPYING.OLD=COPYING.OLD 0644 root bin +f none $PKG/doc/LICENSE=LICENSE 0644 root bin +f none $PKG/doc/README=README 0644 root bin +f none $PKG/doc/WHERE=WHERE 0644 root bin +f none $PKG/doc/INSTALL=INSTALL 0644 root bin +f none $PKG/doc/funzip.txt=funzip.txt 0644 root bin +f none $PKG/doc/unzip.txt=unzip.txt 0644 root bin +f none $PKG/doc/unzipsfx.txt=unzipsfx.txt 0644 root bin +f none $PKG/doc/zipgrep.txt=zipgrep.txt 0644 root bin +f none $PKG/doc/zipinfo.txt=zipinfo.txt 0644 root bin +d none $PKG/man 0755 root bin +d none $PKG/man/man1 0755 root bin +f none $PKG/man/man1/funzip.1=man/funzip.1 0644 root bin +f none $PKG/man/man1/unzip.1=man/unzip.1 0644 root bin +f none $PKG/man/man1/unzipsfx.1=man/unzipsfx.1 0644 root bin +f none $PKG/man/man1/zipgrep.1=man/zipgrep.1 0644 root bin +f none $PKG/man/man1/zipinfo.1=man/zipinfo.1 0644 root bin +i pkginfo +i prototype +i README +i preinstall +i postinstall diff --git a/third_party/unzip/unix/configure b/third_party/unzip/unix/configure new file mode 100644 index 000000000..dc6aa0b6f --- /dev/null +++ b/third_party/unzip/unix/configure @@ -0,0 +1,725 @@ +: +#!/bin/sh -x +# The above ":" is necessary on some buggy systems. + +# configure: Test to determine values for system-dependent variables. +# Output the flag definitions to the file "flags". +# Parameters: $1 = $CC, $2 = $CFLAGS, $3 = $IZ_BZIP2, $4 = $IZ_ZLIB +# +# This file is typically called from Makefile rather than executed +# from the command line. +# +# To construct unzip automatically using this file, type +# "make -f unix/Makefile generic". +# If this fails, then type "make list" to get a list of special targets. + +trap "rm -f conftest* core a.out; exit 1" 1 2 3 15 + +CC=${1:-cc} +CFLAGS=${2} +CFLAGSR=${CFLAGS} +CFLAGS="${CFLAGS} -I. -DUNIX" +LFLAGS1="" +LFLAGS2="-s" +LN="ln -s" + +# bzip2 +IZ_BZIP2=${3-} +CFLAGS_BZ='' + +# zlib +IZ_ZLIB=${4-} + +CFLAGS_OPT='' +BZLF='' + +echo "Check C compiler operation" +cat > conftest.c << _EOF_ +int main() +{ + return 0; +} +_EOF_ +$CC $CFLAGS -c conftest.c +status=$? +if test $status -ne 0; then + echo '' + echo "C compiler \"${CC}\" does not work as expected." + echo "Failing command was: $CC $CFLAGS -c conftest.c" + exit $status +else + echo ' Ok' +fi + +echo 'Check C compiler type (optimization options)' +# Sun C? +cat > conftest.c << _EOF_ +int main() +{ +#ifndef __SUNPRO_C + bad code +#endif + return 0; +} +_EOF_ +$CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null +if test $? -eq 0; then + CFLAGS_OPT='-xO3' + echo " Sun C ($CFLAGS_OPT)" +else + # Tru64 DEC/Compaq/HP C? + cat > conftest.c << _EOF_ +int main() +{ +#ifndef __DECC + bad code +#endif + return 0; +} +_EOF_ + $CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null + if test $? -eq 0; then + CFLAGS_OPT='-O3' + echo " DEC C ($CFLAGS_OPT)" + else + # HP-UX HP C? + cat > conftest.c << _EOF_ +int main() +{ +#ifdef __GNUC__ + bad code +#endif +#ifndef __hpux + bad code +#endif + return 0; +} +_EOF_ + $CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null + if test $? -eq 0; then + # HP-UX, not GCC. Lame bundled or real ANSI compiler? + CFLAGS_OPT_TRY="+O3 +Onolimit" + $CC $CFLAGS $CFLAGS_OPT_TRY -c conftest.c 2>&1 | \ + grep '(Bundled)' > /dev/null + if test $? -ne 0; then + CFLAGS_OPT="$CFLAGS_OPT_TRY" + echo " HP-UX ANSI C ($CFLAGS_OPT)" + else + echo ' HP-UX Bundled C (no opt)' + fi + else + # GNU C? + cat > conftest.c << _EOF_ +int main() +{ +#ifndef __GNUC__ + bad code +#endif + return 0; +} +_EOF_ + $CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null + if test $? -eq 0; then + CFLAGS_OPT='-O3' + echo " GNU C ($CFLAGS_OPT)" + # Special Mac OS X shared library "ld" option? + if test ` uname -s 2> /dev/null ` = 'Darwin'; then + lf='-Wl,-search_paths_first' + $CC $CFLAGS $lf conftest.c > /dev/null 2>/dev/null + if test $? -eq 0; then + BZLF=${lf} + fi + rm -f conftest + fi + else + CFLAGS_OPT='-O' + echo " Other-unknown C ($CFLAGS_OPT)" + fi + fi + fi +fi + +# optimization flags +if test -n "${CFLAGS_OPT}"; then + CFLAGSR="${CFLAGSR} ${CFLAGS_OPT}" + CFLAGS_BZ="${CFLAGS_BZ} ${CFLAGS_OPT}" +fi + +echo Check for the C preprocessor +# on SVR4, cc -E does not produce correct assembler files. Need /lib/cpp. +CPP="${CC} -E" +# solaris as(1) needs -P, maybe others as well ? +[ -f /usr/ccs/lib/cpp ] && CPP="/usr/ccs/lib/cpp -P" +[ -f /usr/lib/cpp ] && CPP=/usr/lib/cpp +[ -f /lib/cpp ] && CPP=/lib/cpp +[ -f /usr/bin/cpp ] && CPP=/usr/bin/cpp +[ -f /xenix ] && CPP="${CC} -E" +[ -f /lynx.os ] && CPP="${CC} -E" + +echo "#include " > conftest.c +$CPP conftest.c >/dev/null 2>/dev/null || CPP="${CC} -E" + +echo Check if we can use asm code +CRC32OA="" +if eval "$CPP crc_i386.S > _crc_i386.s 2>/dev/null"; then + if test ! -s _crc_i386.s || grep error < _crc_i386.s > /dev/null; then + : + elif eval "$CC -c _crc_i386.s >/dev/null 2>/dev/null" && [ -f _crc_i386.o ]; then + CFLAGSR="${CFLAGSR} -DASM_CRC" + CRC32OA="crc_gcc.o" + echo "int foo() { return 0;}" > conftest.c + $CC -c conftest.c >/dev/null 2>/dev/null + echo Check if compiler generates underlines + nm conftest.o | grep "(^|[^_])foo" >/dev/null 2>/dev/null + [ $? -eq 0 ] && CPP="${CPP} -DNO_UNDERLINE" + fi +fi +rm -f _crc_i386.s _crc_i386.o + +# ANSI options for compilers that don't have __STDC__ defined by default +# Currently HPUX, pyramid, Dynix, AIX, OSF/1 and ultrix + +echo Check for ANSI options +cat > conftest.c << _EOF_ +int main() +{ +#ifndef __STDC__ + forget it +#endif + return 0; +} +_EOF_ +$CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null +if [ $? -ne 0 ]; then + for OPT in "-Aa -D_HPUX_SOURCE" -Xa -qlanglvl=ansi -std1 -std + do + $CC $CFLAGS $OPT -c conftest.c > /dev/null 2>/dev/null + [ $? -eq 0 ] && CFLAGSR="${CFLAGSR} ${OPT}" && break + done +fi + +echo Check for prototypes +echo "int main(int argc, char *argv[]) { return 0; }" > conftest.c +$CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_PROTO" + +# const check currently handles mips cc and non ANSI compilers. +# does it need more ? +echo Check the handling of const +cat > conftest.c << _EOF_ +typedef int charset[2]; +int main() +{ + const charset x; + const char *foo; + return 0; +} +_EOF_ +$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_CONST" + +echo Check for time_t +cat > conftest.c << _EOF_ +#include +#include +int main() +{ + time_t t; + return 0; +} +_EOF_ +$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_TIME_T" + +echo Check for size_t +cat > conftest.c << _EOF_ +#include +int main() +{ + size_t s; + return 0; +} +_EOF_ +$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_SIZE_T" + +echo Check for off_t +cat > conftest.c << _EOF_ +#include +int main() +{ + off_t s; + return 0; +} +_EOF_ +$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_OFF_T" + +# Added 11/4/2003 EG +# Revised 8/12/04 EG +# Now we set the 64-bit file environment and check the size of off_t +echo Check for Large File Support +cat > conftest.c << _EOF_ +# 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 */ +#include +#include +#include +#include +int main() +{ + off_t offset; + struct stat s; + /* see if have 64-bit off_t */ + if (sizeof(offset) < 8) + return 1; + printf(" off_t is %d bytes\n", sizeof(off_t)); + /* see if have 64-bit stat */ + if (sizeof(s.st_size) < 8) { + printf(" s.st_size is %d bytes\n", sizeof(s.st_size)); + return 2; + } + return 3; +} +_EOF_ +# compile it +$CC -o conftest conftest.c >/dev/null 2>/dev/null +if [ $? -ne 0 ]; then + echo -- no Large File Support +else +# run it + ./conftest + r=$? + if [ $r -eq 1 ]; then + echo -- no Large File Support - no 64-bit off_t + elif [ $r -eq 2 ]; then + echo -- no Large File Support - no 64-bit stat + elif [ $r -eq 3 ]; then + echo -- yes we have Large File Support! + CFLAGSR="${CFLAGSR} -DLARGE_FILE_SUPPORT" + else + echo -- no Large File Support - conftest returned $r + fi +fi + +# Added 11/24/2005 EG +# Check for wide char for Unicode support +echo Check for wide char support +cat > conftest.c << _EOF_ +#include +#include +#include +int main() +{ + size_t wsize; + wchar_t *wide_string; + + if ((wide_string = (wchar_t *)malloc(4 * sizeof(wchar_t))) == NULL) { + return 0; + } + /* get wide string */ + wsize = mbstowcs(wide_string, "foo", 3); + wide_string[wsize] = (wchar_t) NULL; +#ifndef __STDC_ISO_10646__ + return 1; +#else + printf(" __STDC_ISO_10646__ = %d\n", __STDC_ISO_10646__); + return 2; +#endif +} +_EOF_ +# compile it +$CC -o conftest conftest.c >/dev/null 2>/dev/null +if [ $? -ne 0 ]; then + echo "-- no Unicode (wchar_t) support" +else +# have wide char support +# run it + ./conftest + r=$? + if [ $r -eq 0 ]; then + echo -- no Unicode wchar_t support - wchar_t allocation error + elif [ $r -eq 1 ]; then + echo -- no Unicode support - wchar_t encoding unspecified + elif [ $r -eq 2 ]; then + echo -- have wchar_t with known UCS encoding - enabling Unicode support! + CFLAGSR="${CFLAGSR} -DUNICODE_SUPPORT -DUNICODE_WCHAR" + else + echo "-- no Unicode (wchar_t) support - conftest returned $r" + fi +fi + +echo "Check for setlocale support (needed for UNICODE Native check)" +cat > conftest.c << _EOF_ +#include +int main() +{ + char *loc = setlocale(LC_CTYPE, ""); + return 0; +} +_EOF_ +$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null +if [ $? -eq 0 ]; then + echo "-- have setlocale, can check for charset type" + echo "-- - enabling UTF8-native support!" + CFLAGSR="${CFLAGSR} -DUNICODE_SUPPORT -DUTF8_MAYBE_NATIVE" +else + echo "-- no Unicode (UTF-8 native) support!" + CFLAGSR="${CFLAGSR} -DNO_SETLOCALE" +fi + +# from configure 2.4i (Onno) 12/5/04 +echo Check for gcc no-builtin flag +# -fno-builtin since version 2 +cat > conftest.c << _EOF_ +int main() +{ +#if __GNUC__ >= 2 + return 0; +#else + forget it +#endif +} +_EOF_ +$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null +[ $? -eq 0 ] && BFLAG="-fno-builtin" + +# Check for missing functions +# add NO_'function_name' to flags if missing +for func in fchmod fchown lchown nl_langinfo +do + echo Check for $func + echo "int main(){ $func(); return 0; }" > conftest.c + $CC $BFLAG -o conftest conftest.c >/dev/null 2>/dev/null + [ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_`echo $func | tr '[a-z]' '[A-Z]'`" +done + +# Check (seriously) for a working lchmod. +echo 'Check for lchmod' +temp_file="/tmp/unzip_test_$$" +temp_link="link_$$" +( echo '#include ' ; \ + echo "int main() { lchmod(\"${temp_file}\", 0666); }" \ +) > conftest.c +ln -s "${temp_link}" "${temp_file}" && \ + $CC $BFLAG -o conftest conftest.c >/dev/null 2>/dev/null && \ + ./conftest +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_LCHMOD" +rm -f "${temp_file}" + +echo Check for memset +echo "int main(){ char k; memset(&k,0,0); return 0; }" > conftest.c +$CC -o conftest conftest.c >/dev/null 2>/dev/null +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DZMEM" + +echo Check for errno declaration +cat > conftest.c << _EOF_ +#include +main() +{ + errno = 0; + return 0; +} +_EOF_ +$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_ERRNO" + +echo Check for strerror +cat > conftest.c << _EOF_ +#include +int main() { strerror( 0); return 0; } +_EOF_ +$CC $CFLAGS -o conftest conftest.c >/dev/null 2>/dev/null +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNEED_STRERROR" + +echo Check for directory libraries +cat > conftest.c << _EOF_ +int main() { return closedir(opendir(".")); } +_EOF_ + +$CC -o conftest conftest.c >/dev/null 2>/dev/null +if [ $? -ne 0 ]; then + OPT="" + for lib in ndir dir ucb bsd BSD PW x dirent + do + $CC -o conftest conftest.c -l$lib >/dev/null 2>/dev/null + [ $? -eq 0 ] && OPT=-l$lib && break + done + if [ ${OPT} ]; then + LFLAGS2="${LFLAGS2} ${OPT}" + else + CFLAGSR="${CFLAGSR} -DNO_DIR" + fi +fi + +# Dynix/ptx 1.3 needed this +echo Check for readlink +echo "int main(){ return readlink(); }" > conftest.c +$CC -o conftest conftest.c >/dev/null 2>/dev/null +if [ $? -ne 0 ]; then + $CC -o conftest conftest.c -lseq >/dev/null 2>/dev/null + [ $? -eq 0 ] && LFLAGS2="${LFLAGS2} -lseq" +fi + +echo Check for directory include file +OPT="" +for inc in dirent.h sys/ndir.h ndir.h sys/dir.h +do + echo "#include <$inc>" > conftest.c + $CPP conftest.c > /dev/null 2>/dev/null + [ $? -eq 0 ] && OPT="-DHAVE_`echo $inc | tr '[a-z]./' '[A-Z]__'`" && break +done +CFLAGSR="${CFLAGSR} ${OPT}" + +echo Check for non existent include files +for inc in stdlib.h stddef.h unistd.h fcntl.h string.h langinfo.h +do + echo "#include <$inc>" > conftest.c + $CPP conftest.c >/dev/null 2>/dev/null + [ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_`echo $inc | tr '[a-z]./' '[A-Z]__'`" +done + +echo Check for term I/O include file +OPT="" +for inc in termios.h termio.h sgtty.h +do + echo "#include <$inc>" > conftest.c + $CPP conftest.c > /dev/null 2>/dev/null + [ $? -eq 0 ] && OPT="-DHAVE_`echo $inc | tr '[a-z]./' '[A-Z]__'`" && break +done +CFLAGSR="${CFLAGSR} ${OPT}" + +echo Check for MBCS include files +OPT="" +for inc in mbstr.h mbstring.h mbctype.h +do + echo "#include <$inc>" > conftest.c + $CPP conftest.c > /dev/null 2>/dev/null + [ $? -eq 0 ] && OPT="-DHAVE_`echo $inc | tr '[a-z]./' '[A-Z]__'`" && break +done +CFLAGSR="${CFLAGSR} ${OPT}" + +# Check for MBCS support +echo Check for MBCS support +cat > conftest.c << _EOF_ +#include +#include +#include +#ifdef HAVE_MBSTRING_H +# include +#endif +int main() +{ + char *tst; + tst = "Hallo"; + return mblen(tst, MB_CUR_MAX); +} +_EOF_ +# compile it +$CC ${CFLAGS} ${CFLAGSR} -o conftest conftest.c >/dev/null 2>/dev/null +if [ $? -ne 0 ]; then + echo "-- no MBCS support" + CFLAGSR="${CFLAGSR} -DNO_MBCS" +else +# + echo "-- have MBCS support" + CFLAGSR="${CFLAGSR} -D_MBCS" +# Realistic check for working MBCS library functions. +# Add FUNCTION_NAME='function_name' to flags if found. + for func in mbschr mbsrchr + do + echo Check for MBCS $func + cat > conftest.c << _EOF_ +#include +#ifdef HAVE_MBSTR_H +# include +#endif +int main() +{ + char *tst; + tst = $func( "abc", 'b'); + printf( " tst: >%s<.\n", tst); + return (tst == NULL); +} +_EOF_ + $CC ${CFLAGS} ${CFLAGSR} -o conftest conftest.c >/dev/null 2>/dev/null + [ $? -eq 0 ] && ./conftest > /dev/null + [ $? -eq 0 ] && CFLAGSR="${CFLAGSR} -D`echo $func | tr '[a-z]' '[A-Z]'`=$func" + done +fi + +# needed for AIX (and others ?) when mmap is used +echo Check for valloc +cat > conftest.c << _EOF_ +main() +{ +#ifdef MMAP + valloc(); +#endif +} +_EOF_ +$CC ${CFLAGS} -c conftest.c > /dev/null 2>/dev/null +[ $? -ne 0 ] && CFLAGSR="${CFLAGSR} -DNO_VALLOC" + +echo Check for /usr/local/bin and /usr/local/man +BINDIR=$HOME/bin +[ -d /usr/local/bin ] && BINDIR=/usr/local/bin + +MANDIR=manl +[ -d /usr/man/manl ] && MANDIR=/usr/man/manl +[ -d /usr/local/man/manl ] && MANDIR=/usr/local/man/manl +[ -d /usr/local/man/man1 ] && MANDIR=/usr/local/man/man1 + +echo Checking for OS specialties +if [ -f /usr/bin/hostinfo ]; then + if /usr/bin/hostinfo | grep NeXT > /dev/null; then + CFLAGSR="${CFLAGSR} -posix" + LFLAGS1="${LFLAGS1} -posix -object" + fi +# XXX ATT6300, Cray +elif [ -f /xenix ]; then + if uname -p | grep 286 > /dev/null; then + CFLAGSR="${CFLAGSR} -LARGE -Mel2 -DMEDIUM_MEM -DWSIZE=16384 -DNO_VOID" + LFLAGS1="${LFLAGS1} -LARGE -Mel2" + fi +elif uname -X >/dev/null 2>/dev/null; then +# SCO shared library check + echo "int main() { return 0;}" > conftest.c + $CC -o conftest conftest.c -lc_s -nointl >/dev/null 2> /dev/null + [ $? -eq 0 ] && LFLAGS2="-lc_s -nointl" +else + SYSTEM=`uname -s 2>/dev/null` || SYSTEM="unknown" + echo "int main() { return 0;}" > conftest.c + case $SYSTEM in + OSF1|ULTRIX) + echo Check for -Olimit option + $CC ${CFLAGS} -Olimit 1000 -o conftest conftest.c >/dev/null 2>/dev/null + [ $? -eq 0 ] && CFLAGSR="${CFLAGSR} -Olimit 1000" + ;; +### HP-UX) +### echo Check for +Onolimit option +### $CC ${CFLAGS} +Onolimit -o conftest conftest.c >/dev/null 2>/dev/null +### [ $? -eq 0 ] && CFLAGSR="${CFLAGSR} +Onolimit" +### ;; +### SunOS) +### CFLAGSR="${CFLAGSR} -D_FILE_OFFSET_BITS=64" +### ;; + esac +fi + +echo Check for symbolic links +ln -s /dev/null null > /dev/null 2>/dev/null || LN=ln + +rm -f a.out conftest.c conftest.o conftest null + + +# bzip2 + +echo "Check bzip2 support" +LIBBZ2="" +CC_BZ="${CC}" + +if test -n "${IZ_BZIP2}" -a "${IZ_BZIP2}" != "bzip2" ; then + echo " Check for bzip2 compiled library in IZ_BZIP2 (${IZ_BZIP2})" + if test -f "${IZ_BZIP2}/libbz2.a"; then +# +# A bzip2 library built with BZ_NO_STDIO should have an +# unresolved external, "bz_internal_error". The default, +# full-function library will not mention it. +# + nm ${IZ_BZIP2}/libbz2.a | grep bz_internal_error > /dev/null + if test $? -eq 0; then + echo " Found bzip2 BZ_NO_STDIO library, ${IZ_BZIP2}/libbz2.a" + if test -f "${IZ_BZIP2}/bzlib.h"; then + LIBBZ2="${IZ_BZIP2}/libbz2.a" + echo "-- Found bzip2 library - linking in bzip2" + else + echo " ${IZ_BZIP2}/bzlib.h not found" + echo "-- Since IZ_BZIP2 defined (!= \"bzip2\")," + echo "-- => skipping OS and bzip2 dir checks." + echo "-- NO bzip2 support !" + fi + else + echo " Found bzip2 library, ${IZ_BZIP2}/libbz2.a," + echo " but library not compiled with BZ_NO_STDIO." + echo " ERROR: This (default) variant of bzip2 library is NOT" + echo " supported with UnZip because of its incompatible" + echo " error handling!" + echo " Please see the UnZip installation instructions in" + echo " the INSTALL text file." + echo " Skipping bzip2 support..." + fi + else + echo " ${IZ_BZIP2}/libbz2.a not found" + echo "-- Since IZ_BZIP2 defined (!= \"bzip2\")," + echo "-- => skipping OS and bzip2 dir checks." + echo "-- NO bzip2 support !" + fi +else + echo " Check for bzip2 sources in unzip's bzip2 subdirectory" + if test -f "${IZ_BZIP2}/bzlib.c" -a -f "${IZ_BZIP2}/bzlib.h"; then + echo "-- Found bzip2 source in ${IZ_BZIP2}/ directory" + echo "-- Will try to build bzip2 library from source and link in" + LIBBZ2="${IZ_BZIP2}/libbz2.a" + else + echo "-- bzip2 sources not found - no bzip2 support" + fi +fi + +if test -n "${LIBBZ2}" ; then + CFLAGSR="${CFLAGSR} -DUSE_BZIP2 -I${IZ_BZIP2}" + LFLAGS1="${LFLAGS1} -L${IZ_BZIP2}" + LFLAGS2="${LFLAGS2} ${BZLF} -lbz2" +fi + + +# zlib + +if test -n "${IZ_ZLIB}"; then + echo "Using (expecting) zlib in IZ_ZLIB (${IZ_ZLIB})" + CFLAGSR="${CFLAGSR} -DUSE_ZLIB -I${IZ_ZLIB}" + LFLAGS1="${LFLAGS1} -L${IZ_ZLIB}" + LFLAGS2="${LFLAGS2} ${BZLF} -lz" +fi + + +# System identification +UNAME_M='' +uname_m=` uname -m 2> /dev/null ` && \ + UNAME_M=" -DUNAME_M='\\\"${uname_m}\\\"'" +UNAME_O='' +uname_o=` uname -o 2> /dev/null ` && \ + UNAME_O=" -DUNAME_O='\\\"${uname_o}\\\"'" +UNAME_P='' +uname_p=` uname -p 2> /dev/null ` && \ + UNAME_P=" -DUNAME_P='\\\"${uname_p}\\\"'" +UNAME_R='' +uname_r=` uname -r 2> /dev/null ` && \ + UNAME_R=" -DUNAME_R='\\\"${uname_r}\\\"'" +UNAME_S='' +uname_s=` uname -s 2> /dev/null ` && \ + UNAME_S=" -DUNAME_S='\\\"${uname_s}\\\"'" +UNAME_V='' +uname_v=` uname -v 2> /dev/null ` && \ + UNAME_V=" -DUNAME_V='\\\"${uname_v}\\\"'" + +if [ -f /usr/sbin/sizer ]; then + SIZER_V='' + sizer_v=` /usr/sbin/sizer -v 2> /dev/null | \ + sed -e 's/^[^ ]* [^ ]* [^ ]* \([^ ]*\) .*/\1/' ` && \ + SIZER_V=" -DSIZER_V='\\\"${sizer_v}\\\"'" + + CFLAGSR="${CFLAGSR} ${SIZER_V}" +fi + +CFLAGSR="${CFLAGSR} ${UNAME_M} ${UNAME_O} ${UNAME_P} ${UNAME_R}" +CFLAGSR="${CFLAGSR} ${UNAME_S} ${UNAME_V}" + +echo CC=\"${CC}\" CF=\"${CFLAGSR}\" CRCA_O=\"${CRC32OA}\" \ + AS=\"${CC} -c\" LFLAGS1=\"${LFLAGS1}\" LF2=\"${LFLAGS2}\" \ + CC_BZ=\"${CC_BZ}\" CFLAGS_BZ=\"${CFLAGS_BZ}\" \ + IZ_BZIP2=\"${IZ_BZIP2}\" LIBBZ2=\"${LIBBZ2}\" \ + IZ_ZLIB=\"${IZ_ZLIB}\" > flags + diff --git a/third_party/unzip/unix/macosx.h b/third_party/unzip/unix/macosx.h new file mode 100644 index 000000000..9d0c9eae6 --- /dev/null +++ b/third_party/unzip/unix/macosx.h @@ -0,0 +1,49 @@ +/* + macosx.h - UnZip 6 + + Copyright (c) 2008 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2007-Mar-4 or later + (the contents of which are also included in zip.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 +*/ + +#ifndef __MACOSX_H +# define __MACOSX_H + +# if defined( UNIX) && defined( __APPLE__) + +# include +# include + +# define APL_DBL_PFX "._" +# define APL_DBL_PFX_SQR "__MACOSX/" +# define APL_DBL_SFX "/rsrc" + +# define APL_DBL_HDR_SIZE 82 +# define APL_DBL_HDR_RSRC_FORK_SIZE 46 +# define APL_DBL_HDR_FNDR_INFO_OFFS 50 +# define APL_DBL_OFS_MAGIC 0 +# define APL_DBL_OFS_VERSION 4 +# define APL_DBL_OFS_FILLER 8 +# define APL_DBL_OFS_ENT_CNT 24 +# define APL_DBL_OFS_ENT_DSCR 28 + +# define APL_FNDR_INFO_SIZE 32 + +/* Finder info attribute buffer structure for setattrlist(). */ +typedef struct { + char fndr_info[ APL_FNDR_INFO_SIZE]; +} attr_bufr_fndr_t; + +/* Resource fork attribute buffer structure for getattrlist(). */ +typedef struct { + unsigned int ret_length; + off_t size; +} attr_bufr_rsrc_t; + +# endif /* defined( unix) && defined( __APPLE__) */ + +#endif /* ndef __MACOSX_H */ + diff --git a/third_party/unzip/unix/zipgrep b/third_party/unzip/unix/zipgrep new file mode 100644 index 000000000..f3eb67008 --- /dev/null +++ b/third_party/unzip/unix/zipgrep @@ -0,0 +1,123 @@ +#!/bin/sh +# +# zipgrep: Use unzip and egrep to search the specified members of a +# Zip archive for a string or pattern. Search all members if no members +# are specified explicitly. The script attempts to handle egrep's "-h" +# and "-l" options internally. +# +# This script assumes that the desired "unzip" and "egrep" (and "grep", +# "od", and "sed") programs are on the user's PATH. The user may specify +# a particular "unzip" path in the environment variable ZIPGREP_UNZIP. +# + +# UnZip command. +unzip=${ZIPGREP_UNZIP:-unzip} + +# UnZip command options. (Note: Shell quoting can cause problems with +# enbedded spaces in a single options variable.) +unzopts1='-L-' +unzopts2='-p' +unzopts3='' + +# ASCII/EBCDIC test. (Note: Simple-looking test, if [[ "a" < "A" ]], is +# too modern for an old shell (like Solaris /bin/sh)). +echo A | od -x | grep -i "C115" > /dev/null +if test $? -eq 0; then + unzopts2='-cq' + unzopts3='-aa' +fi + +pat="" +opt="" +while test $# -ne 0; do + case "$1" in + -e | -f) opt="$opt $1"; shift; pat="$1";; + -*) opt="$opt $1";; + *) if test -z "$pat"; then + pat="$1" + else + break; + fi;; + esac + shift +done + +if test $# = 0; then + echo usage: `basename "$0"` "[egrep_options] pattern zipfile [members...]" + echo Uses unzip and egrep to search the zip members for a string or pattern. + exit 1 +fi +zipfile="$1"; shift + +list=0 +silent=0 +opt=`echo "$opt" | sed -e 's/ //g' -e 's/-//g'` +case "$opt" in + *l*) list=1; opt=`echo $opt | sed s/l//` +esac +case "$opt" in + *h*) silent=1 +esac +if test -n "$opt"; then + opt="-$opt" +fi + +status_grep_global=1 +IFS=' +' + +# Escape shell-special characters in "pat". +pat=` echo "$pat" | \ + sed -e 's/\\\\/\\\\\\\\/g' -e 's/|/\\\|/g' -e 's/&/\\\&/g' ` + +# Use "unzip -Z1" to get a listing of the specified members from the +# specified archive. Escape any backslashes in a file name. +for i in `$unzip -Z1 "$zipfile" ${1+"$@"} | sed -e 's/\\\\/\\\\\\\\/g' `; do + if test $list -eq 1; then + # "-l": Show only the archive member name, not the matching line(s). + $unzip $unzopts1 $unzopts2 $unzopts3 "$zipfile" "$i" | \ + egrep $opt "$pat" > /dev/null && echo "$i" + status_grep=$? + elif test $silent -eq 1; then + # "-h": Show only the matching line(s), not the archive member name. + # ("-s" in "opt" will silence "egrep", stopping all output.) + $unzip $unzopts1 $unzopts2 $unzopts3 "$zipfile" "$i" | \ + egrep $opt "$pat" + status_grep=$? + else + # Escape (or re-escape) shell-special characters in the archive + # member name, "i". + i=` echo "$i" | \ + sed -e 's/\\\\/\\\\\\\\/g' -e 's/|/\\\|/g' -e 's/&/\\\&/g' ` + + # Globally, send fd 4 to stdout. In the pipeline, send normal + # stdout to fd 4, and send grep status to fd 3. Collect fd 3 + # with ``. + exec 4>&1 + status_grep=` ( \ + ( $unzip $unzopts1 $unzopts2 $unzopts3 "$zipfile" "$i" | \ + egrep $opt "$pat" 1>&4 ; echo $? >&3 ) 4>&1 | \ + sed "s|^|${i}:|" 1>&4 \ + ) 3>&1 ` + fi + + # Save the primary command status. (May be the grep status.) + sts=$? + # If this grep status was zero, set the global grep status to zero. + test "$status_grep" -eq 0 && status_grep_global=0 + # If this grep status was not zero or one, exit now. + test "$status_grep" -gt 1 && exit "$status_grep" + +done + +# If "sts" is good (0), then exit with the global grep status. +# Else, when "sts" is bad, exit with the worst status we can find. +if test $sts -eq 0 ; then + exit $status_grep_global +else + if test "$status_grep" -gt 1 ; then + exit "$status_grep" + else + exit $sts + fi +fi diff --git a/third_party/unzip/unreduce.c b/third_party/unzip/unreduce.c new file mode 100644 index 000000000..a0c442a47 --- /dev/null +++ b/third_party/unzip/unreduce.c @@ -0,0 +1,36 @@ +// clang-format off +/* + Copyright (c) 1990-2002 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 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 +*/ +/*--------------------------------------------------------------------------- + + unreduce.c + + Copyright-clean dummy module, without any real code. + + If you really need unreduce support, replace this module by the full + source code, available as add-on package from our distribution site. + + ---------------------------------------------------------------------------*/ + + +#define __UNREDUCE_C /* identifies this source module */ +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" /* defines COPYRIGHT_CLEAN by default */ + + +#ifndef COPYRIGHT_CLEAN + + /* This line is indented to hide the #error directive from pure traditional + * K&R C preprocessors. These do not recognize the #error directive, but + * they also recognize only lines that start with a '#' in column 1 as + * preprocessor directives. + */ + #error This dummy-module does not support the unreduce method! + +#endif /* !COPYRIGHT_CLEAN */ diff --git a/third_party/unzip/unshrink.c b/third_party/unzip/unshrink.c new file mode 100644 index 000000000..5bf446bc0 --- /dev/null +++ b/third_party/unzip/unshrink.c @@ -0,0 +1,337 @@ +// clang-format off +/* + Copyright (c) 1990-2008 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 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 +*/ +/*--------------------------------------------------------------------------- + + unshrink.c version 1.22 19 Mar 2008 + + + NOTE: This code may or may not infringe on the so-called "Welch + patent" owned by Unisys. (From reading the patent, it appears + that a pure LZW decompressor is *not* covered, but this claim has + not been tested in court, and Unisys is reported to believe other- + wise.) It is therefore the responsibility of the user to acquire + whatever license(s) may be required for legal use of this code. + + THE INFO-ZIP GROUP DISCLAIMS ALL LIABILITY FOR USE OF THIS CODE + IN VIOLATION OF APPLICABLE PATENT LAW. + + + Shrinking is basically a dynamic LZW algorithm with allowed code sizes of + up to 13 bits; in addition, there is provision for partial clearing of + leaf nodes. PKWARE uses the special code 256 (decimal) to indicate a + change in code size or a partial clear of the code tree: 256,1 for the + former and 256,2 for the latter. [Note that partial clearing can "orphan" + nodes: the parent-to-be can be cleared before its new child is added, + but the child is added anyway (as an orphan, as though the parent still + existed). When the tree fills up to the point where the parent node is + reused, the orphan is effectively "adopted." Versions prior to 1.05 were + affected more due to greater use of pointers (to children and siblings + as well as parents).] + + This replacement version of unshrink.c was written from scratch. It is + based only on the algorithms described in Mark Nelson's _The Data Compres- + sion Book_ and in Terry Welch's original paper in the June 1984 issue of + IEEE _Computer_; no existing source code, including any in Nelson's book, + was used. + + Memory requirements have been reduced in this version and are now no more + than the original Sam Smith code. This is still larger than any of the + other algorithms: at a minimum, 8K+8K+16K (stack+values+parents) assuming + 16-bit short ints, and this does not even include the output buffer (the + other algorithms leave the uncompressed data in the work area, typically + called slide[]). For machines with a 64KB data space this is a problem, + particularly when text conversion is required and line endings have more + than one character. UnZip's solution is to use two roughly equal halves + of outbuf for the ASCII conversion in such a case; the "unshrink" argument + to flush() signals that this is the case. + + For large-memory machines, a second outbuf is allocated for translations, + but only if unshrinking and only if translations are required. + + | binary mode | text mode + --------------------------------------------------- + big mem | big outbuf | big outbuf + big outbuf2 <- malloc'd here + small mem | small outbuf | half + half small outbuf + + Copyright 1994, 1995 Greg Roelofs. See the accompanying file "COPYING" + in UnZip 5.20 (or later) source or binary distributions. + + ---------------------------------------------------------------------------*/ + + +#define __UNSHRINK_C /* identifies this source module */ +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" + + +#ifndef LZW_CLEAN + +static void partial_clear OF((__GPRO__ int lastcodeused)); + +#ifdef DEBUG +# define OUTDBG(c) \ + if ((c)<32 || (c)>=127) fprintf(stderr,"\\x%02x",(c)); else putc((c),stderr); +#else +# define OUTDBG(c) +#endif + +/* HSIZE is defined as 2^13 (8192) in unzip.h (resp. unzpriv.h */ +#define BOGUSCODE 256 +#define FLAG_BITS parent /* upper bits of parent[] used as flag bits */ +#define CODE_MASK (HSIZE - 1) /* 0x1fff (lower bits are parent's index) */ +#define FREE_CODE HSIZE /* 0x2000 (code is unused or was cleared) */ +#define HAS_CHILD (HSIZE << 1) /* 0x4000 (code has a child--do not clear) */ + +#define parent G.area.shrink.Parent +#define Value G.area.shrink.value /* "value" conflicts with Pyramid ioctl.h */ +#define stack G.area.shrink.Stack + + +/***********************/ +/* Function unshrink() */ +/***********************/ + +int unshrink(__G) + __GDEF +{ + uch *stacktop = stack + (HSIZE - 1); + register uch *newstr; + uch finalval; + int codesize=9, len, error; + shrint code, oldcode, curcode; + shrint lastfreecode; + unsigned int outbufsiz; +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + /* Normally realbuf and outbuf will be the same. However, if the data + * are redirected to a large memory buffer, realbuf will point to the + * new location while outbuf will remain pointing to the malloc'd + * memory buffer. */ + uch *realbuf = G.outbuf; +#else +# define realbuf G.outbuf +#endif + + +/*--------------------------------------------------------------------------- + Initialize various variables. + ---------------------------------------------------------------------------*/ + + lastfreecode = BOGUSCODE; + +#ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */ +#ifndef SMALL_MEM + /* non-memory-limited machines: allocate second (large) buffer for + * textmode conversion in flush(), but only if needed */ + if (G.pInfo->textmode && !G.outbuf2 && + (G.outbuf2 = (uch *)malloc(TRANSBUFSIZ)) == (uch *)NULL) + return PK_MEM3; +#endif +#endif /* !VMS */ + + for (code = 0; code < BOGUSCODE; ++code) { + Value[code] = (uch)code; + parent[code] = BOGUSCODE; + } + for (code = BOGUSCODE+1; code < HSIZE; ++code) + parent[code] = FREE_CODE; + +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) { /* use normal outbuf unless we're a DLL routine */ + realbuf = G.redirect_buffer; + outbufsiz = (unsigned)G.redirect_size; + } else +#endif +#ifdef DLL + if (G.pInfo->textmode && !G.redirect_data) +#else + if (G.pInfo->textmode) +#endif + outbufsiz = RAWBUFSIZ; + else + outbufsiz = OUTBUFSIZ; + G.outptr = realbuf; + G.outcnt = 0L; + +/*--------------------------------------------------------------------------- + Get and output first code, then loop over remaining ones. + ---------------------------------------------------------------------------*/ + + READBITS(codesize, oldcode) + if (G.zipeof) + return PK_OK; + + finalval = (uch)oldcode; + OUTDBG(finalval) + *G.outptr++ = finalval; + ++G.outcnt; + + while (TRUE) { + READBITS(codesize, code) + if (G.zipeof) + break; + if (code == BOGUSCODE) { /* possible to have consecutive escapes? */ + READBITS(codesize, code) + if (G.zipeof) + break; + if (code == 1) { + ++codesize; + Trace((stderr, " (codesize now %d bits)\n", codesize)); + if (codesize > MAX_BITS) return PK_ERR; + } else if (code == 2) { + Trace((stderr, " (partial clear code)\n")); + /* clear leafs (nodes with no children) */ + partial_clear(__G__ lastfreecode); + Trace((stderr, " (done with partial clear)\n")); + lastfreecode = BOGUSCODE; /* reset start of free-node search */ + } + continue; + } + + /*----------------------------------------------------------------------- + Translate code: traverse tree from leaf back to root. + -----------------------------------------------------------------------*/ + + newstr = stacktop; + curcode = code; + + if (parent[code] == FREE_CODE) { + /* or (FLAG_BITS[code] & FREE_CODE)? */ + Trace((stderr, " (found a KwKwK code %d; oldcode = %d)\n", code, + oldcode)); + *newstr-- = finalval; + code = oldcode; + } + + while (code != BOGUSCODE) { + if (newstr < stack) { + /* Bogus compression stream caused buffer underflow! */ + Trace((stderr, "unshrink stack overflow!\n")); + return PK_ERR; + } + if (parent[code] == FREE_CODE) { + /* or (FLAG_BITS[code] & FREE_CODE)? */ + Trace((stderr, " (found a KwKwK code %d; oldcode = %d)\n", + code, oldcode)); + *newstr-- = finalval; + code = oldcode; + } else { + *newstr-- = Value[code]; + code = (shrint)(parent[code] & CODE_MASK); + } + } + + len = (int)(stacktop - newstr++); + finalval = *newstr; + + /*----------------------------------------------------------------------- + Write expanded string in reverse order to output buffer. + -----------------------------------------------------------------------*/ + + Trace((stderr, + "code %4d; oldcode %4d; char %3d (%c); len %d; string [", curcode, + oldcode, (int)(*newstr), (*newstr<32 || *newstr>=127)? ' ':*newstr, + len)); + + { + register uch *p; + + for (p = newstr; p < newstr+len; ++p) { + *G.outptr++ = *p; + OUTDBG(*p) + if (++G.outcnt == outbufsiz) { + Trace((stderr, "doing flush(), outcnt = %lu\n", G.outcnt)); + if ((error = flush(__G__ realbuf, G.outcnt, TRUE)) != 0) { + Trace((stderr, "unshrink: flush() error (%d)\n", + error)); + return error; + } + G.outptr = realbuf; + G.outcnt = 0L; + Trace((stderr, "done with flush()\n")); + } + } + } + + /*----------------------------------------------------------------------- + Add new leaf (first character of newstr) to tree as child of oldcode. + -----------------------------------------------------------------------*/ + + /* search for freecode */ + code = (shrint)(lastfreecode + 1); + /* add if-test before loop for speed? */ + while ((code < HSIZE) && (parent[code] != FREE_CODE)) + ++code; + lastfreecode = code; + Trace((stderr, "]; newcode %d\n", code)); + if (code >= HSIZE) + /* invalid compressed data caused max-code overflow! */ + return PK_ERR; + + Value[code] = finalval; + parent[code] = oldcode; + oldcode = curcode; + + } + +/*--------------------------------------------------------------------------- + Flush any remaining data and return to sender... + ---------------------------------------------------------------------------*/ + + if (G.outcnt > 0L) { + Trace((stderr, "doing final flush(), outcnt = %lu\n", G.outcnt)); + if ((error = flush(__G__ realbuf, G.outcnt, TRUE)) != 0) { + Trace((stderr, "unshrink: flush() error (%d)\n", error)); + return error; + } + Trace((stderr, "done with flush()\n")); + } + + return PK_OK; + +} /* end function unshrink() */ + + + + + +/****************************/ +/* Function partial_clear() */ /* no longer recursive... */ +/****************************/ + +static void partial_clear(__G__ lastcodeused) + __GDEF + int lastcodeused; +{ + register shrint code; + + /* clear all nodes which have no children (i.e., leaf nodes only) */ + + /* first loop: mark each parent as such */ + for (code = BOGUSCODE+1; code <= lastcodeused; ++code) { + register shrint cparent = (shrint)(parent[code] & CODE_MASK); + + if (cparent > BOGUSCODE) + FLAG_BITS[cparent] |= HAS_CHILD; /* set parent's child-bit */ + } + + /* second loop: clear all nodes *not* marked as parents; reset flag bits */ + for (code = BOGUSCODE+1; code <= lastcodeused; ++code) { + if (FLAG_BITS[code] & HAS_CHILD) /* just clear child-bit */ + FLAG_BITS[code] &= ~HAS_CHILD; + else { /* leaf: lose it */ + Trace((stderr, "%d\n", code)); + parent[code] = FREE_CODE; + } + } + + return; +} + +#endif /* !LZW_CLEAN */ diff --git a/third_party/unzip/unxcfg.h b/third_party/unzip/unxcfg.h new file mode 100644 index 000000000..cce015473 --- /dev/null +++ b/third_party/unzip/unxcfg.h @@ -0,0 +1,238 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 +#include "libc/calls/struct/stat.h" +#include "libc/sysv/consts/o.h" +#include "libc/str/str.h" +#include "libc/time/time.h" +#include "libc/calls/weirdtypes.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 */ + + + +#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 +#else /* COHERENT */ +# ifdef _I386 +# else +# 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 +# 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__ +# define DIRENT +# define HAVE_TERMIOS_H +# ifndef timezone +# define timezone _timezone +# endif +#endif + +#if (defined(BSD4_4) || (defined(SYSV) && defined(MODERN))) +# if (defined(BSD4_4) || defined(linux) || defined(__GLIBC__)) +# define GOT_UTIMBUF +# endif +# if (!defined(GOT_UTIMBUF) && (defined(__hpux) || defined(__SUNPRO_C))) +# define GOT_UTIMBUF +# endif +# if (!defined(GOT_UTIMBUF) && defined(__GNU__)) +# define GOT_UTIMBUF +# endif +#endif +#if (defined(__DGUX__) && !defined(GOT_UTIMBUF)) + /* DG/UX requires this because of a non-standard struct utimebuf */ +# 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 */ +# 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 +#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(). */ + + +#ifdef USE_ICONV_MAPPING +# define MAX_CP_NAME 25 + +# ifdef SETLOCALE +# undef SETLOCALE +# endif +# define SETLOCALE(category, locale) setlocale(category, locale) + +# 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 /* USE_ICONV_MAPPING */ + +#endif /* !__unxcfg_h */ diff --git a/third_party/unzip/unzip.c b/third_party/unzip/unzip.c new file mode 100644 index 000000000..ce77acbcb --- /dev/null +++ b/third_party/unzip/unzip.c @@ -0,0 +1,4869 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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. (Some of this information is outdated and needs to be + updated.) + + 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 "third_party/unzip/unzip.h" /* includes, typedefs, macros, prototypes, etc. */ +#include "third_party/unzip/crypt.h" +#include "libc/log/log.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "third_party/unzip/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_options OF((__GPRO)); +static void show_version_info OF((__GPRO)); +# endif +static void show_license OF((__GPRO)); + + +/*************/ +/* Constants */ +/*************/ + +#include "third_party/unzip/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 */ +static ZCONST char Far NoMemArgsList[] = + "error: no memory for arguments list"; + +# 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 -M pipe through \"more\" pager\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 __APPLE__ +# ifdef MORE + static ZCONST char Far local3[] = "\ + -K keep setuid/setgid/tacky permissions -M pipe through \"more\" pager\n\ + -J No special AppleDouble file handling\n"; +# else + static ZCONST char Far local3[] = "\ + -K keep setuid/setgid/tacky permissions -J No spec'l AplDbl file handling\ +\n"; +# endif +# else /* def __APPLE__ */ +# 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 +# endif /* def __APPLE__ [else] */ +# 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 + static ZCONST char Far UnzipSFXOpts2[] = + "For license info: \"--license\".\n"; +# 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 (-B creates backup files)"; +# 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 WIN32_WIDE + static ZCONST char Far Use_Win32_Wide[] = "WIN32_WIDE (wide characters supported)"; +# endif +# 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\" for more help. \"unzip --license\" for license. 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 */ + + 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. + */ + /* On openSUSE 11.3 it appears that the console is UTF-8 aware by + * default. Makes using UTF-8 aware console applications, like + * UnZip, easy. Supplying UTF-8 arguments seems to work correctly, + * allowing input patterns to include Japanese directly, for instance. + */ + } +# 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; + +# ifdef WIN32_WIDE + G.has_win32_wide = has_win32_wide(); +# endif + +# endif /* UNICODE_SUPPORT */ + + +#ifdef USE_ICONV_MAPPING +# ifdef UNIX + init_conversion_charsets(); +# endif +#endif /* USE_ICONV_MAPPING */ + +# 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 */ + if (error) { + /* Parsing error message already emitted. + * Leave a blank line, and add the (brief) SFX usage message. + */ + Info(slide, 0x401, ((char *)slide, "\n")); + USAGE( error); + } + +# 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; 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 */ + +# if 0 +/* G.wildzipfn now set in command line switch as first non-option argument */ +# ifndef SFX + G.wildzipfn = *argv++; +# endif +# endif + +# if (defined(SFX) && !defined(SFX_EXDIR)) /* only check for -x */ + +# if 0 + /* all this should be done in the options call now */ + + + 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 */ +# endif + +# else /* !SFX || SFX_EXDIR */ /* check for -x or -d */ + +# if 0 + /* all this should be done in the options call now */ + + 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 */ +# endif /* 0 */ + + 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 + +#if defined( UNIX) && defined( __APPLE__) + /* Set flag according to the capabilities of the destination volume. */ + G.exdir_attr_ok = vol_attr_ok( (uO.exdir == NULL) ? "." : uO.exdir); +#endif /* defined( UNIX) && defined( __APPLE__) */ + +/*--------------------------------------------------------------------------- + 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 */ + + + +/* + ------------------------------------------------------- + Command Line Options + ------------------------------------------------------- + + Valid command line options. + + The function get_option() uses this table to check if an + option is valid and if it takes a value (also called an + option parameter). To add an option to unzip just add it + to this table and add a case in the main switch to handle + it. If either shortopt or longopt not used set to "". + + The fields: + option_group - UZO for UnZip option, ZIO for ZipInfo option + shortopt - short option name (1 or 2 chars) + longopt - long option name + value_type - see zip.h for constants + negatable - option is negatable with trailing - + ID - unsigned long int returned for option + name - short description of option which is + returned on some errors and when options + are listed with -so option, can be NULL +*/ + +/* Most option IDs are set to the shortopt char. For + multichar short options set to arbitrary unused constant. */ +#define o_hh 0x101 +#define o_LI 0x102 +#define o_sc 0x103 +#define o_so 0x104 + + +/* The below is from the old main command line code with a few changes. + Note that UnZip and ZipInfo filter out their own options based on the + option_group value, so the same option letter can be used for both. */ + +static struct option_struct far options[] = { + + /* UnZip options */ + + /* short longopt value_type negatable + ID name */ +# ifdef RISCOS + {UZO, "/", "extensions", o_REQUIRED_VALUE, o_NEGATABLE, + '/', "override Unzip$Exts"}, +# endif + {UZO, "a", "ASCII", o_NO_VALUE, o_NEGATABLE, + 'a', "text convert (EOL char, ASCII->EBCDIC)"}, +# if (defined(DLL) && defined(API_DOC)) + {UZO, "A", "api-help", o_NO_VALUE, o_NEGATABLE, + 'A', "extended help for API"}, +# endif + {UZO, "b", "binary", o_NO_VALUE, o_NEGATABLE, + 'b', "binary, no ASCII conversions"}, +# ifdef UNIXBACKUP + {UZO, "B", "backup", o_NO_VALUE, o_NEGATABLE, + 'B', "back up existing files"}, +# endif +# ifdef CMS_MVS + {UZO, "B", "CMS-MVS-binary", o_NO_VALUE, o_NEGATABLE, + 'b', "CMS/MVS binary"}, +# endif + {UZO, "c", "to-stdout", o_NO_VALUE, o_NEGATABLE, + 'c', "output to stdout"}, +# ifdef CMS_MVS + /* for CMS_MVS map to lower case */ + {UZO, "C", "CMS-MVS-lower", o_NO_VALUE, o_NEGATABLE, + 'C', "CMS/MVS lower case"}, +# else /* ifdef CMS_MVS */ + {ZIO, "C", "ignore-case", o_NO_VALUE, o_NEGATABLE, + 'C', "ignore case"}, +# endif /* ifdef CMS_MVS [else] */ +# if (!defined(SFX) || defined(SFX_EXDIR)) + {UZO, "d", "extract-dir", o_REQUIRED_VALUE, o_NEGATABLE, + 'd', "extraction root directory"}, +# endif +# if (!defined(NO_TIMESTAMPS)) + {UZO, "D", "dir-timestamps", o_NO_VALUE, o_NEGATABLE, + 'D', "don't restore dir (-DD: any) timestamps"}, +# endif + {UZO, "e", "extract", o_NO_VALUE, o_NEGATABLE, + 'e', "extract (not used?)"}, +# ifdef MACOS + {UZO, "E", "Mac-efs", o_NO_VALUE, o_NEGATABLE, + 'E', "display Mac e.f. when restoring"}, +# endif + {UZO, "f", "freshen", o_NO_VALUE, o_NEGATABLE, + 'f', "freshen (extract only newer files)"}, +# if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) + {UZO, "F", "keep-NFS", o_NO_VALUE, o_NEGATABLE, + 'F', "Acorn filetype & NFS extension handling"}, +# endif + {UZO, "h", "help", o_NO_VALUE, o_NOT_NEGATABLE, + 'h', "help"}, + {UZO, "hh", "long-help", o_NO_VALUE, o_NOT_NEGATABLE, + o_hh, "long help"}, +# ifdef MACOS + {UZO, "i", "no-Mac-ef-names", o_NO_VALUE, o_NEGATABLE, + 'i', "ignore filenames stored in Mac ef"}, +# endif +#ifdef USE_ICONV_MAPPING +# ifdef UNIX + {UZO, "I", "ISO-char-set", o_REQUIRED_VALUE, o_NOT_NEGATABLE, + 'I', "ISO char set to use"}, +# endif +#endif + {UZO, "j", "junk-dirs", o_NO_VALUE, o_NEGATABLE, + 'j', "junk directories, extract names only"}, +# ifdef J_FLAG + {UZO, "J", "junk-attrs", o_NO_VALUE, o_NEGATABLE, + 'J', "Junk AtheOS, BeOS or MacOS file attrs"}, +# endif +# ifdef ATH_BEO_UNX + {UZO, "K", "keep-S-attrs", o_NO_VALUE, o_NEGATABLE, + 'K', "retain SUID/SGID/Tacky attrs"}, +# endif +# ifndef SFX + {UZO, "l", "long-list", o_NO_VALUE, o_NEGATABLE, + 'l', "listing verbosity"}, +# endif +# ifndef CMS_MVS + {UZO, "L", "lowercase-names", o_NO_VALUE, o_NEGATABLE, + 'L', "convert (some) names to lower"}, +# endif + {UZO, "", "license", o_NO_VALUE, o_NOT_NEGATABLE, + o_LI, "Info-ZIP license"}, +# ifdef MORE +# ifdef CMS_MVS + {UZO, "m", "more", o_NO_VALUE, o_NEGATABLE, + 'm', "pipe output through more"}, +# endif + {UZO, "M", "More", o_NO_VALUE, o_NEGATABLE, + 'M', "pipe output through more"}, +# endif /* MORE */ + {UZO, "n", "never-overwrite", o_NO_VALUE, o_NEGATABLE, + 'n', "never overwrite files (no prompting)"}, +# ifdef AMIGA + {UZO, "N", "comment-to-note", o_NO_VALUE, o_NEGATABLE, + 'N', "restore comments as filenotes"}, +# endif +#ifdef USE_ICONV_MAPPING +# ifdef UNIX + {UZO, "O", "OEM-char-set", o_REQUIRED_VALUE, o_NOT_NEGATABLE, + 'O', "OEM char set to use"}, +# endif +#endif + {UZO, "o", "overwrite", o_NO_VALUE, o_NEGATABLE, + 'o', "overwrite files without prompting"}, + {UZO, "p", "pipe-to-stdout", o_NO_VALUE, o_NEGATABLE, + 'p', "pipe extraction to stdout, no messages"}, +# if CRYPT + {UZO, "P", "password", o_REQUIRED_VALUE, o_NEGATABLE, + 'P', "password"}, +# endif + {UZO, "q", "quiet", o_NO_VALUE, o_NEGATABLE, + 'q', "quiet mode (additional q's => more quiet)"}, +# ifdef QDOS + {UZO, "Q", "QDOS", o_NO_VALUE, o_NEGATABLE, + 'Q', "QDOS flags"}, +# endif +# ifdef TANDEM + {UZO, "r", "remove-exts", o_NO_VALUE, o_NEGATABLE, + 'r', "remove file extensions"}, +# endif +# ifdef DOS_FLX_NLM_OS2_W32 + {UZO, "s", "space_to_uscore", o_NO_VALUE, o_NEGATABLE, + 's', "spaces to underscores"}, +# endif +# ifdef VMS + {UZO, "S", "stream-LF", o_NO_VALUE, o_NEGATABLE, + 'S', "VMS extract text as Stream LF"}, +# endif +#ifndef SFX + {UZO, "", "commandline", o_NO_VALUE, o_NEGATABLE, + o_sc, "show processed command line and exit"}, + {UZO, "", "options", o_NO_VALUE, o_NEGATABLE, + o_so, "show available options on this system"}, +#endif /* ndef SFX */ + {UZO, "t", "test", o_NO_VALUE, o_NEGATABLE, + 't', "test archive"}, +# ifdef TIMESTAMP + {UZO, "T", "timestamp-new", o_NO_VALUE, o_NEGATABLE, + 'T', "timestamp archive same as newest file"}, +# endif + {UZO, "u", "update", o_NO_VALUE, o_NEGATABLE, + 'u', "update (extract only new/newer files)"}, +# ifdef UNICODE_SUPPORT + {UZO, "U", "Unicode", o_NO_VALUE, o_NEGATABLE, + 'U', "escape non-ASCII Unicode, disable Unicode"}, +# endif /* ?UNICODE_SUPPORT */ +# ifndef SFX + {UZO, "v", "verbose", o_NO_VALUE, o_NEGATABLE, + 'v', "verbose"}, +# endif +# ifndef CMS_MVS + {UZO, "V", "keep-vers-nums", o_NO_VALUE, o_NEGATABLE, + 'V', "don't strip VMS version numbers"}, +# endif +# ifdef WILD_STOP_AT_DIR + {UZO, "W", "wild-no-span", o_NO_VALUE, o_NEGATABLE, + 'W', "wildcard * doesn't span /"}, +# endif + {UZO, "x", "exclude", o_VALUE_LIST, o_NOT_NEGATABLE, + 'x', "exclude this list of files"}, +# if (defined(RESTORE_UIDGID) || defined(RESTORE_ACL)) + {UZO, "X", "restore-info", o_NO_VALUE, o_NEGATABLE, + 'X', "restore owner/prot or UID/GID or ACLs"}, +# endif +# ifdef VMS + {UZO, "Y", "dot-ver-as-sem", o_NO_VALUE, o_NEGATABLE, + 'Y', "VMS treat .nnn as ;nnn version"}, +# endif + {UZO, "z", "zipfile-comment", o_NO_VALUE, o_NEGATABLE, + 'z', "display zipfile comment"}, +# ifndef SFX + {UZO, "Z", "ZipInfo-mode", o_NO_VALUE, o_NOT_NEGATABLE, + 'Z', "ZipInfo mode"}, +# endif +# ifdef VMS + {UZO, "2", "force-ODS2", o_NO_VALUE, o_NEGATABLE, + '2', "Force ODS2-compliant names."}, +# endif +# ifdef DOS_H68_OS2_W32 + {UZO, "$", "volume-labels", o_NO_VALUE, o_NEGATABLE, + '$', "extract volume labels"}, +# endif +# if (!defined(RISCOS) && !defined(CMS_MVS) && !defined(TANDEM)) + {UZO, ":", "do-double-dots", o_NO_VALUE, o_NEGATABLE, + ':', "don't skip ../ path elements"}, +# endif +# ifdef UNIX + {UZO, "^", "control-in-name", o_NO_VALUE, o_NEGATABLE, + '^', "allow control chars in filenames"}, +# endif + +# ifndef NO_ZIPINFO + /* ZipInfo options */ + + /* short longopt value_type negatable + ID name (help text) */ + {ZIO, "1", "shortest-list", o_NO_VALUE, o_NEGATABLE, + '1', "shortest list"}, + {ZIO, "2", "names-headers", o_NO_VALUE, o_NEGATABLE, + '2', "names and headers"}, +# ifndef CMS_MVS + {ZIO, "C", "ignore-case", o_NO_VALUE, o_NEGATABLE, + 'C', "ignore case"}, +# endif + {ZIO, "h", "headers", o_NO_VALUE, o_NEGATABLE, + 'h', "header line"}, +# ifdef USE_ICONV_MAPPING +# ifdef UNIX + {ZIO, "I", "ISO-char-set", o_REQUIRED_VALUE, o_NOT_NEGATABLE, + 'I', "ISO charset to use"}, +# endif +# endif + {ZIO, "l", "long-list", o_NO_VALUE, o_NEGATABLE, + 'l', "longer listing"}, + {ZIO, "m", "medium-list", o_NO_VALUE, o_NEGATABLE, + 'm', "medium listing"}, +# ifdef MORE + {ZIO, "M", "more", o_NO_VALUE, o_NEGATABLE, + 'M', "output like more"}, +# endif +# ifdef USE_ICONV_MAPPING +# ifdef UNIX + {ZIO, "O", "OEM-char-set", o_REQUIRED_VALUE, o_NOT_NEGATABLE, + 'O', "OEM charset to use"}, +# endif +# endif + {ZIO, "s", "shorter-list", o_NO_VALUE, o_NEGATABLE, + 's', "shorter list"}, +# ifndef SFX + {ZIO, "", "commandline", o_NO_VALUE, o_NEGATABLE, + o_sc, "show processed command line and exit"}, + {ZIO, "", "options", o_NO_VALUE, o_NEGATABLE, + o_so, "show available options on this system"}, +# endif /* ndef SFX */ + {ZIO, "t", "totals-line", o_NO_VALUE, o_NEGATABLE, + 't', "totals line"}, + {ZIO, "T", "decimal-time", o_NO_VALUE, o_NEGATABLE, + 'T', "decimal time format"}, +# ifdef UNICODE_SUPPORT + {ZIO, "U", "Unicode", o_NO_VALUE, o_NEGATABLE, + 'U', "escape non-ASCII Unicode, disable Unicode"}, +# endif + {ZIO, "v", "verboselist", o_NO_VALUE, o_NEGATABLE, + 'v', "turbo-verbose listing"}, +# ifdef WILD_STOP_AT_DIR + {ZIO, "W", "wild-dir-parts", o_NO_VALUE, o_NEGATABLE, + 'W', "wild stop at /"}, +# endif + {ZIO, "x", "exclude", o_VALUE_LIST, o_NOT_NEGATABLE, + 'x', "exclude this list of files"}, + {ZIO, "z", "zipfile-comment", o_NO_VALUE, o_NEGATABLE, + 'z', "print zipfile comment"}, + {ZIO, "Z", "ZipInfo-mode", o_NO_VALUE, o_NEGATABLE, + 'Z', "ZipInfo mode"}, +# endif /* !NO_ZIPINFO */ + + /* the end of the list */ + {0, NULL, NULL, o_NO_VALUE, o_NOT_NEGATABLE, + 0, NULL} /* end has option_ID = 0 */ + }; + + + + +/**********************/ +/* Function uz_opts() */ +/**********************/ + +int uz_opts(__G__ pargc, pargv) + __GDEF + int *pargc; + char ***pargv; +{ + char **args; + int argc, error=FALSE, showhelp=0; + + /* used by get_option */ + unsigned long option; /* option ID returned by get_option */ + int argcnt = 0; /* current argcnt in args */ + int argnum = 0; /* arg number */ + int optchar = 0; /* option state */ + char *value = NULL; /* non-option arg, option value or NULL */ + int negative = 0; /* 1 = option negated */ + int fna = 0; /* current first non-opt arg */ + int optnum = 0; /* index in table */ + +# ifdef USE_ICONV_MAPPING +# ifdef UNIX + extern char OEM_CP[MAX_CP_NAME]; + extern char ISO_CP[MAX_CP_NAME]; +# endif +# endif + + + /* since get_option() returns xfiles and files one at a time, store them + in linked lists until have them all */ + + int file_count = 0; + struct file_list *next_file; + + /* files to extract */ + int in_files_count = 0; + struct file_list *in_files = NULL; + struct file_list *next_in_files = NULL; + + /* files to exclude in -x list */ + int in_xfiles_count = 0; + struct file_list *in_xfiles = NULL; + struct file_list *next_in_xfiles = NULL; + + G.wildzipfn = NULL; + + /* make copy of args that can use with insert_arg() used by get_option() */ + args = copy_args(__G__ *pargv, 0); + + + /* Initialize lists */ + G.filespecs = 0; + G.xfilespecs = 0; + + + /* + ------------------------------------------- + Process command line using get_option + ------------------------------------------- + + Each call to get_option() returns either a command + line option and possible value or a non-option argument. + Arguments are permuted so that all options (-r, -b temp) + are returned before non-option arguments (zipfile). + Returns 0 when nothing left to read. + */ + + /* set argnum = 0 on first call to init get_option */ + argnum = 0; + + /* get_option returns the option ID and updates parameters: + args - usually same as argv if no argument file support + argcnt - current argc for args + value - char* to value (free() when done with it) or NULL if none + negated - option was negated with trailing - + */ + + while ((option = get_option(__G__ UZO, &args, &argcnt, &argnum, + &optchar, &value, &negative, + &fna, &optnum, 0))) + { + if(option == o_BAD_ERR) { + return(PK_PARAM); + } + + switch (option) + { +# 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 = value; /* override Unzip$Exts */ + break; +# endif + case ('a'): + if (negative) { + uO.aflag = MAX(uO.aflag-negative,0); + } else + ++uO.aflag; + break; +# if (defined(DLL) && defined(API_DOC)) + case ('A'): /* extended help for API */ + APIhelp(__G__ argc, args); + *pargc = -1; /* signal to exit successfully */ + return 0; +# endif + case ('b'): + if (negative) { +# if (defined(TANDEM) || defined(VMS)) + /* AS negative IS ALWAYS 1, IS THIS RIGHT? */ + uO.bflag = MAX(uO.bflag-negative,0); +# endif + /* 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; + else + uO.B_flag = TRUE; + break; +# endif + case ('c'): + if (negative) { + uO.cflag = FALSE; +# 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 = value; + if (uO.exdir == NULL || *uO.exdir == '\0') { + Info(slide, 0x401, ((char *)slide, + LoadFarString(MustGiveExdir))); + return(PK_PARAM); /* don't extract here by accident */ + } + /* else uO.exdir points at extraction dir */ + } + 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) { + showhelp = 1; + } + break; +# ifndef SFX + case (o_hh): /* just print long help message and quit */ + if (showhelp == 0) { + showhelp = 2; + } + break; +# endif /* !SFX */ +# ifdef MACOS + case ('i'): /* -i [MacOS] ignore filenames stored in Mac ef */ + if( negative ) { + uO.i_flag = FALSE; + } else { + uO.i_flag = TRUE; + } + break; +# endif /* MACOS */ +# ifdef USE_ICONV_MAPPING +# ifdef UNIX + case ('I'): /* -I [UNIX] ISO char set of input entries */ + strncpy(ISO_CP, value, sizeof(ISO_CP)); + free(value); + break; +# endif +# endif + case ('j'): /* junk pathnames/directory structure */ + if (negative) + uO.jflag = FALSE; + else + uO.jflag = TRUE; + break; +#ifdef J_FLAG + case ('J'): /* Junk AtheOS, BeOS or MacOS file attributes */ + if( negative ) { + uO.J_flag = FALSE; + } else { + uO.J_flag = TRUE; + } + break; +# endif /* def J_FLAG */ +# ifdef ATH_BEO_UNX + case ('K'): + if (negative) { + uO.K_flag = FALSE; + } 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-1,0); + } else + ++uO.L_flag; + break; +# endif /* !CMS_MVS */ + case (o_LI): /* show license */ + showhelp = -1; + break; +# 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; + else + G.M_flag = TRUE; + break; +# endif /* MORE */ + case ('n'): /* don't overwrite any files */ + if (negative) + uO.overwrite_none = FALSE; + else + uO.overwrite_none = TRUE; + break; +# ifdef AMIGA + case ('N'): /* restore comments as filenotes */ + if (negative) + uO.N_flag = FALSE; + 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; +# ifdef USE_ICONV_MAPPING +# ifdef UNIX + case ('O'): /* -O [UNIX] OEM char set of input entries */ + strncpy(OEM_CP, value, sizeof(OEM_CP)); + free(value); + break; +# endif +# endif + 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 = value; + if (uO.pwdarg == NULL || *uO.pwdarg == '\0') { + Info(slide, 0x401, ((char *)slide, + LoadFarString(MustGivePasswd))); + return(PK_PARAM); + } + /* else pwdarg points at decryption password */ + } + 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(value, &value, 10); + break; /* we XOR this as we can config qlflags */ +# endif +# ifdef TANDEM + case ('r'): /* remove file extensions */ + if (negative) + uO.rflag = FALSE; + 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; + else + uO.sflag = TRUE; + break; +# endif /* DOS_FLX_NLM_OS2_W32 */ +# ifndef SFX + case (o_sc): /* show processed command line and exit */ + showhelp = -3; + break; + case (o_so): /* show available options on this system */ + showhelp = -2; + break; +# endif +# ifdef VMS + /* VMS: extract "text" files in Stream_LF format (-a[a]) */ + case ('S'): + if (negative) + uO.S_flag = FALSE; + else + uO.S_flag = TRUE; + break; +# endif /* VMS */ + case ('t'): + if (negative) + uO.tflag = FALSE; + else + uO.tflag = TRUE; + break; +# ifdef TIMESTAMP + case ('T'): + if (negative) + uO.T_flag = FALSE; + else + uO.T_flag = TRUE; + break; +# endif + case ('u'): /* update (extract only new and newer files) */ + if (negative) + uO.uflag = FALSE; + 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 - 1, 0); + else + uO.U_flag++; + break; +# 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; + 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; + else + uO.W_flag = TRUE; + break; +# endif /* WILD_STOP_AT_DIR */ + case ('x'): /* extract: default */ + /* add -x file to linked list */ + + if (in_xfiles_count == 0) { + /* first entry */ + if ((in_xfiles = (struct file_list *) + malloc(sizeof(struct file_list)) + ) == NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(NoMemArgsList))); + return PK_MEM; + } + in_xfiles->name = value; + in_xfiles->next = NULL; + next_in_xfiles = in_xfiles; + } else { + /* add next entry */ + if ((next_file = (struct file_list *) + malloc(sizeof(struct file_list)) + ) == NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(NoMemArgsList))); + return PK_MEM; + } + next_in_xfiles->next = next_file; + next_file->name = value; + next_file->next = NULL; + next_in_xfiles = next_file; + } + in_xfiles_count++; + +# if 0 +# ifdef SFX + /* now get -x list one entry at a time */ + + + + /* 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 */ +# endif + 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, -1); + 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; + 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 */ + case o_NON_OPTION_ARG: + /* not an option */ + /* no more options as permuting */ + + + if (G.wildzipfn == NULL) { + /* first non-option argument is zip file */ + G.wildzipfn = value; + + } else { + /* add include file to list */ + if (in_files_count == 0) { + /* first entry */ + if ((next_file = (struct file_list *) + malloc(sizeof(struct file_list)) + ) == NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(NoMemArgsList))); + return PK_MEM; + } + next_file->name = value; + next_file->next = NULL; + in_files = next_file; + next_in_files = next_file; + } else { + /* add next entry */ + if ((next_file = (struct file_list *) + malloc(sizeof(struct file_list)) + ) == NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(NoMemArgsList))); + return PK_MEM; + } + next_in_files->next = next_file; + next_file->name = value; + next_file->next = NULL; + next_in_files = next_file; + } + in_files_count++; + } + break; + default: + error = TRUE; + break; + + } /* end switch */ + } /* get_option() */ + + + /* convert files and xfiles lists to arrays */ + + /* convert files list to array */ + if (in_files_count) { + if ((G.pfnames = (char **) malloc((in_files_count + 1) * sizeof(char *)) + ) == NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArgsList))); + return PK_MEM; + } + file_count = 0; + for (next_file = in_files; next_file;) { + G.pfnames[file_count] = next_file->name; + in_files = next_file; + next_file = next_file->next; + free(in_files); + file_count++; + } + G.pfnames[file_count] = NULL; + G.filespecs = in_files_count; + } + + /* convert xfiles list to array */ + if (in_xfiles_count) { + if ((G.pxnames = (char **) malloc((in_xfiles_count + 1) * sizeof(char *)) + ) == NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArgsList))); + return PK_MEM; + } + file_count = 0; + for (next_file = in_xfiles; next_file;) { + G.pxnames[file_count] = next_file->name; + in_xfiles = next_file; + next_file = next_file->next; + free(in_xfiles); + file_count++; + } + G.pxnames[file_count] = NULL; + G.xfilespecs = in_xfiles_count; + } + + if (in_files_count || in_xfiles_count) { + G.process_all_files = FALSE; + } else { + G.process_all_files = TRUE; /* for speed */ + } + + + /* it's possible the arg count could have been changed by get_option() */ + argc = arg_count(args); + + + +/*--------------------------------------------------------------------------- + Check for nonsensical combinations of options. + ---------------------------------------------------------------------------*/ + + 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 (showhelp == 0 && ((G.wildzipfn == NULL) || error)) +# endif + { + /* tell caller to exit */ + if (argc <= 2) + argc = -1; + + *pargc = argc; + *pargv = args; +# 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); + } + +#if 0 /* Duplicate below. */ +# 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 */ +#endif /* 0 Duplicate below. */ + + if (uO.cflag || uO.tflag || uO.vflag || uO.zflag +# ifdef TIMESTAMP + || uO.T_flag +# endif + ) + G.extract_flag = FALSE; + else + G.extract_flag = TRUE; + +# if 0 +# ifdef SFX +opts_done: /* yes, very ugly...but only used by UnZipSFX with -x xlist */ +# endif /* def SFX */ +# endif /* 0 */ + + 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); + } + } else if (showhelp == -1) { + *pargc = -1; + show_license(__G); + return PK_OK; +# ifndef SFX + } else if (showhelp == -2) { + /* show available options */ + *pargc = -1; + show_options(__G); + return PK_OK; + } else if (showhelp == -3) { + /* show command line args */ + *pargc = -1; + show_commandline(__G__ args); + return PK_OK; +# endif /* ndef SFX */ + } + + 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 = args; +# 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 = args; + 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)); + Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXOpts2))); +# 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 6.1 uses a new command parser which supports long options. Short", + "options begin with a single dash (-h), while long options start with two", + "(--help). Long options can be abbreviated as long as still unique.", + "", + "Option negation now uses trailing dash. So -B turns on backup and -B-", + "turns it off. Using long options, --backup turns on backup and --backup-", + "turns it off. Options later in command line override those earlier.", + "\"unzip --options\" will show all options and which can be negated.", + "", + "UnZip now allows most options to appear anywhere in the command line.", + "An exception is xfile list, which still must be last unless list is", + "terminated by \"@\" argument as in \"-x f1 f2 f3 @ -B\".", + "", + "", + "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.", +#ifdef USE_ICONV_MAPPING + " -I [UNIX] ISO code page to use.", +#endif + " -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.", +#ifdef USE_ICONV_MAPPING + " -O [UNIX] OEM code page to use.", +#endif + " -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.", + "", + " --commandline Show the processed command line and exit.", + "", + "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 and character set conversions:", + " If compiled with Unicode support, unzip automatically handles archives", + " with Unicode entries. On ports where UTF-8 is not the native character", + " set, characters not in current encoding are shown as ASCII escapes in", + " form #Uxxxx or #Lxxxxxx where x is ASCII character for hex digit.", + " Though modern UNIX consoles support full UTF-8, some older console", + " displays may be limited to a specific code page. Either way full UTF-8", + " paths are generally restored on extraction where OS supports. Use -U", + " to force use of escapes in extracted names. Use -UU to totally ignore", + " Unicode. Unicode comments not yet fully supported.", + "", + " \"New\" options -I and -O (from a patch that has been out there awhile)", + " are used on UNIX to set the ISO and OEM code pages used for conversions.", + "", + "", + "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.", +#ifdef USE_ICONV_MAPPING + " -I [UNIX] ISO code page to use.", + " -O [UNIX] OEM code page to use.", +#endif + "", + "", + "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() */ + +# endif /* !SFX */ + +/* Print license to stdout. */ +static void show_license(__G) + __GDEF +{ + extent i; /* counter for license array */ + + /* license array */ + static ZCONST char *text[] = { + "Copyright (c) 1990-2010 Info-ZIP. All rights reserved.", + "", + "This is version 2009-Jan-02 of the Info-ZIP license.", + "", + "For the purposes of this copyright and license, \"Info-ZIP\" is defined as", + "the following set of individuals:", + "", + " Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,", + " Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,", + " Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,", + " David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,", + " Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,", + " Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,", + " Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,", + " Rich Wales, Mike White", + "", + "This software is provided \"as is,\" without warranty of any kind, express", + "or implied. In no event shall Info-ZIP or its contributors be held liable", + "for any direct, indirect, incidental, special or consequential damages", + "arising out of the use of or inability to use this software.", + "", + "Permission is granted to anyone to use this software for any purpose,", + "including commercial applications, and to alter it and redistribute it", + "freely, subject to the above disclaimer and the following restrictions:", + "", + " 1. Redistributions of source code (in whole or in part) must retain", + " the above copyright notice, definition, disclaimer, and this list", + " of conditions.", + "", + " 2. Redistributions in binary form (compiled executables and libraries)", + " must reproduce the above copyright notice, definition, disclaimer,", + " and this list of conditions in documentation and/or other materials", + " provided with the distribution. Additional documentation is not needed", + " for executables where a command line license option provides these and", + " a note regarding this option is in the executable's startup banner. The", + " sole exception to this condition is redistribution of a standard", + " UnZipSFX binary (including SFXWiz) as part of a self-extracting archive;", + " that is permitted without inclusion of this license, as long as the", + " normal SFX banner has not been removed from the binary or disabled.", + "", + " 3. Altered versions--including, but not limited to, ports to new operating", + " systems, existing ports with new graphical interfaces, versions with", + " modified or added functionality, and dynamic, shared, or static library", + " versions not from Info-ZIP--must be plainly marked as such and must not", + " be misrepresented as being the original source or, if binaries,", + " compiled from the original source. Such altered versions also must not", + " be misrepresented as being Info-ZIP releases--including, but not", + " limited to, labeling of the altered versions with the names \"Info-ZIP\"", + " (or any variation thereof, including, but not limited to, different", + " capitalizations), \"Pocket UnZip,\" \"WiZ\" or \"MacZip\" without the", + " explicit permission of Info-ZIP. Such altered versions are further", + " prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP", + " e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP", + " will provide support for the altered versions.", + "", + " 4. Info-ZIP retains the right to use the names \"Info-ZIP,\" \"Zip,\" \"UnZip,\"", + " \"UnZipSFX,\" \"WiZ,\" \"Pocket UnZip,\" \"Pocket Zip,\" and \"MacZip\" for its", + " own source and binary releases.", + "" + }; + + for (i = 0; i < sizeof(text)/sizeof(char *); i++) + { + Info(slide, 0, ((char *)slide, "%s\n", text[i])); + } +} /* end function show_license() */ + +# ifndef SFX + +/* Print available options. */ +static void show_options(__G) + __GDEF +{ + extent i; + int lolen; + char optiontext[200]; + char gr[4]; + char sh[7]; + char lo[80]; + char val_type[5]; + char neg[2]; + +#if 0 + struct option_struct { + int option_group; /* either UZO for UnZip or ZIO for ZipInfo syntax */ + char Far *shortopt; /* pointer to short option string */ + char Far *longopt; /* pointer to long option string */ + int value_type; /* from above */ + int negatable; /* from above */ + unsigned long option_ID; /* value returned by get_option when this option + is found */ + char Far *name; /* optional string for option returned on some + errors */ +#endif + + sprintf(optiontext, "Available options on this system"); + Info(slide, 0, ((char *)slide, "%s\n\n", optiontext)); + + sprintf(optiontext, "grp sh long val n description"); + Info(slide, 0, ((char *)slide, "%s\n", optiontext)); + + for (i = 0; options[i].option_ID != 0; i++) + { + if (options[i].option_group == UZO) + strcpy(gr, "UNZ"); + else if (options[i].option_group == ZIO) + strcpy(gr, "INF"); + else + strcpy(gr, "? "); + + strcpy(sh, options[i].shortopt); + strcat(sh, " "); + sh[2] = '\0'; + + strcpy(lo, options[i].longopt); + lolen = strlen(lo); + strcat(lo, " "); + if (lolen < 15) + lolen = 15; + lo[lolen] = '\0'; + + switch (options[i].value_type) { + case o_NO_VALUE: + strcpy(val_type, "none "); break; + case o_REQUIRED_VALUE: + strcpy(val_type, "requ "); break; + case o_OPTIONAL_VALUE: + strcpy(val_type, "optn "); break; + case o_VALUE_LIST: + strcpy(val_type, "list "); break; + case o_ONE_CHAR_VALUE: + strcpy(val_type, "char "); break; + case o_NUMBER_VALUE: + strcpy(val_type, "numb "); break; + default: + strcpy(val_type, "? "); + } + + if (options[i].negatable == 0) + strcpy(neg, "n"); + else if (options[i].negatable == 1) + strcpy(neg, "y"); + else + strcpy(neg, "?"); + + sprintf(optiontext, "%s %s %s %s %s %s", gr, sh, lo, val_type, + neg, options[i].name); + Info(slide, 0, ((char *)slide, "%s\n", optiontext)); + } +} /* end function show_options() */ + +/* Print processed command line. */ +void show_commandline(__G__ args) + char *args[]; +{ +#define MAX_CARG_LEN (WSIZE>>2) + extent i; + char *argtext = gc(malloc(MAX_CARG_LEN + 1)); + + Info(slide, 0, ((char *)slide, "%s\n\n", "Processed command line:")); + + for (i = 0; args[i]; i++) + { + if (strlen(args[i]) > MAX_CARG_LEN - 6) { + /* If arg too big, truncate it and add ... to end. + We are just displaying the args and exiting. */ + args[i][MAX_CARG_LEN - 6] = '\0'; + strcat(args[i], " ..."); + } + sprintf(argtext, "\"%s\"", args[i]); + Info(slide, 0, ((char *)slide, "%s ", argtext)); + } + Info(slide, 0, ((char *)slide, "%s", "\n")); +} /* end function show_commandline() */ + + +# 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 WIN32_WIDE + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_Win32_Wide))); + ++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 */ + + + + + + +/*--------------------------------------------------------------- + * Long option support + * 8/23/2003 + * Updated 3/1/2008 to support UnZip + * + * Defines function get_option() to get and process the command + * line options and arguments from argv[]. The caller calls + * get_option() in a loop to get either one option and possible + * value or a non-option argument each loop. + * + * This version has been modified to work with UnZip and ZipInfo. + * the major changes are removing the error returns, instead + * passing back error codes for errors, and supporting separate + * groups of options for UnZip and ZipInfo and selecting the option + * group by an argument. + * + * This version does not include argument file support and can + * work directly on argv. The argument file code complicates things and + * it seemed best to leave it out for now. If argument file support + * (reading in command line arguments stored in a file and inserting into + * command line where @filename is found) is added later the arguments + * can change and a freeable copy of argv will be needed and can be + * created using copy_args in the left out code. + * + * Supports short and long options as defined in the array options[] + * in zip.c, multiple short options in an argument (like -jlv), long + * option abbreviation (like --te for --temp-file if --te unique), + * short and long option values (like -b filename or --temp-file filename + * or --temp-file=filename), optional and required values, option negation + * by trailing - (like -S- to not include hidden and system files in MSDOS), + * value lists (like -x a b c), argument permuting (returning all options + * and values before any non-option arguments), and argument files (where + * any non-option non-value argument in form @path gets substituted with + * the white space separated arguments in the text file at path). In this + * version argument file support has been removed to simplify development + * but may be added later. + * + * E. Gordon + */ + + +/* message output - char casts are needed to handle constants */ +#define oWARN(message) Info(slide, 0x401, ((char *)slide, (char *)message)) + + + +/* Although the below provides some support for multibyte characters + the proper thing to do may be to use wide characters and support + Unicode. May get to it soon. Wide support would likely require + the ability to convert the command line to wide strings, which most + modern OS should support now. EG + */ + +/* For now stay with multi-byte characters. May support wide characters + in Zip 3.1 and UnZip 6.1. + */ + +/* multibyte character set support + Multibyte characters use typically two or more sequential bytes + to represent additional characters than can fit in a single byte + character set. The code used here is based on the ANSI mblen function. */ +#define MB_CLEN(ptr) CLEN(ptr) +#define MB_NEXTCHAR(ptr) PREINCSTR(ptr) + + +/* constants */ + +/* function get_args_from_arg_file() can return this in depth parameter */ +#define ARG_FILE_ERR -1 + +/* internal settings for optchar */ +#define SKIP_VALUE_ARG -1 +#define THIS_ARG_DONE -2 +#define START_VALUE_LIST -3 +#define IN_VALUE_LIST -4 +#define NON_OPTION_ARG -5 +#define STOP_VALUE_LIST -6 +/* 7/25/04 EG */ +#define READ_REST_ARGS_VERBATIM -7 + + +/* global veriables */ + +int enable_permute = 1; /* yes - return options first */ +/* 7/25/04 EG */ +int doubledash_ends_options = 1; /* when -- what follows are not options */ + +/* buffer for error messages (this sizing is a guess but must hold 2 paths) */ +#define OPTIONERR_BUF_SIZE (80+ 2* PATH_MAX) +char optionerrbuf[OPTIONERR_BUF_SIZE + 1]; + +/* error messages */ +static ZCONST char Far op_not_neg_err[] = + "option %s not negatable\n"; +static ZCONST char Far op_req_val_err[] = + "option %s requires a value\n"; +static ZCONST char Far op_no_allow_val_err[] = + "option %s does not allow a value\n"; +static ZCONST char Far sh_op_not_sup_err[] = + "short option '%c' not supported\n"; +static ZCONST char Far oco_req_val_err[] = + "option %s requires one character value\n"; +static ZCONST char Far oco_no_mbc_err[] = + "option %s does not support multibyte values\n"; +static ZCONST char Far num_req_val_err[] = + "option %s requires number value\n"; +static ZCONST char Far long_op_ambig_err[] = + "long option '%s' ambiguous\n"; +static ZCONST char Far long_op_not_sup_err[] = + "long option '%s' not supported\n"; + +static ZCONST char Far no_arg_files_err[] = "argument files not enabled\n"; + + +/* below removed as only used for processing argument files */ + +/* get_nextarg */ +/* get_args_from_string */ +/* get_args_from_arg_file */ + + +/* copy error, option name, and option description if any to buf */ +static int optionerr(options, buf, err, optind, islong) + struct option_struct *options; + char *buf; + ZCONST char Far *err; + int optind; + int islong; +{ + char optname[50]; + + if (options[optind].name && options[optind].name[0] != '\0') { + sprintf(optname, "'%s' (%s)", + LoadFarStringSmall2(islong ? options[optind].longopt + : options[optind].shortopt), + LoadFarStringSmall(options[optind].name)); + } else { + sprintf(optname, "'%s'", + LoadFarStringSmall2(islong ? options[optind].longopt + : options[optind].shortopt)); + } + sprintf(buf, LoadFarStringSmall(err), optname); + return 0; +} + + +/* copy_args + * + * Copy arguments in args, allocating storage with malloc. + * Copies until a NULL argument is found or until max_args args + * including args[0] are copied. Set max_args to 0 to copy + * until NULL. Always terminates returned args[] with NULL arg. + * + * Any argument in the returned args can be freed with free(). Any + * freed argument should be replaced with either another string + * allocated with malloc or by NULL if last argument so that free_args + * will properly work. + */ +char **copy_args(__G__ args, max_args) + char **args; + int max_args; +{ + int j; + char **new_args; + + if (args == NULL) { + return NULL; + } + + /* count args */ + for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) ; + + if ((new_args = (char **) malloc((j + 1) * sizeof(char *))) == NULL) { + oWARN("memory - ca"); + return NULL; + } + + for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) { + if (args[j] == NULL) { + /* null argument is end of args */ + new_args[j] = NULL; + break; + } + if ((new_args[j] = malloc(strlen(args[j]) + 1)) == NULL) { + free_args(new_args); + oWARN("memory - ca"); + return NULL; + } + strcpy(new_args[j], args[j]); + } + new_args[j] = NULL; + + return new_args; +} + + +/* count args - count args in argv like array */ +int arg_count(args) + char **args; +{ + int i; + + if (args == NULL) { + return 0; + } + + for (i = 0; args[i]; i++) { + } + return i; +} + + +/* free args - free args created with one of these functions */ +int free_args(args) + char **args; +{ + int i; + + if (args == NULL) { + return 0; + } + + for (i = 0; args[i]; i++) { + free(args[i]); + } + free(args); + return i; +} + + +/* insert_arg + * + * Insert the argument arg into the array args before argument at_arg. + * If at_arg = -1 then append to end. + * Return the new count of arguments (argc). + * + * If free_args is true, this function frees the old args array + * (but not the component strings). DO NOT set free_args on original + * argv but only on args allocated with malloc. + */ + +int insert_arg(__G__ pargs, arg, at_arg, free_args) + char ***pargs; + ZCONST char *arg; + int at_arg; + int free_args; +{ + char *newarg = NULL; + char **args; + char **newargs = NULL; + int argnum; + int newargnum; + int argcnt; + int newargcnt; + + if (pargs == NULL) { + return 0; + } + args = *pargs; + + /* count args */ + if (args == NULL) { + argcnt = 0; + } else { + for (argcnt = 0; args[argcnt]; argcnt++) ; + } + if (arg == NULL) { + /* done */ + return argcnt; + } + if (at_arg == -1) { + at_arg = argcnt; + } + newargcnt = argcnt + 1; + + /* get storage for new args */ + if ((newargs = (char **) malloc((newargcnt + 1) * sizeof(char *))) == NULL) + { + oWARN("memory - ia"); + return 0; + } + + /* copy argument pointers from args to position at_arg, copy the new arg, + then copy the rest of the args */ + argnum = 0; + newargnum = 0; + if (args) { + for (; args[argnum] && argnum < at_arg; argnum++) { + newargs[newargnum++] = args[argnum]; + } + } + /* copy new arg */ + if ((newarg = (char *) malloc(strlen(arg) + 1)) == NULL) { + oWARN("memory - ia"); + return 0; + } + strcpy(newarg, arg); + + newargs[newargnum++] = newarg; + if (args) { + for ( ; args[argnum]; argnum++) { + newargs[newargnum++] = args[argnum]; + } + } + newargs[newargnum] = NULL; + + /* free old args array but not component strings - this assumes that + args was allocated with malloc as copy_args does. DO NOT DO THIS + on the original argv. + */ + if (free_args) + free(args); + + *pargs = newargs; + + return newargnum; +} + +/* ------------------------------------- */ + +/* get_shortopt + * + * Get next short option from arg. The state is stored in argnum, optchar, and + * option_num so no static storage is used. Returns the option_ID. + * + * parameters: + * option_group - either UZO for UnZip options or ZIO for ZipInfo options + * args - argv array of arguments + * argnum - index of current arg in args + * optchar - pointer to index of next char to process. Can be 0 or + * const defined at top of this file like THIS_ARG_DONE + * negated - on return pointer to int set to 1 if option negated + * or 0 otherwise + * value - on return pointer to string set to value of option if any + * or NULL if none. If value is returned then the caller + * should free() it when not needed anymore. + * option_num - pointer to index in options[] of returned option or + * o_NO_OPTION_MATCH if none. Do not change as used by + * value lists. + * depth - recursion depth (0 at top level, 1 or more in arg files) + */ +static unsigned long get_shortopt(__G__ option_group, args, argnum, optchar, negated, + value, option_num, depth) + int option_group; + ZCONST char **args; + int argnum; + int *optchar; + int *negated; + char **value; + int *option_num; + int depth; +{ + ZCONST char *shortopt; + int clen; + ZCONST char *nextchar; + ZCONST char *s; + ZCONST char *start; + int op; + ZCONST char *arg; + int match = -1; + + + /* get arg */ + arg = args[argnum]; + /* current char in arg */ + nextchar = arg + (*optchar); + clen = MB_CLEN(nextchar); + /* next char in arg */ + (*optchar) += clen; + /* get first char of short option */ + shortopt = arg + (*optchar); + /* no value */ + *value = NULL; + + if (*shortopt == '\0') { + /* no more options in arg */ + *optchar = 0; + *option_num = o_NO_OPTION_MATCH; + return 0; + } + + /* look for match in options */ + clen = MB_CLEN(shortopt); + for (op = 0; options[op].option_ID; op++) { + /* Only look at options in this option group */ + if (options[op].option_group == option_group) { + s = options[op].shortopt; + if (s && s[0] == shortopt[0]) { + if (s[1] == '\0' && clen == 1) { + /* single char match */ + match = op; + } else { + /* 2 wide short opt. Could support more chars but should use long opts instead */ + if (s[1] == shortopt[1]) { + /* match 2 char short opt or 2 byte char */ + match = op; + if (clen == 1) (*optchar)++; + break; + } + } + } + } + } + + if (match > -1) { + /* match */ + clen = MB_CLEN(shortopt); + nextchar = arg + (*optchar) + clen; + /* check for trailing dash negating option */ + if (*nextchar == '-') { + /* negated */ + if (options[match].negatable == o_NOT_NEGATABLE) { + if (options[match].value_type == o_NO_VALUE) { + optionerr(options, optionerrbuf, op_not_neg_err, match, 0); + if (depth > 0) { + /* unwind */ + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + } else { + *negated = 1; + /* set up to skip negating dash */ + (*optchar) += clen; + clen = 1; + } + } + + /* value */ + clen = MB_CLEN(arg + (*optchar)); + /* optional value, one char value, and number value must follow option */ + if (options[match].value_type == o_ONE_CHAR_VALUE) { + /* one char value */ + if (arg[(*optchar) + clen]) { + /* has value */ + if (MB_CLEN(arg + (*optchar) + clen) > 1) { + /* multibyte value not allowed for now */ + optionerr(options, optionerrbuf, oco_no_mbc_err, match, 0); + if (depth > 0) { + /* unwind */ + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + if ((*value = (char *) malloc(2)) == NULL) { + oWARN("memory - gso"); + return o_BAD_ERR; + } + (*value)[0] = *(arg + (*optchar) + clen); + (*value)[1] = '\0'; + *optchar += clen; + clen = 1; + } else { + /* one char values require a value */ + optionerr(options, optionerrbuf, oco_req_val_err, match, 0); + if (depth > 0) { + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + } else if (options[match].value_type == o_NUMBER_VALUE) { + /* read chars until end of number */ + start = arg + (*optchar) + clen; + if (*start == '+' || *start == '-') { + start++; + } + s = start; + for (; isdigit(*s); MB_NEXTCHAR(s)) ; + if (s == start) { + /* no digits */ + optionerr(options, optionerrbuf, num_req_val_err, match, 0); + if (depth > 0) { + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + start = arg + (*optchar) + clen; + if ((*value = (char *) malloc((int)(s - start) + 1)) == NULL) { + oWARN("memory - gso"); + return o_BAD_ERR; + } + *optchar += (int)(s - start); + strncpy(*value, start, (int)(s - start)); + (*value)[(int)(s - start)] = '\0'; + clen = MB_CLEN(s); + } else if (options[match].value_type == o_OPTIONAL_VALUE) { + /* optional value */ + /* This seemed inconsistent so now if no value attached to argument look + to the next argument if that argument is not an option for option + value - 11/12/04 EG */ + if (arg[(*optchar) + clen]) { + /* has value */ + /* add support for optional = - 2/6/05 EG */ + if (arg[(*optchar) + clen] == '=') { + /* skip = */ + clen++; + } + if (arg[(*optchar) + clen]) { + if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1)) + == NULL) { + oWARN("memory - gso"); + return o_BAD_ERR; + } + strcpy(*value, arg + (*optchar) + clen); + } + *optchar = THIS_ARG_DONE; + } else if (args[argnum + 1] && args[argnum + 1][0] != '-') { + /* use next arg for value */ + if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) { + oWARN("memory - gso"); + return o_BAD_ERR; + } + /* using next arg as value */ + strcpy(*value, args[argnum + 1]); + *optchar = SKIP_VALUE_ARG; + } + } else if (options[match].value_type == o_REQUIRED_VALUE || + options[match].value_type == o_VALUE_LIST) { + /* see if follows option */ + if (arg[(*optchar) + clen]) { + /* has value following option as -ovalue */ + /* add support for optional = - 6/5/05 EG */ + if (arg[(*optchar) + clen] == '=') { + /* skip = */ + clen++; + } + if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1)) + == NULL) { + oWARN("memory - gso"); + return o_BAD_ERR; + } + strcpy(*value, arg + (*optchar) + clen); + *optchar = THIS_ARG_DONE; + } else { + /* use next arg for value */ + if (args[argnum + 1]) { + if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) + == NULL) { + oWARN("memory - gso"); + return o_BAD_ERR; + } + strcpy(*value, args[argnum + 1]); + if (options[match].value_type == o_VALUE_LIST) { + *optchar = START_VALUE_LIST; + } else { + *optchar = SKIP_VALUE_ARG; + } + } else { + /* no value found */ + optionerr(options, optionerrbuf, op_req_val_err, match, 0); + if (depth > 0) { + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + } + } + + *option_num = match; + return options[match].option_ID; + } + sprintf(optionerrbuf, LoadFarStringSmall(sh_op_not_sup_err), *shortopt); + if (depth > 0) { + /* unwind */ + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } +} + + +/* get_longopt + * + * Get the long option in args array at argnum. + * Parameters same as for get_shortopt. + */ + +static unsigned long get_longopt(__G__ option_group, args, argnum, optchar, + negated, value, option_num, depth) + int option_group; + ZCONST char **args; + int argnum; + int *optchar; + int *negated; + char **value; + int *option_num; + int depth; +{ + char *longopt; + char *lastchr; + char *valuestart; + int op; + char *arg; + int match = -1; + *value = NULL; + + if (args == NULL) { + *option_num = o_NO_OPTION_MATCH; + return 0; + } + if (args[argnum] == NULL) { + *option_num = o_NO_OPTION_MATCH; + return 0; + } + /* copy arg so can chop end if value */ + if ((arg = (char *)malloc(strlen(args[argnum]) + 1)) == NULL) { + oWARN("memory - glo"); + return o_BAD_ERR; + } + strcpy(arg, args[argnum]); + + /* get option */ + longopt = arg + 2; + /* no value */ + *value = NULL; + + /* find = */ + for (lastchr = longopt, valuestart = longopt; + *valuestart && *valuestart != '='; + lastchr = valuestart, MB_NEXTCHAR(valuestart)) ; + if (*valuestart) { + /* found =value */ + *valuestart = '\0'; + valuestart++; + } else { + valuestart = NULL; + } + + if (*lastchr == '-') { + /* option negated */ + *negated = 1; + *lastchr = '\0'; + } else { + *negated = 0; + } + + /* look for long option match */ + for (op = 0; options[op].option_ID; op++) { + /* Only look at options in the option group */ + if (options[op].option_group == option_group) { + if (options[op].longopt && + strcmp(LoadFarStringSmall(options[op].longopt), longopt) == 0) { + /* exact match */ + match = op; + break; + } + if (options[op].longopt && + strncmp(LoadFarStringSmall(options[op].longopt), + longopt, strlen(longopt)) == 0) { + if (match > -1) { + sprintf(optionerrbuf, LoadFarStringSmall(long_op_ambig_err), + longopt); + free(arg); + if (depth > 0) { + /* unwind */ + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + match = op; + } + } + } + + if (match == -1) { + sprintf(optionerrbuf, LoadFarStringSmall(long_op_not_sup_err), longopt); + free(arg); + if (depth > 0) { + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + + /* one long option an arg */ + *optchar = THIS_ARG_DONE; + + /* if negated then see if allowed */ + if (*negated && options[match].negatable == o_NOT_NEGATABLE) { + optionerr(options, optionerrbuf, op_not_neg_err, match, 1); + free(arg); + if (depth > 0) { + /* unwind */ + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + /* get value */ + if (options[match].value_type == o_OPTIONAL_VALUE) { + /* optional value in form option=value */ + if (valuestart) { + /* option=value */ + if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) { + free(arg); + oWARN("memory - glo"); + return o_BAD_ERR; + } + strcpy(*value, valuestart); + } + } else if (options[match].value_type == o_REQUIRED_VALUE || + options[match].value_type == o_NUMBER_VALUE || + options[match].value_type == o_ONE_CHAR_VALUE || + options[match].value_type == o_VALUE_LIST) { + /* handle long option one char and number value as required value */ + if (valuestart) { + /* option=value */ + if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) { + free(arg); + oWARN("memory - glo"); + return o_BAD_ERR; + } + strcpy(*value, valuestart); + } else { + /* use next arg */ + if (args[argnum + 1]) { + if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) { + free(arg); + oWARN("memory - glo"); + return o_BAD_ERR; + } + /* using next arg as value */ + strcpy(*value, args[argnum + 1]); + if (options[match].value_type == o_VALUE_LIST) { + *optchar = START_VALUE_LIST; + } else { + *optchar = SKIP_VALUE_ARG; + } + } else { + /* no value found */ + optionerr(options, optionerrbuf, op_req_val_err, match, 1); + free(arg); + if (depth > 0) { + /* unwind */ + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + } + } else if (options[match].value_type == o_NO_VALUE) { + /* this option does not accept a value */ + if (valuestart) { + /* --option=value */ + optionerr(options, optionerrbuf, op_no_allow_val_err, match, 1); + free(arg); + if (depth > 0) { + oWARN(optionerrbuf); + return o_ARG_FILE_ERR; + } else { + oWARN(optionerrbuf); + return o_BAD_ERR; + } + } + } + free(arg); + + *option_num = match; + return options[match].option_ID; +} + + + +/* get_option + * + * Main interface for user. Use this function to get options, values and + * non-option arguments from a command line provided in argv form. + * + * To use get_option() first define valid options by setting + * the global variable options[] to an array of option_struct. Also + * either change defaults below or make variables global and set elsewhere. + * Zip uses below defaults. + * + * Call get_option() to get an option (like -b or --temp-file) and any + * value for that option (like filename for -b) or a non-option argument + * (like archive name) each call. If *value* is not NULL after calling + * get_option() it is a returned value and the caller should either store + * the char pointer or free() it before calling get_option() again to avoid + * leaking memory. If a non-option non-value argument is returned get_option() + * returns o_NON_OPTION_ARG and value is set to the entire argument. + * When there are no more arguments get_option() returns 0. + * + * The parameters argnum (after set to 0 on initial call), + * optchar, first_nonopt_arg, option_num, and depth (after initial + * call) are set and maintained by get_option() and should not be + * changed. The parameters argc, negated, and value are outputs and + * can be used by the calling program. get_option() returns either the + * option_ID for the current option, a special value defined in + * zip.h, or 0 when no more arguments. + * + * The value returned by get_option() is the ID value in the options + * table. This value can be duplicated in the table if different + * options are really the same option. The index into the options[] + * table is given by option_num, though the ID should be used as + * option numbers change when the table is changed. The ID must + * not be 0 for any option as this ends the table. If get_option() + * finds an option not in the table it calls oERR to post an + * error and exit. Errors also result if the option requires a + * value that is missing, a value is present but the option does + * not take one, and an option is negated but is not + * negatable. Non-option arguments return o_NON_OPTION_ARG + * with the entire argument in value. + * + * For Zip and UnZip, permuting is on and all options and their values + * are returned before any non-option arguments like archive name. + * + * The arguments "-" alone and "--" alone return as non-option arguments. + * Note that "-" should not be used as part of a short option + * entry in the table but can be used in the middle of long + * options such as in the long option "a-long-option". Now "--" alone + * stops option processing, returning any arguments following "--" as + * non-option arguments instead of options. + * + * Argument file support is removed from this version. It may be added later. + * + * After each call: + * argc is set to the current size of args[] but should not change + * with argument file support removed, + * argnum is the index of the current arg, + * value is either the value of the returned option or non-option + * argument or NULL if option with no value, + * negated is set if the option was negated by a trailing dash (-) + * option_num is set to either the index in options[] for the option or + * o_NO_OPTION_MATCH if no match. + * Negation is checked before the value is read if the option is negatable so + * that the - is not included in the value. If the option is not negatable + * but takes a value then the - will start the value. If permuting then + * argnum and first_nonopt_arg are unreliable and should not be used. + * + * Command line is read from left to right. As get_option() finds non-option + * arguments (arguments not starting with - and that are not values to options) + * it moves later options and values in front of the non-option arguments. + * This permuting is turned off by setting enable_permute to 0. Then + * get_option() will return options and non-option arguments in the order + * found. Currently permuting is only done after an argument is completely + * processed so that any value can be moved with options they go with. All + * state information is stored in the parameters argnum, optchar, + * first_nonopt_arg and option_num. You should not change these after the + * first call to get_option(). If you need to back up to a previous arg then + * set argnum to that arg (remembering that args may have been permuted) and + * set optchar = 0 and first_nonopt_arg to the first non-option argument if + * permuting. After all arguments are returned the next call to get_option() + * returns 0. The caller can then call free_args(args) if appropriate. + * + * get_option() accepts arguments in the following forms: + * short options + * of 1 and 2 characters, e.g. a, b, cc, d, and ba, after a single + * leading -, as in -abccdba. In this example if 'b' is followed by 'a' + * it matches short option 'ba' else it is interpreted as short option + * b followed by another option. The character - is not legal as a + * short option or as part of a 2 character short option. + * + * If a short option has a value it immediately follows the option or + * if that option is the end of the arg then the next arg is used as + * the value. So if short option e has a value, it can be given as + * -evalue + * or + * -e value + * and now + * -e=value + * but now that = is optional a leading = is stripped for the first. + * This change allows optional short option values to be defaulted as + * -e= + * Either optional or required values can be specified. Optional values + * now use both forms as ignoring the later got confusing. Any + * non-value short options can preceed a valued short option as in + * -abevalue + * Some value types (one_char and number) allow options after the value + * so if oc is an option that takes a character and n takes a number + * then + * -abocVccn42evalue + * returns value V for oc and value 42 for n. All values are strings + * so programs may have to convert the "42" to a number. See long + * options below for how value lists are handled. + * + * Any short option can be negated by following it with -. Any - is + * handled and skipped over before any value is read unless the option + * is not negatable but takes a value and then - starts the value. + * + * If the value for an optional value is just =, then treated as no + * value. + * + * long options + * of arbitrary length are assumed if an arg starts with -- but is not + * exactly --. Long options are given one per arg and can be abbreviated + * if the abbreviation uniquely matches one of the long options. + * Exact matches always match before partial matches. If ambiguous an + * error is generated. + * + * Values are specified either in the form + * --longoption=value + * or can be the following arg if the value is required as in + * --longoption value + * Optional values to long options must be in the first form. + * + * Value lists are specified by o_VALUE_LIST and consist of an option + * that takes a value followed by one or more value arguments. + * The two forms are + * --option=value + * or + * -ovalue + * for a single value or + * --option value1 value2 value3 ... --option2 + * or + * -o value1 value2 value3 ... + * for a list of values. The list ends at the next option, the + * end of the command line, or at a single "@" argument. + * Each value is treated as if it was preceeded by the option, so + * --option1 val1 val2 + * with option1 value_type set to o_VALUE_LIST is the same as + * --option1=val1 --option1=val2 + * + * Long options can be negated by following the option with - as in + * --longoption- + * Long options with values can also be negated if this makes sense for + * the caller as: + * --longoption-=value + * If = is not followed by anything it is treated as no value. + * + * @path + * Argument files support removed from this version. It may be added + * back later. + * + * non-option argument + * is any argument not given above. If enable_permute is 1 then + * these are returned after all options, otherwise all options and + * args are returned in order. Returns option ID o_NON_OPTION_ARG + * and sets value to the argument. + * + * + * Arguments to get_option: + * int option_group - either UZO for UnZip or ZIO for ZipInfo + * char ***pargs - pointer to arg array in the argv form + * int *argc - returns the current argc for args incl. args[0] + * int *argnum - the index of the current argument (caller + * should set = 0 on first call and not change + * after that) + * int *optchar - index of next short opt in arg or special + * int *first_nonopt_arg - used by get_option to permute args + * int *negated - option was negated (had trailing -) + * char *value - value of option if any (free when done with it) + * or NULL + * int *option_num - the index in options of the last option returned + * (can be o_NO_OPTION_MATCH) + * int recursion_depth - current depth of recursion + * (always set to 0 by caller) + * (always 0 with argument files support removed) + * + * Caller should only read the returned option ID and the value, negated, + * and option_num (if required) parameters after each call. + * + * Ed Gordon + * 8/24/2003 (last updated 3/1/2008 EG) + * + */ + +unsigned long get_option(__G__ option_group, pargs, argc, argnum, optchar, value, + negated, first_nonopt_arg, option_num, recursion_depth) + int option_group; + char ***pargs; + int *argc; + int *argnum; + int *optchar; + char **value; + int *negated; + int *first_nonopt_arg; + int *option_num; + int recursion_depth; +{ + char **args; + unsigned long option_ID; + + int argcnt; + int first_nonoption_arg; + char *arg = NULL; + int h; + int optc; + int argn; + int j; + int v; + int read_rest_args_verbatim = 0; /* 7/25/04 - ignore options and arg files for rest args */ + + /* caller should free value or assign it to another + variable before calling get_option again. */ + *value = NULL; + + /* if args is NULL then done */ + if (pargs == NULL) { + *argc = 0; + return 0; + } + args = *pargs; + if (args == NULL) { + *argc = 0; + return 0; + } + + /* count args */ + for (argcnt = 0; args[argcnt]; argcnt++) ; + + /* if no provided args then nothing to do */ + if (argcnt < 1 || (recursion_depth == 0 && argcnt < 2)) { + *argc = argcnt; + /* return 0 to note that no args are left */ + return 0; + } + + *negated = 0; + first_nonoption_arg = *first_nonopt_arg; + argn = *argnum; + optc = *optchar; + + if (optc == READ_REST_ARGS_VERBATIM) { + read_rest_args_verbatim = 1; + } + + if (argn == -1 || (recursion_depth == 0 && argn == 0)) { + /* first call */ + /* if depth = 0 then args[0] is argv[0] so skip */ + *option_num = o_NO_OPTION_MATCH; + optc = THIS_ARG_DONE; + first_nonoption_arg = -1; + } + + /* if option_num is set then restore last option_ID in case continuing + value list */ + option_ID = 0; + if (*option_num != o_NO_OPTION_MATCH) { + option_ID = options[*option_num].option_ID; + } + + /* get next option if any */ + for (;;) { + if (read_rest_args_verbatim) { + /* rest of args after "--" are non-option args if doubledash_ends_options + set */ + argn++; + if (argn > argcnt || args[argn] == NULL) { + /* done */ + option_ID = 0; + break; + } + arg = args[argn]; + if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) { + oWARN("memory - go"); + return o_BAD_ERR; + } + strcpy(*value, arg); + *option_num = o_NO_OPTION_MATCH; + option_ID = o_NON_OPTION_ARG; + break; + + /* permute non-option args after option args so options are returned + first */ + } else if (enable_permute) { + if (optc == SKIP_VALUE_ARG || optc == THIS_ARG_DONE || + optc == START_VALUE_LIST || optc == IN_VALUE_LIST || + optc == STOP_VALUE_LIST) { + /* moved to new arg */ + if (first_nonoption_arg > -1 && args[first_nonoption_arg]) { + /* do the permuting - move non-options after this option */ + /* if option and value separate args or starting list skip option */ + if (optc == SKIP_VALUE_ARG || optc == START_VALUE_LIST) { + v = 1; + } else { + v = 0; + } + for (h = first_nonoption_arg; h < argn; h++) { + arg = args[first_nonoption_arg]; + for (j = first_nonoption_arg; j < argn + v; j++) { + args[j] = args[j + 1]; + } + args[j] = arg; + } + first_nonoption_arg += 1 + v; + } + } + } else if (optc == NON_OPTION_ARG) { + /* if not permuting then already returned arg */ + optc = THIS_ARG_DONE; + } + + /* value lists */ + if (optc == STOP_VALUE_LIST) { + optc = THIS_ARG_DONE; + } + + if (optc == START_VALUE_LIST || optc == IN_VALUE_LIST) { + if (optc == START_VALUE_LIST) { + /* already returned first value */ + argn++; + optc = IN_VALUE_LIST; + } + argn++; + arg = args[argn]; + /* if end of args and still in list and there are non-option args then + terminate list */ + if (arg == NULL && (optc == START_VALUE_LIST || optc == IN_VALUE_LIST) + && first_nonoption_arg > -1) { + /* terminate value list with @ */ + /* this is only needed for argument files */ + /* but is also good for show command line so command lines with lists + can always be read back in */ + argcnt = insert_arg(__G__ &args, "@", first_nonoption_arg, 1); + argn++; + if (first_nonoption_arg > -1) { + first_nonoption_arg++; + } + } + + arg = args[argn]; + if (arg && arg[0] == '@' && arg[1] == '\0') { + /* inserted arguments terminator */ + optc = STOP_VALUE_LIST; + continue; + } else if (arg && arg[0] != '-') { /* not option */ + /* - and -- are not allowed in value lists unless escaped */ + /* another value in value list */ + if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) { + oWARN("memory - go"); + return o_BAD_ERR; + } + strcpy(*value, args[argn]); + break; + + } else { + argn--; + optc = THIS_ARG_DONE; + } + } + + /* move to next arg */ + if (optc == SKIP_VALUE_ARG) { + argn += 2; + optc = 0; + } else if (optc == THIS_ARG_DONE) { + argn++; + optc = 0; + } + if (argn > argcnt) { + break; + } + if (args[argn] == NULL) { + /* done unless permuting and non-option args */ + if (first_nonoption_arg > -1 && args[first_nonoption_arg]) { + /* return non-option arguments at end */ + if (optc == NON_OPTION_ARG) { + first_nonoption_arg++; + } + /* after first pass args are permuted but skipped over non-option + args */ + /* swap so argn points to first non-option arg */ + j = argn; + argn = first_nonoption_arg; + first_nonoption_arg = j; + } + if (argn > argcnt || args[argn] == NULL) { + /* done */ + option_ID = 0; + break; + } + } + + /* after swap first_nonoption_arg points to end which is NULL */ + if (first_nonoption_arg > -1 && (args[first_nonoption_arg] == NULL)) { + /* only non-option args left */ + if (optc == NON_OPTION_ARG) { + argn++; + } + if (argn > argcnt || args[argn] == NULL) { + /* done */ + option_ID = 0; + break; + } + if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) { + oWARN("memory - go"); + return o_BAD_ERR; + } + strcpy(*value, args[argn]); + optc = NON_OPTION_ARG; + option_ID = o_NON_OPTION_ARG; + break; + } + + arg = args[argn]; + + /* is it an option */ + if (arg[0] == '-') { + /* option */ + if (arg[1] == '\0') { + /* arg = - */ + /* treat like non-option arg */ + *option_num = o_NO_OPTION_MATCH; + if (enable_permute) { + /* permute args to move all non-option args to end */ + if (first_nonoption_arg < 0) { + first_nonoption_arg = argn; + } + argn++; + } else { + /* not permute args so return non-option args when found */ + if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) { + oWARN("memory - go"); + return o_BAD_ERR; + } + strcpy(*value, arg); + optc = NON_OPTION_ARG; + option_ID = o_NON_OPTION_ARG; + break; + } + + } else if (arg[1] == '-') { + /* long option */ + if (arg[2] == '\0') { + /* arg = -- */ + if (doubledash_ends_options) { + /* Now -- stops permuting and forces the rest of + the command line to be read verbatim - 7/25/04 EG */ + + /* never permute args after -- and return as non-option args */ + if (first_nonoption_arg < 1) { + /* -- is first non-option argument - 8/7/04 EG */ + argn--; + } else { + /* go back to start of non-option args - 8/7/04 EG */ + argn = first_nonoption_arg - 1; + } + + /* disable permuting and treat remaining arguments as not + options */ + read_rest_args_verbatim = 1; + optc = READ_REST_ARGS_VERBATIM; + + } else { + /* treat like non-option arg */ + *option_num = o_NO_OPTION_MATCH; + if (enable_permute) { + /* permute args to move all non-option args to end */ + if (first_nonoption_arg < 0) { + first_nonoption_arg = argn; + } + argn++; + } else { + /* not permute args so return non-option args when found */ + if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) { + oWARN("memory - go"); + return o_BAD_ERR; + } + strcpy(*value, arg); + optc = NON_OPTION_ARG; + option_ID = o_NON_OPTION_ARG; + break; + } + } + + } else { + option_ID = get_longopt(__G__ option_group, (ZCONST char **)args, argn, + &optc, negated, + value, option_num, recursion_depth); + if (option_ID == o_BAD_ERR) { + return o_BAD_ERR; + } else if (option_ID == o_ARG_FILE_ERR) { + /* unwind as only get this if recursion_depth > 0 */ + return option_ID; + } + break; + } + + } else { + /* short option */ + option_ID = get_shortopt(__G__ option_group, (ZCONST char **)args, argn, + &optc, negated, + value, option_num, recursion_depth); + + if (option_ID == o_BAD_ERR) { + return o_BAD_ERR; + } else if (option_ID == o_ARG_FILE_ERR) { + /* unwind as only get this if recursion_depth > 0 */ + return option_ID; + } + + if (optc == 0) { + /* if optc = 0 then ran out of short opts this arg */ + optc = THIS_ARG_DONE; + } else { + break; + } + } + +#if 0 + /* argument file code left out + so for now let filenames start with @ + */ + + } else if (allow_arg_files && arg[0] == '@') { + /* arg file */ + oERR(PK_PARMS, no_arg_files_err); +#endif + + } else { + /* non-option */ + if (enable_permute) { + /* permute args to move all non-option args to end */ + if (first_nonoption_arg < 0) { + first_nonoption_arg = argn; + } + argn++; + } else { + /* no permute args so return non-option args when found */ + if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) { + oWARN("memory - go"); + return o_BAD_ERR; + } + strcpy(*value, arg); + *option_num = o_NO_OPTION_MATCH; + optc = NON_OPTION_ARG; + option_ID = o_NON_OPTION_ARG; + break; + } + + } + } + + *pargs = args; + *argc = argcnt; + *first_nonopt_arg = first_nonoption_arg; + *argnum = argn; + *optchar = optc; + + return option_ID; +} diff --git a/third_party/unzip/unzip.h b/third_party/unzip/unzip.h new file mode 100644 index 000000000..3caefa10a --- /dev/null +++ b/third_party/unzip/unzip.h @@ -0,0 +1,715 @@ +// clang-format off +/*--------------------------------------------------------------------------- + + unzip.h (new) + + Copyright (c) 1990-2010 Info-ZIP. All rights reserved. + + This header file contains the public macros and typedefs required by + both the UnZip sources and by any application using the UnZip API. If + UNZIP_INTERNAL is defined, it includes unzpriv.h (containing includes, + prototypes and extern variables used by the actual UnZip sources). + + ---------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------- +This is version 2009-Jan-02 of the Info-ZIP license. +The definitive version of this document should be available at +ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and +a copy at http://www.info-zip.org/pub/infozip/license.html. + + +Copyright (c) 1990-2010 Info-ZIP. All rights reserved. + +For the purposes of this copyright and license, "Info-ZIP" is defined as +the following set of individuals: + + Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, + Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth, + Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, + David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, + Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, + Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda, + Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren, + Rich Wales, Mike White. + +This software is provided "as is," without warranty of any kind, express +or implied. In no event shall Info-ZIP or its contributors be held liable +for any direct, indirect, incidental, special or consequential damages +arising out of the use of or inability to use this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the above disclaimer and the following restrictions: + + 1. Redistributions of source code (in whole or in part) must retain + the above copyright notice, definition, disclaimer, and this list + of conditions. + + 2. Redistributions in binary form (compiled executables and libraries) + must reproduce the above copyright notice, definition, disclaimer, + and this list of conditions in documentation and/or other materials + provided with the distribution. Additional documentation is not needed + for executables where a command line license option provides these and + a note regarding this option is in the executable's startup banner. The + sole exception to this condition is redistribution of a standard + UnZipSFX binary (including SFXWiz) as part of a self-extracting archive; + that is permitted without inclusion of this license, as long as the + normal SFX banner has not been removed from the binary or disabled. + + 3. Altered versions--including, but not limited to, ports to new operating + systems, existing ports with new graphical interfaces, versions with + modified or added functionality, and dynamic, shared, or static library + versions not from Info-ZIP--must be plainly marked as such and must not + be misrepresented as being the original source or, if binaries, + compiled from the original source. Such altered versions also must not + be misrepresented as being Info-ZIP releases--including, but not + limited to, labeling of the altered versions with the names "Info-ZIP" + (or any variation thereof, including, but not limited to, different + capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the + explicit permission of Info-ZIP. Such altered versions are further + prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP + e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP + will provide support for the altered versions. + + 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," + "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its + own source and binary releases. + ---------------------------------------------------------------------------*/ + +#ifndef __unzip_h /* prevent multiple inclusions */ +#define __unzip_h + +/*--------------------------------------------------------------------------- + Predefined, machine-specific macros. + ---------------------------------------------------------------------------*/ + +#ifdef __GO32__ /* MS-DOS extender: NOT Unix */ +# ifdef unix +# undef unix +# endif +# ifdef _unix +# undef _unix +# endif +# ifdef __unix +# undef __unix +# endif +# ifdef __unix__ +# undef __unix__ +# endif +#endif + +#if ((defined(__convex__) || defined(__convexc__)) && !defined(CONVEX)) +# define CONVEX +#endif + +#if (defined(unix) || defined(_unix) || defined(__unix) || defined(__unix__)) +# ifndef UNIX +# define UNIX +# endif +#endif /* unix || _unix || __unix || __unix__ */ +#if (defined(M_XENIX) || defined(COHERENT) || defined(__hpux)) +# ifndef UNIX +# define UNIX +# endif +#endif /* M_XENIX || COHERENT || __hpux */ +#if (defined(__NetBSD__) || defined(__FreeBSD__)) +# ifndef UNIX +# define UNIX +# endif +#endif /* __NetBSD__ || __FreeBSD__ */ +#if (defined(CONVEX) || defined(MINIX) || defined(_AIX) || defined(__QNX__)) +# ifndef UNIX +# define UNIX +# endif +#endif /* CONVEX || MINIX || _AIX || __QNX__ */ + +#if (defined(VM_CMS) || defined(MVS)) +# define CMS_MVS +#endif + +#if (defined(__OS2__) && !defined(OS2)) +# define OS2 +#endif + +#if (defined(__TANDEM) && !defined(TANDEM)) +# define TANDEM +#endif + +#if (defined(__VMS) && !defined(VMS)) +# define VMS +#endif + +#if ((defined(__WIN32__) || defined(_WIN32)) && !defined(WIN32)) +# define WIN32 +#endif +#if ((defined(__WINNT__) || defined(__WINNT)) && !defined(WIN32)) +# define WIN32 +#endif + +#if defined(_WIN32_WCE) +# ifndef WIN32 /* WinCE is treated as a variant of the Win32 API */ +# define WIN32 +# endif +# ifndef UNICODE /* WinCE requires UNICODE wide character support */ +# define UNICODE +# endif +#endif + +#ifdef __COMPILER_KCC__ +# ifdef SYS_T20 +# define TOPS20 +# endif +#endif /* __COMPILER_KCC__ */ + +/* Borland C does not define __TURBOC__ if compiling for a 32-bit platform */ +#ifdef __BORLANDC__ +# ifndef __TURBOC__ +# define __TURBOC__ +# endif +# if (!defined(__MSDOS__) && !defined(OS2) && !defined(WIN32)) +# define __MSDOS__ +# endif +#endif + +/* define MSDOS for Turbo C (unless OS/2) and Power C as well as Microsoft C */ +#ifdef __POWERC +# define __TURBOC__ +# define MSDOS +#endif /* __POWERC */ + +#if (defined(__MSDOS__) && !defined(MSDOS)) /* just to make sure */ +# define MSDOS +#endif + +/* RSXNTDJ (at least up to v1.3) compiles for WIN32 (RSXNT) using a derivate + of the EMX environment, but defines MSDOS and __GO32__. ARG !!! */ +#if (defined(MSDOS) && defined(WIN32)) +# undef MSDOS /* WIN32 is >>>not<<< MSDOS */ +#endif +#if (defined(__GO32__) && defined(__EMX__) && defined(__RSXNT__)) +# undef __GO32__ +#endif + +#if (defined(linux) && !defined(LINUX)) +# define LINUX +#endif + +#ifdef __riscos +# define RISCOS +#endif + +#if (defined(THINK_C) || defined(MPW)) +# define MACOS +#endif +#if (defined(__MWERKS__) && defined(macintosh)) +# define MACOS +#endif + +/* use prototypes and ANSI libraries if __STDC__, or MS-DOS, or OS/2, or Win32, + * or IBM C Set/2, or Borland C, or Watcom C, or GNU gcc (emx or Cygwin), + * or Macintosh, or Sequent, or Atari, or IBM RS/6000, or Silicon Graphics, + * or Convex?, or AtheOS, or BeOS. + */ +#if (defined(__STDC__) || defined(MSDOS) || defined(OS2) || defined(WIN32)) +# ifndef PROTO +# define PROTO +# endif +# ifndef MODERN +# define MODERN +# endif +#endif +#if (defined(__IBMC__) || defined(__BORLANDC__) || defined(__WATCOMC__)) +# ifndef PROTO +# define PROTO +# endif +# ifndef MODERN +# define MODERN +# endif +#endif +#if (defined(__EMX__) || defined(__CYGWIN__)) +# ifndef PROTO +# define PROTO +# endif +# ifndef MODERN +# define MODERN +# endif +#endif +#if (defined(MACOS) || defined(ATARI_ST) || defined(RISCOS) || defined(THEOS)) +# ifndef PROTO +# define PROTO +# endif +# ifndef MODERN +# define MODERN +# endif +#endif +/* Sequent running Dynix/ptx: non-modern compiler */ +#if (defined(_AIX) || defined(sgi) || (defined(_SEQUENT_) && !defined(PTX))) +# ifndef PROTO +# define PROTO +# endif +# ifndef MODERN +# define MODERN +# endif +#endif +#if (defined(CMS_MVS) || defined(__ATHEOS__) || defined(__BEOS__)) +/* || defined(CONVEX) ? */ +# ifndef PROTO +# define PROTO +# endif +# ifndef MODERN +# define MODERN +# endif +#endif +/* Bundled C compiler on HP-UX needs this. Others shouldn't care. */ +#if (defined(__hpux)) +# ifndef MODERN +# define MODERN +# endif +#endif + +/* turn off prototypes if requested */ +#if (defined(NOPROTO) && defined(PROTO)) +# undef PROTO +#endif + +/* used to remove arguments in function prototypes for non-ANSI C */ +#ifdef PROTO +# define OF(a) a +#else +# define OF(a) () +#endif + +/* enable the "const" keyword only if MODERN and if not otherwise instructed */ +#ifdef MODERN +# if (!defined(ZCONST) && (defined(USE_CONST) || !defined(NO_CONST))) +# define ZCONST const +# endif +#endif + +#ifndef ZCONST +# define ZCONST +#endif + +/* Tell Microsoft Visual C++ 2005 (and newer) to leave us alone + * and let us use standard C functions the way we're supposed to. + * (These preprocessor symbols must appear before the first system + * header include. They are located here, because for WINDLL the + * first system header includes follow just below.) + */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +# endif +# ifndef _CRT_NONSTDC_NO_WARNINGS +# define _CRT_NONSTDC_NO_WARNINGS +# endif +# if defined(POCKET_UNZIP) && !defined(_CRT_NON_CONFORMING_SWPRINTFS) +# define _CRT_NON_CONFORMING_SWPRINTFS +# endif +#endif + +/* NO_UNIXBACKUP overrides UNIXBACKUP */ +#if defined(NO_UNIXBACKUP) && defined(UNIXBACKUP) +# undef UNIXBACKUP +#endif + +/*--------------------------------------------------------------------------- + Grab system-dependent definition of EXPENTRY for prototypes below. + ---------------------------------------------------------------------------*/ + +#if 0 +#if (defined(OS2) && !defined(FUNZIP)) +# ifdef UNZIP_INTERNAL +# define INCL_NOPM +# define INCL_DOSNLS +# define INCL_DOSPROCESS +# define INCL_DOSDEVICES +# define INCL_DOSDEVIOCTL +# define INCL_DOSERRORS +# define INCL_DOSMISC +# ifdef OS2DLL +# define INCL_REXXSAA +# endif +# endif /* UNZIP_INTERNAL */ +# define UZ_EXP EXPENTRY +#endif /* OS2 && !FUNZIP */ +#endif /* 0 */ + +#if (defined(OS2) && !defined(FUNZIP)) +# if (defined(__IBMC__) || defined(__WATCOMC__)) +# define UZ_EXP _System /* compiler keyword */ +# else +# define UZ_EXP +# endif +#endif /* OS2 && !FUNZIP */ + +#if (defined(WINDLL) || defined(USE_UNZIP_LIB)) +# ifndef EXPENTRY +# define UZ_EXP WINAPI +# else +# define UZ_EXP EXPENTRY +# endif +#endif + +#ifndef UZ_EXP +# define UZ_EXP +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + Public typedefs. + ---------------------------------------------------------------------------*/ + +#ifndef _IZ_TYPES_DEFINED +#ifdef MODERN + typedef void zvoid; +#else /* !MODERN */ +# ifndef AOS_VS /* mostly modern? */ +# ifndef VAXC /* not fully modern, but has knows 'void' */ +# define void int +# endif /* !VAXC */ +# endif /* !AOS_VS */ + typedef char zvoid; +#endif /* ?MODERN */ +typedef unsigned char uch; /* code assumes unsigned bytes; these type- */ +typedef unsigned short ush; /* defs replace byte/UWORD/ULONG (which are */ +typedef unsigned long ulg; /* predefined on some systems) & match zip */ +#define _IZ_TYPES_DEFINED +#endif /* !_IZ_TYPES_DEFINED */ + +/* InputFn is not yet used and is likely to change: */ +#ifdef PROTO + typedef int (UZ_EXP MsgFn) (zvoid *pG, uch *buf, ulg size, int flag); + typedef int (UZ_EXP InputFn) (zvoid *pG, uch *buf, int *size, int flag); + typedef void (UZ_EXP PauseFn) (zvoid *pG, ZCONST char *prompt, int flag); + typedef int (UZ_EXP PasswdFn) (zvoid *pG, int *rcnt, char *pwbuf, + int size, ZCONST char *zfn, + ZCONST char *efn); + typedef int (UZ_EXP StatCBFn) (zvoid *pG, int fnflag, ZCONST char *zfn, + ZCONST char *efn, ZCONST zvoid *details); + typedef void (UZ_EXP UsrIniFn) (void); +#else /* !PROTO */ + typedef int (UZ_EXP MsgFn) (); + typedef int (UZ_EXP InputFn) (); + typedef void (UZ_EXP PauseFn) (); + typedef int (UZ_EXP PasswdFn) (); + typedef int (UZ_EXP StatCBFn) (); + typedef void (UZ_EXP UsrIniFn) (); +#endif /* ?PROTO */ + +typedef struct _UzpBuffer { /* rxstr */ + ulg strlength; /* length of string */ + char *strptr; /* pointer to string */ +} UzpBuffer; + +typedef struct _UzpInit { + ulg structlen; /* length of the struct being passed */ + + /* GRR: can we assume that each of these is a 32-bit pointer? if not, + * does it matter? add "far" keyword to make sure? */ + MsgFn *msgfn; + InputFn *inputfn; + PauseFn *pausefn; + UsrIniFn *userfn; /* user init function to be called after */ + /* globals constructed and initialized */ + + /* pointer to program's environment area or something? */ + /* hooks for performance testing? */ + /* hooks for extra unzip -v output? (detect CPU or other hardware?) */ + /* anything else? let me (Greg) know... */ +} UzpInit; + +typedef struct _UzpCB { + ulg structlen; /* length of the struct being passed */ + /* GRR: can we assume that each of these is a 32-bit pointer? if not, + * does it matter? add "far" keyword to make sure? */ + MsgFn *msgfn; + InputFn *inputfn; + PauseFn *pausefn; + PasswdFn *passwdfn; + StatCBFn *statrepfn; +} UzpCB; + +/* the collection of general UnZip option flags and option arguments */ +typedef struct _UzpOpts { +#ifndef FUNZIP + char *exdir; /* pointer to extraction root directory (-d option) */ + char *pwdarg; /* pointer to command-line password (-P option) */ + int zipinfo_mode; /* behave like ZipInfo or like normal UnZip? */ + int aflag; /* -a: do ASCII-EBCDIC and/or end-of-line translation */ +#ifdef VMS + int bflag; /* -b: force fixed record format for binary files */ +#endif +#ifdef TANDEM + int bflag; /* -b: create text files in 'C' format (180)*/ +#endif +#if defined(UNIX) || defined(OS2) || defined(WIN32) + int B_flag; /* -B: back up existing files by renaming to *~##### */ +#else +#ifdef UNIXBACKUP + int B_flag; /* -B: back up existing files by renaming to *~##### */ +#endif +#endif + int cflag; /* -c: output to stdout */ + int C_flag; /* -C: match filenames case-insensitively */ + int D_flag; /* -D: don't restore directory (-DD: any) timestamps */ +#ifdef MACOS + int E_flag; /* -E: [MacOS] show Mac extra field during restoring */ +#endif + int fflag; /* -f: "freshen" (extract only newer files) */ +#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) + int acorn_nfs_ext; /* -F: RISC OS types & NFS filetype extensions */ +#endif + int hflag; /* -h: header line (zipinfo) */ +#ifdef MACOS + int i_flag; /* -i: [MacOS] ignore filenames stored in Mac e.f. */ +#endif +#ifdef RISCOS + int scanimage; /* -I: scan image files */ +#endif + int jflag; /* -j: junk pathnames (unzip) */ +/* + * VAX C V3.1-051 loves "\" in #define, but hates it in #if. + * HP C V7.3-009 dislikes "defined" in macro in #if (%CC-I-EXPANDEDDEFINED). + * It seems safest to avoid any continuation lines in either. + */ +#if defined(__ATHEOS__) || defined(__BEOS__) || defined(MACOS) +# define J_FLAG 1 +#else +# if defined( UNIX) && defined( __APPLE__) +# define J_FLAG 1 +# endif +#endif +#ifdef J_FLAG + int J_flag; /* -J: ignore AtheOS/BeOS/MacOS e. f. info (unzip) */ +#endif +#if (defined(__ATHEOS__) || defined(__BEOS__) || defined(UNIX)) + int K_flag; /* -K: keep setuid/setgid/tacky permissions */ +#endif + int lflag; /* -12slmv: listing format (zipinfo) */ + int L_flag; /* -L: convert filenames from some OSes to lowercase */ + int overwrite_none; /* -n: never overwrite files (no prompting) */ +#ifdef AMIGA + int N_flag; /* -N: restore comments as AmigaDOS filenotes */ +#endif + int overwrite_all; /* -o: OK to overwrite files without prompting */ +#endif /* !FUNZIP */ + int qflag; /* -q: produce a lot less output */ +#ifdef TANDEM + int rflag; /* -r: remove file extensions */ +#endif +#ifndef FUNZIP +#if (defined(MSDOS) || defined(FLEXOS) || defined(OS2) || defined(WIN32)) + int sflag; /* -s: convert spaces in filenames to underscores */ +#endif +#if (defined(NLM)) + int sflag; /* -s: convert spaces in filenames to underscores */ +#endif +#ifdef VMS + int S_flag; /* -S: use Stream_LF for text files (-a[a]) */ +#endif +#if (defined(MSDOS) || defined(__human68k__) || defined(OS2) || defined(WIN32)) + int volflag; /* -$: extract volume labels */ +#endif + int tflag; /* -t: test (unzip) or totals line (zipinfo) */ + int T_flag; /* -T: timestamps (unzip) or dec. time fmt (zipinfo) */ + int uflag; /* -u: "update" (extract only newer/brand-new files) */ +#if defined(UNIX) || defined(VMS) || defined(WIN32) + int U_flag; /* -U: escape non-ASCII, -UU No Unicode paths */ +#endif + int vflag; /* -v: (verbosely) list directory */ + int V_flag; /* -V: don't strip VMS version numbers */ + int W_flag; /* -W: wildcard '*' won't match '/' dir separator */ +#if (defined (__ATHEOS__) || defined(__BEOS__) || defined(UNIX)) + int X_flag; /* -X: restore owner/protection or UID/GID or ACLs */ +#else +#if (defined(TANDEM) || defined(THEOS)) + int X_flag; /* -X: restore owner/protection or UID/GID or ACLs */ +#else +#if (defined(OS2) || defined(VMS) || defined(WIN32)) + int X_flag; /* -X: restore owner/protection or UID/GID or ACLs */ +#endif +#endif +#endif +#ifdef VMS + int Y_flag; /* -Y: treat ".nnn" as ";nnn" version */ +#endif + int zflag; /* -z: display the zipfile comment (only, for unzip) */ +#ifdef VMS + int ods2_flag; /* -2: force names to conform to ODS2 */ +#endif +#if (!defined(RISCOS) && !defined(CMS_MVS) && !defined(TANDEM)) + int ddotflag; /* -:: don't skip over "../" path elements */ +#endif +#ifdef UNIX + int cflxflag; /* -^: allow control chars in extracted filenames */ +#endif +#endif /* !FUNZIP */ +} UzpOpts; + +/* intended to be a private struct: */ +typedef struct _ver { + uch major; /* e.g., integer 5 */ + uch minor; /* e.g., 2 */ + uch patchlevel; /* e.g., 0 */ + uch not_used; +} _version_type; + +typedef struct _UzpVer { + ulg structlen; /* length of the struct being passed */ + ulg flag; /* bit 0: is_beta bit 1: uses_zlib */ + ZCONST char *betalevel; /* e.g. "g BETA" or "" */ + ZCONST char *date; /* e.g. "9 Oct 08" (beta) or "9 October 2008" */ + ZCONST char *zlib_version;/* e.g. "1.2.3" or NULL */ + _version_type unzip; /* current UnZip version */ + _version_type zipinfo; /* current ZipInfo version */ + _version_type os2dll; /* OS2DLL version (retained for compatibility */ + _version_type windll; /* WinDLL version (retained for compatibility */ + _version_type dllapimin; /* last incompatible change of library API */ +} UzpVer; + +/* for Visual BASIC access to Windows DLLs: */ +typedef struct _UzpVer2 { + ulg structlen; /* length of the struct being passed */ + ulg flag; /* bit 0: is_beta bit 1: uses_zlib */ + char betalevel[10]; /* e.g. "g BETA" or "" */ + char date[20]; /* e.g. "9 Oct 08" (beta) or "9 October 2008" */ + char zlib_version[10]; /* e.g. "1.2.3" or NULL */ + _version_type unzip; /* current UnZip version */ + _version_type zipinfo; /* current ZipInfo version */ + _version_type os2dll; /* OS2DLL version (retained for compatibility */ + _version_type windll; /* WinDLL version (retained for compatibility */ + _version_type dllapimin; /* last incompatible change of library API */ +} UzpVer2; + + +typedef struct _Uzp_Siz64 { + unsigned long lo32; + unsigned long hi32; +} Uzp_Siz64; + +typedef struct _Uzp_cdir_Rec { + uch version_made_by[2]; + uch version_needed_to_extract[2]; + ush general_purpose_bit_flag; + ush compression_method; + ulg last_mod_dos_datetime; + ulg crc32; + Uzp_Siz64 csize; + Uzp_Siz64 ucsize; + ush filename_length; + ush extra_field_length; + ush file_comment_length; + ush disk_number_start; + ush internal_file_attributes; + ulg external_file_attributes; + Uzp_Siz64 relative_offset_local_header; +} Uzp_cdir_Rec; + + +#define UZPINIT_LEN sizeof(UzpInit) +#define UZPVER_LEN sizeof(UzpVer) +#define cbList(func) int (* UZ_EXP func)(char *filename, Uzp_cdir_Rec *crec) + + +/*--------------------------------------------------------------------------- + Return (and exit) values of the public UnZip API functions. + ---------------------------------------------------------------------------*/ + +/* external return codes */ +#define PK_OK 0 /* no error */ +#define PK_COOL 0 /* no error */ +#define PK_WARN 1 /* warning error */ +#define PK_ERR 2 /* error in zipfile */ +#define PK_BADERR 3 /* severe error in zipfile */ +#define PK_MEM 4 /* insufficient memory (during initialization) */ +#define PK_MEM2 5 /* insufficient memory (password failure) */ +#define PK_MEM3 6 /* insufficient memory (file decompression) */ +#define PK_MEM4 7 /* insufficient memory (memory decompression) */ +#define PK_MEM5 8 /* insufficient memory (not yet used) */ +#define PK_NOZIP 9 /* zipfile not found */ +#define PK_PARAM 10 /* bad or illegal parameters specified */ +#define PK_FIND 11 /* no files found */ +#define PK_DISK 50 /* disk full */ +#define PK_EOF 51 /* unexpected EOF */ + +#define IZ_CTRLC 80 /* user hit ^C to terminate */ +#define IZ_UNSUP 81 /* no files found: all unsup. compr/encrypt. */ +#define IZ_BADPWD 82 /* no files found: all had bad password */ +#define IZ_ERRBF 83 /* big-file archive, small-file program */ + +/* return codes of password fetches (negative = user abort; positive = error) */ +#define IZ_PW_ENTERED 0 /* got some password string; use/try it */ +#define IZ_PW_CANCEL -1 /* no password available (for this entry) */ +#define IZ_PW_CANCELALL -2 /* no password, skip any further pwd. request */ +#define IZ_PW_ERROR 5 /* = PK_MEM2 : failure (no mem, no tty, ...) */ + +/* flag values for status callback function */ +#define UZ_ST_START_EXTRACT 1 /* no details */ +#define UZ_ST_IN_PROGRESS 2 /* no details */ +#define UZ_ST_FINISH_MEMBER 3 /* 'details': extracted size */ + +/* return values of status callback function */ +#define UZ_ST_CONTINUE 0 +#define UZ_ST_BREAK 1 + + +/*--------------------------------------------------------------------------- + Prototypes for public UnZip API (DLL) functions. + ---------------------------------------------------------------------------*/ + +#define UzpMatch match + +int UZ_EXP UzpMain OF((int argc, char **argv)); +int UZ_EXP UzpAltMain OF((int argc, char **argv, UzpInit *init)); +ZCONST UzpVer * UZ_EXP UzpVersion OF((void)); +void UZ_EXP UzpFreeMemBuffer OF((UzpBuffer *retstr)); +#ifndef WINDLL +int UZ_EXP UzpUnzipToMemory OF((char *zip, char *file, UzpOpts *optflgs, + UzpCB *UsrFunc, UzpBuffer *retstr)); +int UZ_EXP UzpGrep OF((char *archive, char *file, + char *pattern, int cmd, int SkipBin, + UzpCB *UsrFunc)); +#endif +#ifdef OS2 +int UZ_EXP UzpFileTree OF((char *name, cbList(callBack), + char *cpInclude[], char *cpExclude[])); +#endif + +unsigned UZ_EXP UzpVersion2 OF((UzpVer2 *version)); +int UZ_EXP UzpValidate OF((char *archive, int AllCodes)); + +void show_commandline OF((char *args[])); + + +/* default I/O functions (can be swapped out via UzpAltMain() entry point): */ + +int UZ_EXP UzpMessagePrnt OF((zvoid *pG, uch *buf, ulg size, int flag)); +int UZ_EXP UzpMessageNull OF((zvoid *pG, uch *buf, ulg size, int flag)); +int UZ_EXP UzpInput OF((zvoid *pG, uch *buf, int *size, int flag)); +void UZ_EXP UzpMorePause OF((zvoid *pG, ZCONST char *prompt, int flag)); +int UZ_EXP UzpPassword OF((zvoid *pG, int *rcnt, char *pwbuf, + int size, ZCONST char *zfn, + ZCONST char *efn)); + +#define UTF8_BIT (1<<11) + +#ifdef __cplusplus +} +#endif + + +/*--------------------------------------------------------------------------- + Remaining private stuff for UnZip compilation. + ---------------------------------------------------------------------------*/ + +#ifdef UNZIP_INTERNAL +#include "third_party/unzip/unzpriv.h" +#endif + + +#endif /* !__unzip_h */ + diff --git a/third_party/unzip/unzip.mk b/third_party/unzip/unzip.mk new file mode 100644 index 000000000..982e6a656 --- /dev/null +++ b/third_party/unzip/unzip.mk @@ -0,0 +1,76 @@ +#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ +#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ + +PKGS += THIRD_PARTY_UNZIP + +THIRD_PARTY_UNZIP_ARTIFACTS += THIRD_PARTY_UNZIP_A +THIRD_PARTY_UNZIP = $(THIRD_PARTY_UNZIP_A_DEPS) $(THIRD_PARTY_UNZIP_A) +THIRD_PARTY_UNZIP_A = o/$(MODE)/third_party/unzip/unzip.a +THIRD_PARTY_UNZIP_A_FILES := $(wildcard third_party/unzip/*) +THIRD_PARTY_UNZIP_A_HDRS = $(filter %.h,$(THIRD_PARTY_UNZIP_A_FILES)) +THIRD_PARTY_UNZIP_A_INCS = $(filter %.inc,$(THIRD_PARTY_UNZIP_A_FILES)) +THIRD_PARTY_UNZIP_A_SRCS = $(filter %.c,$(THIRD_PARTY_UNZIP_A_FILES)) +THIRD_PARTY_UNZIP_A_OBJS = $(THIRD_PARTY_UNZIP_A_SRCS:%.c=o/$(MODE)/%.o) + +THIRD_PARTY_UNZIP_A_DIRECTDEPS = \ + LIBC_CALLS \ + LIBC_FMT \ + LIBC_INTRIN \ + LIBC_LOG \ + LIBC_MEM \ + LIBC_NEXGEN32E \ + LIBC_RUNTIME \ + LIBC_STDIO \ + LIBC_STR \ + LIBC_STUBS \ + LIBC_SYSV \ + LIBC_TIME \ + LIBC_UNICODE \ + LIBC_ZIPOS \ + THIRD_PARTY_BZIP2 + +THIRD_PARTY_UNZIP_A_DEPS := \ + $(call uniq,$(foreach x,$(THIRD_PARTY_UNZIP_A_DIRECTDEPS),$($(x)))) + +THIRD_PARTY_UNZIP_A_CHECKS = \ + $(THIRD_PARTY_UNZIP_A).pkg + +$(THIRD_PARTY_UNZIP_A): \ + third_party/unzip/ \ + $(THIRD_PARTY_UNZIP_A).pkg \ + $(THIRD_PARTY_UNZIP_A_OBJS) + +$(THIRD_PARTY_UNZIP_A).pkg: \ + $(THIRD_PARTY_UNZIP_A_OBJS) \ + $(foreach x,$(THIRD_PARTY_UNZIP_A_DIRECTDEPS),$($(x)_A).pkg) + +o/$(MODE)/third_party/unzip/unzip.com.dbg: \ + $(THIRD_PARTY_UNZIP) \ + o/$(MODE)/third_party/unzip/unzip.o \ + $(CRT) \ + $(APE_NO_MODIFY_SELF) + @$(APELINK) + +$(THIRD_PARTY_UNZIP_A_OBJS): \ + OVERRIDE_CPPFLAGS += \ + -DUSE_BZIP2 \ + -DUNICODE_SUPPORT \ + -DHAVE_UNLINK \ + -DLARGE_FILE_SUPPORT \ + -DHAVE_TERMIOS_H \ + -DNO_LCHMOD + +THIRD_PARTY_UNZIP_COMS = o/$(MODE)/third_party/unzip/unzip.com +THIRD_PARTY_UNZIP_BINS = $(THIRD_PARTY_UNZIP_COMS) $(THIRD_PARTY_UNZIP_COMS:%=%.dbg) +THIRD_PARTY_UNZIP_LIBS = $(foreach x,$(THIRD_PARTY_UNZIP_ARTIFACTS),$($(x))) +THIRD_PARTY_UNZIP_SRCS = $(foreach x,$(THIRD_PARTY_UNZIP_ARTIFACTS),$($(x)_SRCS)) +THIRD_PARTY_UNZIP_HDRS = $(foreach x,$(THIRD_PARTY_UNZIP_ARTIFACTS),$($(x)_HDRS)) +THIRD_PARTY_UNZIP_INCS = $(foreach x,$(THIRD_PARTY_UNZIP_ARTIFACTS),$($(x)_INCS)) +THIRD_PARTY_UNZIP_CHECKS = $(foreach x,$(THIRD_PARTY_UNZIP_ARTIFACTS),$($(x)_CHECKS)) +THIRD_PARTY_UNZIP_OBJS = $(foreach x,$(THIRD_PARTY_UNZIP_ARTIFACTS),$($(x)_OBJS)) +$(THIRD_PARTY_UNZIP_OBJS): third_party/unzip/unzip.mk + +.PHONY: o/$(MODE)/third_party/unzip +o/$(MODE)/third_party/unzip: \ + $(THIRD_PARTY_UNZIP_BINS) \ + $(THIRD_PARTY_UNZIP_CHECKS) diff --git a/third_party/unzip/unzip.txt b/third_party/unzip/unzip.txt new file mode 100644 index 000000000..e8e971968 --- /dev/null +++ b/third_party/unzip/unzip.txt @@ -0,0 +1,955 @@ +UNZIP(1L) UNZIP(1L) + +NAME + unzip - list, test and extract compressed files in a ZIP archive + +SYNOPSIS + unzip [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] file[.zip] [file(s) ...] + [-x xfile(s) ...] [-d exdir] + +DESCRIPTION + unzip will list, test, or extract files from a ZIP archive, commonly + found on MS-DOS systems. The default behavior (with no options) is to + extract into the current directory (and subdirectories below it) all + files from the specified ZIP archive. A companion program, zip(1L), + creates ZIP archives; both programs are compatible with archives cre- + ated by PKWARE's PKZIP and PKUNZIP for MS-DOS, but in many cases the + program options or default behaviors differ. + +ARGUMENTS + file[.zip] + Path of the ZIP archive(s). If the file specification is a + wildcard, each matching file is processed in an order determined + by the operating system (or file system). Only the filename can + be a wildcard; the path itself cannot. Wildcard expressions are + similar to those supported in commonly used Unix shells (sh, + ksh, csh) and may contain: + + * matches a sequence of 0 or more characters + + ? matches exactly 1 character + + [...] matches any single character found inside the brackets; + ranges are specified by a beginning character, a hyphen, + and an ending character. If an exclamation point or a + caret (`!' or `^') follows the left bracket, then the + range of characters within the brackets is complemented + (that is, anything except the characters inside the + brackets is considered a match). To specify a verbatim + left bracket, the three-character sequence ``[[]'' has to + be used. + + (Be sure to quote any character that might otherwise be inter- + preted or modified by the operating system, particularly under + Unix and VMS.) If no matches are found, the specification is + assumed to be a literal filename; and if that also fails, the + suffix .zip is appended. Note that self-extracting ZIP files + are supported, as with any other ZIP archive; just specify the + .exe suffix (if any) explicitly. + + [file(s)] + An optional list of archive members to be processed, separated + by spaces. (VMS versions compiled with VMSCLI defined must + delimit files with commas instead. See -v in OPTIONS below.) + Regular expressions (wildcards) may be used to match multiple + members; see above. Again, be sure to quote expressions that + would otherwise be expanded or modified by the operating system. + + [-x xfile(s)] + An optional list of archive members to be excluded from process- + ing. Since wildcard characters normally match (`/') directory + separators (for exceptions see the option -W), this option may + be used to exclude any files that are in subdirectories. For + example, ``unzip foo *.[ch] -x */*'' would extract all C source + files in the main directory, but none in any subdirectories. + Without the -x option, all C source files in all directories + within the zipfile would be extracted. + + [-d exdir] + An optional directory to which to extract files. By default, + all files and subdirectories are recreated in the current direc- + tory; the -d option allows extraction in an arbitrary directory + (always assuming one has permission to write to the directory). + This option need not appear at the end of the command line; it + is also accepted before the zipfile specification (with the nor- + mal options), immediately after the zipfile specification, or + between the file(s) and the -x option. The option and directory + may be concatenated without any white space between them, but + note that this may cause normal shell behavior to be suppressed. + In particular, ``-d ~'' (tilde) is expanded by Unix C shells + into the name of the user's home directory, but ``-d~'' is + treated as a literal subdirectory ``~'' of the current direc- + tory. + +OPTIONS + Note that, in order to support obsolescent hardware, unzip's usage + screen is limited to 22 or 23 lines and should therefore be considered + only a reminder of the basic unzip syntax rather than an exhaustive + list of all possible flags. The exhaustive list follows: + + -Z zipinfo(1L) mode. If the first option on the command line is + -Z, the remaining options are taken to be zipinfo(1L) options. + See the appropriate manual page for a description of these + options. + + -A [OS/2, Unix DLL] print extended help for the DLL's programming + interface (API). + + -c extract files to stdout/screen (``CRT''). This option is simi- + lar to the -p option except that the name of each file is + printed as it is extracted, the -a option is allowed, and ASCII- + EBCDIC conversion is automatically performed if appropriate. + This option is not listed in the unzip usage screen. + + -f freshen existing files, i.e., extract only those files that + already exist on disk and that are newer than the disk copies. + By default unzip queries before overwriting, but the -o option + may be used to suppress the queries. Note that under many oper- + ating systems, the TZ (timezone) environment variable must be + set correctly in order for -f and -u to work properly (under + Unix the variable is usually set automatically). The reasons + for this are somewhat subtle but have to do with the differences + between DOS-format file times (always local time) and Unix-for- + mat times (always in GMT/UTC) and the necessity to compare the + two. A typical TZ value is ``PST8PDT'' (US Pacific time with + automatic adjustment for Daylight Savings Time or ``summer + time''). + + -l list archive files (short format). The names, uncompressed file + sizes and modification dates and times of the specified files + are printed, along with totals for all files specified. If + UnZip was compiled with OS2_EAS defined, the -l option also + lists columns for the sizes of stored OS/2 extended attributes + (EAs) and OS/2 access control lists (ACLs). In addition, the + zipfile comment and individual file comments (if any) are dis- + played. If a file was archived from a single-case file system + (for example, the old MS-DOS FAT file system) and the -L option + was given, the filename is converted to lowercase and is pre- + fixed with a caret (^). + + -p extract files to pipe (stdout). Nothing but the file data is + sent to stdout, and the files are always extracted in binary + format, just as they are stored (no conversions). + + -t test archive files. This option extracts each specified file in + memory and compares the CRC (cyclic redundancy check, an + enhanced checksum) of the expanded file with the original file's + stored CRC value. + + -T [most OSes] set the timestamp on the archive(s) to that of the + newest file in each one. This corresponds to zip's -go option + except that it can be used on wildcard zipfiles (e.g., ``unzip + -T \*.zip'') and is much faster. + + -u update existing files and create new ones if needed. This + option performs the same function as the -f option, extracting + (with query) files that are newer than those with the same name + on disk, and in addition it extracts those files that do not + already exist on disk. See -f above for information on setting + the timezone properly. + + -v list archive files (verbose format) or show diagnostic version + info. This option has evolved and now behaves as both an option + and a modifier. As an option it has two purposes: when a zip- + file is specified with no other options, -v lists archive files + verbosely, adding to the basic -l info the compression method, + compressed size, compression ratio and 32-bit CRC. In contrast + to most of the competing utilities, unzip removes the 12 addi- + tional header bytes of encrypted entries from the compressed + size numbers. Therefore, compressed size and compression ratio + figures are independent of the entry's encryption status and + show the correct compression performance. (The complete size of + the encrypted compressed data stream for zipfile entries is + reported by the more verbose zipinfo(1L) reports, see the sepa- + rate manual.) When no zipfile is specified (that is, the com- + plete command is simply ``unzip -v''), a diagnostic screen is + printed. In addition to the normal header with release date and + version, unzip lists the home Info-ZIP ftp site and where to + find a list of other ftp and non-ftp sites; the target operating + system for which it was compiled, as well as (possibly) the + hardware on which it was compiled, the compiler and version + used, and the compilation date; any special compilation options + that might affect the program's operation (see also DECRYPTION + below); and any options stored in environment variables that + might do the same (see ENVIRONMENT OPTIONS below). As a modi- + fier it works in conjunction with other options (e.g., -t) to + produce more verbose or debugging output; this is not yet fully + implemented but will be in future releases. + + -z display only the archive comment. + +MODIFIERS + -a convert text files. Ordinarily all files are extracted exactly + as they are stored (as ``binary'' files). The -a option causes + files identified by zip as text files (those with the `t' label + in zipinfo listings, rather than `b') to be automatically + extracted as such, converting line endings, end-of-file charac- + ters and the character set itself as necessary. (For example, + Unix files use line feeds (LFs) for end-of-line (EOL) and have + no end-of-file (EOF) marker; Macintoshes use carriage returns + (CRs) for EOLs; and most PC operating systems use CR+LF for EOLs + and control-Z for EOF. In addition, IBM mainframes and the + Michigan Terminal System use EBCDIC rather than the more common + ASCII character set, and NT supports Unicode.) Note that zip's + identification of text files is by no means perfect; some + ``text'' files may actually be binary and vice versa. unzip + therefore prints ``[text]'' or ``[binary]'' as a visual check + for each file it extracts when using the -a option. The -aa + option forces all files to be extracted as text, regardless of + the supposed file type. On VMS, see also -S. + + -b [general] treat all files as binary (no text conversions). This + is a shortcut for ---a. + + -b [Tandem] force the creation files with filecode type 180 ('C') + when extracting Zip entries marked as "text". (On Tandem, -a is + enabled by default, see above). + + -b [VMS] auto-convert binary files (see -a above) to fixed-length, + 512-byte record format. Doubling the option (-bb) forces all + files to be extracted in this format. When extracting to stan- + dard output (-c or -p option in effect), the default conversion + of text record delimiters is disabled for binary (-b) resp. all + (-bb) files. + + -B [when compiled with UNIXBACKUP defined] save a backup copy of + each overwritten file. The backup file is gets the name of the + target file with a tilde and optionally a unique sequence number + (up to 5 digits) appended. The sequence number is applied when- + ever another file with the original name plus tilde already + exists. When used together with the "overwrite all" option -o, + numbered backup files are never created. In this case, all + backup files are named as the original file with an appended + tilde, existing backup files are deleted without notice. This + feature works similarly to the default behavior of emacs(1) in + many locations. + + Example: the old copy of ``foo'' is renamed to ``foo~''. + + Warning: Users should be aware that the -B option does not pre- + vent loss of existing data under all circumstances. For exam- + ple, when unzip is run in overwrite-all mode, an existing + ``foo~'' file is deleted before unzip attempts to rename ``foo'' + to ``foo~''. When this rename attempt fails (because of a file + locks, insufficient privileges, or ...), the extraction of + ``foo~'' gets cancelled, but the old backup file is already + lost. A similar scenario takes place when the sequence number + range for numbered backup files gets exhausted (99999, or 65535 + for 16-bit systems). In this case, the backup file with the + maximum sequence number is deleted and replaced by the new + backup version without notice. + + -C use case-insensitive matching for the selection of archive + entries from the command-line list of extract selection pat- + terns. unzip's philosophy is ``you get what you ask for'' (this + is also responsible for the -L/-U change; see the relevant + options below). Because some file systems are fully case-sensi- + tive (notably those under the Unix operating system) and because + both ZIP archives and unzip itself are portable across plat- + forms, unzip's default behavior is to match both wildcard and + literal filenames case-sensitively. That is, specifying ``make- + file'' on the command line will only match ``makefile'' in the + archive, not ``Makefile'' or ``MAKEFILE'' (and similarly for + wildcard specifications). Since this does not correspond to the + behavior of many other operating/file systems (for example, OS/2 + HPFS, which preserves mixed case but is not sensitive to it), + the -C option may be used to force all filename matches to be + case-insensitive. In the example above, all three files would + then match ``makefile'' (or ``make*'', or similar). The -C + option affects file specs in both the normal file list and the + excluded-file list (xlist). + + Please note that the -C option does neither affect the search + for the zipfile(s) nor the matching of archive entries to exist- + ing files on the extraction path. On a case-sensitive file sys- + tem, unzip will never try to overwrite a file ``FOO'' when + extracting an entry ``foo''! + + -D skip restoration of timestamps for extracted items. Normally, + unzip tries to restore all meta-information for extracted items + that are supplied in the Zip archive (and do not require privi- + leges or impose a security risk). By specifying -D, unzip is + told to suppress restoration of timestamps for directories + explicitly created from Zip archive entries. This option only + applies to ports that support setting timestamps for directories + (currently ATheOS, BeOS, MacOS, OS/2, Unix, VMS, Win32, for + other unzip ports, -D has no effect). The duplicated option -DD + forces suppression of timestamp restoration for all extracted + entries (files and directories). This option results in setting + the timestamps for all extracted entries to the current time. + + On VMS, the default setting for this option is -D for consis- + tency with the behaviour of BACKUP: file timestamps are + restored, timestamps of extracted directories are left at the + current time. To enable restoration of directory timestamps, + the negated option --D should be specified. On VMS, the option + -D disables timestamp restoration for all extracted Zip archive + items. (Here, a single -D on the command line combines with the + default -D to do what an explicit -DD does on other systems.) + + -E [MacOS only] display contents of MacOS extra field during + restore operation. + + -F [Acorn only] suppress removal of NFS filetype extension from + stored filenames. + + -F [non-Acorn systems supporting long filenames with embedded com- + mas, and only if compiled with ACORN_FTYPE_NFS defined] trans- + late filetype information from ACORN RISC OS extra field blocks + into a NFS filetype extension and append it to the names of the + extracted files. (When the stored filename appears to already + have an appended NFS filetype extension, it is replaced by the + info from the extra field.) + + -i [MacOS only] ignore filenames stored in MacOS extra fields. + Instead, the most compatible filename stored in the generic part + of the entry's header is used. + + -j junk paths. The archive's directory structure is not recreated; + all files are deposited in the extraction directory (by default, + the current one). + + -J [BeOS only] junk file attributes. The file's BeOS file + attributes are not restored, just the file's data. + + -J [MacOS only] ignore MacOS extra fields. All Macintosh specific + info is skipped. Data-fork and resource-fork are restored as + separate files. + + -K [AtheOS, BeOS, Unix only] retain SUID/SGID/Tacky file + attributes. Without this flag, these attribute bits are cleared + for security reasons. + + -L convert to lowercase any filename originating on an uppercase- + only operating system or file system. (This was unzip's default + behavior in releases prior to 5.11; the new default behavior is + identical to the old behavior with the -U option, which is now + obsolete and will be removed in a future release.) Depending on + the archiver, files archived under single-case file systems + (VMS, old MS-DOS FAT, etc.) may be stored as all-uppercase + names; this can be ugly or inconvenient when extracting to a + case-preserving file system such as OS/2 HPFS or a case-sensi- + tive one such as under Unix. By default unzip lists and + extracts such filenames exactly as they're stored (excepting + truncation, conversion of unsupported characters, etc.); this + option causes the names of all files from certain systems to be + converted to lowercase. The -LL option forces conversion of + every filename to lowercase, regardless of the originating file + system. + + -M pipe all output through an internal pager similar to the Unix + more(1) command. At the end of a screenful of output, unzip + pauses with a ``--More--'' prompt; the next screenful may be + viewed by pressing the Enter (Return) key or the space bar. + unzip can be terminated by pressing the ``q'' key and, on some + systems, the Enter/Return key. Unlike Unix more(1), there is no + forward-searching or editing capability. Also, unzip doesn't + notice if long lines wrap at the edge of the screen, effectively + resulting in the printing of two or more lines and the likeli- + hood that some text will scroll off the top of the screen before + being viewed. On some systems the number of available lines on + the screen is not detected, in which case unzip assumes the + height is 24 lines. + + -n never overwrite existing files. If a file already exists, skip + the extraction of that file without prompting. By default unzip + queries before extracting any file that already exists; the user + may choose to overwrite only the current file, overwrite all + files, skip extraction of the current file, skip extraction of + all existing files, or rename the current file. + + -N [Amiga] extract file comments as Amiga filenotes. File comments + are created with the -c option of zip(1L), or with the -N option + of the Amiga port of zip(1L), which stores filenotes as com- + ments. + + -o overwrite existing files without prompting. This is a dangerous + option, so use it with care. (It is often used with -f, how- + ever, and is the only way to overwrite directory EAs under + OS/2.) + + -P password + use password to decrypt encrypted zipfile entries (if any). + THIS IS INSECURE! Many multi-user operating systems provide + ways for any user to see the current command line of any other + user; even on stand-alone systems there is always the threat of + over-the-shoulder peeking. Storing the plaintext password as + part of a command line in an automated script is even worse. + Whenever possible, use the non-echoing, interactive prompt to + enter passwords. (And where security is truly important, use + strong encryption such as Pretty Good Privacy instead of the + relatively weak encryption provided by standard zipfile utili- + ties.) + + -q perform operations quietly (-qq = even quieter). Ordinarily + unzip prints the names of the files it's extracting or testing, + the extraction methods, any file or zipfile comments that may be + stored in the archive, and possibly a summary when finished with + each archive. The -q[q] options suppress the printing of some + or all of these messages. + + -s [OS/2, NT, MS-DOS] convert spaces in filenames to underscores. + Since all PC operating systems allow spaces in filenames, unzip + by default extracts filenames with spaces intact (e.g., + ``EA DATA. SF''). This can be awkward, however, since MS-DOS in + particular does not gracefully support spaces in filenames. + Conversion of spaces to underscores can eliminate the awkward- + ness in some cases. + + -S [VMS] convert text files (-a, -aa) into Stream_LF record format, + instead of the text-file default, variable-length record format. + (Stream_LF is the default record format of VMS unzip. It is + applied unless conversion (-a, -aa and/or -b, -bb) is requested + or a VMS-specific entry is processed.) + + -U [UNICODE_SUPPORT only] modify or disable UTF-8 handling. When + UNICODE_SUPPORT is available, the option -U forces unzip to + escape all non-ASCII characters from UTF-8 coded filenames as + ``#Uxxxx'' (for UCS-2 characters, or ``#Lxxxxxx'' for unicode + codepoints needing 3 octets). This option is mainly provided + for debugging purpose when the fairly new UTF-8 support is sus- + pected to mangle up extracted filenames. + + The option -UU allows to entirely disable the recognition of + UTF-8 encoded filenames. The handling of filename codings + within unzip falls back to the behaviour of previous versions. + + [old, obsolete usage] leave filenames uppercase if created under + MS-DOS, VMS, etc. See -L above. + + -V retain (VMS) file version numbers. VMS files can be stored with + a version number, in the format file.ext;##. By default the + ``;##'' version numbers are stripped, but this option allows + them to be retained. (On file systems that limit filenames to + particularly short lengths, the version numbers may be truncated + or stripped regardless of this option.) + + -W [only when WILD_STOP_AT_DIR compile-time option enabled] modi- + fies the pattern matching routine so that both `?' (single-char + wildcard) and `*' (multi-char wildcard) do not match the direc- + tory separator character `/'. (The two-character sequence + ``**'' acts as a multi-char wildcard that includes the directory + separator in its matched characters.) Examples: + + "*.c" matches "foo.c" but not "mydir/foo.c" + "**.c" matches both "foo.c" and "mydir/foo.c" + "*/*.c" matches "bar/foo.c" but not "baz/bar/foo.c" + "??*/*" matches "ab/foo" and "abc/foo" + but not "a/foo" or "a/b/foo" + + This modified behaviour is equivalent to the pattern matching + style used by the shells of some of UnZip's supported target OSs + (one example is Acorn RISC OS). This option may not be avail- + able on systems where the Zip archive's internal directory sepa- + rator character `/' is allowed as regular character in native + operating system filenames. (Currently, UnZip uses the same + pattern matching rules for both wildcard zipfile specifications + and zip entry selection patterns in most ports. For systems + allowing `/' as regular filename character, the -W option would + not work as expected on a wildcard zipfile specification.) + + -X [VMS, Unix, OS/2, NT, Tandem] restore owner/protection info + (UICs and ACL entries) under VMS, or user and group info + (UID/GID) under Unix, or access control lists (ACLs) under cer- + tain network-enabled versions of OS/2 (Warp Server with IBM LAN + Server/Requester 3.0 to 5.0; Warp Connect with IBM Peer 1.0), or + security ACLs under Windows NT. In most cases this will require + special system privileges, and doubling the option (-XX) under + NT instructs unzip to use privileges for extraction; but under + Unix, for example, a user who belongs to several groups can + restore files owned by any of those groups, as long as the user + IDs match his or her own. Note that ordinary file attributes + are always restored--this option applies only to optional, extra + ownership info available on some operating systems. [NT's + access control lists do not appear to be especially compatible + with OS/2's, so no attempt is made at cross-platform portability + of access privileges. It is not clear under what conditions + this would ever be useful anyway.] + + -Y [VMS] treat archived file name endings of ``.nnn'' (where + ``nnn'' is a decimal number) as if they were VMS version num- + bers (``;nnn''). (The default is to treat them as file types.) + Example: + "a.b.3" -> "a.b;3". + + -$ [MS-DOS, OS/2, NT] restore the volume label if the extraction + medium is removable (e.g., a diskette). Doubling the option + (-$$) allows fixed media (hard disks) to be labelled as well. + By default, volume labels are ignored. + + -/ extensions + [Acorn only] overrides the extension list supplied by Unzip$Ext + environment variable. During extraction, filename extensions + that match one of the items in this extension list are swapped + in front of the base name of the extracted file. + + -: [all but Acorn, VM/CMS, MVS, Tandem] allows to extract archive + members into locations outside of the current `` extraction root + folder''. For security reasons, unzip normally removes ``parent + dir'' path components (``../'') from the names of extracted + file. This safety feature (new for version 5.50) prevents unzip + from accidentally writing files to ``sensitive'' areas outside + the active extraction folder tree head. The -: option lets + unzip switch back to its previous, more liberal behaviour, to + allow exact extraction of (older) archives that used ``../'' + components to create multiple directory trees at the level of + the current extraction folder. This option does not enable + writing explicitly to the root directory (``/''). To achieve + this, it is necessary to set the extraction target folder to + root (e.g. -d / ). However, when the -: option is specified, it + is still possible to implicitly write to the root directory by + specifying enough ``../'' path components within the zip + archive. Use this option with extreme caution. + + -^ [Unix only] allow control characters in names of extracted ZIP + archive entries. On Unix, a file name may contain any (8-bit) + character code with the two exception '/' (directory delimiter) + and NUL (0x00, the C string termination indicator), unless the + specific file system has more restrictive conventions. Gener- + ally, this allows to embed ASCII control characters (or even + sophisticated control sequences) in file names, at least on + 'native' Unix file systems. However, it may be highly suspi- + cious to make use of this Unix "feature". Embedded control + characters in file names might have nasty side effects when dis- + played on screen by some listing code without sufficient filter- + ing. And, for ordinary users, it may be difficult to handle + such file names (e.g. when trying to specify it for open, copy, + move, or delete operations). Therefore, unzip applies a filter + by default that removes potentially dangerous control characters + from the extracted file names. The -^ option allows to override + this filter in the rare case that embedded filename control + characters are to be intentionally restored. + + -2 [VMS] force unconditionally conversion of file names to + ODS2-compatible names. The default is to exploit the destina- + tion file system, preserving case and extended file name charac- + ters on an ODS5 destination file system; and applying the + ODS2-compatibility file name filtering on an ODS2 destination + file system. + +ENVIRONMENT OPTIONS + unzip's default behavior may be modified via options placed in an envi- + ronment variable. This can be done with any option, but it is probably + most useful with the -a, -L, -C, -q, -o, or -n modifiers: make unzip + auto-convert text files by default, make it convert filenames from + uppercase systems to lowercase, make it match names case-insensitively, + make it quieter, or make it always overwrite or never overwrite files + as it extracts them. For example, to make unzip act as quietly as pos- + sible, only reporting errors, one would use one of the following com- + mands: + + Unix Bourne shell: + UNZIP=-qq; export UNZIP + + Unix C shell: + setenv UNZIP -qq + + OS/2 or MS-DOS: + set UNZIP=-qq + + VMS (quotes for lowercase): + define UNZIP_OPTS "-qq" + + Environment options are, in effect, considered to be just like any + other command-line options, except that they are effectively the first + options on the command line. To override an environment option, one + may use the ``minus operator'' to remove it. For instance, to override + one of the quiet-flags in the example above, use the command + + unzip --q[other options] zipfile + + The first hyphen is the normal switch character, and the second is a + minus sign, acting on the q option. Thus the effect here is to cancel + one quantum of quietness. To cancel both quiet flags, two (or more) + minuses may be used: + + unzip -t--q zipfile + unzip ---qt zipfile + + (the two are equivalent). This may seem awkward or confusing, but it + is reasonably intuitive: just ignore the first hyphen and go from + there. It is also consistent with the behavior of Unix nice(1). + + As suggested by the examples above, the default variable names are + UNZIP_OPTS for VMS (where the symbol used to install unzip as a foreign + command would otherwise be confused with the environment variable), and + UNZIP for all other operating systems. For compatibility with zip(1L), + UNZIPOPT is also accepted (don't ask). If both UNZIP and UNZIPOPT are + defined, however, UNZIP takes precedence. unzip's diagnostic option + (-v with no zipfile name) can be used to check the values of all four + possible unzip and zipinfo environment variables. + + The timezone variable (TZ) should be set according to the local time- + zone in order for the -f and -u to operate correctly. See the descrip- + tion of -f above for details. This variable may also be necessary to + get timestamps of extracted files to be set correctly. The WIN32 + (Win9x/ME/NT4/2K/XP/2K3) port of unzip gets the timezone configuration + from the registry, assuming it is correctly set in the Control Panel. + The TZ variable is ignored for this port. + +DECRYPTION + Encrypted archives are fully supported by Info-ZIP software, but due to + United States export restrictions, de-/encryption support might be dis- + abled in your compiled binary. However, since spring 2000, US export + restrictions have been liberated, and our source archives do now + include full crypt code. In case you need binary distributions with + crypt support enabled, see the file ``WHERE'' in any Info-ZIP source or + binary distribution for locations both inside and outside the US. + + Some compiled versions of unzip may not support decryption. To check a + version for crypt support, either attempt to test or extract an + encrypted archive, or else check unzip's diagnostic screen (see the -v + option above) for ``[decryption]'' as one of the special compilation + options. + + As noted above, the -P option may be used to supply a password on the + command line, but at a cost in security. The preferred decryption + method is simply to extract normally; if a zipfile member is encrypted, + unzip will prompt for the password without echoing what is typed. + unzip continues to use the same password as long as it appears to be + valid, by testing a 12-byte header on each file. The correct password + will always check out against the header, but there is a 1-in-256 + chance that an incorrect password will as well. (This is a security + feature of the PKWARE zipfile format; it helps prevent brute-force + attacks that might otherwise gain a large speed advantage by testing + only the header.) In the case that an incorrect password is given but + it passes the header test anyway, either an incorrect CRC will be gen- + erated for the extracted data or else unzip will fail during the + extraction because the ``decrypted'' bytes do not constitute a valid + compressed data stream. + + If the first password fails the header check on some file, unzip will + prompt for another password, and so on until all files are extracted. + If a password is not known, entering a null password (that is, just a + carriage return or ``Enter'') is taken as a signal to skip all further + prompting. Only unencrypted files in the archive(s) will thereafter be + extracted. (In fact, that's not quite true; older versions of zip(1L) + and zipcloak(1L) allowed null passwords, so unzip checks each encrypted + file to see if the null password works. This may result in ``false + positives'' and extraction errors, as noted above.) + + Archives encrypted with 8-bit passwords (for example, passwords with + accented European characters) may not be portable across systems and/or + other archivers. This problem stems from the use of multiple encoding + methods for such characters, including Latin-1 (ISO 8859-1) and OEM + code page 850. DOS PKZIP 2.04g uses the OEM code page; Windows PKZIP + 2.50 uses Latin-1 (and is therefore incompatible with DOS PKZIP); Info- + ZIP uses the OEM code page on DOS, OS/2 and Win3.x ports but ISO coding + (Latin-1 etc.) everywhere else; and Nico Mak's WinZip 6.x does not + allow 8-bit passwords at all. UnZip 5.3 (or newer) attempts to use the + default character set first (e.g., Latin-1), followed by the alternate + one (e.g., OEM code page) to test passwords. On EBCDIC systems, if + both of these fail, EBCDIC encoding will be tested as a last resort. + (EBCDIC is not tested on non-EBCDIC systems, because there are no known + archivers that encrypt using EBCDIC encoding.) ISO character encodings + other than Latin-1 are not supported. The new addition of (partially) + Unicode (resp. UTF-8) support in UnZip 6.0 has not yet been adapted to + the encryption password handling in unzip. On systems that use UTF-8 + as native character encoding, unzip simply tries decryption with the + native UTF-8 encoded password; the built-in attempts to check the pass- + word in translated encoding have not yet been adapted for UTF-8 support + and will consequently fail. + +EXAMPLES + To use unzip to extract all members of the archive letters.zip into the + current directory and subdirectories below it, creating any subdirecto- + ries as necessary: + + unzip letters + + To extract all members of letters.zip into the current directory only: + + unzip -j letters + + To test letters.zip, printing only a summary message indicating whether + the archive is OK or not: + + unzip -tq letters + + To test all zipfiles in the current directory, printing only the sum- + maries: + + unzip -tq \*.zip + + (The backslash before the asterisk is only required if the shell + expands wildcards, as in Unix; double quotes could have been used + instead, as in the source examples below.) To extract to standard out- + put all members of letters.zip whose names end in .tex, auto-converting + to the local end-of-line convention and piping the output into more(1): + + unzip -ca letters \*.tex | more + + To extract the binary file paper1.dvi to standard output and pipe it to + a printing program: + + unzip -p articles paper1.dvi | dvips + + To extract all FORTRAN and C source files--*.f, *.c, *.h, and Make- + file--into the /tmp directory: + + unzip source.zip "*.[fch]" Makefile -d /tmp + + (the double quotes are necessary only in Unix and only if globbing is + turned on). To extract all FORTRAN and C source files, regardless of + case (e.g., both *.c and *.C, and any makefile, Makefile, MAKEFILE or + similar): + + unzip -C source.zip "*.[fch]" makefile -d /tmp + + To extract any such files but convert any uppercase MS-DOS or VMS names + to lowercase and convert the line-endings of all of the files to the + local standard (without respect to any files that might be marked + ``binary''): + + unzip -aaCL source.zip "*.[fch]" makefile -d /tmp + + To extract only newer versions of the files already in the current + directory, without querying (NOTE: be careful of unzipping in one + timezone a zipfile created in another--ZIP archives other than those + created by Zip 2.1 or later contain no timezone information, and a + ``newer'' file from an eastern timezone may, in fact, be older): + + unzip -fo sources + + To extract newer versions of the files already in the current directory + and to create any files not already there (same caveat as previous + example): + + unzip -uo sources + + To display a diagnostic screen showing which unzip and zipinfo options + are stored in environment variables, whether decryption support was + compiled in, the compiler with which unzip was compiled, etc.: + + unzip -v + + In the last five examples, assume that UNZIP or UNZIP_OPTS is set to + -q. To do a singly quiet listing: + + unzip -l file.zip + + To do a doubly quiet listing: + + unzip -ql file.zip + + (Note that the ``.zip'' is generally not necessary.) To do a standard + listing: + + unzip --ql file.zip + or + unzip -l-q file.zip + or + unzip -l--q file.zip + (Extra minuses in options don't hurt.) + +TIPS + The current maintainer, being a lazy sort, finds it very useful to + define a pair of aliases: tt for ``unzip -tq'' and ii for ``unzip -Z'' + (or ``zipinfo''). One may then simply type ``tt zipfile'' to test an + archive, something that is worth making a habit of doing. With luck + unzip will report ``No errors detected in compressed data of zip- + file.zip,'' after which one may breathe a sigh of relief. + + The maintainer also finds it useful to set the UNZIP environment vari- + able to ``-aL'' and is tempted to add ``-C'' as well. His ZIPINFO + variable is set to ``-z''. + +DIAGNOSTICS + The exit status (or error level) approximates the exit codes defined by + PKWARE and takes on the following values, except under VMS: + + 0 normal; no errors or warnings detected. + + 1 one or more warning errors were encountered, but process- + ing completed successfully anyway. This includes zip- + files where one or more files was skipped due to unsup- + ported compression method or encryption with an unknown + password. + + 2 a generic error in the zipfile format was detected. Pro- + cessing may have completed successfully anyway; some bro- + ken zipfiles created by other archivers have simple work- + arounds. + + 3 a severe error in the zipfile format was detected. Pro- + cessing probably failed immediately. + + 4 unzip was unable to allocate memory for one or more + buffers during program initialization. + + 5 unzip was unable to allocate memory or unable to obtain a + tty to read the decryption password(s). + + 6 unzip was unable to allocate memory during decompression + to disk. + + 7 unzip was unable to allocate memory during in-memory + decompression. + + 8 [currently not used] + + 9 the specified zipfiles were not found. + + 10 invalid options were specified on the command line. + + 11 no matching files were found. + + 50 the disk is (or was) full during extraction. + + 51 the end of the ZIP archive was encountered prematurely. + + 80 the user aborted unzip prematurely with control-C (or + similar) + + 81 testing or extraction of one or more files failed due to + unsupported compression methods or unsupported decryp- + tion. + + 82 no files were found due to bad decryption password(s). + (If even one file is successfully processed, however, the + exit status is 1.) + + VMS interprets standard Unix (or PC) return values as other, scarier- + looking things, so unzip instead maps them into VMS-style status codes. + The current mapping is as follows: 1 (success) for normal exit, + 0x7fff0001 for warning errors, and (0x7fff000? + 16*nor- + mal_unzip_exit_status) for all other errors, where the `?' is 2 (error) + for unzip values 2, 9-11 and 80-82, and 4 (fatal error) for the remain- + ing ones (3-8, 50, 51). In addition, there is a compilation option to + expand upon this behavior: defining RETURN_CODES results in a human- + readable explanation of what the error status means. + +BUGS + Multi-part archives are not yet supported, except in conjunction with + zip. (All parts must be concatenated together in order, and then ``zip + -F'' (for zip 2.x) or ``zip -FF'' (for zip 3.x) must be performed on + the concatenated archive in order to ``fix'' it. Also, zip 3.0 and + later can combine multi-part (split) archives into a combined single- + file archive using ``zip -s- inarchive -O outarchive''. See the zip 3 + manual page for more information.) This will definitely be corrected + in the next major release. + + Archives read from standard input are not yet supported, except with + funzip (and then only the first member of the archive can be + extracted). + + Archives encrypted with 8-bit passwords (e.g., passwords with accented + European characters) may not be portable across systems and/or other + archivers. See the discussion in DECRYPTION above. + + unzip's -M (``more'') option tries to take into account automatic wrap- + ping of long lines. However, the code may fail to detect the correct + wrapping locations. First, TAB characters (and similar control + sequences) are not taken into account, they are handled as ordinary + printable characters. Second, depending on the actual system / OS + port, unzip may not detect the true screen geometry but rather rely on + "commonly used" default dimensions. The correct handling of tabs would + require the implementation of a query for the actual tabulator setup on + the output console. + + Dates, times and permissions of stored directories are not restored + except under Unix. (On Windows NT and successors, timestamps are now + restored.) + + [MS-DOS] When extracting or testing files from an archive on a defec- + tive floppy diskette, if the ``Fail'' option is chosen from DOS's + ``Abort, Retry, Fail?'' message, older versions of unzip may hang the + system, requiring a reboot. This problem appears to be fixed, but con- + trol-C (or control-Break) can still be used to terminate unzip. + + Under DEC Ultrix, unzip would sometimes fail on long zipfiles (bad CRC, + not always reproducible). This was apparently due either to a hardware + bug (cache memory) or an operating system bug (improper handling of + page faults?). Since Ultrix has been abandoned in favor of Digital + Unix (OSF/1), this may not be an issue anymore. + + [Unix] Unix special files such as FIFO buffers (named pipes), block + devices and character devices are not restored even if they are somehow + represented in the zipfile, nor are hard-linked files relinked. Basi- + cally the only file types restored by unzip are regular files, directo- + ries and symbolic (soft) links. + + [OS/2] Extended attributes for existing directories are only updated if + the -o (``overwrite all'') option is given. This is a limitation of + the operating system; because directories only have a creation time + associated with them, unzip has no way to determine whether the stored + attributes are newer or older than those on disk. In practice this may + mean a two-pass approach is required: first unpack the archive nor- + mally (with or without freshening/updating existing files), then + overwrite just the directory entries (e.g., ``unzip -o foo */''). + + [VMS] When extracting to another directory, only the [.foo] syntax is + accepted for the -d option; the simple Unix foo syntax is silently + ignored (as is the less common VMS foo.dir syntax). + + [VMS] When the file being extracted already exists, unzip's query only + allows skipping, overwriting or renaming; there should additionally be + a choice for creating a new version of the file. In fact, the ``over- + write'' choice does create a new version; the old version is not over- + written or deleted. + +SEE ALSO + funzip(1L), zip(1L), zipcloak(1L), zipgrep(1L), zipinfo(1L), zip- + note(1L), zipsplit(1L) + +URL + The Info-ZIP home page is currently at + http://www.info-zip.org/pub/infozip/ + or + ftp://ftp.info-zip.org/pub/infozip/ . + +AUTHORS + The primary Info-ZIP authors (current semi-active members of the Zip- + Bugs workgroup) are: Ed Gordon (Zip, general maintenance, shared code, + Zip64, Win32, Unix, Unicode); Christian Spieler (UnZip maintenance + coordination, VMS, MS-DOS, Win32, shared code, general Zip and UnZip + integration and optimization); Onno van der Linden (Zip); Mike White + (Win32, Windows GUI, Windows DLLs); Kai Uwe Rommel (OS/2, Win32); + Steven M. Schweda (VMS, Unix, support of new features); Paul Kienitz + (Amiga, Win32, Unicode); Chris Herborth (BeOS, QNX, Atari); Jonathan + Hudson (SMS/QDOS); Sergio Monesi (Acorn RISC OS); Harald Denker (Atari, + MVS); John Bush (Solaris, Amiga); Hunter Goatley (VMS, Info-ZIP Site + maintenance); Steve Salisbury (Win32); Steve Miller (Windows CE GUI), + Johnny Lee (MS-DOS, Win32, Zip64); and Dave Smith (Tandem NSK). + + The following people were former members of the Info-ZIP development + group and provided major contributions to key parts of the current + code: Greg ``Cave Newt'' Roelofs (UnZip, unshrink decompression); Jean- + loup Gailly (deflate compression); Mark Adler (inflate decompression, + fUnZip). + + The author of the original unzip code upon which Info-ZIP's was based + is Samuel H. Smith; Carl Mascott did the first Unix port; and David P. + Kirschbaum organized and led Info-ZIP in its early days with Keith + Petersen hosting the original mailing list at WSMR-SimTel20. The full + list of contributors to UnZip has grown quite large; please refer to + the CONTRIBS file in the UnZip source distribution for a relatively + complete version. + +VERSIONS + v1.2 15 Mar 89 Samuel H. Smith + v2.0 9 Sep 89 Samuel H. Smith + v2.x fall 1989 many Usenet contributors + v3.0 1 May 90 Info-ZIP (DPK, consolidator) + v3.1 15 Aug 90 Info-ZIP (DPK, consolidator) + v4.0 1 Dec 90 Info-ZIP (GRR, maintainer) + v4.1 12 May 91 Info-ZIP + v4.2 20 Mar 92 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.0 21 Aug 92 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.01 15 Jan 93 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.1 7 Feb 94 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.11 2 Aug 94 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.12 28 Aug 94 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.2 30 Apr 96 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.3 22 Apr 97 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.31 31 May 97 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.32 3 Nov 97 Info-ZIP (Zip-Bugs subgroup, GRR) + v5.4 28 Nov 98 Info-ZIP (Zip-Bugs subgroup, SPC) + v5.41 16 Apr 00 Info-ZIP (Zip-Bugs subgroup, SPC) + v5.42 14 Jan 01 Info-ZIP (Zip-Bugs subgroup, SPC) + v5.5 17 Feb 02 Info-ZIP (Zip-Bugs subgroup, SPC) + v5.51 22 May 04 Info-ZIP (Zip-Bugs subgroup, SPC) + v5.52 28 Feb 05 Info-ZIP (Zip-Bugs subgroup, SPC) + v6.0 20 Apr 09 Info-ZIP (Zip-Bugs subgroup, SPC) + +Info-ZIP 20 April 2009 (v6.0) UNZIP(1L) diff --git a/third_party/unzip/unzpriv.h b/third_party/unzip/unzpriv.h new file mode 100644 index 000000000..1548aa880 --- /dev/null +++ b/third_party/unzip/unzpriv.h @@ -0,0 +1,2869 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 */ + +/*--------------------------------------------------------------------------- + Unix section: + ---------------------------------------------------------------------------*/ + +#include "libc/sysv/consts/s.h" +#include "libc/calls/calls.h" +#include "libc/str/str.h" +#include "libc/unicode/locale.h" +#include "libc/errno.h" +#include "third_party/unzip/unzpriv.h" +#include "libc/calls/calls.h" +#include "libc/fmt/fmt.h" +#include "third_party/unzip/unxcfg.h" + + +/* ---------------------------------------------------------------------------- + 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 (?) */ +#endif + +#ifdef USE_STRINGS_H +#else +#endif +#if (defined(MODERN) && !defined(NO_LIMITS_H)) +#endif + +/* this include must be down here for SysV.4, for some reason... */ + + +#ifdef MODERN +# ifndef NO_STDDEF_H +# endif +# ifndef NO_STDLIB_H +# 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 */ +# else + char *malloc(); +# endif /* ?VAXC */ +# endif /* !AOS_VS */ + typedef unsigned int extent; +#endif /* ?MODERN */ + +#ifdef NEED_STRERROR + char *strerror(); +#endif /* def NEED_STRERROR */ + + + + +/*************/ +/* 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__)) +# 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 +#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)) +# endif +# endif +# ifndef _MBCS /* no need to include twice, see below */ +# 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 +# ifdef HAVE_MBSTR_H +# endif /* def HAVE_MBSTR_H */ + /* Multi Byte Character Set */ +# define ___MBS_TMP_DEF char *___tmp_ptr; +# define ___TMP_PTR ___tmp_ptr +# ifndef CLEN +# define NEED_UZMBCLEN +# define CLEN(ptr) (int)uzmbclen((ZCONST unsigned char *)(ptr)) +# endif +# ifndef PREINCSTR +# define PREINCSTR(ptr) (ptr += CLEN(ptr)) +# endif +# define POSTINCSTR(ptr) (___TMP_PTR=(char *)(ptr), PREINCSTR(ptr),___TMP_PTR) + char *plastchar OF((ZCONST char *ptr, extent len)); +# define lastchar(ptr, len) ((int)(unsigned)*plastchar(ptr, len)) +# ifndef MBSCHR +# define NEED_UZMBSCHR +# define MBSCHR(str,c) (char *)uzmbschr((ZCONST unsigned char *)(str), c) +# endif +# ifndef MBSRCHR +# define NEED_UZMBSRCHR +# define MBSRCHR(str,c) (char *)uzmbsrchr((ZCONST unsigned char *)(str), c) +# endif +# ifndef SETLOCALE +# define SETLOCALE(category, locale) setlocale(category, locale) +# endif +#else /* !_MBCS */ +# define ___MBS_TMP_DEF +# define ___TMP_PTR +# define CLEN(ptr) 1 +# define PREINCSTR(ptr) (++(ptr)) +# define POSTINCSTR(ptr) ((ptr)++) +# define plastchar(ptr, len) (&ptr[(len)-1]) +# define lastchar(ptr, len) (ptr[(len)-1]) +# define MBSCHR(str, c) strchr(str, c) +# define MBSRCHR(str, c) strrchr(str, c) +# ifndef SETLOCALE +# define SETLOCALE(category, locale) +# endif +#endif /* ?_MBCS */ +#define INCSTR(ptr) PREINCSTR(ptr) + + +#if (defined(MALLOC_WORK) && !defined(MY_ZCALLOC)) + /* Any system without a special calloc function */ +# ifndef zcalloc +# define zcalloc(items, size) \ + (zvoid far *)calloc((unsigned)(items), (unsigned)(size)) +# endif +# ifndef zcfree +# define zcfree free +# endif +#endif /* MALLOC_WORK && !MY_ZCALLOC */ + +#if (defined(CRAY) && defined(ZMEM)) +# undef ZMEM +#endif + +#ifdef ZMEM +# undef ZMEM +# define memcmp(b1,b2,len) bcmp(b2,b1,len) +# define memcpy(dest,src,len) bcopy(src,dest,len) +# define memzero bzero +#else +# define memzero(dest,len) memset(dest,0,len) +#endif + +#ifndef TRUE +# define TRUE 1 /* sort of obvious */ +#endif +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif + +#if (!defined(S_IEXEC) && defined(S_IXUSR)) +# define S_IEXEC S_IXUSR +#endif + +#if (defined(UNIX) && defined(S_IFLNK) && !defined(MTS)) +# define SYMLINKS +# ifndef S_ISLNK +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# endif +#endif /* UNIX && S_IFLNK && !MTS */ + +#ifndef S_ISDIR +# ifdef CMS_MVS +# define S_ISDIR(m) (FALSE) +# else +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# endif +#endif + +#ifndef IS_VOLID +# define IS_VOLID(m) ((m) & 0x08) +#endif + + +/*-------------------------------------------------------------------- + Long option support + 23 August 2003 + Updated for UnZip 1 March 2008 + See unzip.c + --------------------------------------------------------------------*/ + +/* The below is for use in the caller-provided options table */ + +/* option groups */ +#define UZO 1 /* UnZip option */ +#define ZIO 2 /* ZipInfo option */ + + +/* value_type - value is always returned as a string. */ +#define o_NO_VALUE 0 /* this option does not take a value */ +#define o_REQUIRED_VALUE 1 /* this option requires a value */ +#define o_OPTIONAL_VALUE 2 /* value is optional (see get_option() for details) */ +#define o_VALUE_LIST 3 /* this option takes a list of values */ +#define o_ONE_CHAR_VALUE 4 /* next char is value (does not end short opt string) */ +#define o_NUMBER_VALUE 5 /* value is integer (does not end short opt string) */ + + +/* negatable - a dash following the option (but before any value) sets negated. */ +#define o_NOT_NEGATABLE 0 /* trailing '-' to negate either starts value or generates error */ +#define o_NEGATABLE 1 /* trailing '-' sets negated to TRUE */ + + +/* option_num can be this when option not in options table */ +#define o_NO_OPTION_MATCH -1 + +/* special values returned by get_option - do not use these as option IDs */ +#define o_NON_OPTION_ARG ((unsigned long) 0xFFFF) /* returned for non-option + args */ +#define o_ARG_FILE_ERR ((unsigned long) 0xFFFE) /* internal recursion + return (user never sees) */ +#define o_BAD_ERR ((unsigned long) 0xFFFD) /* bad error */ + +/* options array is set in unzip.c */ +struct option_struct { + int option_group; /* either UZO for UnZip or ZIO for ZipInfo syntax */ + char Far *shortopt; /* pointer to short option string */ + char Far *longopt; /* pointer to long option string */ + int value_type; /* from above */ + int negatable; /* from above */ + unsigned long option_ID; /* value returned by get_option when this option + is found */ + char Far *name; /* optional string for option returned on some + errors */ +}; + +/* structure used to create -x and include file lists */ +struct file_list { + char *name; + struct file_list *next; +}; + + +/* function prototypes */ + +/* get the next option from args */ +unsigned long get_option OF((int option_group, + char ***pargs, int *argc, int *argnum, + int *optchar, + char **value, int *negated, int *first_nonopt_arg, + int *option_num, int recursion_depth)); + +/* copy args - copy an args array, allocating space as needed */ +char **copy_args OF((char **args, int max_args)); + +/* arg count - count args in argv like array */ +int arg_count OF((char **args)); + +/* free args - free args created with one of these functions */ +int free_args OF((char **args)); + +/* insert arg - copy an arg into args */ +int insert_arg OF((char ***args, ZCONST char *arg, int insert_at, + int free_args)); + +/*-------------------------------------------------------------------- + End of Long option support + --------------------------------------------------------------------*/ + + +/***********************************/ +/* 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 +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) +# define zstatw _wstati64 +# endif + + /* 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 +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) +# define zfopenw _wfopen +# endif +# 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_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; +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + typedef struct direntryw { /* head of system-specific struct holding */ + struct direntryw *next; /* defered directory attributes info */ + wchar_t *fnw; /* filename of directory */ + wchar_t buf[1]; /* start of system-specific internal data */ + } direntryw; +# endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ +#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 "third_party/unzip/os2/os2data.h" +#endif + +#include "third_party/unzip/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 */ +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) +int check_for_newerw OF((__GPRO__ wchar_t *filenamew)); /* os2,vmcms,vms */ +#endif +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 + unsigned 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 */ +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + int zstat_win32w OF((__W32STAT_GLOBALS__ + const wchar_t *pathw, z_stat *buf)); /* win32.c */ +# endif +#endif +#endif + +/*--------------------------------------------------------------------------- + Mac-OS-X-only functions: + ---------------------------------------------------------------------------*/ + +#if defined( UNIX) && defined( __APPLE__) + int vol_attr_ok( const char *path); +#endif /* defined( UNIX) && defined( __APPLE__) */ + +/*--------------------------------------------------------------------------- + Miscellaneous/shared functions: + ---------------------------------------------------------------------------*/ + +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 */ +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) +int iswildw OF((ZCONST wchar_t *pw)); /* match.c */ +#endif + +/* 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 */ +#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + int mapnamew OF((__GPRO__ int renamed)); /* local */ + int checkdirw OF((__GPRO__ wchar_t *pathcomp, int flag)); /* local */ +#endif +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 */ + void 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 */ +# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) + int defer_dir_attribsw OF((__GPRO__ direntryw **pd)); /* local */ + int set_direc_attribsw OF((__GPRO__ direntryw *d)); /* local */ +# endif +#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)); + + char *wchar_to_local_string OF((wchar_t *, int)); + + zwchar *wchar_to_wide_string OF((wchar_t *)); + + /* 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) + + wchar_t *wide_to_wchar_string(zwchar *wide_string); + + zwchar *wchar_to_wide_string(wchar_t *wchar_string); + + /* convert local to wide string */ + zwchar *local_to_wide_string OF ((ZCONST char *local_string)); + +# 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 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 --git a/third_party/unzip/unzvers.h b/third_party/unzip/unzvers.h new file mode 100644 index 000000000..9be67cf36 --- /dev/null +++ b/third_party/unzip/unzvers.h @@ -0,0 +1,96 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 +*/ +/* + unzvers.h (for UnZip) by Info-ZIP. + */ + +#ifndef __unzvers_h /* don't include more than once */ +#define __unzvers_h + +/* +#ifdef BETA +# undef BETA +#endif +*/ + +#ifndef BETA +# define BETA /* undefine BETA for public releases */ +#endif + +#ifdef BETA +# define UZ_BETALEVEL "b BETA" +# define UZ_VERSION_DATE "10 Dec 10" /* internal beta version */ +#else +# define UZ_BETALEVEL "" +# define UZ_VERSION_DATE "20 April 2009" /* official release version */ +# define RELEASE +#endif + +#define UZ_MAJORVER 6 /* UnZip */ +#define UZ_MINORVER 1 + +#define ZI_MAJORVER 3 /* ZipInfo */ +#define ZI_MINORVER 1 + +#define UZ_PATCHLEVEL 0 + +#define UZ_VER_STRING "6.1" /* keep in sync with Version numbers! */ + +#ifndef IZ_COMPANY_NAME /* might be already defined... */ +# define IZ_COMPANY_NAME "Info-ZIP" +#endif + +/* these are obsolete but remain for backward compatibility: */ +#if (defined(OS2) || defined(__OS2__)) +# define D2_MAJORVER UZ_MAJORVER /* DLL for OS/2 */ +# define D2_MINORVER UZ_MINORVER +# define D2_PATCHLEVEL UZ_PATCHLEVEL +#endif + +#define DW_MAJORVER UZ_MAJORVER /* DLL for MS Windows */ +#define DW_MINORVER UZ_MINORVER +#define DW_PATCHLEVEL UZ_PATCHLEVEL + +#define WIN_VERSION_DATE UZ_VERSION_DATE + +#define UNZ_DLL_VERSION UZ_VER_STRING + +/* The following version constants specify the UnZip version that introduced + * the most recent incompatible change (means: change that breaks backward + * compatibility) of a DLL/Library binary API definition. + * + * Currently, UnZip supports three distinct DLL/Library APIs, which each + * carry their own "compatibility level": + * a) The "generic" (console-mode oriented) API has been used on UNIX, + * for example. This API provides a "callable" interface similar to the + * interactive command line of the normal program executables. + * b) The OS/2-only API provides (additional) functions specially tailored + * for interfacing with the REXX shell. + * c) The Win32 DLL API with a pure binary interface which can be used to + * build GUI mode as well as Console mode applications. + * + * Whenever a change that breaks backward compatibility gets applied to + * any of the DLL/Library APIs, the corresponding compatibility level should + * be synchronized with the current UnZip version numbers. + */ +/* generic DLL API minimum compatible version*/ +#define UZ_GENAPI_COMP_MAJOR 6 +#define UZ_GENAPI_COMP_MINOR 0 +#define UZ_GENAPI_COMP_REVIS 0 +/* os2dll API minimum compatible version*/ +#define UZ_OS2API_COMP_MAJOR 6 +#define UZ_OS2API_COMP_MINOR 0 +#define UZ_OS2API_COMP_REVIS 0 +/* windll API minimum compatible version*/ +#define UZ_WINAPI_COMP_MAJOR 6 +#define UZ_WINAPI_COMP_MINOR 0 +#define UZ_WINAPI_COMP_REVIS 0 + +#endif /* !__unzvers_h */ diff --git a/third_party/unzip/zip.h b/third_party/unzip/zip.h new file mode 100644 index 000000000..0532ae0f3 --- /dev/null +++ b/third_party/unzip/zip.h @@ -0,0 +1,26 @@ +// clang-format off +/* + Copyright (c) 1990-2005 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2003-May-08 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 +*/ +/* This is a dummy zip.h to allow the source files shared with Zip + (crypt.c, crc32.c, ttyio.c, win32/win32i64.c) to compile for UnZip. + (In case you are looking for the Info-ZIP license, please follow + the pointers above.) */ + +#ifndef __zip_h /* don't include more than once */ +#define __zip_h + +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" + +#define local static + +#define ZE_MEM PK_MEM +#define ziperr(c, h) return + +#endif /* !__zip_h */ diff --git a/third_party/unzip/zipinfo.c b/third_party/unzip/zipinfo.c new file mode 100644 index 000000000..bea1284d6 --- /dev/null +++ b/third_party/unzip/zipinfo.c @@ -0,0 +1,2522 @@ +// clang-format off +/* + Copyright (c) 1990-2010 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 +*/ +/*--------------------------------------------------------------------------- + + zipinfo.c Greg Roelofs et al. + + This file contains all of the ZipInfo-specific listing routines for UnZip. + + Contains: zi_opts() + zi_end_central() + zipinfo() + zi_long() + zi_short() + zi_time() + + ---------------------------------------------------------------------------*/ + + +#define UNZIP_INTERNAL +#include "third_party/unzip/unzip.h" + + +#ifndef NO_ZIPINFO /* strings use up too much space in small-memory systems */ + +/* Define OS-specific attributes for use on ALL platforms--the S_xxxx + * versions of these are defined differently (or not defined) by different + * compilers and operating systems. */ + +#define UNX_IFMT 0170000 /* Unix file type mask */ +#define UNX_IFREG 0100000 /* Unix regular file */ +#define UNX_IFSOCK 0140000 /* Unix socket (BSD, not SysV or Amiga) */ +#define UNX_IFLNK 0120000 /* Unix symbolic link (not SysV, Amiga) */ +#define UNX_IFBLK 0060000 /* Unix block special (not Amiga) */ +#define UNX_IFDIR 0040000 /* Unix directory */ +#define UNX_IFCHR 0020000 /* Unix character special (not Amiga) */ +#define UNX_IFIFO 0010000 /* Unix fifo (BCC, not MSC or Amiga) */ +#define UNX_ISUID 04000 /* Unix set user id on execution */ +#define UNX_ISGID 02000 /* Unix set group id on execution */ +#define UNX_ISVTX 01000 /* Unix directory permissions control */ +#define UNX_ENFMT UNX_ISGID /* Unix record locking enforcement flag */ +#define UNX_IRWXU 00700 /* Unix read, write, execute: owner */ +#define UNX_IRUSR 00400 /* Unix read permission: owner */ +#define UNX_IWUSR 00200 /* Unix write permission: owner */ +#define UNX_IXUSR 00100 /* Unix execute permission: owner */ +#define UNX_IRWXG 00070 /* Unix read, write, execute: group */ +#define UNX_IRGRP 00040 /* Unix read permission: group */ +#define UNX_IWGRP 00020 /* Unix write permission: group */ +#define UNX_IXGRP 00010 /* Unix execute permission: group */ +#define UNX_IRWXO 00007 /* Unix read, write, execute: other */ +#define UNX_IROTH 00004 /* Unix read permission: other */ +#define UNX_IWOTH 00002 /* Unix write permission: other */ +#define UNX_IXOTH 00001 /* Unix execute permission: other */ + +#define VMS_IRUSR UNX_IRUSR /* VMS read/owner */ +#define VMS_IWUSR UNX_IWUSR /* VMS write/owner */ +#define VMS_IXUSR UNX_IXUSR /* VMS execute/owner */ +#define VMS_IRGRP UNX_IRGRP /* VMS read/group */ +#define VMS_IWGRP UNX_IWGRP /* VMS write/group */ +#define VMS_IXGRP UNX_IXGRP /* VMS execute/group */ +#define VMS_IROTH UNX_IROTH /* VMS read/other */ +#define VMS_IWOTH UNX_IWOTH /* VMS write/other */ +#define VMS_IXOTH UNX_IXOTH /* VMS execute/other */ + +#define AMI_IFMT 06000 /* Amiga file type mask */ +#define AMI_IFDIR 04000 /* Amiga directory */ +#define AMI_IFREG 02000 /* Amiga regular file */ +#define AMI_IHIDDEN 00200 /* to be supported in AmigaDOS 3.x */ +#define AMI_ISCRIPT 00100 /* executable script (text command file) */ +#define AMI_IPURE 00040 /* allow loading into resident memory */ +#define AMI_IARCHIVE 00020 /* not modified since bit was last set */ +#define AMI_IREAD 00010 /* can be opened for reading */ +#define AMI_IWRITE 00004 /* can be opened for writing */ +#define AMI_IEXECUTE 00002 /* executable image, a loadable runfile */ +#define AMI_IDELETE 00001 /* can be deleted */ + +#define THS_IFMT 0xF000 /* Theos file type mask */ +#define THS_IFIFO 0x1000 /* pipe */ +#define THS_IFCHR 0x2000 /* char device */ +#define THS_IFSOCK 0x3000 /* socket */ +#define THS_IFDIR 0x4000 /* directory */ +#define THS_IFLIB 0x5000 /* library */ +#define THS_IFBLK 0x6000 /* block device */ +#define THS_IFREG 0x8000 /* regular file */ +#define THS_IFREL 0x9000 /* relative (direct) */ +#define THS_IFKEY 0xA000 /* keyed */ +#define THS_IFIND 0xB000 /* indexed */ +#define THS_IFRND 0xC000 /* ???? */ +#define THS_IFR16 0xD000 /* 16 bit real mode program */ +#define THS_IFP16 0xE000 /* 16 bit protected mode prog */ +#define THS_IFP32 0xF000 /* 32 bit protected mode prog */ +#define THS_IMODF 0x0800 /* modified */ +#define THS_INHID 0x0400 /* not hidden */ +#define THS_IEUSR 0x0200 /* erase permission: owner */ +#define THS_IRUSR 0x0100 /* read permission: owner */ +#define THS_IWUSR 0x0080 /* write permission: owner */ +#define THS_IXUSR 0x0040 /* execute permission: owner */ +#define THS_IROTH 0x0004 /* read permission: other */ +#define THS_IWOTH 0x0002 /* write permission: other */ +#define THS_IXOTH 0x0001 /* execute permission: other */ + +#ifndef NSK_UNSTRUCTURED +# define NSK_UNSTRUCTURED 0 +#endif +#ifndef NSK_OBJECTFILECODE +# define NSK_OBJECTFILECODE 100 +#endif +#ifndef NSK_EDITFILECODE +# define NSK_EDITFILECODE 101 +#endif + +#define LFLAG 3 /* short "ls -l" type listing */ + +static int zi_long OF((__GPRO__ zusz_t *pEndprev, int error_in_archive)); +static int zi_short OF((__GPRO)); +static void zi_showMacTypeCreator + OF((__GPRO__ uch *ebfield)); +static char *zi_time OF((__GPRO__ ZCONST ulg *datetimez, + ZCONST time_t *modtimez, char *d_t_str)); + + +/**********************************************/ +/* Strings used in zipinfo.c (ZipInfo half) */ +/**********************************************/ + +static ZCONST char nullStr[] = ""; +static ZCONST char PlurSufx[] = "s"; + +static ZCONST char Far ZipInfHeader2[] = + "Zip file size: %s bytes, number of entries: %s\n"; +static ZCONST char Far EndCentDirRec[] = "\nEnd-of-central-directory record:\n"; +static ZCONST char Far LineSeparators[] = "-------------------------------\n\n"; +static ZCONST char Far ZipFSizeVerbose[] = "\ + Zip archive file size: %s (%sh)\n"; +static ZCONST char Far ActOffsetCentDir[] = "\ + Actual end-cent-dir record offset: %s (%sh)\n\ + Expected end-cent-dir record offset: %s (%sh)\n\ + (based on the length of the central directory and its expected offset)\n\n"; +static ZCONST char Far SinglePartArchive1[] = "\ + This zipfile constitutes the sole disk of a single-part archive; its\n\ + central directory contains %s %s.\n\ + The central directory is %s (%sh) bytes long,\n"; +static ZCONST char Far SinglePartArchive2[] = "\ + and its (expected) offset in bytes from the beginning of the zipfile\n\ + is %s (%sh).\n\n"; +static ZCONST char Far MultiPartArchive1[] = "\ + This zipfile constitutes disk %lu of a multi-part archive. The central\n\ + directory starts on disk %lu at an offset within that archive part\n"; +static ZCONST char Far MultiPartArchive2[] = "\ + of %s (%sh) bytes. The entire\n\ + central directory is %s (%sh) bytes long.\n"; +static ZCONST char Far MultiPartArchive3[] = "\ + %s of the archive entries %s contained within this zipfile volume,\n\ + out of a total of %s %s.\n\n"; +static ZCONST char Far NoMemArguments[] = + "envargs: cannot get memory for arguments"; + +static ZCONST char Far CentralDirEntry[] = + "\nCentral directory entry #%lu:\n---------------------------\n\n"; +static ZCONST char Far ZipfileStats[] = + "%lu file%s, %s bytes uncompressed, %s bytes compressed: %s%d.%d%%\n"; + +/* zi_long() strings */ +static ZCONST char Far OS_FAT[] = "MS-DOS, OS/2 or NT FAT"; +static ZCONST char Far OS_Amiga[] = "Amiga"; +static ZCONST char Far OS_VMS[] = "VMS"; +static ZCONST char Far OS_Unix[] = "Unix"; +static ZCONST char Far OS_VMCMS[] = "VM/CMS"; +static ZCONST char Far OS_AtariST[] = "Atari ST"; +static ZCONST char Far OS_HPFS[] = "OS/2 or NT HPFS"; +static ZCONST char Far OS_Macintosh[] = "Macintosh HFS"; +static ZCONST char Far OS_ZSystem[] = "Z-System"; +static ZCONST char Far OS_CPM[] = "CP/M"; +static ZCONST char Far OS_TOPS20[] = "TOPS-20"; +static ZCONST char Far OS_NTFS[] = "NTFS"; +static ZCONST char Far OS_QDOS[] = "SMS/QDOS"; +static ZCONST char Far OS_Acorn[] = "Acorn RISC OS"; +static ZCONST char Far OS_MVS[] = "MVS"; +static ZCONST char Far OS_VFAT[] = "Win32 VFAT"; +static ZCONST char Far OS_AtheOS[] = "AtheOS"; +static ZCONST char Far OS_BeOS[] = "BeOS"; +static ZCONST char Far OS_Tandem[] = "Tandem NSK"; +static ZCONST char Far OS_Theos[] = "Theos"; +static ZCONST char Far OS_MacDarwin[] = "Mac OS/X (Darwin)"; +#ifdef OLD_THEOS_EXTRA + static ZCONST char Far OS_TheosOld[] = "Theos (Old)"; +#endif /* OLD_THEOS_EXTRA */ + +static ZCONST char Far MthdNone[] = "none (stored)"; +static ZCONST char Far MthdShrunk[] = "shrunk"; +static ZCONST char Far MthdRedF1[] = "reduced (factor 1)"; +static ZCONST char Far MthdRedF2[] = "reduced (factor 2)"; +static ZCONST char Far MthdRedF3[] = "reduced (factor 3)"; +static ZCONST char Far MthdRedF4[] = "reduced (factor 4)"; +static ZCONST char Far MthdImplode[] = "imploded"; +static ZCONST char Far MthdToken[] = "tokenized"; +static ZCONST char Far MthdDeflate[] = "deflated"; +static ZCONST char Far MthdDeflat64[] = "deflated (enhanced-64k)"; +static ZCONST char Far MthdDCLImplode[] = "imploded (PK DCL)"; +static ZCONST char Far MthdBZip2[] = "bzipped"; +static ZCONST char Far MthdLZMA[] = "LZMA-ed"; +static ZCONST char Far MthdTerse[] = "tersed (IBM)"; +static ZCONST char Far MthdLZ77[] = "LZ77-compressed (IBM)"; +static ZCONST char Far MthdWavPack[] = "WavPacked"; +static ZCONST char Far MthdPPMd[] = "PPMd-ed"; + +static ZCONST char Far DeflNorm[] = "normal"; +static ZCONST char Far DeflMax[] = "maximum"; +static ZCONST char Far DeflFast[] = "fast"; +static ZCONST char Far DeflSFast[] = "superfast"; + +static ZCONST char Far ExtraBytesPreceding[] = + " There are an extra %s bytes preceding this file.\n\n"; + +static ZCONST char Far UnknownNo[] = "unknown (%d)"; + +#ifdef ZIP64_SUPPORT + static ZCONST char Far LocalHeaderOffset[] = + "\n offset of local header from start of archive: %s\n\ + (%sh) bytes\n"; +#else + static ZCONST char Far LocalHeaderOffset[] = + "\n offset of local header from start of archive: %s (%sh) bytes\n"; +#endif +static ZCONST char Far HostOS[] = + " file system or operating system of origin: %s\n"; +static ZCONST char Far EncodeSWVer[] = + " version of encoding software: %u.%u\n"; +static ZCONST char Far MinOSCompReq[] = + " minimum file system compatibility required: %s\n"; +static ZCONST char Far MinSWVerReq[] = + " minimum software version required to extract: %u.%u\n"; +static ZCONST char Far CompressMethod[] = + " compression method: %s\n"; +static ZCONST char Far SlideWindowSizeImplode[] = + " size of sliding dictionary (implosion): %cK\n"; +static ZCONST char Far ShannonFanoTrees[] = + " number of Shannon-Fano trees (implosion): %c\n"; +static ZCONST char Far CompressSubtype[] = + " compression sub-type (deflation): %s\n"; +static ZCONST char Far FileSecurity[] = + " file security status: %sencrypted\n"; +static ZCONST char Far ExtendedLocalHdr[] = + " extended local header: %s\n"; +static ZCONST char Far FileModDate[] = + " file last modified on (DOS date/time): %s\n"; +#ifdef USE_EF_UT_TIME + static ZCONST char Far UT_FileModDate[] = + " file last modified on (UT extra field modtime): %s %s\n"; + static ZCONST char Far LocalTime[] = "local"; +#ifndef NO_GMTIME + static ZCONST char Far GMTime[] = "UTC"; +#endif +#endif /* USE_EF_UT_TIME */ +static ZCONST char Far CRC32Value[] = + " 32-bit CRC value (hex): %.8lx\n"; +static ZCONST char Far CompressedFileSize[] = + " compressed size: %s bytes\n"; +static ZCONST char Far UncompressedFileSize[] = + " uncompressed size: %s bytes\n"; +static ZCONST char Far FilenameLength[] = + " length of filename: %u characters\n"; +static ZCONST char Far ExtraFieldLength[] = + " length of extra field: %u bytes\n"; +static ZCONST char Far FileCommentLength[] = + " length of file comment: %u characters\n"; +static ZCONST char Far FileDiskNum[] = + " disk number on which file begins: disk %lu\n"; +static ZCONST char Far ApparentFileType[] = + " apparent file type: %s\n"; +static ZCONST char Far VMSFileAttributes[] = + " VMS file attributes (%06o octal): %s\n"; +static ZCONST char Far AmigaFileAttributes[] = + " Amiga file attributes (%06o octal): %s\n"; +static ZCONST char Far UnixFileAttributes[] = + " Unix file attributes (%06o octal): %s\n"; +static ZCONST char Far NonMSDOSFileAttributes[] = + " non-MSDOS external file attributes: %06lX hex\n"; +static ZCONST char Far MSDOSFileAttributes[] = + " MS-DOS file attributes (%02X hex): none\n"; +static ZCONST char Far MSDOSFileAttributesRO[] = + " MS-DOS file attributes (%02X hex): read-only\n"; +static ZCONST char Far MSDOSFileAttributesAlpha[] = + " MS-DOS file attributes (%02X hex): %s%s%s%s%s%s%s%s\n"; +static ZCONST char Far TheosFileAttributes[] = + " Theos file attributes (%04X hex): %s\n"; + +static ZCONST char Far TheosFTypLib[] = "Library "; +static ZCONST char Far TheosFTypDir[] = "Directory "; +static ZCONST char Far TheosFTypReg[] = "Sequential "; +static ZCONST char Far TheosFTypRel[] = "Direct "; +static ZCONST char Far TheosFTypKey[] = "Keyed "; +static ZCONST char Far TheosFTypInd[] = "Indexed "; +static ZCONST char Far TheosFTypR16[] = " 86 program "; +static ZCONST char Far TheosFTypP16[] = "286 program "; +static ZCONST char Far TheosFTypP32[] = "386 program "; +static ZCONST char Far TheosFTypUkn[] = "??? "; + +static ZCONST char Far ExtraFieldTrunc[] = "\n\ + error: EF data block (type 0x%04x) size %u exceeds remaining extra field\n\ + space %u; block length has been truncated.\n"; +static ZCONST char Far ExtraFields[] = "\n\ + The central-directory extra field contains:"; +static ZCONST char Far ExtraFieldType[] = "\n\ + - A subfield with ID 0x%04x (%s) and %u data bytes"; +static ZCONST char Far efPKSZ64[] = "PKWARE 64-bit sizes"; +static ZCONST char Far efAV[] = "PKWARE AV"; +static ZCONST char Far efOS2[] = "OS/2"; +static ZCONST char Far efPKVMS[] = "PKWARE VMS"; +static ZCONST char Far efPKWin32[] = "PKWARE Win32"; +static ZCONST char Far efPKUnix[] = "PKWARE Unix"; +static ZCONST char Far efIZVMS[] = "Info-ZIP VMS"; +static ZCONST char Far efIZUnix[] = "old Info-ZIP Unix/OS2/NT"; +static ZCONST char Far efIZUnix2[] = "Unix UID/GID (16-bit)"; +static ZCONST char Far efIZUnix3[] = "Unix UID/GID (any size)"; +static ZCONST char Far efTime[] = "universal time"; +static ZCONST char Far efU8Path[] = "UTF8 path name"; +static ZCONST char Far efU8Commnt[] = "UTF8 entry comment"; +static ZCONST char Far efJLMac[] = "old Info-ZIP Macintosh"; +static ZCONST char Far efMac3[] = "new Info-ZIP Macintosh"; +static ZCONST char Far efZipIt[] = "ZipIt Macintosh"; +static ZCONST char Far efSmartZip[] = "SmartZip Macintosh"; +static ZCONST char Far efZipIt2[] = "ZipIt Macintosh (short)"; +static ZCONST char Far efVMCMS[] = "VM/CMS"; +static ZCONST char Far efMVS[] = "MVS"; +static ZCONST char Far efACL[] = "OS/2 ACL"; +static ZCONST char Far efNTSD[] = "Security Descriptor"; +static ZCONST char Far efAtheOS[] = "AtheOS"; +static ZCONST char Far efBeOS[] = "BeOS"; +static ZCONST char Far efQDOS[] = "SMS/QDOS"; +static ZCONST char Far efAOSVS[] = "AOS/VS"; +static ZCONST char Far efSpark[] = "Acorn SparkFS"; +static ZCONST char Far efMD5[] = "Fred Kantor MD5"; +static ZCONST char Far efASiUnix[] = "ASi Unix"; +static ZCONST char Far efTandem[] = "Tandem NSK"; +static ZCONST char Far efTheos[] = "Theos"; +static ZCONST char Far efUnknown[] = "unknown"; + +static ZCONST char Far OS2EAs[] = ".\n\ + The local extra field has %lu bytes of OS/2 extended attributes.\n\ + (May not match OS/2 \"dir\" amount due to storage method)"; +static ZCONST char Far izVMSdata[] = ". The extra\n\ + field is %s and has %u bytes of VMS %s information%s"; +static ZCONST char Far izVMSstored[] = "stored"; +static ZCONST char Far izVMSrleenc[] = "run-length encoded"; +static ZCONST char Far izVMSdeflat[] = "deflated"; +static ZCONST char Far izVMScunknw[] = "compressed(?)"; +static ZCONST char Far *izVMScomp[4] = + {izVMSstored, izVMSrleenc, izVMSdeflat, izVMScunknw}; +static ZCONST char Far ACLdata[] = ".\n\ + The local extra field has %lu bytes of access control list information"; +static ZCONST char Far NTSDData[] = ".\n\ + The local extra field has %lu bytes of NT security descriptor data"; +static ZCONST char Far UTdata[] = ".\n\ + The local extra field has UTC/GMT %s time%s"; +static ZCONST char Far UTmodification[] = "modification"; +static ZCONST char Far UTaccess[] = "access"; +static ZCONST char Far UTcreation[] = "creation"; +static ZCONST char Far U8PthCmnComplete[] = ".\n\ + The UTF8 data of the extra field (V%u, ASCII name CRC `%.8lx') are:\n "; +static ZCONST char Far U8PthCmnF24[] = ". The first\n\ + 24 UTF8 bytes in the extra field (V%u, ASCII name CRC `%.8lx') are:\n "; +static ZCONST char Far ZipItFname[] = ".\n\ + The Mac long filename is %s"; +static ZCONST char Far Mac3data[] = ".\n\ + The local extra field has %lu bytes of %scompressed Macintosh\n\ + finder attributes"; + /* MacOSdata[] is used by EF_MAC3, EF_ZIPIT, EF_ZIPIT2 and EF_JLEE e. f. */ +static ZCONST char Far MacOSdata[] = ".\n\ + The associated file has type code `%c%c%c%c' and creator code `%c%c%c%c'"; +static ZCONST char Far MacOSdata1[] = ".\n\ + The associated file has type code `0x%lx' and creator code `0x%lx'"; +static ZCONST char Far MacOSJLEEflags[] = ".\n File is marked as %s"; +static ZCONST char Far MacOS_RF[] = "Resource-fork"; +static ZCONST char Far MacOS_DF[] = "Data-fork"; +static ZCONST char Far MacOSMAC3flags[] = ".\n\ + File is marked as %s, File Dates are in %d Bit"; +static ZCONST char Far AtheOSdata[] = ".\n\ + The local extra field has %lu bytes of %scompressed AtheOS file attributes"; +static ZCONST char Far BeOSdata[] = ".\n\ + The local extra field has %lu bytes of %scompressed BeOS file attributes"; + /* The associated file has type code `%c%c%c%c' and creator code `%c%c%c%c'" */ +static ZCONST char Far QDOSdata[] = ".\n\ + The QDOS extra field subtype is `%c%c%c%c'"; +static ZCONST char Far AOSVSdata[] = ".\n\ + The AOS/VS extra field revision is %d.%d"; +static ZCONST char Far TandemUnstr[] = "Unstructured"; +static ZCONST char Far TandemRel[] = "Relative"; +static ZCONST char Far TandemEntry[] = "Entry Sequenced"; +static ZCONST char Far TandemKey[] = "Key Sequenced"; +static ZCONST char Far TandemEdit[] = "Edit"; +static ZCONST char Far TandemObj[] = "Object"; +static ZCONST char Far *TandemFileformat[6] = + {TandemUnstr, TandemRel, TandemEntry, TandemKey, TandemEdit, TandemObj}; +static ZCONST char Far Tandemdata[] = ".\n\ + The file was originally a Tandem %s file, with file code %u"; +static ZCONST char Far MD5data[] = ".\n\ + The 128-bit MD5 signature is %s"; +#ifdef CMS_MVS + static ZCONST char Far VmMvsExtraField[] = ".\n\ + The stored file open mode (FLDATA TYPE) is \"%s\""; + static ZCONST char Far VmMvsInvalid[] = "[invalid]"; +#endif /* CMS_MVS */ + +static ZCONST char Far First20[] = ". The first\n 20 are: "; +static ZCONST char Far ColonIndent[] = ":\n "; +static ZCONST char Far efFormat[] = " %02x"; + +static ZCONST char Far lExtraFieldType[] = "\n\ + There %s a local extra field with ID 0x%04x (%s) and\n\ + %u data bytes (%s).\n"; +static ZCONST char Far efIZuid[] = + "GMT modification/access times and Unix UID/GID"; +static ZCONST char Far efIZnouid[] = "GMT modification/access times only"; + + +static ZCONST char Far NoFileComment[] = "\n There is no file comment.\n"; +static ZCONST char Far FileCommBegin[] = "\n\ +------------------------- file comment begins ----------------------------\n"; +static ZCONST char Far FileCommEnd[] = "\ +-------------------------- file comment ends -----------------------------\n"; + +/* zi_time() strings */ +static ZCONST char Far BogusFmt[] = "%03d"; +static ZCONST char Far shtYMDHMTime[] = "%02u-%s-%02u %02u:%02u"; +static ZCONST char Far lngYMDHMSTime[] = "%u %s %u %02u:%02u:%02u"; +static ZCONST char Far DecimalTime[] = "%04u%02u%02u.%02u%02u%02u"; +#ifdef USE_EF_UT_TIME + static ZCONST char Far lngYMDHMSTimeError[] = "???? ??? ?? ??:??:??"; +#endif + + + + + +#ifndef WINDLL + +/************************/ +/* Function zi_opts() */ +/************************/ + +int zi_opts(__G__ pargc, pargv) + int *pargc; + char ***pargv; + __GDEF +{ + int argc, error=FALSE; + int hflag_slmv=TRUE, hflag_2=FALSE; /* diff options => diff defaults */ + int tflag_slm=TRUE, tflag_2v=FALSE; + int explicit_h=FALSE, explicit_t=FALSE; + + char **args; + + + /* used by get_option */ + unsigned long option; /* option ID returned by get_option */ + int argcnt = 0; /* current argcnt in args */ + int argnum = 0; /* arg number */ + int optchar = 0; /* option state */ + char *value = NULL; /* non-option arg, option value or NULL */ + int negative = 0; /* 1 = option negated */ + int fna = 0; /* current first non-opt arg */ + int optnum = 0; /* index in table */ + int showhelp = 0; /* for --commandline */ + +#ifdef USE_ICONV_MAPPING +# ifdef UNIX + extern char OEM_CP[MAX_CP_NAME]; + extern char ISO_CP[MAX_CP_NAME]; +# endif +#endif + + /* since get_option() returns xfiles and files one at a time, store them in + linked lists until have them all */ + + int file_count; + struct file_list *next_file; + + /* files to extract */ + int in_files_count = 0; + struct file_list *in_files = NULL; + struct file_list *next_in_files = NULL; + + /* files to exclude in -x list */ + int in_xfiles_count = 0; + struct file_list *in_xfiles = NULL; + struct file_list *next_in_xfiles = NULL; + + G.wildzipfn = NULL; + + /* make copy of args that can use with insert_arg() used by get_option() */ + args = copy_args(*pargv, 0); + + + /* Initialize lists */ + G.filespecs = 0; + G.xfilespecs = 0; + +#ifdef MACOS + uO.lflag = LFLAG; /* reset default on each call */ +#endif + G.extract_flag = FALSE; /* zipinfo does not extract to disk */ + + /* + ------------------------------------------- + Process command line using get_option + ------------------------------------------- + + Each call to get_option() returns either a command + line option and possible value or a non-option argument. + Arguments are permuted so that all options (-r, -b temp) + are returned before non-option arguments (zipfile). + Returns 0 when nothing left to read. + */ + + /* set argnum = 0 on first call to init get_option */ + argnum = 0; + + /* get_option returns the option ID and updates parameters: + args - usually same as argv if no argument file support + argcnt - current argc for args + value - char* to value (free() when done with it) or NULL if no value + negated - option was negated with trailing - + */ + + +/* Copied from unzip.c */ +#define o_sc 0x103 +#define o_so 0x104 + + + while ((option = get_option(ZIO, &args, &argcnt, &argnum, + &optchar, &value, &negative, + &fna, &optnum, 0))) + { + if(option == o_BAD_ERR) { + return(PK_PARAM); + } + + switch (option) + { + case '1': /* shortest listing: JUST filenames */ + if (negative) + uO.lflag = -2; + else + uO.lflag = 1; + break; + case '2': /* just filenames, plus headers if specified */ + if (negative) + uO.lflag = -2; + else + uO.lflag = 2; + break; +#ifndef CMS_MVS + case ('C'): /* -C: match filenames case-insensitively */ + if (negative) + uO.C_flag = FALSE; + else + uO.C_flag = TRUE; + break; +#endif /* !CMS_MVS */ + case 'h': /* header line */ + if (negative) + hflag_2 = hflag_slmv = FALSE; + else { + hflag_2 = hflag_slmv = explicit_h = TRUE; + if (uO.lflag == -1) + uO.lflag = 0; + } + break; +#ifdef USE_ICONV_MAPPING +# ifdef UNIX + case ('I'): /* -I: map ISO name to internal */ + strncpy(ISO_CP, value, sizeof(ISO_CP)); + free(value); + break; +# endif +#endif + case 'l': /* longer form of "ls -l" type listing */ + if (negative) + uO.lflag = -2; + else + uO.lflag = 5; + break; + case 'm': /* medium form of "ls -l" type listing */ + if (negative) + uO.lflag = -2; + else + uO.lflag = 4; + break; +#ifdef MORE + case 'M': /* send output through built-in "more" */ + if (negative) + G.M_flag = FALSE; + else + G.M_flag = TRUE; + break; +#endif +#ifdef USE_ICONV_MAPPING +# ifdef UNIX + case ('O'): /* -O: map OEM name to internal */ + strncpy(OEM_CP, value, sizeof(OEM_CP)); + free(value); + break; +# endif +#endif + case 's': /* default: shorter "ls -l" type listing */ + if (negative) + uO.lflag = -2; + else + uO.lflag = 3; + break; +#ifndef SFX + case (o_sc): /* show processed command line and exit */ + *pargc = -1; + showhelp = -3; + break; +#endif + case 't': /* totals line */ + if (negative) + tflag_2v = tflag_slm = FALSE; + else { + tflag_2v = tflag_slm = explicit_t = TRUE; + if (uO.lflag == -1) + uO.lflag = 0; + } + break; + case ('T'): /* use (sortable) decimal time format */ + if (negative) + uO.T_flag = FALSE; + else + uO.T_flag = TRUE; + break; +#ifdef UNICODE_SUPPORT + case ('U'): /* escape UTF-8, or disable UTF-8 support */ + if (negative) + uO.U_flag = MAX(uO.U_flag - 1, 0); + else + uO.U_flag++; + break; +#endif /* UNICODE_SUPPORT */ + case 'v': /* turbo-verbose listing */ + if (negative) + uO.lflag = -2; + else + uO.lflag = 10; + break; +#ifdef WILD_STOP_AT_DIR + case ('W'): /* Wildcard interpretation (stop at '/'?) */ + if (negative) + uO.W_flag = FALSE; + else + uO.W_flag = TRUE; + break; +#endif /* WILD_STOP_AT_DIR */ + case ('x'): /* extract: default */ + /* add -x file to linked list */ + + if (in_xfiles_count == 0) { + /* first entry */ + if ((in_xfiles = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments))); + return PK_MEM; + } + in_xfiles->name = value; + in_xfiles->next = NULL; + next_in_xfiles = in_xfiles; + } else { + /* add next entry */ + if ((next_file = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments))); + return PK_MEM; + } + next_in_xfiles->next = next_file; + next_file->name = value; + next_file->next = NULL; + next_in_xfiles = next_file; + } + in_xfiles_count++; + case 'z': /* print zipfile comment */ + if (negative) + uO.zflag = 0; + else + uO.zflag = 1; + break; + case 'Z': /* ZipInfo mode: ignore */ + break; + case o_NON_OPTION_ARG: + /* not an option */ + /* no more options as permuting */ + + + if (G.wildzipfn == NULL) { + /* first non-option argument is zip file */ + G.wildzipfn = value; + + } else { + /* add include file to list */ + if (in_files_count == 0) { + /* first entry */ + if ((next_file = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments))); + return PK_MEM; + } + next_file->name = value; + next_file->next = NULL; + in_files = next_file; + next_in_files = next_file; + } else { + /* add next entry */ + if ((next_file = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments))); + return PK_MEM; + } + next_in_files->next = next_file; + next_file->name = value; + next_file->next = NULL; + next_in_files = next_file; + } + in_files_count++; + } + break; + default: + error = TRUE; + break; + } /* switch */ + } /* get_option() */ + + if (showhelp == -3) { + show_commandline(args); + return PK_OK; + } + + /* convert files and xfiles lists to arrays */ + + /* convert files list to array */ + if (in_files_count) { + if ((G.pfnames = (char **) malloc((in_files_count + 1) * sizeof(char *))) == NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments))); + return PK_MEM; + } + file_count = 0; + for (next_file = in_files; next_file;) { + G.pfnames[file_count] = next_file->name; + in_files = next_file; + next_file = next_file->next; + free(in_files); + file_count++; + } + G.pfnames[file_count] = NULL; + G.filespecs = in_files_count; + } + + /* convert xfiles list to array */ + if (in_xfiles_count) { + if ((G.pxnames = (char **) malloc((in_xfiles_count + 1) * sizeof(char *))) == NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments))); + return PK_MEM; + } + file_count = 0; + for (next_file = in_xfiles; next_file;) { + G.pxnames[file_count] = next_file->name; + in_xfiles = next_file; + next_file = next_file->next; + free(in_xfiles); + file_count++; + } + G.pxnames[file_count] = NULL; + G.xfilespecs = in_xfiles_count; + } + + if (in_files_count || in_xfiles_count) { + G.process_all_files = FALSE; + } else { + G.process_all_files = TRUE; /* for speed */ + } + + /* it's possible the arg count could have been changed by get_option() */ + argc = arg_count(args); + + if ((G.wildzipfn == NULL) || error) { + argc = -1; /* tell the caller to stop processing */ + *pargc = argc; + *pargv = args; + return USAGE(error); + } + +#ifdef MORE + if (G.M_flag && !isatty(1)) /* stdout redirected: "more" func useless */ + G.M_flag = 0; +#endif + + /* if no listing options given (or all negated), or if only -h/-t given + * with individual files specified, use default listing format */ + if ((uO.lflag < 0) || ((argc > 0) && (uO.lflag == 0))) + uO.lflag = LFLAG; + + /* set header and totals flags to default or specified values */ + switch (uO.lflag) { + case 0: /* 0: can only occur if either -t or -h explicitly given; */ + case 2: /* therefore set both flags equal to normally false value */ + uO.hflag = hflag_2; + uO.tflag = tflag_2v; + break; + case 1: /* only filenames, *always* */ + uO.hflag = FALSE; + uO.tflag = FALSE; + uO.zflag = FALSE; + break; + case 3: + case 4: + case 5: + uO.hflag = ((argc > 0) && !explicit_h)? FALSE : hflag_slmv; + uO.tflag = ((argc > 0) && !explicit_t)? FALSE : tflag_slm; + break; + case 10: + uO.hflag = hflag_slmv; + uO.tflag = tflag_2v; + break; + } + + *pargc = argc; + *pargv = args; + return 0; + +} /* end function zi_opts() */ + +#endif /* !WINDLL */ + + + + + +/*******************************/ +/* Function zi_end_central() */ +/*******************************/ + +void zi_end_central(__G) + __GDEF +{ +/*--------------------------------------------------------------------------- + Print out various interesting things about the zipfile. + ---------------------------------------------------------------------------*/ + + if (uO.lflag > 9) { + /* verbose format */ + Info(slide, 0, ((char *)slide, LoadFarString(EndCentDirRec))); + Info(slide, 0, ((char *)slide, LoadFarString(LineSeparators))); + + Info(slide, 0, ((char *)slide, LoadFarString(ZipFSizeVerbose), + FmZofft(G.ziplen, "11", NULL), + FmZofft(G.ziplen, FZOFFT_HEX_DOT_WID, "X"))); + Info(slide, 0, ((char *)slide, LoadFarString(ActOffsetCentDir), + FmZofft(G.real_ecrec_offset, "11", "u"), + FmZofft(G.real_ecrec_offset, FZOFFT_HEX_DOT_WID, "X"), + FmZofft(G.expect_ecrec_offset, "11", "u"), + FmZofft(G.expect_ecrec_offset, FZOFFT_HEX_DOT_WID, "X"))); + + if (G.ecrec.number_this_disk == 0) { + Info(slide, 0, ((char *)slide, LoadFarString(SinglePartArchive1), + FmZofft(G.ecrec.total_entries_central_dir, NULL, "u"), + (G.ecrec.total_entries_central_dir == 1)? "entry" : "entries", + FmZofft(G.ecrec.size_central_directory, NULL, "u"), + FmZofft(G.ecrec.size_central_directory, + FZOFFT_HEX_DOT_WID, "X"))); + Info(slide, 0, ((char *)slide, LoadFarString(SinglePartArchive2), + FmZofft(G.ecrec.offset_start_central_directory, NULL, "u"), + FmZofft(G.ecrec.offset_start_central_directory, + FZOFFT_HEX_DOT_WID, "X"))); + } else { + Info(slide, 0, ((char *)slide, LoadFarString(MultiPartArchive1), + (ulg)(G.ecrec.number_this_disk + 1), + (ulg)(G.ecrec.num_disk_start_cdir + 1))); + Info(slide, 0, ((char *)slide, LoadFarString(MultiPartArchive2), + FmZofft(G.ecrec.offset_start_central_directory, NULL, "u"), + FmZofft(G.ecrec.offset_start_central_directory, + FZOFFT_HEX_DOT_WID, "X"), + FmZofft(G.ecrec.size_central_directory, NULL, "u"), + FmZofft(G.ecrec.size_central_directory, + FZOFFT_HEX_DOT_WID, "X"))); + Info(slide, 0, ((char *)slide, LoadFarString(MultiPartArchive3), + FmZofft(G.ecrec.num_entries_centrl_dir_ths_disk, NULL, "u"), + (G.ecrec.num_entries_centrl_dir_ths_disk == 1)? "is" : "are", + FmZofft(G.ecrec.total_entries_central_dir, NULL, "u"), + (G.ecrec.total_entries_central_dir == 1) ? "entry" : "entries")); + } + } + else if (uO.hflag) { + /* print zip file size and number of contained entries: */ + Info(slide, 0, ((char *)slide, LoadFarString(ZipInfHeader2), + FmZofft(G.ziplen, NULL, NULL), + FmZofft(G.ecrec.total_entries_central_dir, NULL, "u"))); + } + +} /* end function zi_end_central() */ + + + + + +/************************/ +/* Function zipinfo() */ +/************************/ + +int zipinfo(__G) /* return PK-type error code */ + __GDEF +{ + int do_this_file=FALSE, error, error_in_archive=PK_COOL; + int *fn_matched=NULL, *xn_matched=NULL; + ulg j, members=0L; + zusz_t tot_csize=0L, tot_ucsize=0L; + zusz_t endprev; /* buffers end of previous entry for zi_long()'s check + * of extra bytes */ + + +/*--------------------------------------------------------------------------- + Malloc space for check on unmatched filespecs (no big deal if one or both + are NULL). + ---------------------------------------------------------------------------*/ + + if (G.filespecs > 0 && + (fn_matched=(int *)malloc(G.filespecs*sizeof(int))) != NULL) + for (j = 0; j < G.filespecs; ++j) + fn_matched[j] = FALSE; + + if (G.xfilespecs > 0 && + (xn_matched=(int *)malloc(G.xfilespecs*sizeof(int))) != NULL) + for (j = 0; j < G.xfilespecs; ++j) + xn_matched[j] = FALSE; + +/*--------------------------------------------------------------------------- + Set file pointer to start of central directory, then loop through cen- + tral directory entries. Check that directory-entry signature bytes are + actually there (just a precaution), then process the entry. We know + the entire central directory is on this disk: we wouldn't have any of + this information unless the end-of-central-directory record was on this + disk, and we wouldn't 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 maybe someday we'll add + multi-disk support. + ---------------------------------------------------------------------------*/ + + uO.L_flag = FALSE; /* zipinfo mode: never convert name to lowercase */ + G.pInfo = G.info; /* (re-)initialize, (just to make sure) */ + G.pInfo->textmode = 0; /* so one can read on screen (is this ever used?) */ + + /* reset endprev for new zipfile; account for multi-part archives (?) */ + endprev = (G.crec.relative_offset_local_header == 4L)? 4L : 0L; + + + for (j = 1L;; j++) { + if (readbuf(__G__ G.sig, 4) == 0) { + error_in_archive = PK_EOF; + break; + } + 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, LoadFarString(ReportMsg))); + error_in_archive = PK_BADERR; /* sig not found */ + 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 */ + 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 */ + break; + } + + 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; + 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 in match */ + if (xn_matched) + xn_matched[i] = TRUE; + 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) { + + /* Read the extra field, if any. The extra field info is required + * for resolving the Zip64 sizes/offsets and may be used in more + * analysis of the entry below. + */ + if ((error = do_string(__G__ G.crec.extra_field_length, + EXTRA_FIELD)) != 0) + { + if (G.extra_field != NULL) { + free(G.extra_field); + G.extra_field = NULL; + } + error_in_archive = error; + /* The premature return in case of a "fatal" error (PK_EOF) is + * delayed until we analyze the extra field contents. + * This allows us to display all the other info that has been + * successfully read in. + */ + } + + switch (uO.lflag) { + case 1: + case 2: + fnprint(__G); + SKIP_(G.crec.file_comment_length) + break; + + case 3: + case 4: + case 5: + if ((error = zi_short(__G)) != PK_COOL) { + error_in_archive = error; /* might be warning */ + } + break; + + case 10: + Info(slide, 0, ((char *)slide, + LoadFarString(CentralDirEntry), j)); + if ((error = zi_long(__G__ &endprev, + error_in_archive)) != PK_COOL) { + error_in_archive = error; /* might be warning */ + } + break; + + default: + SKIP_(G.crec.file_comment_length) + break; + + } /* end switch (lflag) */ + if (error > PK_WARN) /* fatal */ + break; + + tot_csize += G.crec.csize; + tot_ucsize += G.crec.ucsize; + if (G.crec.general_purpose_bit_flag & 1) + tot_csize -= 12; /* don't count encryption header */ + ++members; + +#ifdef DLL + if ((G.statreportcb != NULL) && + (*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn, + G.filename, (zvoid *)&G.crec.ucsize)) { + /* cancel operation by user request */ + error_in_archive = IZ_CTRLC; + break; + } +#endif +#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */ + UserStop(); +#endif + + } else { /* not listing this file */ + SKIP_(G.crec.extra_field_length) + SKIP_(G.crec.file_comment_length) + if (endprev != 0) endprev = 0; + + } /* end if (list member?) */ + + } /* end for-loop (j: member files) */ + +/*--------------------------------------------------------------------------- + Check that we actually found requested files; if so, print totals. + ---------------------------------------------------------------------------*/ + + if ((error_in_archive <= PK_WARN) && uO.tflag) { + char *sgn = ""; + int cfactor = ratio(tot_ucsize, tot_csize); + + if (cfactor < 0) { + sgn = "-"; + cfactor = -cfactor; + } + Info(slide, 0, ((char *)slide, LoadFarString(ZipfileStats), + members, (members==1L)? nullStr:PlurSufx, + FmZofft(tot_ucsize, NULL, "u"), + FmZofft(tot_csize, NULL, "u"), + sgn, cfactor/10, cfactor%10)); + } + +/*--------------------------------------------------------------------------- + Check for unmatched filespecs on command line and print warning if any + found. + ---------------------------------------------------------------------------*/ + + if (fn_matched) { + if (error_in_archive <= PK_WARN) + for (j = 0; j < G.filespecs; ++j) + if (!fn_matched[j]) + Info(slide, 0x401, ((char *)slide, + LoadFarString(FilenameNotMatched), G.pfnames[j])); + free((zvoid *)fn_matched); + } + if (xn_matched) { + if (error_in_archive <= PK_WARN) + for (j = 0; j < G.xfilespecs; ++j) + if (!xn_matched[j]) + Info(slide, 0x401, ((char *)slide, + LoadFarString(ExclFilenameNotMatched), G.pxnames[j])); + free((zvoid *)xn_matched); + } + + + /* 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, 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; + + if (uO.lflag >= 10) + (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); + } + + return error_in_archive; + +} /* end function zipinfo() */ + + + + + +/************************/ +/* Function zi_long() */ +/************************/ + +static int zi_long(__G__ pEndprev, error_in_archive) + /* return PK-type error code */ + __GDEF + zusz_t *pEndprev; /* for zi_long() check of extra bytes */ + int error_in_archive; /* may signal premature return */ +{ +#ifdef USE_EF_UT_TIME + iztimes z_utime; +#endif + int error; + unsigned hostnum, hostver, extnum, extver, methid, methnum, xattr; + char workspace[12], attribs[22]; + ZCONST char *varmsg_str; + char unkn[16]; + static ZCONST char Far *os[NUM_HOSTS] = { + OS_FAT, OS_Amiga, OS_VMS, OS_Unix, OS_VMCMS, OS_AtariST, OS_HPFS, + OS_Macintosh, OS_ZSystem, OS_CPM, OS_TOPS20, OS_NTFS, OS_QDOS, + OS_Acorn, OS_VFAT, OS_MVS, OS_BeOS, OS_Tandem, OS_Theos, OS_MacDarwin, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + OS_AtheOS + }; + static ZCONST char Far *method[NUM_METHODS] = { + MthdNone, MthdShrunk, MthdRedF1, MthdRedF2, MthdRedF3, MthdRedF4, + MthdImplode, MthdToken, MthdDeflate, MthdDeflat64, MthdDCLImplode, + MthdBZip2, MthdLZMA, MthdTerse, MthdLZ77, MthdWavPack, MthdPPMd + }; + static ZCONST char Far *dtypelng[4] = { + DeflNorm, DeflMax, DeflFast, DeflSFast + }; + + +/*--------------------------------------------------------------------------- + Check whether there's any extra space inside the zipfile. If *pEndprev is + zero, it's probably a signal that OS/2 extra fields are involved (with + unknown compressed size). We won't worry about prepended junk here... + ---------------------------------------------------------------------------*/ + + if (G.crec.relative_offset_local_header != *pEndprev && *pEndprev > 0L) { + /* GRR DEBUG + Info(slide, 0, ((char *)slide, + " [crec.relative_offset_local_header = %lu, endprev = %lu]\n", + G.crec.relative_offset_local_header, *pEndprev)); + */ + Info(slide, 0, ((char *)slide, LoadFarString(ExtraBytesPreceding), + FmZofft((G.crec.relative_offset_local_header - (*pEndprev)), + NULL, NULL))); + } + + /* calculate endprev for next time around (problem: extra fields may + * differ in length between local and central-directory records) */ + *pEndprev = G.crec.relative_offset_local_header + (4L + LREC_SIZE) + + G.crec.filename_length + G.crec.extra_field_length + G.crec.csize; + +/*--------------------------------------------------------------------------- + Print out various interesting things about the compressed file. + ---------------------------------------------------------------------------*/ + + hostnum = (unsigned)(G.pInfo->hostnum); + hostver = (unsigned)(G.pInfo->hostver); + extnum = (unsigned)MIN(G.crec.version_needed_to_extract[1], NUM_HOSTS); + extver = (unsigned)G.crec.version_needed_to_extract[0]; + methid = (unsigned)G.crec.compression_method; + methnum = find_compr_idx(G.crec.compression_method); + + (*G.message)((zvoid *)&G, (uch *)" ", 2L, 0); fnprint(__G); + + Info(slide, 0, ((char *)slide, LoadFarString(LocalHeaderOffset), + FmZofft(G.crec.relative_offset_local_header, NULL, "u"), + FmZofft(G.crec.relative_offset_local_header, FZOFFT_HEX_DOT_WID, "X"))); + + if (hostnum >= NUM_HOSTS) { + sprintf(unkn, LoadFarString(UnknownNo), + (int)G.crec.version_made_by[1]); + varmsg_str = unkn; + } else { + varmsg_str = LoadFarStringSmall(os[hostnum]); +#ifdef OLD_THEOS_EXTRA + if (hostnum == FS_VFAT_ && hostver == 20) { + /* entry made by old non-official THEOS port zip archive */ + varmsg_str = LoadFarStringSmall(OS_TheosOld); + } +#endif /* OLD_THEOS_EXTRA */ + } + Info(slide, 0, ((char *)slide, LoadFarString(HostOS), varmsg_str)); + Info(slide, 0, ((char *)slide, LoadFarString(EncodeSWVer), hostver/10, + hostver%10)); + + if ((extnum >= NUM_HOSTS) || (os[extnum] == NULL)) { + sprintf(unkn, LoadFarString(UnknownNo), + (int)G.crec.version_needed_to_extract[1]); + varmsg_str = unkn; + } else { + varmsg_str = LoadFarStringSmall(os[extnum]); + } + Info(slide, 0, ((char *)slide, LoadFarString(MinOSCompReq), varmsg_str)); + Info(slide, 0, ((char *)slide, LoadFarString(MinSWVerReq), extver/10, + extver%10)); + + if (methnum >= NUM_METHODS) { + sprintf(unkn, LoadFarString(UnknownNo), G.crec.compression_method); + varmsg_str = unkn; + } else { + varmsg_str = LoadFarStringSmall(method[methnum]); + } + Info(slide, 0, ((char *)slide, LoadFarString(CompressMethod), varmsg_str)); + if (methid == IMPLODED) { + Info(slide, 0, ((char *)slide, LoadFarString(SlideWindowSizeImplode), + (G.crec.general_purpose_bit_flag & 2)? '8' : '4')); + Info(slide, 0, ((char *)slide, LoadFarString(ShannonFanoTrees), + (G.crec.general_purpose_bit_flag & 4)? '3' : '2')); + } else if (methid == DEFLATED || methid == ENHDEFLATED) { + ush dnum=(ush)((G.crec.general_purpose_bit_flag>>1) & 3); + + Info(slide, 0, ((char *)slide, LoadFarString(CompressSubtype), + LoadFarStringSmall(dtypelng[dnum]))); + } + + Info(slide, 0, ((char *)slide, LoadFarString(FileSecurity), + (G.crec.general_purpose_bit_flag & 1) ? nullStr : "not ")); + Info(slide, 0, ((char *)slide, LoadFarString(ExtendedLocalHdr), + (G.crec.general_purpose_bit_flag & 8) ? "yes" : "no")); + /* print upper 3 bits for amusement? */ + + /* For printing of date & time, a "char d_t_buf[21]" is required. + * To save stack space, we reuse the "char attribs[22]" buffer which + * is not used yet. + */ +# define d_t_buf attribs + + zi_time(__G__ &G.crec.last_mod_dos_datetime, NULL, d_t_buf); + Info(slide, 0, ((char *)slide, LoadFarString(FileModDate), d_t_buf)); +#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 or Macintosh */ + d_t_buf[0] = (char)0; /* signal "show local time" */ + zi_time(__G__ &G.crec.last_mod_dos_datetime, &(z_utime.mtime), d_t_buf); + Info(slide, 0, ((char *)slide, LoadFarString(UT_FileModDate), + d_t_buf, LoadFarStringSmall(LocalTime))); +#ifndef NO_GMTIME + d_t_buf[0] = (char)1; /* signal "show UTC (GMT) time" */ + zi_time(__G__ &G.crec.last_mod_dos_datetime, &(z_utime.mtime), d_t_buf); + Info(slide, 0, ((char *)slide, LoadFarString(UT_FileModDate), + d_t_buf, LoadFarStringSmall(GMTime))); +#endif /* !NO_GMTIME */ + } +#endif /* USE_EF_UT_TIME */ + + Info(slide, 0, ((char *)slide, LoadFarString(CRC32Value), G.crec.crc32)); + Info(slide, 0, ((char *)slide, LoadFarString(CompressedFileSize), + FmZofft(G.crec.csize, NULL, "u"))); + Info(slide, 0, ((char *)slide, LoadFarString(UncompressedFileSize), + FmZofft(G.crec.ucsize, NULL, "u"))); + Info(slide, 0, ((char *)slide, LoadFarString(FilenameLength), + G.crec.filename_length)); + Info(slide, 0, ((char *)slide, LoadFarString(ExtraFieldLength), + G.crec.extra_field_length)); + Info(slide, 0, ((char *)slide, LoadFarString(FileCommentLength), + G.crec.file_comment_length)); + Info(slide, 0, ((char *)slide, LoadFarString(FileDiskNum), + (ulg)(G.crec.disk_number_start + 1))); + Info(slide, 0, ((char *)slide, LoadFarString(ApparentFileType), + (G.crec.internal_file_attributes & 1)? "text" + : (G.crec.internal_file_attributes & 2)? "ebcdic" + : "binary")); /* changed to accept EBCDIC */ +#ifdef ATARI + printf(" external file attributes (hex): %.8lx\n", + G.crec.external_file_attributes); +#endif + xattr = (unsigned)((G.crec.external_file_attributes >> 16) & 0xFFFF); + if (hostnum == VMS_) { + char *p=attribs, *q=attribs+1; + int i, j, k; + + for (k = 0; k < 12; ++k) + workspace[k] = 0; + if (xattr & VMS_IRUSR) + workspace[0] = 'R'; + if (xattr & VMS_IWUSR) { + workspace[1] = 'W'; + workspace[3] = 'D'; + } + if (xattr & VMS_IXUSR) + workspace[2] = 'E'; + if (xattr & VMS_IRGRP) + workspace[4] = 'R'; + if (xattr & VMS_IWGRP) { + workspace[5] = 'W'; + workspace[7] = 'D'; + } + if (xattr & VMS_IXGRP) + workspace[6] = 'E'; + if (xattr & VMS_IROTH) + workspace[8] = 'R'; + if (xattr & VMS_IWOTH) { + workspace[9] = 'W'; + workspace[11] = 'D'; + } + if (xattr & VMS_IXOTH) + workspace[10] = 'E'; + + *p++ = '('; + for (k = j = 0; j < 3; ++j) { /* loop over groups of permissions */ + for (i = 0; i < 4; ++i, ++k) /* loop over perms within a group */ + if (workspace[k]) + *p++ = workspace[k]; + *p++ = ','; /* group separator */ + if (j == 0) + while ((*p++ = *q++) != ',') + ; /* system, owner perms are same */ + } + *p-- = '\0'; + *p = ')'; /* overwrite last comma */ + Info(slide, 0, ((char *)slide, LoadFarString(VMSFileAttributes), xattr, + attribs)); + + } else if (hostnum == AMIGA_) { + switch (xattr & AMI_IFMT) { + case AMI_IFDIR: attribs[0] = 'd'; break; + case AMI_IFREG: attribs[0] = '-'; break; + default: attribs[0] = '?'; break; + } + attribs[1] = (xattr & AMI_IHIDDEN)? 'h' : '-'; + attribs[2] = (xattr & AMI_ISCRIPT)? 's' : '-'; + attribs[3] = (xattr & AMI_IPURE)? 'p' : '-'; + attribs[4] = (xattr & AMI_IARCHIVE)? 'a' : '-'; + attribs[5] = (xattr & AMI_IREAD)? 'r' : '-'; + attribs[6] = (xattr & AMI_IWRITE)? 'w' : '-'; + attribs[7] = (xattr & AMI_IEXECUTE)? 'e' : '-'; + attribs[8] = (xattr & AMI_IDELETE)? 'd' : '-'; + attribs[9] = 0; /* better dlm the string */ + Info(slide, 0, ((char *)slide, LoadFarString(AmigaFileAttributes), + xattr, attribs)); + + } else if (hostnum == THEOS_) { + ZCONST char Far *fpFtyp; + + switch (xattr & THS_IFMT) { + case THS_IFLIB: fpFtyp = TheosFTypLib; break; + case THS_IFDIR: fpFtyp = TheosFTypDir; break; + case THS_IFREG: fpFtyp = TheosFTypReg; break; + case THS_IFREL: fpFtyp = TheosFTypRel; break; + case THS_IFKEY: fpFtyp = TheosFTypKey; break; + case THS_IFIND: fpFtyp = TheosFTypInd; break; + case THS_IFR16: fpFtyp = TheosFTypR16; break; + case THS_IFP16: fpFtyp = TheosFTypP16; break; + case THS_IFP32: fpFtyp = TheosFTypP32; break; + default: fpFtyp = TheosFTypUkn; break; + } + strcpy(attribs, LoadFarStringSmall(fpFtyp)); + attribs[12] = (xattr & THS_INHID) ? '.' : 'H'; + attribs[13] = (xattr & THS_IMODF) ? '.' : 'M'; + attribs[14] = (xattr & THS_IWOTH) ? '.' : 'W'; + attribs[15] = (xattr & THS_IROTH) ? '.' : 'R'; + attribs[16] = (xattr & THS_IEUSR) ? '.' : 'E'; + attribs[17] = (xattr & THS_IXUSR) ? '.' : 'X'; + attribs[18] = (xattr & THS_IWUSR) ? '.' : 'W'; + attribs[19] = (xattr & THS_IRUSR) ? '.' : 'R'; + attribs[20] = 0; + Info(slide, 0, ((char *)slide, LoadFarString(TheosFileAttributes), + xattr, attribs)); + +#ifdef OLD_THEOS_EXTRA + } else if (hostnum == FS_VFAT_ && hostver == 20) { + /* process old non-official THEOS port zip archive */ + ZCONST char Far *fpFtyp; + + switch (xattr & _THS_IFMT) { + case _THS_IFLIB: fpFtyp = TheosFTypLib; break; + case _THS_IFDIR: fpFtyp = TheosFTypDir; break; + case _THS_IFREG: fpFtyp = TheosFTypReg; break; + case _THS_IODRC: fpFtyp = TheosFTypRel; break; + case _THS_IOKEY: fpFtyp = TheosFTypKey; break; + case _THS_IOIND: fpFtyp = TheosFTypInd; break; + case _THS_IOPRG: fpFtyp = TheosFTypR16; break; + case _THS_IO286: fpFtyp = TheosFTypP16; break; + case _THS_IO386: fpFtyp = TheosFTypP32; break; + default: fpFtyp = TheosFTypUkn; break; + } + strcpy(attribs, LoadFarStringSmall(fpFtyp)); + attribs[12] = (xattr & _THS_HIDDN) ? 'H' : '.'; + attribs[13] = (xattr & _THS_IXOTH) ? '.' : 'X'; + attribs[14] = (xattr & _THS_IWOTH) ? '.' : 'W'; + attribs[15] = (xattr & _THS_IROTH) ? '.' : 'R'; + attribs[16] = (xattr & _THS_IEUSR) ? '.' : 'E'; + attribs[17] = (xattr & _THS_IXUSR) ? '.' : 'X'; + attribs[18] = (xattr & _THS_IWUSR) ? '.' : 'W'; + attribs[19] = (xattr & _THS_IRUSR) ? '.' : 'R'; + attribs[20] = 0; + Info(slide, 0, ((char *)slide, LoadFarString(TheosFileAttributes), + xattr, attribs)); +#endif /* OLD_THEOS_EXTRA */ + + } else if ((hostnum != FS_FAT_) && (hostnum != FS_HPFS_) && + (hostnum != FS_NTFS_) && (hostnum != FS_VFAT_) && + (hostnum != ACORN_) && + (hostnum != VM_CMS_) && (hostnum != MVS_)) + { /* assume Unix-like */ + switch ((unsigned)(xattr & UNX_IFMT)) { + case (unsigned)UNX_IFDIR: attribs[0] = 'd'; break; + case (unsigned)UNX_IFREG: attribs[0] = '-'; break; + case (unsigned)UNX_IFLNK: attribs[0] = 'l'; break; + case (unsigned)UNX_IFBLK: attribs[0] = 'b'; break; + case (unsigned)UNX_IFCHR: attribs[0] = 'c'; break; + case (unsigned)UNX_IFIFO: attribs[0] = 'p'; break; + case (unsigned)UNX_IFSOCK: attribs[0] = 's'; break; + default: attribs[0] = '?'; break; + } + attribs[1] = (xattr & UNX_IRUSR)? 'r' : '-'; + attribs[4] = (xattr & UNX_IRGRP)? 'r' : '-'; + attribs[7] = (xattr & UNX_IROTH)? 'r' : '-'; + + attribs[2] = (xattr & UNX_IWUSR)? 'w' : '-'; + attribs[5] = (xattr & UNX_IWGRP)? 'w' : '-'; + attribs[8] = (xattr & UNX_IWOTH)? 'w' : '-'; + + if (xattr & UNX_IXUSR) + attribs[3] = (xattr & UNX_ISUID)? 's' : 'x'; + else + attribs[3] = (xattr & UNX_ISUID)? 'S' : '-'; /* S = undefined */ + if (xattr & UNX_IXGRP) + attribs[6] = (xattr & UNX_ISGID)? 's' : 'x'; /* == UNX_ENFMT */ + else + attribs[6] = (xattr & UNX_ISGID)? 'l' : '-'; + if (xattr & UNX_IXOTH) + attribs[9] = (xattr & UNX_ISVTX)? 't' : 'x'; /* "sticky bit" */ + else + attribs[9] = (xattr & UNX_ISVTX)? 'T' : '-'; /* T = undefined */ + attribs[10] = 0; + + Info(slide, 0, ((char *)slide, LoadFarString(UnixFileAttributes), xattr, + attribs)); + + } else { + Info(slide, 0, ((char *)slide, LoadFarString(NonMSDOSFileAttributes), + G.crec.external_file_attributes >> 8)); + + } /* endif (hostnum: external attributes format) */ + + if ((xattr=(unsigned)(G.crec.external_file_attributes & 0xFF)) == 0) + Info(slide, 0, ((char *)slide, LoadFarString(MSDOSFileAttributes), + xattr)); + else if (xattr == 1) + Info(slide, 0, ((char *)slide, LoadFarString(MSDOSFileAttributesRO), + xattr)); + else + Info(slide, 0, ((char *)slide, LoadFarString(MSDOSFileAttributesAlpha), + xattr, (xattr&1)? "rdo " : nullStr, + (xattr&2)? "hid " : nullStr, + (xattr&4)? "sys " : nullStr, + (xattr&8)? "lab " : nullStr, + (xattr&16)? "dir " : nullStr, + (xattr&32)? "arc " : nullStr, + (xattr&64)? "lnk " : nullStr, + (xattr&128)? "exe" : nullStr)); + +/*--------------------------------------------------------------------------- + Analyze the extra field, if any, and print the file comment, if any (the + filename has already been printed, above). That finishes up this file + entry... + ---------------------------------------------------------------------------*/ + + if (G.crec.extra_field_length > 0) { + uch *ef_ptr = G.extra_field; + ush ef_len = G.crec.extra_field_length; + ush eb_id, eb_datalen; + ZCONST char Far *ef_fieldname; + + if (error_in_archive > PK_WARN) /* fatal: can't continue */ + /* delayed "fatal error" return from extra field reading */ + return error_in_archive; + if (G.extra_field == (uch *)NULL) + return PK_ERR; /* not consistent with crec length */ + + Info(slide, 0, ((char *)slide, LoadFarString(ExtraFields))); + + while (ef_len >= EB_HEADSIZE) { + eb_id = makeword(&ef_ptr[EB_ID]); + eb_datalen = makeword(&ef_ptr[EB_LEN]); + ef_ptr += EB_HEADSIZE; + ef_len -= EB_HEADSIZE; + + if (eb_datalen > (ush)ef_len) { + Info(slide, 0x421, ((char *)slide, + LoadFarString(ExtraFieldTrunc), eb_id, eb_datalen, ef_len)); + eb_datalen = ef_len; + } + + switch (eb_id) { + case EF_PKSZ64: + ef_fieldname = efPKSZ64; + if ((G.crec.relative_offset_local_header + & (~(zusz_t)0xFFFFFFFFL)) != 0) { + /* Subtract the size of the 64bit local offset from + the local e.f. size, local Z64 e.f. block has no + offset; when only local offset present, the entire + local PKSZ64 block is missing. */ + *pEndprev -= (eb_datalen == 8 ? 12 : 8); + } + break; + case EF_AV: + ef_fieldname = efAV; + break; + case EF_OS2: + ef_fieldname = efOS2; + break; + case EF_ACL: + ef_fieldname = efACL; + break; + case EF_NTSD: + ef_fieldname = efNTSD; + break; + case EF_PKVMS: + ef_fieldname = efPKVMS; + break; + case EF_IZVMS: + ef_fieldname = efIZVMS; + break; + case EF_PKW32: + ef_fieldname = efPKWin32; + break; + case EF_PKUNIX: + ef_fieldname = efPKUnix; + break; + case EF_IZUNIX: + ef_fieldname = efIZUnix; + if (hostnum == UNIX_ && *pEndprev > 0L) + *pEndprev += 4L; /* also have UID/GID in local copy */ + break; + case EF_IZUNIX2: + ef_fieldname = efIZUnix2; + if (*pEndprev > 0L) + *pEndprev += 4L; /* 4 byte UID/GID in local copy */ + break; + case EF_IZUNIX3: + ef_fieldname = efIZUnix3; +#if 0 + if (*pEndprev > 0L) + *pEndprev += 4L; /* 4 byte UID/GID in local copy */ +#endif + break; + case EF_TIME: + ef_fieldname = efTime; + break; + case EF_UNIPATH: + ef_fieldname = efU8Path; + break; + case EF_UNICOMNT: + ef_fieldname = efU8Commnt; + break; + case EF_MAC3: + ef_fieldname = efMac3; + break; + case EF_JLMAC: + ef_fieldname = efJLMac; + break; + case EF_ZIPIT: + ef_fieldname = efZipIt; + break; + case EF_ZIPIT2: + ef_fieldname = efZipIt2; + break; + case EF_VMCMS: + ef_fieldname = efVMCMS; + break; + case EF_MVS: + ef_fieldname = efMVS; + break; + case EF_ATHEOS: + ef_fieldname = efAtheOS; + break; + case EF_BEOS: + ef_fieldname = efBeOS; + break; + case EF_QDOS: + ef_fieldname = efQDOS; + break; + case EF_AOSVS: + ef_fieldname = efAOSVS; + break; + case EF_SPARK: /* from RISC OS */ + ef_fieldname = efSpark; + break; + case EF_MD5: + ef_fieldname = efMD5; + break; + case EF_ASIUNIX: + ef_fieldname = efASiUnix; + break; + case EF_TANDEM: + ef_fieldname = efTandem; + break; + case EF_SMARTZIP: + ef_fieldname = efSmartZip; + break; + case EF_THEOS: +#ifdef OLD_THEOS_EXTRA + case EF_THEOSO: +#endif + ef_fieldname = efTheos; + break; + default: + ef_fieldname = efUnknown; + break; + } + Info(slide, 0, ((char *)slide, LoadFarString(ExtraFieldType), + eb_id, LoadFarStringSmall(ef_fieldname), eb_datalen)); + + /* additional, field-specific information: */ + switch (eb_id) { + case EF_OS2: + case EF_ACL: + if (eb_datalen >= EB_OS2_HLEN) { + if (eb_id == EF_OS2) + ef_fieldname = OS2EAs; + else + ef_fieldname = ACLdata; + Info(slide, 0, ((char *)slide, + LoadFarString(ef_fieldname), makelong(ef_ptr))); + *pEndprev = 0L; /* no clue about csize of local */ + } else { + goto ef_default_display; + } + break; + case EF_NTSD: + if (eb_datalen >= EB_NTSD_C_LEN) { + Info(slide, 0, ((char *)slide, LoadFarString(NTSDData), + makelong(ef_ptr))); + *pEndprev = 0L; /* no clue about csize of local */ + } else { + goto ef_default_display; + } + break; + case EF_IZVMS: + if (eb_datalen >= 8) { + char *p, q[8]; + unsigned compr = makeword(ef_ptr+EB_IZVMS_FLGS) + & EB_IZVMS_BCMASK; + + *q = '\0'; + if (compr > 3) + compr = 3; + switch (makelong(ef_ptr)) { + case 0x42414656: /* "VFAB" */ + p = "FAB"; break; + case 0x4C4C4156: /* "VALL" */ + p = "XABALL"; break; + case 0x43484656: /* "VFHC" */ + p = "XABFHC"; break; + case 0x54414456: /* "VDAT" */ + p = "XABDAT"; break; + case 0x54445256: /* "VRDT" */ + p = "XABRDT"; break; + case 0x4F525056: /* "VPRO" */ + p = "XABPRO"; break; + case 0x59454B56: /* "VKEY" */ + p = "XABKEY"; break; + case 0x56534D56: /* "VMSV" */ + p = "version"; + if (eb_datalen >= 16) { + /* put termitation first, for A_TO_N() */ + q[7] = '\0'; + q[0] = ' '; + q[1] = '('; + strncpy(q+2, + (char *)ef_ptr+EB_IZVMS_HLEN, 4); + A_TO_N(q+2); + q[6] = ')'; + } + break; + default: + p = "unknown"; + } + Info(slide, 0, ((char *)slide, + LoadFarString(izVMSdata), + LoadFarStringSmall(izVMScomp[compr]), + makeword(ef_ptr+EB_IZVMS_UCSIZ), p, q)); + } else { + goto ef_default_display; + } + break; + case EF_TIME: + if (eb_datalen > 0) { + char types[80]; + int num = 0, len; + + *types = '\0'; + if (*ef_ptr & 1) { + strcpy(types, LoadFarString(UTmodification)); + ++num; + } + if (*ef_ptr & 2) { + len = strlen(types); + if (num) + types[len++] = '/'; + strcpy(types+len, LoadFarString(UTaccess)); + ++num; + if (*pEndprev > 0L) + *pEndprev += 4L; + } + if (*ef_ptr & 4) { + len = strlen(types); + if (num) + types[len++] = '/'; + strcpy(types+len, LoadFarString(UTcreation)); + ++num; + if (*pEndprev > 0L) + *pEndprev += 4L; + } + if (num > 0) + Info(slide, 0, ((char *)slide, + LoadFarString(UTdata), types, + num == 1? nullStr : PlurSufx)); + } + break; + case EF_UNIPATH: + case EF_UNICOMNT: + if (eb_datalen >= 5) { + unsigned i, n; + ulg name_crc = makelong(ef_ptr+1); + + if (eb_datalen <= 29) { + Info(slide, 0, ((char *)slide, + LoadFarString(U8PthCmnComplete), + (unsigned)ef_ptr[0], name_crc)); + n = eb_datalen; + } else { + Info(slide, 0, ((char *)slide, + LoadFarString(U8PthCmnF24), + (unsigned)ef_ptr[0], name_crc)); + n = 29; + } + for (i = 5; i < n; ++i) + Info(slide, 0, ((char *)slide, + LoadFarString(efFormat), ef_ptr[i])); + } else { + goto ef_default_display; + } + break; + case EF_MAC3: + if (eb_datalen >= EB_MAC3_HLEN) { + ulg eb_uc = makelong(ef_ptr); + unsigned mac3_flgs = makeword(ef_ptr+EB_FLGS_OFFS); + unsigned eb_is_uc = mac3_flgs & EB_M3_FL_UNCMPR; + + Info(slide, 0, ((char *)slide, LoadFarString(Mac3data), + eb_uc, eb_is_uc ? "un" : nullStr)); + if (eb_is_uc) { + if (*pEndprev > 0L) + *pEndprev += makelong(ef_ptr); + } else { + *pEndprev = 0L; /* no clue about csize of local */ + } + + Info(slide, 0, ((char *)slide, + LoadFarString(MacOSMAC3flags), + LoadFarStringSmall(mac3_flgs & EB_M3_FL_DATFRK ? + MacOS_DF : MacOS_RF), + (mac3_flgs & EB_M3_FL_TIME64 ? 64 : 32))); + zi_showMacTypeCreator(__G__ &ef_ptr[6]); + } else { + goto ef_default_display; + } + break; + case EF_ZIPIT2: + if (eb_datalen >= 5 && + makelong(ef_ptr) == 0x5449505A /* "ZPIT" */) { + + if (eb_datalen >= 12) { + zi_showMacTypeCreator(__G__ &ef_ptr[4]); + } + } else { + goto ef_default_display; + } + break; + case EF_ZIPIT: + if (eb_datalen >= 5 && + makelong(ef_ptr) == 0x5449505A /* "ZPIT" */) { + unsigned fnlen = ef_ptr[4]; + + if ((unsigned)eb_datalen >= fnlen + (5 + 8)) { + uch nullchar = ef_ptr[fnlen+5]; + + ef_ptr[fnlen+5] = '\0'; /* terminate filename */ + A_TO_N(ef_ptr+5); + Info(slide, 0, ((char *)slide, + LoadFarString(ZipItFname), (char *)ef_ptr+5)); + ef_ptr[fnlen+5] = nullchar; + zi_showMacTypeCreator(__G__ &ef_ptr[fnlen+5]); + } + } else { + goto ef_default_display; + } + break; + case EF_JLMAC: + if (eb_datalen >= 40 && + makelong(ef_ptr) == 0x45454C4A /* "JLEE" */) + { + zi_showMacTypeCreator(__G__ &ef_ptr[4]); + + Info(slide, 0, ((char *)slide, + LoadFarString(MacOSJLEEflags), + LoadFarStringSmall(ef_ptr[31] & 1 ? + MacOS_DF : MacOS_RF))); + } else { + goto ef_default_display; + } + break; + case EF_SMARTZIP: + if ((eb_datalen == EB_SMARTZIP_HLEN) && + makelong(ef_ptr) == 0x70695A64 /* "dZip" */) { + char filenameBuf[32]; + zi_showMacTypeCreator(__G__ &ef_ptr[4]); + memcpy(filenameBuf, &ef_ptr[33], 31); + filenameBuf[ef_ptr[32]] = '\0'; + A_TO_N(filenameBuf); + Info(slide, 0, ((char *)slide, + LoadFarString(ZipItFname), filenameBuf)); + } else { + goto ef_default_display; + } + break; +#ifdef CMS_MVS + case EF_VMCMS: + case EF_MVS: + { + char type[100]; + + Info(slide, 0, ((char *)slide, + LoadFarString(VmMvsExtraField), + (getVMMVSexfield(type, ef_ptr-EB_HEADSIZE, + (unsigned)eb_datalen) > 0)? + type : LoadFarStringSmall(VmMvsInvalid))); + } + break; +#endif /* CMS_MVS */ + case EF_ATHEOS: + case EF_BEOS: + if (eb_datalen >= EB_BEOS_HLEN) { + ulg eb_uc = makelong(ef_ptr); + unsigned eb_is_uc = + *(ef_ptr+EB_FLGS_OFFS) & EB_BE_FL_UNCMPR; + + if (eb_id == EF_ATHEOS) + ef_fieldname = AtheOSdata; + else + ef_fieldname = BeOSdata; + Info(slide, 0, ((char *)slide, + LoadFarString(ef_fieldname), + eb_uc, eb_is_uc ? "un" : nullStr)); + if (eb_is_uc) { + if (*pEndprev > 0L) + *pEndprev += makelong(ef_ptr); + } else { + *pEndprev = 0L; /* no clue about csize of local */ + } + } else { + goto ef_default_display; + } + break; + case EF_QDOS: + if (eb_datalen >= 4) { + Info(slide, 0, ((char *)slide, LoadFarString(QDOSdata), + ef_ptr[0], ef_ptr[1], ef_ptr[2], ef_ptr[3])); + } else { + goto ef_default_display; + } + break; + case EF_AOSVS: + if (eb_datalen >= 5) { + Info(slide, 0, ((char *)slide, LoadFarString(AOSVSdata), + ((int)(uch)ef_ptr[4])/10, ((int)(uch)ef_ptr[4])%10)); + } else { + goto ef_default_display; + } + break; + case EF_TANDEM: + if (eb_datalen == 20) { + unsigned type, code; + + type = (ef_ptr[18] & 0x60) >> 5; + code = makeword(ef_ptr); + /* Arrg..., Tandem e.f. uses BigEndian byte-order */ + code = ((code << 8) & 0xff00) | ((code >> 8) & 0x00ff); + if (type == NSK_UNSTRUCTURED) { + if (code == NSK_EDITFILECODE) + type = 4; + else if (code == NSK_OBJECTFILECODE) + type = 5; + } + Info(slide, 0, ((char *)slide, + LoadFarString(Tandemdata), + LoadFarStringSmall(TandemFileformat[type]), + code)); + } else { + goto ef_default_display; + } + break; + case EF_MD5: + if (eb_datalen >= 19) { + char md5[33]; + int i; + + for (i = 0; i < 16; ++i) + sprintf(&md5[i<<1], "%02x", ef_ptr[15-i]); + md5[32] = '\0'; + Info(slide, 0, ((char *)slide, LoadFarString(MD5data), + md5)); + break; + } /* else: fall through !! */ + default: +ef_default_display: + if (eb_datalen > 0) { + unsigned i, n; + + if (eb_datalen <= 24) { + Info(slide, 0, ((char *)slide, + LoadFarString(ColonIndent))); + n = eb_datalen; + } else { + Info(slide, 0, ((char *)slide, + LoadFarString(First20))); + n = 20; + } + for (i = 0; i < n; ++i) + Info(slide, 0, ((char *)slide, + LoadFarString(efFormat), ef_ptr[i])); + } + break; + } + (*G.message)((zvoid *)&G, (uch *)".", 1L, 0); + + ef_ptr += eb_datalen; + ef_len -= eb_datalen; + } + (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); + } + + /* high bit == Unix/OS2/NT GMT times (mtime, atime); next bit == UID/GID */ + if ((xattr = (unsigned)((G.crec.external_file_attributes & 0xC000) >> 12)) + & 8) + { + if (hostnum == UNIX_ || hostnum == FS_HPFS_ || hostnum == FS_NTFS_) + { + Info(slide, 0, ((char *)slide, LoadFarString(lExtraFieldType), + "is", EF_IZUNIX, LoadFarStringSmall(efIZUnix), + (unsigned)(xattr&12), (xattr&4)? efIZuid : efIZnouid)); + if (*pEndprev > 0L) + *pEndprev += (ulg)(xattr&12); + } + else if (hostnum == FS_FAT_ && !(xattr&4)) + Info(slide, 0, ((char *)slide, LoadFarString(lExtraFieldType), + "may be", EF_IZUNIX, LoadFarStringSmall(efIZUnix), 8, + efIZnouid)); + } + + if (!G.crec.file_comment_length) + Info(slide, 0, ((char *)slide, LoadFarString(NoFileComment))); + else { + Info(slide, 0, ((char *)slide, LoadFarString(FileCommBegin))); + if ((error = do_string(__G__ G.crec.file_comment_length, DISPL_8)) != + PK_COOL) + { + error_in_archive = error; /* might be warning */ + if (error > PK_WARN) /* fatal */ + return error; + } + Info(slide, 0, ((char *)slide, LoadFarString(FileCommEnd))); + } + + return error_in_archive; + +} /* end function zi_long() */ + + + + + +/*************************/ +/* Function zi_short() */ +/*************************/ + +static int zi_short(__G) /* return PK-type error code */ + __GDEF +{ +#ifdef USE_EF_UT_TIME + iztimes z_utime; + time_t *z_modtim; +#endif + int k, error, error_in_archive=PK_COOL; + unsigned hostnum, hostver, methid, methnum, xattr; + char *p, workspace[12], attribs[32]; + char methbuf[16]; + static ZCONST char dtype[5]="NXFS"; /* normal, maximum, fast, superfast */ + static ZCONST char Far os[NUM_HOSTS+1][4] = { + "fat", "ami", "vms", "unx", "cms", "atr", "hpf", "mac", "zzz", + "cpm", "t20", "ntf", "qds", "aco", "vft", "mvs", "be ", "nsk", + "ths", "osx", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "ath", "???" + }; +#ifdef OLD_THEOS_EXTRA + static ZCONST char Far os_TheosOld[] = "tho"; +#endif + static ZCONST char Far method[NUM_METHODS+1][5] = { + "stor", "shrk", "re:1", "re:2", "re:3", "re:4", "i#:#", "tokn", + "def#", "d64#", "dcli", "bzp2", "lzma", "ters", "lz77", "wavp", + "ppmd", "u###" + }; + + +/*--------------------------------------------------------------------------- + Print out various interesting things about the compressed file. + ---------------------------------------------------------------------------*/ + + methid = (unsigned)(G.crec.compression_method); + methnum = find_compr_idx(G.crec.compression_method); + hostnum = (unsigned)(G.pInfo->hostnum); + hostver = (unsigned)(G.pInfo->hostver); +/* + extnum = (unsigned)MIN(G.crec.version_needed_to_extract[1], NUM_HOSTS); + extver = (unsigned)G.crec.version_needed_to_extract[0]; + */ + + zfstrcpy(methbuf, method[methnum]); + if (methid == IMPLODED) { + methbuf[1] = (char)((G.crec.general_purpose_bit_flag & 2)? '8' : '4'); + methbuf[3] = (char)((G.crec.general_purpose_bit_flag & 4)? '3' : '2'); + } else if (methid == DEFLATED || methid == ENHDEFLATED) { + 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); + } + + for (k = 0; k < 15; ++k) + attribs[k] = ' '; + attribs[15] = 0; + + xattr = (unsigned)((G.crec.external_file_attributes >> 16) & 0xFFFF); + switch (hostnum) { + case VMS_: + { int i, j; + + for (k = 0; k < 12; ++k) + workspace[k] = 0; + if (xattr & VMS_IRUSR) + workspace[0] = 'R'; + if (xattr & VMS_IWUSR) { + workspace[1] = 'W'; + workspace[3] = 'D'; + } + if (xattr & VMS_IXUSR) + workspace[2] = 'E'; + if (xattr & VMS_IRGRP) + workspace[4] = 'R'; + if (xattr & VMS_IWGRP) { + workspace[5] = 'W'; + workspace[7] = 'D'; + } + if (xattr & VMS_IXGRP) + workspace[6] = 'E'; + if (xattr & VMS_IROTH) + workspace[8] = 'R'; + if (xattr & VMS_IWOTH) { + workspace[9] = 'W'; + workspace[11] = 'D'; + } + if (xattr & VMS_IXOTH) + workspace[10] = 'E'; + + p = attribs; + for (k = j = 0; j < 3; ++j) { /* groups of permissions */ + for (i = 0; i < 4; ++i, ++k) /* perms within a group */ + if (workspace[k]) + *p++ = workspace[k]; + *p++ = ','; /* group separator */ + } + *--p = ' '; /* overwrite last comma */ + if ((p - attribs) < 12) + sprintf(&attribs[12], "%u.%u", hostver/10, hostver%10); + } + break; + + case AMIGA_: + switch (xattr & AMI_IFMT) { + case AMI_IFDIR: attribs[0] = 'd'; break; + case AMI_IFREG: attribs[0] = '-'; break; + default: attribs[0] = '?'; break; + } + attribs[1] = (xattr & AMI_IHIDDEN)? 'h' : '-'; + attribs[2] = (xattr & AMI_ISCRIPT)? 's' : '-'; + attribs[3] = (xattr & AMI_IPURE)? 'p' : '-'; + attribs[4] = (xattr & AMI_IARCHIVE)? 'a' : '-'; + attribs[5] = (xattr & AMI_IREAD)? 'r' : '-'; + attribs[6] = (xattr & AMI_IWRITE)? 'w' : '-'; + attribs[7] = (xattr & AMI_IEXECUTE)? 'e' : '-'; + attribs[8] = (xattr & AMI_IDELETE)? 'd' : '-'; + sprintf(&attribs[12], "%u.%u", hostver/10, hostver%10); + break; + + case THEOS_: + switch (xattr & THS_IFMT) { + case THS_IFLIB: *attribs = 'L'; break; + case THS_IFDIR: *attribs = 'D'; break; + case THS_IFCHR: *attribs = 'C'; break; + case THS_IFREG: *attribs = 'S'; break; + case THS_IFREL: *attribs = 'R'; break; + case THS_IFKEY: *attribs = 'K'; break; + case THS_IFIND: *attribs = 'I'; break; + case THS_IFR16: *attribs = 'P'; break; + case THS_IFP16: *attribs = '2'; break; + case THS_IFP32: *attribs = '3'; break; + default: *attribs = '?'; break; + } + attribs[1] = (xattr & THS_INHID) ? '.' : 'H'; + attribs[2] = (xattr & THS_IMODF) ? '.' : 'M'; + attribs[3] = (xattr & THS_IWOTH) ? '.' : 'W'; + attribs[4] = (xattr & THS_IROTH) ? '.' : 'R'; + attribs[5] = (xattr & THS_IEUSR) ? '.' : 'E'; + attribs[6] = (xattr & THS_IXUSR) ? '.' : 'X'; + attribs[7] = (xattr & THS_IWUSR) ? '.' : 'W'; + attribs[8] = (xattr & THS_IRUSR) ? '.' : 'R'; + sprintf(&attribs[12], "%u.%u", hostver/10, hostver%10); + break; + + case FS_VFAT_: +#ifdef OLD_THEOS_EXTRA + if (hostver == 20) { + switch (xattr & _THS_IFMT) { + case _THS_IFLIB: *attribs = 'L'; break; + case _THS_IFDIR: *attribs = 'd'; break; + case _THS_IFCHR: *attribs = 'c'; break; + case _THS_IFREG: *attribs = 'S'; break; + case _THS_IODRC: *attribs = 'D'; break; + case _THS_IOKEY: *attribs = 'K'; break; + case _THS_IOIND: *attribs = 'I'; break; + case _THS_IOPRG: *attribs = 'P'; break; + case _THS_IO286: *attribs = '2'; break; + case _THS_IO386: *attribs = '3'; break; + default: *attribs = '?'; break; + } + attribs[1] = (xattr & _THS_HIDDN) ? 'H' : '.'; + attribs[2] = (xattr & _THS_IXOTH) ? '.' : 'X'; + attribs[3] = (xattr & _THS_IWOTH) ? '.' : 'W'; + attribs[4] = (xattr & _THS_IROTH) ? '.' : 'R'; + attribs[5] = (xattr & _THS_IEUSR) ? '.' : 'E'; + attribs[6] = (xattr & _THS_IXUSR) ? '.' : 'X'; + attribs[7] = (xattr & _THS_IWUSR) ? '.' : 'W'; + attribs[8] = (xattr & _THS_IRUSR) ? '.' : 'R'; + sprintf(&attribs[12], "%u.%u", hostver/10, hostver%10); + break; + } /* else: fall through! */ +#endif /* OLD_THEOS_EXTRA */ + + case FS_FAT_: + case FS_HPFS_: + case FS_NTFS_: + case VM_CMS_: + case MVS_: + case ACORN_: + if (hostnum != FS_FAT_ || + (unsigned)(xattr & 0700) != + ((unsigned)0400 | + ((unsigned)!(G.crec.external_file_attributes & 1) << 7) | + ((unsigned)(G.crec.external_file_attributes & 0x10) << 2)) + ) + { + xattr = (unsigned)(G.crec.external_file_attributes & 0xFF); + sprintf(attribs, ".r.-... %u.%u", hostver/10, hostver%10); + attribs[2] = (xattr & 0x01)? '-' : 'w'; + attribs[5] = (xattr & 0x02)? 'h' : '-'; + attribs[6] = (xattr & 0x04)? 's' : '-'; + attribs[4] = (xattr & 0x20)? 'a' : '-'; + if (xattr & 0x10) { + attribs[0] = 'd'; + attribs[3] = 'x'; + } else + attribs[0] = '-'; + if (IS_VOLID(xattr)) + attribs[0] = 'V'; + else if ((p = MBSRCHR(G.filename, '.')) != (char *)NULL) { + ++p; + if (STRNICMP(p, "com", 3) == 0 || + STRNICMP(p, "exe", 3) == 0 || + STRNICMP(p, "btm", 3) == 0 || + STRNICMP(p, "cmd", 3) == 0 || + STRNICMP(p, "bat", 3) == 0) + attribs[3] = 'x'; + } + break; + } /* else: fall through! */ + + default: /* assume Unix-like */ + switch ((unsigned)(xattr & UNX_IFMT)) { + case (unsigned)UNX_IFDIR: attribs[0] = 'd'; break; + case (unsigned)UNX_IFREG: attribs[0] = '-'; break; + case (unsigned)UNX_IFLNK: attribs[0] = 'l'; break; + case (unsigned)UNX_IFBLK: attribs[0] = 'b'; break; + case (unsigned)UNX_IFCHR: attribs[0] = 'c'; break; + case (unsigned)UNX_IFIFO: attribs[0] = 'p'; break; + case (unsigned)UNX_IFSOCK: attribs[0] = 's'; break; + default: attribs[0] = '?'; break; + } + attribs[1] = (xattr & UNX_IRUSR)? 'r' : '-'; + attribs[4] = (xattr & UNX_IRGRP)? 'r' : '-'; + attribs[7] = (xattr & UNX_IROTH)? 'r' : '-'; + attribs[2] = (xattr & UNX_IWUSR)? 'w' : '-'; + attribs[5] = (xattr & UNX_IWGRP)? 'w' : '-'; + attribs[8] = (xattr & UNX_IWOTH)? 'w' : '-'; + + if (xattr & UNX_IXUSR) + attribs[3] = (xattr & UNX_ISUID)? 's' : 'x'; + else + attribs[3] = (xattr & UNX_ISUID)? 'S' : '-'; /* S==undefined */ + if (xattr & UNX_IXGRP) + attribs[6] = (xattr & UNX_ISGID)? 's' : 'x'; /* == UNX_ENFMT */ + else + /* attribs[6] = (xattr & UNX_ISGID)? 'l' : '-'; real 4.3BSD */ + attribs[6] = (xattr & UNX_ISGID)? 'S' : '-'; /* SunOS 4.1.x */ + if (xattr & UNX_IXOTH) + attribs[9] = (xattr & UNX_ISVTX)? 't' : 'x'; /* "sticky bit" */ + else + attribs[9] = (xattr & UNX_ISVTX)? 'T' : '-'; /* T==undefined */ + + sprintf(&attribs[12], "%u.%u", hostver/10, hostver%10); + break; + + } /* end switch (hostnum: external attributes format) */ + +#ifdef OLD_THEOS_EXTRA + Info(slide, 0, ((char *)slide, "%s %s %s ", attribs, + LoadFarStringSmall(((hostnum == FS_VFAT_ && hostver == 20) ? + os_TheosOld : + os[hostnum])), + FmZofft(G.crec.ucsize, "8", "u"))); +#else + Info(slide, 0, ((char *)slide, "%s %s %s ", attribs, + LoadFarStringSmall(os[hostnum]), + FmZofft(G.crec.ucsize, "8", "u"))); +#endif + Info(slide, 0, ((char *)slide, "%c", + (G.crec.general_purpose_bit_flag & 1)? + ((G.crec.internal_file_attributes & 1)? 'T' : 'B') : /* encrypted */ + ((G.crec.internal_file_attributes & 1)? 't' : 'b'))); /* plaintext */ + k = (G.crec.extra_field_length || + /* a local-only "UX" (old Unix/OS2/NT GMT times "IZUNIX") e.f.? */ + ((G.crec.external_file_attributes & 0x8000) && + (hostnum == UNIX_ || hostnum == FS_HPFS_ || hostnum == FS_NTFS_))); + Info(slide, 0, ((char *)slide, "%c", k? + ((G.crec.general_purpose_bit_flag & 8)? 'X' : 'x') : /* extra field */ + ((G.crec.general_purpose_bit_flag & 8)? 'l' : '-'))); /* no extra field */ + /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ extended local header or not */ + + if (uO.lflag == 4) { + zusz_t csiz = G.crec.csize; + + if (G.crec.general_purpose_bit_flag & 1) + csiz -= 12; /* if encrypted, don't count encryption header */ + Info(slide, 0, ((char *)slide, "%3d%%", + (ratio(G.crec.ucsize,csiz)+5)/10)); + } else if (uO.lflag == 5) + Info(slide, 0, ((char *)slide, " %s", + FmZofft(G.crec.csize, "8", "u"))); + + /* For printing of date & time, a "char d_t_buf[16]" is required. + * To save stack space, we reuse the "char attribs[16]" buffer whose + * content is no longer needed. + */ +# define d_t_buf attribs +#ifdef USE_EF_UT_TIME + z_modtim = 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) + ? &z_utime.mtime : NULL; + TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7.0 or Macintosh */ + d_t_buf[0] = (char)0; /* signal "show local time" */ +#else +# define z_modtim NULL +#endif + Info(slide, 0, ((char *)slide, " %s %s ", methbuf, + zi_time(__G__ &G.crec.last_mod_dos_datetime, z_modtim, d_t_buf))); + fnprint(__G); + +/*--------------------------------------------------------------------------- + Skip the file comment, if any (the filename has already been printed, + above). That finishes up this file entry... + ---------------------------------------------------------------------------*/ + + SKIP_(G.crec.file_comment_length) + + return error_in_archive; + +} /* end function zi_short() */ + + + + + +/**************************************/ +/* Function zi_showMacTypeCreator() */ +/**************************************/ + +static void zi_showMacTypeCreator(__G__ ebfield) + __GDEF + uch *ebfield; +{ + /* not every Type / Creator character is printable */ + if (isprint(native(ebfield[0])) && isprint(native(ebfield[1])) && + isprint(native(ebfield[2])) && isprint(native(ebfield[3])) && + isprint(native(ebfield[4])) && isprint(native(ebfield[5])) && + isprint(native(ebfield[6])) && isprint(native(ebfield[7]))) { + Info(slide, 0, ((char *)slide, LoadFarString(MacOSdata), + native(ebfield[0]), native(ebfield[1]), + native(ebfield[2]), native(ebfield[3]), + native(ebfield[4]), native(ebfield[5]), + native(ebfield[6]), native(ebfield[7]))); + } else { + Info(slide, 0, ((char *)slide, LoadFarString(MacOSdata1), + (((ulg)ebfield[0]) << 24) + + (((ulg)ebfield[1]) << 16) + + (((ulg)ebfield[2]) << 8) + + ((ulg)ebfield[3]), + (((ulg)ebfield[4]) << 24) + + (((ulg)ebfield[5]) << 16) + + (((ulg)ebfield[6]) << 8) + + ((ulg)ebfield[7]))); + } +} /* end function zi_showMacTypeCreator() */ + + + + + +/************************/ +/* Function zi_time() */ +/************************/ + +static char *zi_time(__G__ datetimez, modtimez, d_t_str) + __GDEF + ZCONST ulg *datetimez; + ZCONST time_t *modtimez; + char *d_t_str; +{ + unsigned yr, mo, dy, hh, mm, ss; + char monthbuf[4]; + ZCONST char *monthstr; + static ZCONST char Far month[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; +#ifdef USE_EF_UT_TIME + struct tm *t; +#endif + + + +/*--------------------------------------------------------------------------- + Convert the file-modification date and time info to a string of the form + "1991 Feb 23 17:15:00", "23-Feb-91 17:15" or "19910223.171500", depending + on values of lflag and T_flag. If using Unix-time extra fields, convert + to local time or not, depending on value of first character in d_t_str[]. + ---------------------------------------------------------------------------*/ + +#ifdef USE_EF_UT_TIME + if (modtimez != NULL) { +#ifndef NO_GMTIME + /* check for our secret message from above... */ + t = (d_t_str[0] == (char)1)? gmtime(modtimez) : localtime(modtimez); +#else + t = localtime(modtimez); +#endif + if (uO.lflag > 9 && t == (struct tm *)NULL) + /* time conversion error in verbose listing format, + * return string with '?' instead of data + */ + return (strcpy(d_t_str, LoadFarString(lngYMDHMSTimeError))); + } 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); + + hh = (unsigned)(t->tm_hour); + mm = (unsigned)(t->tm_min); + ss = (unsigned)(t->tm_sec); + } else +#endif /* USE_EF_UT_TIME */ + { + yr = ((unsigned)(*datetimez >> 25) & 0x7f) + 80; + mo = ((unsigned)(*datetimez >> 21) & 0x0f); + dy = ((unsigned)(*datetimez >> 16) & 0x1f); + + hh = (((unsigned)*datetimez >> 11) & 0x1f); + mm = (((unsigned)*datetimez >> 5) & 0x3f); + ss = (((unsigned)*datetimez << 1) & 0x3e); + } + + if (mo == 0 || mo > 12) { + sprintf(monthbuf, LoadFarString(BogusFmt), mo); + monthstr = monthbuf; + } else + monthstr = LoadFarStringSmall(month[mo-1]); + + if (uO.lflag > 9) /* verbose listing format */ + sprintf(d_t_str, LoadFarString(lngYMDHMSTime), yr+1900, monthstr, dy, + hh, mm, ss); + else if (uO.T_flag) + sprintf(d_t_str, LoadFarString(DecimalTime), yr+1900, mo, dy, + hh, mm, ss); + else /* was: if ((uO.lflag >= 3) && (uO.lflag <= 5)) */ + sprintf(d_t_str, LoadFarString(shtYMDHMTime), yr%100, monthstr, dy, + hh, mm); + + return d_t_str; + +} /* end function zi_time() */ + +#endif /* !NO_ZIPINFO */ + diff --git a/third_party/unzip/zipinfo.txt b/third_party/unzip/zipinfo.txt new file mode 100644 index 000000000..ae674b714 --- /dev/null +++ b/third_party/unzip/zipinfo.txt @@ -0,0 +1,436 @@ +ZIPINFO(1L) ZIPINFO(1L) + +NAME + zipinfo - list detailed information about a ZIP archive + +SYNOPSIS + zipinfo [-12smlvhMtTz] file[.zip] [file(s) ...] [-x xfile(s) ...] + + unzip -Z [-12smlvhMtTz] file[.zip] [file(s) ...] [-x xfile(s) ...] + +DESCRIPTION + zipinfo lists technical information about files in a ZIP archive, most + commonly found on MS-DOS systems. Such information includes file + access permissions, encryption status, type of compression, version and + operating system or file system of compressing program, and the like. + The default behavior (with no options) is to list single-line entries + for each file in the archive, with header and trailer lines providing + summary information for the entire archive. The format is a cross + between Unix ``ls -l'' and ``unzip -v'' output. See DETAILED DESCRIP- + TION below. Note that zipinfo is the same program as unzip (under + Unix, a link to it); on some systems, however, zipinfo support may have + been omitted when unzip was compiled. + +ARGUMENTS + file[.zip] + Path of the ZIP archive(s). If the file specification is a + wildcard, each matching file is processed in an order determined + by the operating system (or file system). Only the filename can + be a wildcard; the path itself cannot. Wildcard expressions are + similar to Unix egrep(1) (regular) expressions and may contain: + + * matches a sequence of 0 or more characters + + ? matches exactly 1 character + + [...] matches any single character found inside the brackets; + ranges are specified by a beginning character, a hyphen, + and an ending character. If an exclamation point or a + caret (`!' or `^') follows the left bracket, then the + range of characters within the brackets is complemented + (that is, anything except the characters inside the + brackets is considered a match). To specify a verbatim + left bracket, the three-character sequence ``[[]'' has to + be used. + + (Be sure to quote any character that might otherwise be inter- + preted or modified by the operating system, particularly under + Unix and VMS.) If no matches are found, the specification is + assumed to be a literal filename; and if that also fails, the + suffix .zip is appended. Note that self-extracting ZIP files + are supported, as with any other ZIP archive; just specify the + .exe suffix (if any) explicitly. + + [file(s)] + An optional list of archive members to be processed, separated + by spaces. (VMS versions compiled with VMSCLI defined must + delimit files with commas instead.) Regular expressions (wild- + cards) may be used to match multiple members; see above. Again, + be sure to quote expressions that would otherwise be expanded or + modified by the operating system. + + [-x xfile(s)] + An optional list of archive members to be excluded from process- + ing. + +OPTIONS + -1 list filenames only, one per line. This option excludes all + others; headers, trailers and zipfile comments are never + printed. It is intended for use in Unix shell scripts. + + -2 list filenames only, one per line, but allow headers (-h), + trailers (-t) and zipfile comments (-z), as well. This option + may be useful in cases where the stored filenames are particu- + larly long. + + -s list zipfile info in short Unix ``ls -l'' format. This is the + default behavior; see below. + + -m list zipfile info in medium Unix ``ls -l'' format. Identical to + the -s output, except that the compression factor, expressed as + a percentage, is also listed. + + -l list zipfile info in long Unix ``ls -l'' format. As with -m + except that the compressed size (in bytes) is printed instead of + the compression ratio. + + -v list zipfile information in verbose, multi-page format. + + -h list header line. The archive name, actual size (in bytes) and + total number of files is printed. + + -M pipe all output through an internal pager similar to the Unix + more(1) command. At the end of a screenful of output, zipinfo + pauses with a ``--More--'' prompt; the next screenful may be + viewed by pressing the Enter (Return) key or the space bar. + zipinfo can be terminated by pressing the ``q'' key and, on some + systems, the Enter/Return key. Unlike Unix more(1), there is no + forward-searching or editing capability. Also, zipinfo doesn't + notice if long lines wrap at the edge of the screen, effectively + resulting in the printing of two or more lines and the likeli- + hood that some text will scroll off the top of the screen before + being viewed. On some systems the number of available lines on + the screen is not detected, in which case zipinfo assumes the + height is 24 lines. + + -t list totals for files listed or for all files. The number of + files listed, their uncompressed and compressed total sizes , + and their overall compression factor is printed; or, if only the + totals line is being printed, the values for the entire archive + are given. The compressed total size does not include the 12 + additional header bytes of each encrypted entry. Note that the + total compressed (data) size will never match the actual zipfile + size, since the latter includes all of the internal zipfile + headers in addition to the compressed data. + + -T print the file dates and times in a sortable decimal format + (yymmdd.hhmmss). The default date format is a more standard, + human-readable version with abbreviated month names (see exam- + ples below). + + -U [UNICODE_SUPPORT only] modify or disable UTF-8 handling. When + UNICODE_SUPPORT is available, the option -U forces unzip to + escape all non-ASCII characters from UTF-8 coded filenames as + ``#Uxxxx''. This option is mainly provided for debugging pur- + pose when the fairly new UTF-8 support is suspected to mangle up + extracted filenames. + + The option -UU allows to entirely disable the recognition of + UTF-8 encoded filenames. The handling of filename codings + within unzip falls back to the behaviour of previous versions. + + -z include the archive comment (if any) in the listing. + +DETAILED DESCRIPTION + zipinfo has a number of modes, and its behavior can be rather difficult + to fathom if one isn't familiar with Unix ls(1) (or even if one is). + The default behavior is to list files in the following format: + + -rw-rws--- 1.9 unx 2802 t- defX 11-Aug-91 13:48 perms.2660 + + The last three fields are the modification date and time of the file, + and its name. The case of the filename is respected; thus files that + come from MS-DOS PKZIP are always capitalized. If the file was zipped + with a stored directory name, that is also displayed as part of the + filename. + + The second and third fields indicate that the file was zipped under + Unix with version 1.9 of zip. Since it comes from Unix, the file per- + missions at the beginning of the line are printed in Unix format. The + uncompressed file-size (2802 in this example) is the fourth field. + + The fifth field consists of two characters, either of which may take on + several values. The first character may be either `t' or `b', indicat- + ing that zip believes the file to be text or binary, respectively; but + if the file is encrypted, zipinfo notes this fact by capitalizing the + character (`T' or `B'). The second character may also take on four + values, depending on whether there is an extended local header and/or + an ``extra field'' associated with the file (fully explained in + PKWare's APPNOTE.TXT, but basically analogous to pragmas in ANSI + C--i.e., they provide a standard way to include non-standard informa- + tion in the archive). If neither exists, the character will be a + hyphen (`-'); if there is an extended local header but no extra field, + `l'; if the reverse, `x'; and if both exist, `X'. Thus the file in + this example is (probably) a text file, is not encrypted, and has nei- + ther an extra field nor an extended local header associated with it. + The example below, on the other hand, is an encrypted binary file with + an extra field: + + RWD,R,R 0.9 vms 168 Bx shrk 9-Aug-91 19:15 perms.0644 + + Extra fields are used for various purposes (see discussion of the -v + option below) including the storage of VMS file attributes, which is + presumably the case here. Note that the file attributes are listed in + VMS format. Some other possibilities for the host operating system + (which is actually a misnomer--host file system is more correct) + include OS/2 or NT with High Performance File System (HPFS), MS-DOS, + OS/2 or NT with File Allocation Table (FAT) file system, and Macintosh. + These are denoted as follows: + + -rw-a-- 1.0 hpf 5358 Tl i4:3 4-Dec-91 11:33 longfilename.hpfs + -r--ahs 1.1 fat 4096 b- i4:2 14-Jul-91 12:58 EA DATA. SF + --w------- 1.0 mac 17357 bx i8:2 4-May-92 04:02 unzip.macr + + File attributes in the first two cases are indicated in a Unix-like + format, where the seven subfields indicate whether the file: (1) is a + directory, (2) is readable (always true), (3) is writable, (4) is exe- + cutable (guessed on the basis of the extension--.exe, .com, .bat, .cmd + and .btm files are assumed to be so), (5) has its archive bit set, (6) + is hidden, and (7) is a system file. Interpretation of Macintosh file + attributes is unreliable because some Macintosh archivers don't store + any attributes in the archive. + + Finally, the sixth field indicates the compression method and possible + sub-method used. There are six methods known at present: storing (no + compression), reducing, shrinking, imploding, tokenizing (never pub- + licly released), and deflating. In addition, there are four levels of + reducing (1 through 4); four types of imploding (4K or 8K sliding dic- + tionary, and 2 or 3 Shannon-Fano trees); and four levels of deflating + (superfast, fast, normal, maximum compression). zipinfo represents + these methods and their sub-methods as follows: stor; re:1, re:2, + etc.; shrk; i4:2, i8:3, etc.; tokn; and defS, defF, defN, and defX. + + The medium and long listings are almost identical to the short format + except that they add information on the file's compression. The medium + format lists the file's compression factor as a percentage indicating + the amount of space that has been ``removed'': + + -rw-rws--- 1.5 unx 2802 t- 81% defX 11-Aug-91 13:48 perms.2660 + + In this example, the file has been compressed by more than a factor of + five; the compressed data are only 19% of the original size. The long + format gives the compressed file's size in bytes, instead: + + -rw-rws--- 1.5 unx 2802 t- 538 defX 11-Aug-91 13:48 perms.2660 + + In contrast to the unzip listings, the compressed size figures in this + listing format denote the complete size of compressed data, including + the 12 extra header bytes in case of encrypted entries. + + Adding the -T option changes the file date and time to decimal format: + + -rw-rws--- 1.5 unx 2802 t- 538 defX 910811.134804 perms.2660 + + Note that because of limitations in the MS-DOS format used to store + file times, the seconds field is always rounded to the nearest even + second. For Unix files this is expected to change in the next major + releases of zip(1L) and unzip. + + In addition to individual file information, a default zipfile listing + also includes header and trailer lines: + + Archive: OS2.zip 5453 bytes 5 files + ,,rw, 1.0 hpf 730 b- i4:3 26-Jun-92 23:40 Contents + ,,rw, 1.0 hpf 3710 b- i4:3 26-Jun-92 23:33 makefile.os2 + ,,rw, 1.0 hpf 8753 b- i8:3 26-Jun-92 15:29 os2unzip.c + ,,rw, 1.0 hpf 98 b- stor 21-Aug-91 15:34 unzip.def + ,,rw, 1.0 hpf 95 b- stor 21-Aug-91 17:51 zipinfo.def + 5 files, 13386 bytes uncompressed, 4951 bytes compressed: 63.0% + + The header line gives the name of the archive, its total size, and the + total number of files; the trailer gives the number of files listed, + their total uncompressed size, and their total compressed size (not + including any of zip's internal overhead). If, however, one or more + file(s) are provided, the header and trailer lines are not listed. + This behavior is also similar to that of Unix's ``ls -l''; it may be + overridden by specifying the -h and -t options explicitly. In such a + case the listing format must also be specified explicitly, since -h or + -t (or both) in the absence of other options implies that ONLY the + header or trailer line (or both) is listed. See the EXAMPLES section + below for a semi-intelligible translation of this nonsense. + + The verbose listing is mostly self-explanatory. It also lists file + comments and the zipfile comment, if any, and the type and number of + bytes in any stored extra fields. Currently known types of extra + fields include PKWARE's authentication (``AV'') info; OS/2 extended + attributes; VMS filesystem info, both PKWARE and Info-ZIP versions; + Macintosh resource forks; Acorn/Archimedes SparkFS info; and so on. + (Note that in the case of OS/2 extended attributes--perhaps the most + common use of zipfile extra fields--the size of the stored EAs as + reported by zipinfo may not match the number given by OS/2's dir com- + mand: OS/2 always reports the number of bytes required in 16-bit for- + mat, whereas zipinfo always reports the 32-bit storage.) + + Again, the compressed size figures of the individual entries include + the 12 extra header bytes for encrypted entries. In contrast, the + archive total compressed size and the average compression ratio shown + in the summary bottom line are calculated without the extra 12 header + bytes of encrypted entries. + +ENVIRONMENT OPTIONS + Modifying zipinfo's default behavior via options placed in an environ- + ment variable can be a bit complicated to explain, due to zipinfo's + attempts to handle various defaults in an intuitive, yet Unix-like, + manner. (Try not to laugh.) Nevertheless, there is some underlying + logic. In brief, there are three ``priority levels'' of options: the + default options; environment options, which can override or add to the + defaults; and explicit options given by the user, which can override or + add to either of the above. + + The default listing format, as noted above, corresponds roughly to the + "zipinfo -hst" command (except when individual zipfile members are + specified). A user who prefers the long-listing format (-l) can make + use of the zipinfo's environment variable to change this default: + + Unix Bourne shell: + ZIPINFO=-l; export ZIPINFO + + Unix C shell: + setenv ZIPINFO -l + + OS/2 or MS-DOS: + set ZIPINFO=-l + + VMS (quotes for lowercase): + define ZIPINFO_OPTS "-l" + + If, in addition, the user dislikes the trailer line, zipinfo's concept + of ``negative options'' may be used to override the default inclusion + of the line. This is accomplished by preceding the undesired option + with one or more minuses: e.g., ``-l-t'' or ``--tl'', in this example. + The first hyphen is the regular switch character, but the one before + the `t' is a minus sign. The dual use of hyphens may seem a little + awkward, but it's reasonably intuitive nonetheless: simply ignore the + first hyphen and go from there. It is also consistent with the behav- + ior of the Unix command nice(1). + + As suggested above, the default variable names are ZIPINFO_OPTS for VMS + (where the symbol used to install zipinfo as a foreign command would + otherwise be confused with the environment variable), and ZIPINFO for + all other operating systems. For compatibility with zip(1L), ZIPIN- + FOOPT is also accepted (don't ask). If both ZIPINFO and ZIPINFOOPT are + defined, however, ZIPINFO takes precedence. unzip's diagnostic option + (-v with no zipfile name) can be used to check the values of all four + possible unzip and zipinfo environment variables. + +EXAMPLES + To get a basic, short-format listing of the complete contents of a ZIP + archive storage.zip, with both header and totals lines, use only the + archive name as an argument to zipinfo: + + zipinfo storage + + To produce a basic, long-format listing (not verbose), including header + and totals lines, use -l: + + zipinfo -l storage + + To list the complete contents of the archive without header and totals + lines, either negate the -h and -t options or else specify the contents + explicitly: + + zipinfo --h-t storage + zipinfo storage \* + + (where the backslash is required only if the shell would otherwise + expand the `*' wildcard, as in Unix when globbing is turned on--double + quotes around the asterisk would have worked as well). To turn off the + totals line by default, use the environment variable (C shell is + assumed here): + + setenv ZIPINFO --t + zipinfo storage + + To get the full, short-format listing of the first example again, given + that the environment variable is set as in the previous example, it is + necessary to specify the -s option explicitly, since the -t option by + itself implies that ONLY the footer line is to be printed: + + setenv ZIPINFO --t + zipinfo -t storage [only totals line] + zipinfo -st storage [full listing] + + The -s option, like -m and -l, includes headers and footers by default, + unless otherwise specified. Since the environment variable specified + no footers and that has a higher precedence than the default behavior + of -s, an explicit -t option was necessary to produce the full listing. + Nothing was indicated about the header, however, so the -s option was + sufficient. Note that both the -h and -t options, when used by them- + selves or with each other, override any default listing of member + files; only the header and/or footer are printed. This behavior is + useful when zipinfo is used with a wildcard zipfile specification; the + contents of all zipfiles are then summarized with a single command. + + To list information on a single file within the archive, in medium for- + mat, specify the filename explicitly: + + zipinfo -m storage unshrink.c + + The specification of any member file, as in this example, will override + the default header and totals lines; only the single line of informa- + tion about the requested file will be printed. This is intuitively + what one would expect when requesting information about a single file. + For multiple files, it is often useful to know the total compressed and + uncompressed size; in such cases -t may be specified explicitly: + + zipinfo -mt storage "*.[ch]" Mak\* + + To get maximal information about the ZIP archive, use the verbose + option. It is usually wise to pipe the output into a filter such as + Unix more(1) if the operating system allows it: + + zipinfo -v storage | more + + Finally, to see the most recently modified files in the archive, use + the -T option in conjunction with an external sorting utility such as + Unix sort(1) (and sed(1) as well, in this example): + + zipinfo -T storage | sort -nr -k 7 | sed 15q + + The -nr option to sort(1) tells it to sort numerically in reverse order + rather than in textual order, and the -k 7 option tells it to sort on + the seventh field. This assumes the default short-listing format; if + -m or -l is used, the proper sort(1) option would be -k 8. Older ver- + sions of sort(1) do not support the -k option, but you can use the + traditional + option instead, e.g., +6 instead of -k 7. The sed(1) + command filters out all but the first 15 lines of the listing. Future + releases of zipinfo may incorporate date/time and filename sorting as + built-in options. + +TIPS + The author finds it convenient to define an alias ii for zipinfo on + systems that allow aliases (or, on other systems, copy/rename the exe- + cutable, create a link or create a command file with the name ii). The + ii usage parallels the common ll alias for long listings in Unix, and + the similarity between the outputs of the two commands was intentional. + +BUGS + As with unzip, zipinfo's -M (``more'') option is overly simplistic in + its handling of screen output; as noted above, it fails to detect the + wrapping of long lines and may thereby cause lines at the top of the + screen to be scrolled off before being read. zipinfo should detect and + treat each occurrence of line-wrap as one additional line printed. + This requires knowledge of the screen's width as well as its height. + In addition, zipinfo should detect the true screen geometry on all sys- + tems. + + zipinfo's listing-format behavior is unnecessarily complex and should + be simplified. (This is not to say that it will be.) + +SEE ALSO + ls(1), funzip(1L), unzip(1L), unzipsfx(1L), zip(1L), zipcloak(1L), zip- + note(1L), zipsplit(1L) + +URL + The Info-ZIP home page is currently at + http://www.info-zip.org/pub/infozip/ + or + ftp://ftp.info-zip.org/pub/infozip/ . + +AUTHOR + Greg ``Cave Newt'' Roelofs. ZipInfo contains pattern-matching code by + Mark Adler and fixes/improvements by many others. Please refer to the + CONTRIBS file in the UnZip source distribution for a more complete + list. + +Info-ZIP 20 April 2009 (v3.0) ZIPINFO(1L) diff --git a/third_party/zip/zip.mk b/third_party/zip/zip.mk index c89f659db..74cfffd5e 100644 --- a/third_party/zip/zip.mk +++ b/third_party/zip/zip.mk @@ -5,7 +5,7 @@ PKGS += THIRD_PARTY_ZIP THIRD_PARTY_ZIP_FILES := $(wildcard third_party/zip/*) THIRD_PARTY_ZIP_SRCS = $(filter %.c,$(THIRD_PARTY_ZIP_FILES)) -THIRD_PARTY_ZIP_HDRS = $(filter %.h,$(THIRD_PARTY_ZIP_FILES)) +#THIRD_PARTY_ZIP_HDRS = $(filter %.h,$(THIRD_PARTY_ZIP_FILES)) THIRD_PARTY_ZIP_INCS = $(filter %.inc,$(THIRD_PARTY_ZIP_FILES)) THIRD_PARTY_ZIP_COMS = \ diff --git a/tool/viz/basicidea.c b/tool/viz/basicidea.c index 754f1b63b..3e37ec20e 100644 --- a/tool/viz/basicidea.c +++ b/tool/viz/basicidea.c @@ -22,6 +22,7 @@ #include "libc/calls/struct/stat.h" #include "libc/fmt/fmt.h" #include "libc/log/log.h" +#include "libc/macros.internal.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/exit.h" #include "libc/sysv/consts/fileno.h"