diff options
Diffstat (limited to 'win32/win32.c')
-rw-r--r-- | win32/win32.c | 1488 |
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(<m); + + /* 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 +*/ + |