/* 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 #include #include #include #include #define WIN32_LEAN_AND_MEAN #include /* for LARGE_FILE_SUPPORT but may not be needed */ #include #ifdef __RSXNT__ # include # 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 # 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+. */ /* 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 */