summaryrefslogtreecommitdiff
path: root/win32/win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'win32/win32.c')
-rw-r--r--win32/win32.c1488
1 files changed, 1488 insertions, 0 deletions
diff --git a/win32/win32.c b/win32/win32.c
new file mode 100644
index 0000000..5798053
--- /dev/null
+++ b/win32/win32.c
@@ -0,0 +1,1488 @@
+/*
+ win32/win32.c - Zip 3
+
+ Copyright (c) 1990-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
+*/
+
+/*
+ * WIN32 specific functions for ZIP.
+ *
+ * The WIN32 version of ZIP heavily relies on the MSDOS and OS2 versions,
+ * since we have to do similar things to switch between NTFS, HPFS and FAT.
+ */
+
+
+#include "../zip.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+/* for LARGE_FILE_SUPPORT but may not be needed */
+#include <io.h>
+
+#ifdef __RSXNT__
+# include <alloca.h>
+# include "../win32/rsxntwin.h"
+#endif
+#include "../win32/win32zip.h"
+
+#define A_RONLY 0x01
+#define A_HIDDEN 0x02
+#define A_SYSTEM 0x04
+#define A_LABEL 0x08
+#define A_DIR 0x10
+#define A_ARCHIVE 0x20
+
+
+#define EAID 0x0009
+
+#if (defined(__MINGW32__) && !defined(USE_MINGW_GLOBBING))
+ int _CRT_glob = 0; /* suppress command line globbing by C RTL */
+#endif
+
+#ifndef UTIL
+
+extern int noisy;
+
+#ifdef NT_TZBUG_WORKAROUND
+local int FSusesLocalTime(const char *path);
+#ifdef UNICODE_SUPPORt
+local int FSusesLocalTimeW(const wchar_t *path);
+#endif
+#endif
+#if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND))
+local int FileTime2utime(FILETIME *pft, time_t *ut);
+#endif
+#if (defined(NT_TZBUG_WORKAROUND) && defined(W32_STAT_BANDAID))
+local int VFatFileTime2utime(const FILETIME *pft, time_t *ut);
+#endif
+
+
+/* FAT / HPFS detection */
+
+int IsFileSystemOldFAT(char *dir)
+{
+ static char lastDrive = '\0'; /* cached drive of last GetVolumeInformation call */
+ static int lastDriveOldFAT = 0; /* cached OldFAT value of last GetVolumeInformation call */
+ char root[4];
+ DWORD vfnsize;
+ DWORD vfsflags;
+
+ /*
+ * We separate FAT and HPFS+other file systems here.
+ * I consider other systems to be similar to HPFS/NTFS, i.e.
+ * support for long file names and being case sensitive to some extent.
+ */
+
+ strncpy(root, dir, 3);
+ if ( isalpha((uch)root[0]) && (root[1] == ':') ) {
+ root[0] = to_up(dir[0]);
+ root[2] = '\\';
+ root[3] = 0;
+ }
+ else {
+ root[0] = '\\';
+ root[1] = 0;
+ }
+ if (lastDrive == root[0]) {
+ return lastDriveOldFAT;
+ }
+
+ if ( !GetVolumeInformation(root, NULL, 0,
+ NULL, &vfnsize, &vfsflags,
+ NULL, 0)) {
+ fprintf(mesg, "zip diagnostic: GetVolumeInformation failed\n");
+ return(FALSE);
+ }
+
+ lastDrive = root[0];
+ lastDriveOldFAT = vfnsize <= 12;
+
+ return lastDriveOldFAT;
+}
+
+#ifdef UNICODE_SUPPORT
+int IsFileSystemOldFATW(wchar_t *dir)
+{
+ static wchar_t lastDrive = (wchar_t)'\0'; /* cached drive of last GetVolumeInformation call */
+ static int lastDriveOldFAT = 0; /* cached OldFAT value of last GetVolumeInformation call */
+ wchar_t root[4];
+ DWORD vfnsize;
+ DWORD vfsflags;
+
+ /*
+ * We separate FAT and HPFS+other file systems here.
+ * I consider other systems to be similar to HPFS/NTFS, i.e.
+ * support for long file names and being case sensitive to some extent.
+ */
+
+ wcsncpy(root, dir, 3);
+ if ( iswalpha(root[0]) && (root[1] == (wchar_t)':') ) {
+ root[0] = towupper(dir[0]);
+ root[2] = (wchar_t)'\\';
+ root[3] = 0;
+ }
+ else {
+ root[0] = (wchar_t)'\\';
+ root[1] = 0;
+ }
+ if (lastDrive == root[0]) {
+ return lastDriveOldFAT;
+ }
+
+ if ( !GetVolumeInformationW(root, NULL, 0,
+ NULL, &vfnsize, &vfsflags,
+ NULL, 0)) {
+ fprintf(mesg, "zip diagnostic: GetVolumeInformation failed\n");
+ return(FALSE);
+ }
+
+ lastDrive = root[0];
+ lastDriveOldFAT = vfnsize <= 12;
+
+ return lastDriveOldFAT;
+}
+#endif
+
+
+/* access mode bits and time stamp */
+
+int GetFileMode(char *name)
+{
+DWORD dwAttr;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_name = (char *)alloca(strlen(name) + 1);
+
+ OemToAnsi(name, ansi_name);
+ name = ansi_name;
+#endif
+
+ dwAttr = GetFileAttributes(name);
+ if ( dwAttr == 0xFFFFFFFF ) {
+ zipwarn("reading file attributes failed: ", name);
+ /*
+ fprintf(mesg, "zip diagnostic: GetFileAttributes failed");
+ fflush();
+ */
+ return(0x20); /* the most likely, though why the error? security? */
+ }
+ return(
+ (dwAttr&FILE_ATTRIBUTE_READONLY ? A_RONLY :0)
+ | (dwAttr&FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN :0)
+ | (dwAttr&FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM :0)
+ | (dwAttr&FILE_ATTRIBUTE_DIRECTORY ? A_DIR :0)
+ | (dwAttr&FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE :0));
+}
+
+#ifdef UNICODE_SUPPORT
+int GetFileModeW(wchar_t *namew)
+{
+DWORD dwAttr;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ wchar_t *ansi_namew = (wchar_t *)alloca((wcslen(namew) + 1) * sizeof(wchar_t));
+
+ CharToAnsiW(namew, ansi_namew);
+ namew = ansi_namew;
+#endif
+
+ dwAttr = GetFileAttributesW(namew);
+ if ( dwAttr == 0xFFFFFFFF ) {
+ char *name = wchar_to_local_string(namew);
+ zipwarn("reading file attributes failed: ", name);
+ free(name);
+ return(0x20); /* the most likely, though why the error? security? */
+ }
+ return(
+ (dwAttr&FILE_ATTRIBUTE_READONLY ? A_RONLY :0)
+ | (dwAttr&FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN :0)
+ | (dwAttr&FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM :0)
+ | (dwAttr&FILE_ATTRIBUTE_DIRECTORY ? A_DIR :0)
+ | (dwAttr&FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE :0));
+}
+#endif
+
+
+int ClearArchiveBitW(wchar_t *namew)
+{
+DWORD dwAttr;
+ dwAttr = GetFileAttributesW(namew);
+ if ( dwAttr == 0xFFFFFFFF ) {
+ fprintf(mesg, "zip diagnostic: GetFileAttributes failed\n");
+ return(0);
+ }
+
+ if (!SetFileAttributesW(namew, (DWORD)(dwAttr & ~FILE_ATTRIBUTE_ARCHIVE))) {
+ fprintf(mesg, "zip diagnostic: SetFileAttributes failed\n");
+ perror("SetFileAttributes");
+ return(0);
+ }
+ return(1);
+}
+
+int ClearArchiveBit(char *name)
+{
+DWORD dwAttr;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_name = (char *)alloca(strlen(name) + 1);
+
+ OemToAnsi(name, ansi_name);
+ name = ansi_name;
+#endif
+
+ dwAttr = GetFileAttributes(name);
+ if ( dwAttr == 0xFFFFFFFF ) {
+ fprintf(mesg, "zip diagnostic: GetFileAttributes failed\n");
+ return(0);
+ }
+
+ if (!SetFileAttributes(name, (DWORD)(dwAttr & ~FILE_ATTRIBUTE_ARCHIVE))) {
+ fprintf(mesg, "zip diagnostic: SetFileAttributes failed\n");
+ perror("SetFileAttributes");
+ return(0);
+ }
+ return(1);
+}
+
+
+#ifdef NT_TZBUG_WORKAROUND
+local int FSusesLocalTime(const char *path)
+{
+ char *tmp0;
+ char rootPathName[4];
+ char tmp1[MAX_PATH], tmp2[MAX_PATH];
+ DWORD volSerNo, maxCompLen, fileSysFlags;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(path) + 1);
+
+ OemToAnsi(path, ansi_path);
+ path = ansi_path;
+#endif
+
+ if (isalpha((uch)path[0]) && (path[1] == ':'))
+ tmp0 = (char *)path;
+ else
+ {
+ GetFullPathName(path, MAX_PATH, tmp1, &tmp0);
+ tmp0 = &tmp1[0];
+ }
+ strncpy(rootPathName, tmp0, 3); /* Build the root path name, */
+ rootPathName[3] = '\0'; /* e.g. "A:/" */
+
+ GetVolumeInformation((LPCTSTR)rootPathName, (LPTSTR)tmp1, (DWORD)MAX_PATH,
+ &volSerNo, &maxCompLen, &fileSysFlags,
+ (LPTSTR)tmp2, (DWORD)MAX_PATH);
+
+ /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
+ * local time!
+ */
+ return !strncmp(strupr(tmp2), "FAT", 3) ||
+ !strncmp(tmp2, "VFAT", 4) ||
+ !strncmp(tmp2, "HPFS", 4);
+
+} /* end function FSusesLocalTime() */
+
+# ifdef UNICODE_SUPPORT
+local int FSusesLocalTimeW(const wchar_t *path)
+{
+ wchar_t *tmp0;
+ wchar_t rootPathName[4];
+ wchar_t tmp1[MAX_PATH], tmp2[MAX_PATH];
+ DWORD volSerNo, maxCompLen, fileSysFlags;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ wchar_t *ansi_path = (wchar_t *)alloca((wcslen(path) + 1) * sizeof(wchar_t));
+
+ CharToAnsiW(path, ansi_path);
+ path = ansi_path;
+#endif
+
+ if (iswalpha(path[0]) && (path[1] == (wchar_t)':'))
+ tmp0 = (wchar_t *)path;
+ else
+ {
+ GetFullPathNameW(path, MAX_PATH, tmp1, &tmp0);
+ tmp0 = &tmp1[0];
+ }
+ wcsncpy(rootPathName, tmp0, 3); /* Build the root path name, */
+ rootPathName[3] = (wchar_t)'\0'; /* e.g. "A:/" */
+
+ GetVolumeInformationW(rootPathName, tmp1, (DWORD)MAX_PATH,
+ &volSerNo, &maxCompLen, &fileSysFlags,
+ tmp2, (DWORD)MAX_PATH);
+
+ /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
+ * local time!
+ */
+ return !wcsncmp(_wcsupr(tmp2), L"FAT", 3) ||
+ !wcsncmp(tmp2, L"VFAT", 4) ||
+ !wcsncmp(tmp2, L"HPFS", 4);
+
+} /* end function FSusesLocalTimeW() */
+# endif
+
+#endif /* NT_TZBUG_WORKAROUND */
+
+
+#if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND))
+
+#if (defined(__GNUC__) || defined(ULONG_LONG_MAX))
+ typedef long long LLONG64;
+ typedef unsigned long long ULLNG64;
+#elif (defined(__WATCOMC__) && (__WATCOMC__ >= 1100))
+ typedef __int64 LLONG64;
+ typedef unsigned __int64 ULLNG64;
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1100))
+ typedef __int64 LLONG64;
+ typedef unsigned __int64 ULLNG64;
+#elif (defined(__IBMC__) && (__IBMC__ >= 350))
+ typedef __int64 LLONG64;
+ typedef unsigned __int64 ULLNG64;
+#else
+# define NO_INT64
+#endif
+
+# define UNIX_TIME_ZERO_HI 0x019DB1DEUL
+# define UNIX_TIME_ZERO_LO 0xD53E8000UL
+# define NT_QUANTA_PER_UNIX 10000000L
+# define FTQUANTA_PER_UT_L (NT_QUANTA_PER_UNIX & 0xFFFF)
+# define FTQUANTA_PER_UT_H (NT_QUANTA_PER_UNIX >> 16)
+# define UNIX_TIME_UMAX_HI 0x0236485EUL
+# define UNIX_TIME_UMAX_LO 0xD4A5E980UL
+# define UNIX_TIME_SMIN_HI 0x0151669EUL
+# define UNIX_TIME_SMIN_LO 0xD53E8000UL
+# define UNIX_TIME_SMAX_HI 0x01E9FD1EUL
+# define UNIX_TIME_SMAX_LO 0xD4A5E980UL
+
+local int FileTime2utime(FILETIME *pft, time_t *ut)
+{
+#ifndef NO_INT64
+ ULLNG64 NTtime;
+
+ NTtime = ((ULLNG64)pft->dwLowDateTime +
+ ((ULLNG64)pft->dwHighDateTime << 32));
+
+ /* underflow and overflow handling */
+#ifdef CHECK_UTIME_SIGNED_UNSIGNED
+ if ((time_t)0x80000000L < (time_t)0L)
+ {
+ if (NTtime < ((ULLNG64)UNIX_TIME_SMIN_LO +
+ ((ULLNG64)UNIX_TIME_SMIN_HI << 32))) {
+ *ut = (time_t)LONG_MIN;
+ return FALSE;
+ }
+ if (NTtime > ((ULLNG64)UNIX_TIME_SMAX_LO +
+ ((ULLNG64)UNIX_TIME_SMAX_HI << 32))) {
+ *ut = (time_t)LONG_MAX;
+ return FALSE;
+ }
+ }
+ else
+#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
+ {
+ if (NTtime < ((ULLNG64)UNIX_TIME_ZERO_LO +
+ ((ULLNG64)UNIX_TIME_ZERO_HI << 32))) {
+ *ut = (time_t)0;
+ return FALSE;
+ }
+ if (NTtime > ((ULLNG64)UNIX_TIME_UMAX_LO +
+ ((ULLNG64)UNIX_TIME_UMAX_HI << 32))) {
+ *ut = (time_t)ULONG_MAX;
+ return FALSE;
+ }
+ }
+
+ NTtime -= ((ULLNG64)UNIX_TIME_ZERO_LO +
+ ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
+ *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX);
+ return TRUE;
+#else /* NO_INT64 (64-bit integer arithmetics may not be supported) */
+ /* 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 1970 to `y' (not including `y' itself) */
+# define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400)
+ /* daycount at the end of month[m-1] */
+ static ZCONST ush ydays[] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
+
+ time_t days;
+ SYSTEMTIME w32tm;
+
+ /* underflow and overflow handling */
+#ifdef CHECK_UTIME_SIGNED_UNSIGNED
+ if ((time_t)0x80000000L < (time_t)0L)
+ {
+ if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
+ (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
+ *ut = (time_t)LONG_MIN;
+ return FALSE;
+ if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
+ (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
+ *ut = (time_t)LONG_MAX;
+ return FALSE;
+ }
+ }
+ else
+#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
+ {
+ if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
+ (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
+ *ut = (time_t)0;
+ return FALSE;
+ }
+ if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
+ (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
+ *ut = (time_t)ULONG_MAX;
+ return FALSE;
+ }
+ }
+
+ FileTimeToSystemTime(pft, &w32tm);
+
+ /* set `days' to the number of days into the year */
+ days = w32tm.wDay - 1 + ydays[w32tm.wMonth-1] +
+ (w32tm.wMonth > 2 && leap (w32tm.wYear));
+
+ /* now set `days' to the number of days since 1 Jan 1970 */
+ days += 365 * (time_t)(w32tm.wYear - 1970) +
+ (time_t)(nleap(w32tm.wYear));
+
+ *ut = (time_t)(86400L * days + 3600L * (time_t)w32tm.wHour +
+ (time_t)(60 * w32tm.wMinute + w32tm.wSecond));
+ return TRUE;
+#endif /* ?NO_INT64 */
+} /* end function FileTime2utime() */
+#endif /* USE_EF_UT_TIME || NT_TZBUG_WORKAROUND */
+
+
+#if (defined(NT_TZBUG_WORKAROUND) && defined(W32_STAT_BANDAID))
+
+local int VFatFileTime2utime(const FILETIME *pft, time_t *ut)
+{
+ FILETIME lft;
+ SYSTEMTIME w32tm;
+ struct tm ltm;
+
+ FileTimeToLocalFileTime(pft, &lft);
+ FileTimeToSystemTime(&lft, &w32tm);
+ /* underflow and overflow handling */
+ /* TODO: The range checks are not accurate, the actual limits may
+ * be off by one daylight-saving-time shift (typically 1 hour),
+ * depending on the current state of "is_dst".
+ */
+#ifdef CHECK_UTIME_SIGNED_UNSIGNED
+ if ((time_t)0x80000000L < (time_t)0L)
+ {
+ if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
+ (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
+ *ut = (time_t)LONG_MIN;
+ return FALSE;
+ if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
+ (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
+ *ut = (time_t)LONG_MAX;
+ return FALSE;
+ }
+ }
+ else
+#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
+ {
+ if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
+ (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
+ *ut = (time_t)0;
+ return FALSE;
+ }
+ if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
+ (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
+ *ut = (time_t)ULONG_MAX;
+ return FALSE;
+ }
+ }
+ ltm.tm_year = w32tm.wYear - 1900;
+ ltm.tm_mon = w32tm.wMonth - 1;
+ ltm.tm_mday = w32tm.wDay;
+ ltm.tm_hour = w32tm.wHour;
+ ltm.tm_min = w32tm.wMinute;
+ ltm.tm_sec = w32tm.wSecond;
+ ltm.tm_isdst = -1; /* let mktime determine if DST is in effect */
+ *ut = mktime(&ltm);
+
+ /* a cheap error check: mktime returns "(time_t)-1L" on conversion errors.
+ * Normally, we would have to apply a consistency check because "-1"
+ * could also be a valid time. But, it is quite unlikely to read back odd
+ * time numbers from file systems that store time stamps in DOS format.
+ * (The only known exception is creation time on VFAT partitions.)
+ */
+ return (*ut != (time_t)-1L);
+
+} /* end function VFatFileTime2utime() */
+#endif /* NT_TZBUG_WORKAROUND && W32_STAT_BANDAID */
+
+
+#if 0 /* Currently, this is not used at all */
+
+long GetTheFileTime(char *name, iztimes *z_ut)
+{
+HANDLE h;
+FILETIME Modft, Accft, Creft, lft;
+WORD dh, dl;
+#ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_name = (char *)alloca(strlen(name) + 1);
+
+ OemToAnsi(name, ansi_name);
+ name = ansi_name;
+#endif
+
+ h = CreateFile(name, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if ( h != INVALID_HANDLE_VALUE ) {
+ BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+ CloseHandle(h);
+#ifdef USE_EF_UT_TIME
+ if (ftOK && (z_ut != NULL)) {
+ FileTime2utime(&Modft, &(z_ut->mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ FileTime2utime(&Accft, &(z_ut->atime));
+ else
+ z_ut->atime = z_ut->mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ FileTime2utime(&Creft, &(z_ut->ctime));
+ else
+ z_ut->ctime = z_ut->mtime;
+ }
+#endif
+ FileTimeToLocalFileTime(&ft, &lft);
+ FileTimeToDosDateTime(&lft, &dh, &dl);
+ return(dh<<16) | dl;
+ }
+ else
+ return 0L;
+}
+
+#endif /* never */
+
+
+void ChangeNameForFAT(char *name)
+{
+ char *src, *dst, *next, *ptr, *dot, *start;
+ static char invalid[] = ":;,=+\"[]<>| \t";
+
+ if ( isalpha((uch)name[0]) && (name[1] == ':') )
+ start = name + 2;
+ else
+ start = name;
+
+ src = dst = start;
+ if ( (*src == '/') || (*src == '\\') )
+ src++, dst++;
+
+ while ( *src )
+ {
+ for ( next = src; *next && (*next != '/') && (*next != '\\'); next++ );
+
+ for ( ptr = src, dot = NULL; ptr < next; ptr++ )
+ if ( *ptr == '.' )
+ {
+ dot = ptr; /* remember last dot */
+ *ptr = '_';
+ }
+
+ if ( dot == NULL )
+ for ( ptr = src; ptr < next; ptr++ )
+ if ( *ptr == '_' )
+ dot = ptr; /* remember last _ as if it were a dot */
+
+ if ( dot && (dot > src) &&
+ ((next - dot <= 4) ||
+ ((next - src > 8) && (dot - src > 3))) )
+ {
+ if ( dot )
+ *dot = '.';
+
+ for ( ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++ )
+ *dst++ = *ptr;
+
+ for ( ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++ )
+ *dst++ = *ptr;
+ }
+ else
+ {
+ if ( dot && (next - src == 1) )
+ *dot = '.'; /* special case: "." as a path component */
+
+ for ( ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++ )
+ *dst++ = *ptr;
+ }
+
+ *dst++ = *next; /* either '/' or 0 */
+
+ if ( *next )
+ {
+ src = next + 1;
+
+ if ( *src == 0 ) /* handle trailing '/' on dirs ! */
+ *dst = 0;
+ }
+ else
+ break;
+ }
+
+ for ( src = start; *src != 0; ++src )
+ if ( (strchr(invalid, *src) != NULL) || (*src == ' ') )
+ *src = '_';
+}
+
+char *GetLongPathEA(char *name)
+{
+ return(NULL); /* volunteers ? */
+}
+
+#ifdef UNICODE_SUPPORT
+wchar_t *GetLongPathEAW(wchar_t *name)
+{
+ return(NULL); /* volunteers ? */
+}
+#endif
+
+
+int IsFileNameValid(x)
+char *x;
+{
+ WIN32_FIND_DATA fd;
+ HANDLE h;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_name = (char *)alloca(strlen(x) + 1);
+
+ OemToAnsi(x, ansi_name);
+ x = ansi_name;
+#endif
+
+ if ((h = FindFirstFile(x, &fd)) == INVALID_HANDLE_VALUE)
+ return FALSE;
+ FindClose(h);
+ return TRUE;
+}
+
+char *getVolumeLabel(drive, vtime, vmode, vutim)
+ int drive; /* drive name: 'A' .. 'Z' or '\0' for current drive */
+ ulg *vtime; /* volume label creation time (DOS format) */
+ ulg *vmode; /* volume label file mode */
+ time_t *vutim;/* volume label creationtime (UNIX format) */
+
+/* If a volume label exists for the given drive, return its name and
+ pretend to set its time and mode. The returned name is static data. */
+{
+ char rootpath[4];
+ static char vol[14];
+ DWORD fnlen, flags;
+
+ *vmode = A_ARCHIVE | A_LABEL; /* this is what msdos returns */
+ *vtime = dostime(1980, 1, 1, 0, 0, 0); /* no true date info available */
+ *vutim = dos2unixtime(*vtime);
+ strcpy(rootpath, "x:\\");
+ rootpath[0] = (char)drive;
+ if (GetVolumeInformation(drive ? rootpath : NULL, vol, 13, NULL,
+ &fnlen, &flags, NULL, 0))
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ return (AnsiToOem(vol, vol), vol);
+#else
+ return vol;
+#endif
+ else
+ return NULL;
+}
+
+#endif /* !UTIL */
+
+
+
+int ZipIsWinNT(void) /* returns TRUE if real NT, FALSE if Win95 or Win32s */
+{
+ static DWORD g_PlatformId = 0xFFFFFFFF; /* saved platform indicator */
+
+ if (g_PlatformId == 0xFFFFFFFF) {
+ /* note: GetVersionEx() doesn't exist on WinNT 3.1 */
+ if (GetVersion() < 0x80000000)
+ g_PlatformId = TRUE;
+ else
+ g_PlatformId = FALSE;
+ }
+ return (int)g_PlatformId;
+}
+
+
+#ifndef UTIL
+#ifdef __WATCOMC__
+# include <io.h>
+# define _get_osfhandle _os_handle
+/* gaah -- Watcom's docs claim that _get_osfhandle exists, but it doesn't. */
+#endif
+
+#ifdef HAVE_FSEEKABLE
+/*
+ * return TRUE if file is seekable
+ */
+int fseekable(fp)
+FILE *fp;
+{
+ return GetFileType((HANDLE)_get_osfhandle(fileno(fp))) == FILE_TYPE_DISK;
+}
+#endif /* HAVE_FSEEKABLE */
+#endif /* !UTIL */
+
+
+#if 0 /* seems to be never used; try it out... */
+char *StringLower(char *szArg)
+{
+ char *szPtr;
+/* unsigned char *szPtr; */
+ for ( szPtr = szArg; *szPtr; szPtr++ )
+ *szPtr = lower[*szPtr];
+ return szArg;
+}
+#endif /* never */
+
+
+
+#ifdef W32_STAT_BANDAID
+
+/* All currently known variants of WIN32 operating systems (Windows 95/98,
+ * WinNT 3.x, 4.0, 5.0) have a nasty bug in the OS kernel concerning
+ * conversions between UTC and local time: In the time conversion functions
+ * of the Win32 API, the timezone offset (including seasonal daylight saving
+ * shift) between UTC and local time evaluation is erratically based on the
+ * current system time. The correct evaluation must determine the offset
+ * value as it {was/is/will be} for the actual time to be converted.
+ *
+ * The C runtime lib's stat() returns utc time-stamps so that
+ * localtime(timestamp) corresponds to the (potentially false) local
+ * time shown by the OS' system programs (Explorer, command shell dir, etc.)
+ *
+ * For the NTFS file system (and other filesystems that store time-stamps
+ * as UTC values), this results in st_mtime (, st_{c|a}time) fields which
+ * are not stable but vary according to the seasonal change of "daylight
+ * saving time in effect / not in effect".
+ *
+ * To achieve timestamp consistency of UTC (UT extra field) values in
+ * Zip archives, the Info-ZIP programs require work-around code for
+ * proper time handling in stat() (and other time handling routines).
+ */
+/* stat() functions under Windows95 tend to fail for root directories. *
+ * Watcom and Borland, at least, are affected by this bug. Watcom made *
+ * a partial fix for 11.0 but still missed some cases. This substitute *
+ * detects the case and fills in reasonable values. Otherwise we get *
+ * effects like failure to extract to a root dir because it's not found. */
+
+#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */
+ int zstat_zipwin32(const char *path, z_stat *buf)
+#else
+ int zstat_zipwin32(const char *path, struct stat *buf)
+#endif
+{
+# ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */
+ if (!zstat(path, buf))
+# else
+ if (!stat(path, buf))
+# endif
+ {
+#ifdef NT_TZBUG_WORKAROUND
+ /* stat was successful, now redo the time-stamp fetches */
+ int fs_uses_loctime = FSusesLocalTime(path);
+ HANDLE h;
+ FILETIME Modft, Accft, Creft;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(path) + 1);
+
+ OemToAnsi(path, ansi_path);
+# define Ansi_Path ansi_path
+#else
+# define Ansi_Path path
+#endif
+
+ Trace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime));
+ h = CreateFile(Ansi_Path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (h != INVALID_HANDLE_VALUE) {
+ BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+ CloseHandle(h);
+
+ if (ftOK) {
+ if (!fs_uses_loctime) {
+ /* On a filesystem that stores UTC timestamps, we refill
+ * the time fields of the struct stat buffer by directly
+ * using the UTC values as returned by the Win32
+ * GetFileTime() API call.
+ */
+ FileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ FileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ FileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ Tracev((stdout,"NTFS, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ } else {
+ /* On VFAT and FAT-like filesystems, the FILETIME values
+ * are converted back to the stable local time before
+ * converting them to UTC unix time-stamps.
+ */
+ VFatFileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ Tracev((stdout, "VFAT, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ }
+ }
+ }
+# undef Ansi_Path
+#endif /* NT_TZBUG_WORKAROUND */
+ return 0;
+ }
+#ifdef W32_STATROOT_FIX
+ else
+ {
+ DWORD flags;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(path) + 1);
+
+ OemToAnsi(path, ansi_path);
+# define Ansi_Path ansi_path
+#else
+# define Ansi_Path path
+#endif
+
+ flags = GetFileAttributes(Ansi_Path);
+ if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
+ Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
+ path));
+#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */
+ memset(buf, 0, sizeof(z_stat));
+#else
+ memset(buf, 0, sizeof(struct stat));
+#endif
+ buf->st_atime = buf->st_ctime = buf->st_mtime =
+ dos2unixtime(DOSTIME_MINIMUM);
+ /* !!! you MUST NOT add a cast to the type of "st_mode" here;
+ * !!! different compilers do not agree on the "st_mode" size!
+ * !!! (And, some compiler may not declare the "mode_t" type
+ * !!! identifier, so you cannot use it, either.)
+ */
+ buf->st_mode = S_IFDIR | S_IREAD |
+ ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
+ return 0;
+ } /* assumes: stat() won't fail on non-dirs without good reason */
+# undef Ansi_Path
+ }
+#endif /* W32_STATROOT_FIX */
+ return -1;
+}
+
+
+# ifdef UNICODE_SUPPORT
+
+int zstat_zipwin32w(const wchar_t *pathw, zw_stat *buf)
+{
+ if (!zwstat(pathw, buf))
+ {
+#ifdef NT_TZBUG_WORKAROUND
+ /* stat was successful, now redo the time-stamp fetches */
+ int fs_uses_loctime = FSusesLocalTimeW(pathw);
+ HANDLE h;
+ FILETIME Modft, Accft, Creft;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(pathw) + 1);
+
+ OemToAnsi(path, ansi_path);
+# define Ansi_Path ansi_path
+#else
+# define Ansi_Path pathw
+#endif
+
+ Trace((stdout, "stat(%s) finds modtime %08lx\n", pathw, buf->st_mtime));
+ h = CreateFileW(Ansi_Path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (h != INVALID_HANDLE_VALUE) {
+ BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+ CloseHandle(h);
+
+ if (ftOK) {
+ if (!fs_uses_loctime) {
+ /* On a filesystem that stores UTC timestamps, we refill
+ * the time fields of the struct stat buffer by directly
+ * using the UTC values as returned by the Win32
+ * GetFileTime() API call.
+ */
+ FileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ FileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ FileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ Tracev((stdout,"NTFS, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ } else {
+ /* On VFAT and FAT-like filesystems, the FILETIME values
+ * are converted back to the stable local time before
+ * converting them to UTC unix time-stamps.
+ */
+ VFatFileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ Tracev((stdout, "VFAT, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ }
+ }
+ }
+# undef Ansi_Path
+#endif /* NT_TZBUG_WORKAROUND */
+ return 0;
+ }
+#ifdef W32_STATROOT_FIX
+ else
+ {
+ DWORD flags;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(pathw) + 1);
+
+ OemToAnsi(path, ansi_path);
+# define Ansi_Path ansi_path
+#else
+# define Ansi_Path pathw
+#endif
+
+ flags = GetFileAttributesW(Ansi_Path);
+ if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
+ Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
+ pathw));
+#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */
+ memset(buf, 0, sizeof(z_stat));
+#else
+ memset(buf, 0, sizeof(struct stat));
+#endif
+ buf->st_atime = buf->st_ctime = buf->st_mtime =
+ dos2unixtime(DOSTIME_MINIMUM);
+ /* !!! you MUST NOT add a cast to the type of "st_mode" here;
+ * !!! different compilers do not agree on the "st_mode" size!
+ * !!! (And, some compiler may not declare the "mode_t" type
+ * !!! identifier, so you cannot use it, either.)
+ */
+ buf->st_mode = S_IFDIR | S_IREAD |
+ ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
+ return 0;
+ } /* assumes: stat() won't fail on non-dirs without good reason */
+# undef Ansi_Path
+ }
+#endif /* W32_STATROOT_FIX */
+ return -1;
+}
+
+# endif
+
+
+#endif /* W32_STAT_BANDAID */
+
+
+
+#ifdef W32_USE_IZ_TIMEZONE
+#include "timezone.h"
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule);
+
+static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule)
+{
+ if (lpw32tm->wYear != 0) {
+ ptrule->r_type = JULIAN_DAY;
+ ptrule->r_day = ydays[lpw32tm->wMonth - 1] + lpw32tm->wDay;
+ } else {
+ ptrule->r_type = MONTH_NTH_DAY_OF_WEEK;
+ ptrule->r_mon = lpw32tm->wMonth;
+ ptrule->r_day = lpw32tm->wDayOfWeek;
+ ptrule->r_week = lpw32tm->wDay;
+ }
+ ptrule->r_time = (long)lpw32tm->wHour * SECSPERHOUR +
+ (long)(lpw32tm->wMinute * SECSPERMIN) +
+ (long)lpw32tm->wSecond;
+}
+
+int GetPlatformLocalTimezone(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))
+{
+ TIME_ZONE_INFORMATION tzinfo;
+ DWORD res;
+
+ /* read current timezone settings from registry if TZ envvar missing */
+ res = GetTimeZoneInformation(&tzinfo);
+ if (res != TIME_ZONE_ID_INVALID)
+ {
+ struct rule startrule, stoprule;
+
+ conv_to_rule(&(tzinfo.StandardDate), &stoprule);
+ conv_to_rule(&(tzinfo.DaylightDate), &startrule);
+ sp->timecnt = 0;
+ sp->ttis[0].tt_abbrind = 0;
+ if ((sp->charcnt =
+ WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1,
+ sp->chars, sizeof(sp->chars), NULL, NULL))
+ == 0)
+ sp->chars[sp->charcnt++] = '\0';
+ sp->ttis[1].tt_abbrind = sp->charcnt;
+ sp->charcnt +=
+ WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1,
+ sp->chars + sp->charcnt,
+ sizeof(sp->chars) - sp->charcnt, NULL, NULL);
+ if ((sp->charcnt - sp->ttis[1].tt_abbrind) == 0)
+ sp->chars[sp->charcnt++] = '\0';
+ sp->ttis[0].tt_gmtoff = - (tzinfo.Bias + tzinfo.StandardBias)
+ * MINSPERHOUR;
+ sp->ttis[1].tt_gmtoff = - (tzinfo.Bias + tzinfo.DaylightBias)
+ * MINSPERHOUR;
+ sp->ttis[0].tt_isdst = 0;
+ sp->ttis[1].tt_isdst = 1;
+ sp->typecnt = (startrule.r_mon == 0 && stoprule.r_mon == 0) ? 1 : 2;
+
+ if (sp->typecnt > 1)
+ (*fill_tzstate_from_rules)(sp, &startrule, &stoprule);
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif /* W32_USE_IZ_TIMEZONE */
+
+
+
+#ifndef WINDLL
+/* This replacement getch() function was originally created for Watcom C
+ * and then additionally used with CYGWIN. Since UnZip 5.4, all other Win32
+ * ports apply this replacement rather that their supplied getch() (or
+ * alike) function. There are problems with unabsorbed LF characters left
+ * over in the keyboard buffer under Win95 (and 98) when ENTER was pressed.
+ * (Under Win95, ENTER returns two(!!) characters: CR-LF.) This problem
+ * does not appear when run on a WinNT console prompt!
+ */
+
+/* Watcom 10.6's getch() does not handle Alt+<digit><digit><digit>. */
+/* Note that if PASSWD_FROM_STDIN is defined, the file containing */
+/* the password must have a carriage return after the word, not a */
+/* Unix-style newline (linefeed only). This discards linefeeds. */
+
+int getch_win32(void)
+{
+ HANDLE stin;
+ DWORD rc;
+ unsigned char buf[2];
+ int ret = -1;
+ DWORD odemode = ~(DWORD)0;
+
+# ifdef PASSWD_FROM_STDIN
+ stin = GetStdHandle(STD_INPUT_HANDLE);
+# else
+ stin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (stin == INVALID_HANDLE_VALUE)
+ return -1;
+# endif
+ if (GetConsoleMode(stin, &odemode))
+ SetConsoleMode(stin, ENABLE_PROCESSED_INPUT); /* raw except ^C noticed */
+ if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
+ ret = buf[0];
+ /* when the user hits return we get CR LF. We discard the LF, not the CR,
+ * because when we call this for the first time after a previous input
+ * such as the one for "replace foo? [y]es, ..." the LF may still be in
+ * the input stream before whatever the user types at our prompt. */
+ if (ret == '\n')
+ if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
+ ret = buf[0];
+ if (odemode != ~(DWORD)0)
+ SetConsoleMode(stin, odemode);
+# ifndef PASSWD_FROM_STDIN
+ CloseHandle(stin);
+# endif
+ return ret;
+}
+
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s.\n\n";
+#if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DJGPP__))
+ char buf[80];
+#if (defined(_MSC_VER) && (_MSC_VER > 900))
+ char buf2[80];
+#endif
+#endif
+
+/* Define the compiler name and version strings */
+#if defined(_MSC_VER) /* MSC == MSVC++, including the SDK compiler */
+ sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100);
+# define COMPILER_NAME1 buf
+# if (_MSC_VER == 800)
+# define COMPILER_NAME2 "(Visual C++ v1.1)"
+# elif (_MSC_VER == 850)
+# define COMPILER_NAME2 "(Windows NT v3.5 SDK)"
+# elif (_MSC_VER == 900)
+# define COMPILER_NAME2 "(Visual C++ v2.x)"
+# elif (_MSC_VER > 900)
+ sprintf(buf2, "(Visual C++ v%d.%d)", _MSC_VER/100 - 6, _MSC_VER%100/10);
+# define COMPILER_NAME2 buf2
+# else
+# define COMPILER_NAME2 "(bad version)"
+# endif
+#elif defined(__WATCOMC__)
+# if (__WATCOMC__ % 10 > 0)
+/* We do this silly test because __WATCOMC__ gives two digits for the */
+/* minor version, but Watcom packaging prefers to show only one digit. */
+ sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
+ __WATCOMC__ % 100);
+# else
+ sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
+ (__WATCOMC__ % 100) / 10);
+# endif /* __WATCOMC__ % 10 > 0 */
+# define COMPILER_NAME1 buf
+# define COMPILER_NAME2 ""
+#elif defined(__TURBOC__)
+# ifdef __BORLANDC__
+# define COMPILER_NAME1 "Borland C++"
+# if (__BORLANDC__ == 0x0452) /* __BCPLUSPLUS__ = 0x0320 */
+# define COMPILER_NAME2 " 4.0 or 4.02"
+# elif (__BORLANDC__ == 0x0460) /* __BCPLUSPLUS__ = 0x0340 */
+# define COMPILER_NAME2 " 4.5"
+# elif (__BORLANDC__ == 0x0500) /* __TURBOC__ = 0x0500 */
+# define COMPILER_NAME2 " 5.0"
+# elif (__BORLANDC__ == 0x0520) /* __TURBOC__ = 0x0520 */
+# define COMPILER_NAME2 " 5.2 (C++ Builder 1.0)"
+# elif (__BORLANDC__ == 0x0530) /* __BCPLUSPLUS__ = 0x0530 */
+# define COMPILER_NAME2 " 5.3 (C++ Builder 3.0)"
+# elif (__BORLANDC__ == 0x0540) /* __BCPLUSPLUS__ = 0x0540 */
+# define COMPILER_NAME2 " 5.4 (C++ Builder 4.0)"
+# elif (__BORLANDC__ == 0x0550) /* __BCPLUSPLUS__ = 0x0550 */
+# define COMPILER_NAME2 " 5.5 (C++ Builder 5.0)"
+# elif (__BORLANDC__ == 0x0551) /* __BCPLUSPLUS__ = 0x0551 */
+# define COMPILER_NAME2 " 5.5.1 (C++ Builder 5.0.1)"
+# elif (__BORLANDC__ == 0x0560) /* __BCPLUSPLUS__ = 0x0560 */
+# define COMPILER_NAME2 " 5.6 (C++ Builder 6)"
+# else
+# define COMPILER_NAME2 " later than 5.6"
+# endif
+# else /* !__BORLANDC__ */
+# define COMPILER_NAME1 "Turbo C"
+# if (__TURBOC__ >= 0x0400) /* Kevin: 3.0 -> 0x0401 */
+# define COMPILER_NAME2 "++ 3.0 or later"
+# elif (__TURBOC__ == 0x0295) /* [661] vfy'd by Kevin */
+# define COMPILER_NAME2 "++ 1.0"
+# endif
+# endif /* __BORLANDC__ */
+#elif defined(__GNUC__)
+# ifdef __RSXNT__
+# if (defined(__DJGPP__) && !defined(__EMX__))
+ sprintf(buf, "rsxnt(djgpp v%d.%02d) / gcc ",
+ __DJGPP__, __DJGPP_MINOR__);
+# define COMPILER_NAME1 buf
+# elif defined(__DJGPP__)
+ sprintf(buf, "rsxnt(emx+djgpp v%d.%02d) / gcc ",
+ __DJGPP__, __DJGPP_MINOR__);
+# define COMPILER_NAME1 buf
+# elif (defined(__GO32__) && !defined(__EMX__))
+# define COMPILER_NAME1 "rsxnt(djgpp v1.x) / gcc "
+# elif defined(__GO32__)
+# define COMPILER_NAME1 "rsxnt(emx + djgpp v1.x) / gcc "
+# elif defined(__EMX__)
+# define COMPILER_NAME1 "rsxnt(emx)+gcc "
+# else
+# define COMPILER_NAME1 "rsxnt(unknown) / gcc "
+# endif
+# elif defined(__CYGWIN__)
+# define COMPILER_NAME1 "Cygnus win32 / gcc "
+# elif defined(__MINGW32__)
+# define COMPILER_NAME1 "mingw32 / gcc "
+# else
+# define COMPILER_NAME1 "gcc "
+# endif
+# define COMPILER_NAME2 __VERSION__
+#elif defined(__LCC__)
+# define COMPILER_NAME1 "LCC-Win32"
+# define COMPILER_NAME2 ""
+#else
+# define COMPILER_NAME1 "unknown compiler (SDK?)"
+# define COMPILER_NAME2 ""
+#endif
+
+/* Define the compile date string */
+#ifdef __DATE__
+# define COMPILE_DATE " on " __DATE__
+#else
+# define COMPILE_DATE ""
+#endif
+
+ printf(CompiledWith, COMPILER_NAME1, COMPILER_NAME2,
+ "\nWindows 9x / Windows NT", " (32-bit)", COMPILE_DATE);
+
+ return;
+
+} /* end function version_local() */
+#endif /* !WINDLL */
+
+
+/* --------------------------------------------------- */
+/* Large File Support
+ *
+ * Moved to Win32i64.c to avoid conflicts in same name functions
+ * in WiZ using UnZip and Zip libraries.
+ * 9/25/2003
+ */
+
+
+/* --------------------------------------------------- */
+/* Unicode Support for Win32
+ *
+ */
+
+#ifdef UNICODE_SUPPORT
+# if 0
+
+ /* get the wide command line and convert to argvw */
+ /* windows ignores argv and gets argvw separately */
+ zchar **get_wide_argv(argv)
+ char **argv;
+ {
+ int i;
+ int argc;
+ int size;
+ zchar **argvw = NULL;
+ zchar *commandline = NULL;
+ zchar **a = NULL;
+
+ commandline = GetCommandLineW();
+ a = CommandLineToArgvW(commandline, &argc);
+
+ if (a == NULL) {
+ /* failed */
+ ZIPERR(ZE_COMPERR, "get_wide_argv");
+ }
+
+ /* copy args so can use free_args() */
+ if ((argvw = (zchar **)malloc((argc + 1) * sizeof(zchar *))) == NULL) {
+ ZIPERR(ZE_MEM, "get_wide_argv");
+ }
+ for (i = 0; i < argc; i++) {
+ size = zstrlen(a[i]) + 1;
+ if ((argvw[i] = (zchar *)malloc(size * sizeof(zchar))) == NULL) {
+ ZIPERR(ZE_MEM, "get_wide_argv");
+ }
+ if ((argvw[i] = copy_zstring(a[i])) == NULL) {
+ ZIPERR(ZE_MEM, "get_wide_argv");
+ }
+ }
+ argvw[argc] = L'\0';
+
+ /* free original argvw */
+ LocalFree(a);
+
+ return argvw;
+ }
+# endif
+
+
+/* convert wide character string to multi-byte character string */
+/* win32 version */
+char *wide_to_local_string(wide_string)
+ zwchar *wide_string;
+{
+ int i;
+ wchar_t wc;
+ int bytes_char;
+ int default_used;
+ int wsize = 0;
+ int max_bytes = 9;
+ char buf[9];
+ char *buffer = NULL;
+ char *local_string = NULL;
+
+ if (wide_string == NULL)
+ return NULL;
+
+ for (wsize = 0; wide_string[wsize]; wsize++) ;
+
+ if (max_bytes < MB_CUR_MAX)
+ max_bytes = MB_CUR_MAX;
+
+ if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "wide_to_local_string");
+ }
+
+ /* convert it */
+ buffer[0] = '\0';
+ 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];
+ }
+ /* Unter some vendor's C-RTL, the Wide-to-MultiByte conversion functions
+ * (like wctomb() et. al.) do not use the same codepage as the other
+ * string arguments I/O functions (fopen, mkdir, rmdir etc.).
+ * Therefore, we have to fall back to the underlying Win32-API call to
+ * achieve a consistent behaviour for all supported compiler environments.
+ * Failing RTLs are for example:
+ * Borland (locale uses OEM-CP as default, but I/O functions expect ANSI
+ * names)
+ * Watcom (only "C" locale, wctomb() always uses OEM CP)
+ * (in other words: all supported environments except the Microsoft RTLs)
+ */
+ bytes_char = WideCharToMultiByte(
+ CP_ACP, WC_COMPOSITECHECK,
+ &wc, 1,
+ (LPSTR)buf, sizeof(buf),
+ NULL, &default_used);
+ if (default_used)
+ bytes_char = -1;
+ if (unicode_escape_all) {
+ if (bytes_char == 1 && (uch)buf[0] <= 0x7f) {
+ /* ASCII */
+ strncat(buffer, buf, 1);
+ } else {
+ /* use escape for wide character */
+ char *e = wide_char_to_escape_string(wide_string[i]);
+ strcat(buffer, e);
+ free(e);
+ }
+ } else if (bytes_char > 0) {
+ /* multi-byte char */
+ strncat(buffer, buf, bytes_char);
+ } else {
+ /* no MB for this wide */
+ if (use_wide_to_mb_default) {
+ /* default character */
+ strcat(buffer, wide_to_mb_default_string);
+ } else {
+ /* use escape for wide character */
+ char *e = wide_char_to_escape_string(wide_string[i]);
+ strcat(buffer, e);
+ free(e);
+ }
+ }
+ }
+ if ((local_string = (char *)realloc(buffer, strlen(buffer) + 1)) == NULL) {
+ free(buffer);
+ ZIPERR(ZE_MEM, "wide_to_local_string");
+ }
+
+ return local_string;
+}
+
+/* convert multi-byte character string to wide character string */
+/* win32 version */
+zwchar *local_to_wide_string(local_string)
+ 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 = MultiByteToWideChar(CP_ACP, 0,
+ local_string, -1, NULL, 0);
+ if (wsize == (size_t)-1) {
+ /* could not convert */
+ return NULL;
+ }
+
+ /* convert it */
+ if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) {
+ ZIPERR(ZE_MEM, "local_to_wide_string");
+ }
+ wsize = MultiByteToWideChar(CP_ACP, 0,
+ local_string, -1,
+ wc_string, wsize + 1);
+ wc_string[wsize] = (wchar_t) 0;
+
+ /* in case wchar_t is not zwchar */
+ if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) {
+ free(wc_string);
+ ZIPERR(ZE_MEM, "local_to_wide_string");
+ }
+ for (wsize = 0; (wide_string[wsize] = (zwchar)wc_string[wsize]); wsize++) ;
+ wide_string[wsize] = (zwchar)0;
+ free(wc_string);
+
+ return wide_string;
+}
+#endif /* UNICODE_SUPPORT */
+
+
+/*
+# if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+/* convert oem to ansi character string */
+char *oem_to_local_string(local_string, oem_string)
+ char *local_string;
+ char *oem_string;
+{
+ /* convert OEM to ANSI character set */
+ OemToChar(oem_string, local_string);
+
+ return local_string;
+}
+/*
+# endif
+*/
+
+
+/*
+#if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+/* convert local to oem character string */
+char *local_to_oem_string(oem_string, local_string)
+ char *oem_string;
+ char *local_string;
+{
+ /* convert to OEM display character set */
+ CharToOem(local_string, oem_string);
+ return oem_string;
+}
+/*
+#endif
+*/
+