1/* 2 win32/win32.c - Zip 3 3 4 Copyright (c) 1990-2008 Info-ZIP. All rights reserved. 5 6 See the accompanying file LICENSE, version 2007-Mar-4 or later 7 (the contents of which are also included in zip.h) for terms of use. 8 If, for some reason, all these files are missing, the Info-ZIP license 9 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html 10*/ 11 12/* 13 * WIN32 specific functions for ZIP. 14 * 15 * The WIN32 version of ZIP heavily relies on the MSDOS and OS2 versions, 16 * since we have to do similar things to switch between NTFS, HPFS and FAT. 17 */ 18 19 20#include "../zip.h" 21 22#include <stdlib.h> 23#include <stdio.h> 24#include <limits.h> 25#include <time.h> 26#include <ctype.h> 27#define WIN32_LEAN_AND_MEAN 28#include <windows.h> 29/* for LARGE_FILE_SUPPORT but may not be needed */ 30#include <io.h> 31 32#ifdef __RSXNT__ 33# include <alloca.h> 34# include "../win32/rsxntwin.h" 35#endif 36#include "../win32/win32zip.h" 37 38#define A_RONLY 0x01 39#define A_HIDDEN 0x02 40#define A_SYSTEM 0x04 41#define A_LABEL 0x08 42#define A_DIR 0x10 43#define A_ARCHIVE 0x20 44 45 46#define EAID 0x0009 47 48#if (defined(__MINGW32__) && !defined(USE_MINGW_GLOBBING)) 49 int _CRT_glob = 0; /* suppress command line globbing by C RTL */ 50#endif 51 52#ifndef UTIL 53 54extern int noisy; 55 56#ifdef NT_TZBUG_WORKAROUND 57local int FSusesLocalTime(const char *path); 58#ifdef UNICODE_SUPPORt 59local int FSusesLocalTimeW(const wchar_t *path); 60#endif 61#endif 62#if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND)) 63local int FileTime2utime(FILETIME *pft, time_t *ut); 64#endif 65#if (defined(NT_TZBUG_WORKAROUND) && defined(W32_STAT_BANDAID)) 66local int VFatFileTime2utime(const FILETIME *pft, time_t *ut); 67#endif 68 69 70/* FAT / HPFS detection */ 71 72int IsFileSystemOldFAT(char *dir) 73{ 74 static char lastDrive = '\0'; /* cached drive of last GetVolumeInformation call */ 75 static int lastDriveOldFAT = 0; /* cached OldFAT value of last GetVolumeInformation call */ 76 char root[4]; 77 DWORD vfnsize; 78 DWORD vfsflags; 79 80 /* 81 * We separate FAT and HPFS+other file systems here. 82 * I consider other systems to be similar to HPFS/NTFS, i.e. 83 * support for long file names and being case sensitive to some extent. 84 */ 85 86 strncpy(root, dir, 3); 87 if ( isalpha((uch)root[0]) && (root[1] == ':') ) { 88 root[0] = to_up(dir[0]); 89 root[2] = '\\'; 90 root[3] = 0; 91 } 92 else { 93 root[0] = '\\'; 94 root[1] = 0; 95 } 96 if (lastDrive == root[0]) { 97 return lastDriveOldFAT; 98 } 99 100 if ( !GetVolumeInformation(root, NULL, 0, 101 NULL, &vfnsize, &vfsflags, 102 NULL, 0)) { 103 fprintf(mesg, "zip diagnostic: GetVolumeInformation failed\n"); 104 return(FALSE); 105 } 106 107 lastDrive = root[0]; 108 lastDriveOldFAT = vfnsize <= 12; 109 110 return lastDriveOldFAT; 111} 112 113#ifdef UNICODE_SUPPORT 114int IsFileSystemOldFATW(wchar_t *dir) 115{ 116 static wchar_t lastDrive = (wchar_t)'\0'; /* cached drive of last GetVolumeInformation call */ 117 static int lastDriveOldFAT = 0; /* cached OldFAT value of last GetVolumeInformation call */ 118 wchar_t root[4]; 119 DWORD vfnsize; 120 DWORD vfsflags; 121 122 /* 123 * We separate FAT and HPFS+other file systems here. 124 * I consider other systems to be similar to HPFS/NTFS, i.e. 125 * support for long file names and being case sensitive to some extent. 126 */ 127 128 wcsncpy(root, dir, 3); 129 if ( iswalpha(root[0]) && (root[1] == (wchar_t)':') ) { 130 root[0] = towupper(dir[0]); 131 root[2] = (wchar_t)'\\'; 132 root[3] = 0; 133 } 134 else { 135 root[0] = (wchar_t)'\\'; 136 root[1] = 0; 137 } 138 if (lastDrive == root[0]) { 139 return lastDriveOldFAT; 140 } 141 142 if ( !GetVolumeInformationW(root, NULL, 0, 143 NULL, &vfnsize, &vfsflags, 144 NULL, 0)) { 145 fprintf(mesg, "zip diagnostic: GetVolumeInformation failed\n"); 146 return(FALSE); 147 } 148 149 lastDrive = root[0]; 150 lastDriveOldFAT = vfnsize <= 12; 151 152 return lastDriveOldFAT; 153} 154#endif 155 156 157/* access mode bits and time stamp */ 158 159int GetFileMode(char *name) 160{ 161DWORD dwAttr; 162#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 163 char *ansi_name = (char *)alloca(strlen(name) + 1); 164 165 OemToAnsi(name, ansi_name); 166 name = ansi_name; 167#endif 168 169 dwAttr = GetFileAttributes(name); 170 if ( dwAttr == 0xFFFFFFFF ) { 171 zipwarn("reading file attributes failed: ", name); 172 /* 173 fprintf(mesg, "zip diagnostic: GetFileAttributes failed"); 174 fflush(); 175 */ 176 return(0x20); /* the most likely, though why the error? security? */ 177 } 178 return( 179 (dwAttr&FILE_ATTRIBUTE_READONLY ? A_RONLY :0) 180 | (dwAttr&FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN :0) 181 | (dwAttr&FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM :0) 182 | (dwAttr&FILE_ATTRIBUTE_DIRECTORY ? A_DIR :0) 183 | (dwAttr&FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE :0)); 184} 185 186#ifdef UNICODE_SUPPORT 187int GetFileModeW(wchar_t *namew) 188{ 189DWORD dwAttr; 190#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 191 wchar_t *ansi_namew = (wchar_t *)alloca((wcslen(namew) + 1) * sizeof(wchar_t)); 192 193 CharToAnsiW(namew, ansi_namew); 194 namew = ansi_namew; 195#endif 196 197 dwAttr = GetFileAttributesW(namew); 198 if ( dwAttr == 0xFFFFFFFF ) { 199 char *name = wchar_to_local_string(namew); 200 zipwarn("reading file attributes failed: ", name); 201 free(name); 202 return(0x20); /* the most likely, though why the error? security? */ 203 } 204 return( 205 (dwAttr&FILE_ATTRIBUTE_READONLY ? A_RONLY :0) 206 | (dwAttr&FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN :0) 207 | (dwAttr&FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM :0) 208 | (dwAttr&FILE_ATTRIBUTE_DIRECTORY ? A_DIR :0) 209 | (dwAttr&FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE :0)); 210} 211#endif 212 213 214int ClearArchiveBitW(wchar_t *namew) 215{ 216DWORD dwAttr; 217 dwAttr = GetFileAttributesW(namew); 218 if ( dwAttr == 0xFFFFFFFF ) { 219 fprintf(mesg, "zip diagnostic: GetFileAttributes failed\n"); 220 return(0); 221 } 222 223 if (!SetFileAttributesW(namew, (DWORD)(dwAttr & ~FILE_ATTRIBUTE_ARCHIVE))) { 224 fprintf(mesg, "zip diagnostic: SetFileAttributes failed\n"); 225 perror("SetFileAttributes"); 226 return(0); 227 } 228 return(1); 229} 230 231int ClearArchiveBit(char *name) 232{ 233DWORD dwAttr; 234#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 235 char *ansi_name = (char *)alloca(strlen(name) + 1); 236 237 OemToAnsi(name, ansi_name); 238 name = ansi_name; 239#endif 240 241 dwAttr = GetFileAttributes(name); 242 if ( dwAttr == 0xFFFFFFFF ) { 243 fprintf(mesg, "zip diagnostic: GetFileAttributes failed\n"); 244 return(0); 245 } 246 247 if (!SetFileAttributes(name, (DWORD)(dwAttr & ~FILE_ATTRIBUTE_ARCHIVE))) { 248 fprintf(mesg, "zip diagnostic: SetFileAttributes failed\n"); 249 perror("SetFileAttributes"); 250 return(0); 251 } 252 return(1); 253} 254 255 256#ifdef NT_TZBUG_WORKAROUND 257local int FSusesLocalTime(const char *path) 258{ 259 char *tmp0; 260 char rootPathName[4]; 261 char tmp1[MAX_PATH], tmp2[MAX_PATH]; 262 DWORD volSerNo, maxCompLen, fileSysFlags; 263#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 264 char *ansi_path = (char *)alloca(strlen(path) + 1); 265 266 OemToAnsi(path, ansi_path); 267 path = ansi_path; 268#endif 269 270 if (isalpha((uch)path[0]) && (path[1] == ':')) 271 tmp0 = (char *)path; 272 else 273 { 274 GetFullPathName(path, MAX_PATH, tmp1, &tmp0); 275 tmp0 = &tmp1[0]; 276 } 277 strncpy(rootPathName, tmp0, 3); /* Build the root path name, */ 278 rootPathName[3] = '\0'; /* e.g. "A:/" */ 279 280 GetVolumeInformation((LPCTSTR)rootPathName, (LPTSTR)tmp1, (DWORD)MAX_PATH, 281 &volSerNo, &maxCompLen, &fileSysFlags, 282 (LPTSTR)tmp2, (DWORD)MAX_PATH); 283 284 /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in 285 * local time! 286 */ 287 return !strncmp(strupr(tmp2), "FAT", 3) || 288 !strncmp(tmp2, "VFAT", 4) || 289 !strncmp(tmp2, "HPFS", 4); 290 291} /* end function FSusesLocalTime() */ 292 293# ifdef UNICODE_SUPPORT 294local int FSusesLocalTimeW(const wchar_t *path) 295{ 296 wchar_t *tmp0; 297 wchar_t rootPathName[4]; 298 wchar_t tmp1[MAX_PATH], tmp2[MAX_PATH]; 299 DWORD volSerNo, maxCompLen, fileSysFlags; 300#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 301 wchar_t *ansi_path = (wchar_t *)alloca((wcslen(path) + 1) * sizeof(wchar_t)); 302 303 CharToAnsiW(path, ansi_path); 304 path = ansi_path; 305#endif 306 307 if (iswalpha(path[0]) && (path[1] == (wchar_t)':')) 308 tmp0 = (wchar_t *)path; 309 else 310 { 311 GetFullPathNameW(path, MAX_PATH, tmp1, &tmp0); 312 tmp0 = &tmp1[0]; 313 } 314 wcsncpy(rootPathName, tmp0, 3); /* Build the root path name, */ 315 rootPathName[3] = (wchar_t)'\0'; /* e.g. "A:/" */ 316 317 GetVolumeInformationW(rootPathName, tmp1, (DWORD)MAX_PATH, 318 &volSerNo, &maxCompLen, &fileSysFlags, 319 tmp2, (DWORD)MAX_PATH); 320 321 /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in 322 * local time! 323 */ 324 return !wcsncmp(_wcsupr(tmp2), L"FAT", 3) || 325 !wcsncmp(tmp2, L"VFAT", 4) || 326 !wcsncmp(tmp2, L"HPFS", 4); 327 328} /* end function FSusesLocalTimeW() */ 329# endif 330 331#endif /* NT_TZBUG_WORKAROUND */ 332 333 334#if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND)) 335 336#if (defined(__GNUC__) || defined(ULONG_LONG_MAX)) 337 typedef long long LLONG64; 338 typedef unsigned long long ULLNG64; 339#elif (defined(__WATCOMC__) && (__WATCOMC__ >= 1100)) 340 typedef __int64 LLONG64; 341 typedef unsigned __int64 ULLNG64; 342#elif (defined(_MSC_VER) && (_MSC_VER >= 1100)) 343 typedef __int64 LLONG64; 344 typedef unsigned __int64 ULLNG64; 345#elif (defined(__IBMC__) && (__IBMC__ >= 350)) 346 typedef __int64 LLONG64; 347 typedef unsigned __int64 ULLNG64; 348#else 349# define NO_INT64 350#endif 351 352# define UNIX_TIME_ZERO_HI 0x019DB1DEUL 353# define UNIX_TIME_ZERO_LO 0xD53E8000UL 354# define NT_QUANTA_PER_UNIX 10000000L 355# define FTQUANTA_PER_UT_L (NT_QUANTA_PER_UNIX & 0xFFFF) 356# define FTQUANTA_PER_UT_H (NT_QUANTA_PER_UNIX >> 16) 357# define UNIX_TIME_UMAX_HI 0x0236485EUL 358# define UNIX_TIME_UMAX_LO 0xD4A5E980UL 359# define UNIX_TIME_SMIN_HI 0x0151669EUL 360# define UNIX_TIME_SMIN_LO 0xD53E8000UL 361# define UNIX_TIME_SMAX_HI 0x01E9FD1EUL 362# define UNIX_TIME_SMAX_LO 0xD4A5E980UL 363 364local int FileTime2utime(FILETIME *pft, time_t *ut) 365{ 366#ifndef NO_INT64 367 ULLNG64 NTtime; 368 369 NTtime = ((ULLNG64)pft->dwLowDateTime + 370 ((ULLNG64)pft->dwHighDateTime << 32)); 371 372 /* underflow and overflow handling */ 373#ifdef CHECK_UTIME_SIGNED_UNSIGNED 374 if ((time_t)0x80000000L < (time_t)0L) 375 { 376 if (NTtime < ((ULLNG64)UNIX_TIME_SMIN_LO + 377 ((ULLNG64)UNIX_TIME_SMIN_HI << 32))) { 378 *ut = (time_t)LONG_MIN; 379 return FALSE; 380 } 381 if (NTtime > ((ULLNG64)UNIX_TIME_SMAX_LO + 382 ((ULLNG64)UNIX_TIME_SMAX_HI << 32))) { 383 *ut = (time_t)LONG_MAX; 384 return FALSE; 385 } 386 } 387 else 388#endif /* CHECK_UTIME_SIGNED_UNSIGNED */ 389 { 390 if (NTtime < ((ULLNG64)UNIX_TIME_ZERO_LO + 391 ((ULLNG64)UNIX_TIME_ZERO_HI << 32))) { 392 *ut = (time_t)0; 393 return FALSE; 394 } 395 if (NTtime > ((ULLNG64)UNIX_TIME_UMAX_LO + 396 ((ULLNG64)UNIX_TIME_UMAX_HI << 32))) { 397 *ut = (time_t)ULONG_MAX; 398 return FALSE; 399 } 400 } 401 402 NTtime -= ((ULLNG64)UNIX_TIME_ZERO_LO + 403 ((ULLNG64)UNIX_TIME_ZERO_HI << 32)); 404 *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX); 405 return TRUE; 406#else /* NO_INT64 (64-bit integer arithmetics may not be supported) */ 407 /* nonzero if `y' is a leap year, else zero */ 408# define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0) 409 /* number of leap years from 1970 to `y' (not including `y' itself) */ 410# define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400) 411 /* daycount at the end of month[m-1] */ 412 static ZCONST ush ydays[] = 413 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; 414 415 time_t days; 416 SYSTEMTIME w32tm; 417 418 /* underflow and overflow handling */ 419#ifdef CHECK_UTIME_SIGNED_UNSIGNED 420 if ((time_t)0x80000000L < (time_t)0L) 421 { 422 if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) || 423 ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) && 424 (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) { 425 *ut = (time_t)LONG_MIN; 426 return FALSE; 427 if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) || 428 ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) && 429 (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) { 430 *ut = (time_t)LONG_MAX; 431 return FALSE; 432 } 433 } 434 else 435#endif /* CHECK_UTIME_SIGNED_UNSIGNED */ 436 { 437 if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) || 438 ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) && 439 (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) { 440 *ut = (time_t)0; 441 return FALSE; 442 } 443 if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) || 444 ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) && 445 (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) { 446 *ut = (time_t)ULONG_MAX; 447 return FALSE; 448 } 449 } 450 451 FileTimeToSystemTime(pft, &w32tm); 452 453 /* set `days' to the number of days into the year */ 454 days = w32tm.wDay - 1 + ydays[w32tm.wMonth-1] + 455 (w32tm.wMonth > 2 && leap (w32tm.wYear)); 456 457 /* now set `days' to the number of days since 1 Jan 1970 */ 458 days += 365 * (time_t)(w32tm.wYear - 1970) + 459 (time_t)(nleap(w32tm.wYear)); 460 461 *ut = (time_t)(86400L * days + 3600L * (time_t)w32tm.wHour + 462 (time_t)(60 * w32tm.wMinute + w32tm.wSecond)); 463 return TRUE; 464#endif /* ?NO_INT64 */ 465} /* end function FileTime2utime() */ 466#endif /* USE_EF_UT_TIME || NT_TZBUG_WORKAROUND */ 467 468 469#if (defined(NT_TZBUG_WORKAROUND) && defined(W32_STAT_BANDAID)) 470 471local int VFatFileTime2utime(const FILETIME *pft, time_t *ut) 472{ 473 FILETIME lft; 474 SYSTEMTIME w32tm; 475 struct tm ltm; 476 477 FileTimeToLocalFileTime(pft, &lft); 478 FileTimeToSystemTime(&lft, &w32tm); 479 /* underflow and overflow handling */ 480 /* TODO: The range checks are not accurate, the actual limits may 481 * be off by one daylight-saving-time shift (typically 1 hour), 482 * depending on the current state of "is_dst". 483 */ 484#ifdef CHECK_UTIME_SIGNED_UNSIGNED 485 if ((time_t)0x80000000L < (time_t)0L) 486 { 487 if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) || 488 ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) && 489 (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) { 490 *ut = (time_t)LONG_MIN; 491 return FALSE; 492 if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) || 493 ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) && 494 (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) { 495 *ut = (time_t)LONG_MAX; 496 return FALSE; 497 } 498 } 499 else 500#endif /* CHECK_UTIME_SIGNED_UNSIGNED */ 501 { 502 if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) || 503 ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) && 504 (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) { 505 *ut = (time_t)0; 506 return FALSE; 507 } 508 if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) || 509 ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) && 510 (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) { 511 *ut = (time_t)ULONG_MAX; 512 return FALSE; 513 } 514 } 515 ltm.tm_year = w32tm.wYear - 1900; 516 ltm.tm_mon = w32tm.wMonth - 1; 517 ltm.tm_mday = w32tm.wDay; 518 ltm.tm_hour = w32tm.wHour; 519 ltm.tm_min = w32tm.wMinute; 520 ltm.tm_sec = w32tm.wSecond; 521 ltm.tm_isdst = -1; /* let mktime determine if DST is in effect */ 522 *ut = mktime(<m); 523 524 /* a cheap error check: mktime returns "(time_t)-1L" on conversion errors. 525 * Normally, we would have to apply a consistency check because "-1" 526 * could also be a valid time. But, it is quite unlikely to read back odd 527 * time numbers from file systems that store time stamps in DOS format. 528 * (The only known exception is creation time on VFAT partitions.) 529 */ 530 return (*ut != (time_t)-1L); 531 532} /* end function VFatFileTime2utime() */ 533#endif /* NT_TZBUG_WORKAROUND && W32_STAT_BANDAID */ 534 535 536#if 0 /* Currently, this is not used at all */ 537 538long GetTheFileTime(char *name, iztimes *z_ut) 539{ 540HANDLE h; 541FILETIME Modft, Accft, Creft, lft; 542WORD dh, dl; 543#ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */ 544 char *ansi_name = (char *)alloca(strlen(name) + 1); 545 546 OemToAnsi(name, ansi_name); 547 name = ansi_name; 548#endif 549 550 h = CreateFile(name, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, 551 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 552 if ( h != INVALID_HANDLE_VALUE ) { 553 BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft); 554 CloseHandle(h); 555#ifdef USE_EF_UT_TIME 556 if (ftOK && (z_ut != NULL)) { 557 FileTime2utime(&Modft, &(z_ut->mtime)); 558 if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0) 559 FileTime2utime(&Accft, &(z_ut->atime)); 560 else 561 z_ut->atime = z_ut->mtime; 562 if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0) 563 FileTime2utime(&Creft, &(z_ut->ctime)); 564 else 565 z_ut->ctime = z_ut->mtime; 566 } 567#endif 568 FileTimeToLocalFileTime(&ft, &lft); 569 FileTimeToDosDateTime(&lft, &dh, &dl); 570 return(dh<<16) | dl; 571 } 572 else 573 return 0L; 574} 575 576#endif /* never */ 577 578 579void ChangeNameForFAT(char *name) 580{ 581 char *src, *dst, *next, *ptr, *dot, *start; 582 static char invalid[] = ":;,=+\"[]<>| \t"; 583 584 if ( isalpha((uch)name[0]) && (name[1] == ':') ) 585 start = name + 2; 586 else 587 start = name; 588 589 src = dst = start; 590 if ( (*src == '/') || (*src == '\\') ) 591 src++, dst++; 592 593 while ( *src ) 594 { 595 for ( next = src; *next && (*next != '/') && (*next != '\\'); next++ ); 596 597 for ( ptr = src, dot = NULL; ptr < next; ptr++ ) 598 if ( *ptr == '.' ) 599 { 600 dot = ptr; /* remember last dot */ 601 *ptr = '_'; 602 } 603 604 if ( dot == NULL ) 605 for ( ptr = src; ptr < next; ptr++ ) 606 if ( *ptr == '_' ) 607 dot = ptr; /* remember last _ as if it were a dot */ 608 609 if ( dot && (dot > src) && 610 ((next - dot <= 4) || 611 ((next - src > 8) && (dot - src > 3))) ) 612 { 613 if ( dot ) 614 *dot = '.'; 615 616 for ( ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++ ) 617 *dst++ = *ptr; 618 619 for ( ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++ ) 620 *dst++ = *ptr; 621 } 622 else 623 { 624 if ( dot && (next - src == 1) ) 625 *dot = '.'; /* special case: "." as a path component */ 626 627 for ( ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++ ) 628 *dst++ = *ptr; 629 } 630 631 *dst++ = *next; /* either '/' or 0 */ 632 633 if ( *next ) 634 { 635 src = next + 1; 636 637 if ( *src == 0 ) /* handle trailing '/' on dirs ! */ 638 *dst = 0; 639 } 640 else 641 break; 642 } 643 644 for ( src = start; *src != 0; ++src ) 645 if ( (strchr(invalid, *src) != NULL) || (*src == ' ') ) 646 *src = '_'; 647} 648 649char *GetLongPathEA(char *name) 650{ 651 return(NULL); /* volunteers ? */ 652} 653 654#ifdef UNICODE_SUPPORT 655wchar_t *GetLongPathEAW(wchar_t *name) 656{ 657 return(NULL); /* volunteers ? */ 658} 659#endif 660 661 662int IsFileNameValid(x) 663char *x; 664{ 665 WIN32_FIND_DATA fd; 666 HANDLE h; 667#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 668 char *ansi_name = (char *)alloca(strlen(x) + 1); 669 670 OemToAnsi(x, ansi_name); 671 x = ansi_name; 672#endif 673 674 if ((h = FindFirstFile(x, &fd)) == INVALID_HANDLE_VALUE) 675 return FALSE; 676 FindClose(h); 677 return TRUE; 678} 679 680char *getVolumeLabel(drive, vtime, vmode, vutim) 681 int drive; /* drive name: 'A' .. 'Z' or '\0' for current drive */ 682 ulg *vtime; /* volume label creation time (DOS format) */ 683 ulg *vmode; /* volume label file mode */ 684 time_t *vutim;/* volume label creationtime (UNIX format) */ 685 686/* If a volume label exists for the given drive, return its name and 687 pretend to set its time and mode. The returned name is static data. */ 688{ 689 char rootpath[4]; 690 static char vol[14]; 691 DWORD fnlen, flags; 692 693 *vmode = A_ARCHIVE | A_LABEL; /* this is what msdos returns */ 694 *vtime = dostime(1980, 1, 1, 0, 0, 0); /* no true date info available */ 695 *vutim = dos2unixtime(*vtime); 696 strcpy(rootpath, "x:\\"); 697 rootpath[0] = (char)drive; 698 if (GetVolumeInformation(drive ? rootpath : NULL, vol, 13, NULL, 699 &fnlen, &flags, NULL, 0)) 700#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 701 return (AnsiToOem(vol, vol), vol); 702#else 703 return vol; 704#endif 705 else 706 return NULL; 707} 708 709#endif /* !UTIL */ 710 711 712 713int ZipIsWinNT(void) /* returns TRUE if real NT, FALSE if Win95 or Win32s */ 714{ 715 static DWORD g_PlatformId = 0xFFFFFFFF; /* saved platform indicator */ 716 717 if (g_PlatformId == 0xFFFFFFFF) { 718 /* note: GetVersionEx() doesn't exist on WinNT 3.1 */ 719 if (GetVersion() < 0x80000000) 720 g_PlatformId = TRUE; 721 else 722 g_PlatformId = FALSE; 723 } 724 return (int)g_PlatformId; 725} 726 727 728#ifndef UTIL 729#ifdef __WATCOMC__ 730# include <io.h> 731# define _get_osfhandle _os_handle 732/* gaah -- Watcom's docs claim that _get_osfhandle exists, but it doesn't. */ 733#endif 734 735#ifdef HAVE_FSEEKABLE 736/* 737 * return TRUE if file is seekable 738 */ 739int fseekable(fp) 740FILE *fp; 741{ 742 return GetFileType((HANDLE)_get_osfhandle(fileno(fp))) == FILE_TYPE_DISK; 743} 744#endif /* HAVE_FSEEKABLE */ 745#endif /* !UTIL */ 746 747 748#if 0 /* seems to be never used; try it out... */ 749char *StringLower(char *szArg) 750{ 751 char *szPtr; 752/* unsigned char *szPtr; */ 753 for ( szPtr = szArg; *szPtr; szPtr++ ) 754 *szPtr = lower[*szPtr]; 755 return szArg; 756} 757#endif /* never */ 758 759 760 761#ifdef W32_STAT_BANDAID 762 763/* All currently known variants of WIN32 operating systems (Windows 95/98, 764 * WinNT 3.x, 4.0, 5.0) have a nasty bug in the OS kernel concerning 765 * conversions between UTC and local time: In the time conversion functions 766 * of the Win32 API, the timezone offset (including seasonal daylight saving 767 * shift) between UTC and local time evaluation is erratically based on the 768 * current system time. The correct evaluation must determine the offset 769 * value as it {was/is/will be} for the actual time to be converted. 770 * 771 * The C runtime lib's stat() returns utc time-stamps so that 772 * localtime(timestamp) corresponds to the (potentially false) local 773 * time shown by the OS' system programs (Explorer, command shell dir, etc.) 774 * 775 * For the NTFS file system (and other filesystems that store time-stamps 776 * as UTC values), this results in st_mtime (, st_{c|a}time) fields which 777 * are not stable but vary according to the seasonal change of "daylight 778 * saving time in effect / not in effect". 779 * 780 * To achieve timestamp consistency of UTC (UT extra field) values in 781 * Zip archives, the Info-ZIP programs require work-around code for 782 * proper time handling in stat() (and other time handling routines). 783 */ 784/* stat() functions under Windows95 tend to fail for root directories. * 785 * Watcom and Borland, at least, are affected by this bug. Watcom made * 786 * a partial fix for 11.0 but still missed some cases. This substitute * 787 * detects the case and fills in reasonable values. Otherwise we get * 788 * effects like failure to extract to a root dir because it's not found. */ 789 790#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */ 791 int zstat_zipwin32(const char *path, z_stat *buf) 792#else 793 int zstat_zipwin32(const char *path, struct stat *buf) 794#endif 795{ 796# ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */ 797 if (!zstat(path, buf)) 798# else 799 if (!stat(path, buf)) 800# endif 801 { 802#ifdef NT_TZBUG_WORKAROUND 803 /* stat was successful, now redo the time-stamp fetches */ 804 int fs_uses_loctime = FSusesLocalTime(path); 805 HANDLE h; 806 FILETIME Modft, Accft, Creft; 807#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 808 char *ansi_path = (char *)alloca(strlen(path) + 1); 809 810 OemToAnsi(path, ansi_path); 811# define Ansi_Path ansi_path 812#else 813# define Ansi_Path path 814#endif 815 816 Trace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime)); 817 h = CreateFile(Ansi_Path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, 818 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 819 if (h != INVALID_HANDLE_VALUE) { 820 BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft); 821 CloseHandle(h); 822 823 if (ftOK) { 824 if (!fs_uses_loctime) { 825 /* On a filesystem that stores UTC timestamps, we refill 826 * the time fields of the struct stat buffer by directly 827 * using the UTC values as returned by the Win32 828 * GetFileTime() API call. 829 */ 830 FileTime2utime(&Modft, &(buf->st_mtime)); 831 if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0) 832 FileTime2utime(&Accft, &(buf->st_atime)); 833 else 834 buf->st_atime = buf->st_mtime; 835 if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0) 836 FileTime2utime(&Creft, &(buf->st_ctime)); 837 else 838 buf->st_ctime = buf->st_mtime; 839 Tracev((stdout,"NTFS, recalculated modtime %08lx\n", 840 buf->st_mtime)); 841 } else { 842 /* On VFAT and FAT-like filesystems, the FILETIME values 843 * are converted back to the stable local time before 844 * converting them to UTC unix time-stamps. 845 */ 846 VFatFileTime2utime(&Modft, &(buf->st_mtime)); 847 if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0) 848 VFatFileTime2utime(&Accft, &(buf->st_atime)); 849 else 850 buf->st_atime = buf->st_mtime; 851 if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0) 852 VFatFileTime2utime(&Creft, &(buf->st_ctime)); 853 else 854 buf->st_ctime = buf->st_mtime; 855 Tracev((stdout, "VFAT, recalculated modtime %08lx\n", 856 buf->st_mtime)); 857 } 858 } 859 } 860# undef Ansi_Path 861#endif /* NT_TZBUG_WORKAROUND */ 862 return 0; 863 } 864#ifdef W32_STATROOT_FIX 865 else 866 { 867 DWORD flags; 868#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 869 char *ansi_path = (char *)alloca(strlen(path) + 1); 870 871 OemToAnsi(path, ansi_path); 872# define Ansi_Path ansi_path 873#else 874# define Ansi_Path path 875#endif 876 877 flags = GetFileAttributes(Ansi_Path); 878 if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) { 879 Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n", 880 path)); 881#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */ 882 memset(buf, 0, sizeof(z_stat)); 883#else 884 memset(buf, 0, sizeof(struct stat)); 885#endif 886 buf->st_atime = buf->st_ctime = buf->st_mtime = 887 dos2unixtime(DOSTIME_MINIMUM); 888 /* !!! you MUST NOT add a cast to the type of "st_mode" here; 889 * !!! different compilers do not agree on the "st_mode" size! 890 * !!! (And, some compiler may not declare the "mode_t" type 891 * !!! identifier, so you cannot use it, either.) 892 */ 893 buf->st_mode = S_IFDIR | S_IREAD | 894 ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE); 895 return 0; 896 } /* assumes: stat() won't fail on non-dirs without good reason */ 897# undef Ansi_Path 898 } 899#endif /* W32_STATROOT_FIX */ 900 return -1; 901} 902 903 904# ifdef UNICODE_SUPPORT 905 906int zstat_zipwin32w(const wchar_t *pathw, zw_stat *buf) 907{ 908 if (!zwstat(pathw, buf)) 909 { 910#ifdef NT_TZBUG_WORKAROUND 911 /* stat was successful, now redo the time-stamp fetches */ 912 int fs_uses_loctime = FSusesLocalTimeW(pathw); 913 HANDLE h; 914 FILETIME Modft, Accft, Creft; 915#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 916 char *ansi_path = (char *)alloca(strlen(pathw) + 1); 917 918 OemToAnsi(path, ansi_path); 919# define Ansi_Path ansi_path 920#else 921# define Ansi_Path pathw 922#endif 923 924 Trace((stdout, "stat(%s) finds modtime %08lx\n", pathw, buf->st_mtime)); 925 h = CreateFileW(Ansi_Path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, 926 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 927 if (h != INVALID_HANDLE_VALUE) { 928 BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft); 929 CloseHandle(h); 930 931 if (ftOK) { 932 if (!fs_uses_loctime) { 933 /* On a filesystem that stores UTC timestamps, we refill 934 * the time fields of the struct stat buffer by directly 935 * using the UTC values as returned by the Win32 936 * GetFileTime() API call. 937 */ 938 FileTime2utime(&Modft, &(buf->st_mtime)); 939 if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0) 940 FileTime2utime(&Accft, &(buf->st_atime)); 941 else 942 buf->st_atime = buf->st_mtime; 943 if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0) 944 FileTime2utime(&Creft, &(buf->st_ctime)); 945 else 946 buf->st_ctime = buf->st_mtime; 947 Tracev((stdout,"NTFS, recalculated modtime %08lx\n", 948 buf->st_mtime)); 949 } else { 950 /* On VFAT and FAT-like filesystems, the FILETIME values 951 * are converted back to the stable local time before 952 * converting them to UTC unix time-stamps. 953 */ 954 VFatFileTime2utime(&Modft, &(buf->st_mtime)); 955 if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0) 956 VFatFileTime2utime(&Accft, &(buf->st_atime)); 957 else 958 buf->st_atime = buf->st_mtime; 959 if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0) 960 VFatFileTime2utime(&Creft, &(buf->st_ctime)); 961 else 962 buf->st_ctime = buf->st_mtime; 963 Tracev((stdout, "VFAT, recalculated modtime %08lx\n", 964 buf->st_mtime)); 965 } 966 } 967 } 968# undef Ansi_Path 969#endif /* NT_TZBUG_WORKAROUND */ 970 return 0; 971 } 972#ifdef W32_STATROOT_FIX 973 else 974 { 975 DWORD flags; 976#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */ 977 char *ansi_path = (char *)alloca(strlen(pathw) + 1); 978 979 OemToAnsi(path, ansi_path); 980# define Ansi_Path ansi_path 981#else 982# define Ansi_Path pathw 983#endif 984 985 flags = GetFileAttributesW(Ansi_Path); 986 if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) { 987 Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n", 988 pathw)); 989#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */ 990 memset(buf, 0, sizeof(z_stat)); 991#else 992 memset(buf, 0, sizeof(struct stat)); 993#endif 994 buf->st_atime = buf->st_ctime = buf->st_mtime = 995 dos2unixtime(DOSTIME_MINIMUM); 996 /* !!! you MUST NOT add a cast to the type of "st_mode" here; 997 * !!! different compilers do not agree on the "st_mode" size! 998 * !!! (And, some compiler may not declare the "mode_t" type 999 * !!! identifier, so you cannot use it, either.) 1000 */ 1001 buf->st_mode = S_IFDIR | S_IREAD | 1002 ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE); 1003 return 0; 1004 } /* assumes: stat() won't fail on non-dirs without good reason */ 1005# undef Ansi_Path 1006 } 1007#endif /* W32_STATROOT_FIX */ 1008 return -1; 1009} 1010 1011# endif 1012 1013 1014#endif /* W32_STAT_BANDAID */ 1015 1016 1017 1018#ifdef W32_USE_IZ_TIMEZONE 1019#include "timezone.h" 1020#define SECSPERMIN 60 1021#define MINSPERHOUR 60 1022#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) 1023static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule); 1024 1025static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule) 1026{ 1027 if (lpw32tm->wYear != 0) { 1028 ptrule->r_type = JULIAN_DAY; 1029 ptrule->r_day = ydays[lpw32tm->wMonth - 1] + lpw32tm->wDay; 1030 } else { 1031 ptrule->r_type = MONTH_NTH_DAY_OF_WEEK; 1032 ptrule->r_mon = lpw32tm->wMonth; 1033 ptrule->r_day = lpw32tm->wDayOfWeek; 1034 ptrule->r_week = lpw32tm->wDay; 1035 } 1036 ptrule->r_time = (long)lpw32tm->wHour * SECSPERHOUR + 1037 (long)(lpw32tm->wMinute * SECSPERMIN) + 1038 (long)lpw32tm->wSecond; 1039} 1040 1041int GetPlatformLocalTimezone(register struct state * ZCONST sp, 1042 void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res, 1043 ZCONST struct rule * ZCONST start, 1044 ZCONST struct rule * ZCONST end)) 1045{ 1046 TIME_ZONE_INFORMATION tzinfo; 1047 DWORD res; 1048 1049 /* read current timezone settings from registry if TZ envvar missing */ 1050 res = GetTimeZoneInformation(&tzinfo); 1051 if (res != TIME_ZONE_ID_INVALID) 1052 { 1053 struct rule startrule, stoprule; 1054 1055 conv_to_rule(&(tzinfo.StandardDate), &stoprule); 1056 conv_to_rule(&(tzinfo.DaylightDate), &startrule); 1057 sp->timecnt = 0; 1058 sp->ttis[0].tt_abbrind = 0; 1059 if ((sp->charcnt = 1060 WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1, 1061 sp->chars, sizeof(sp->chars), NULL, NULL)) 1062 == 0) 1063 sp->chars[sp->charcnt++] = '\0'; 1064 sp->ttis[1].tt_abbrind = sp->charcnt; 1065 sp->charcnt += 1066 WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1, 1067 sp->chars + sp->charcnt, 1068 sizeof(sp->chars) - sp->charcnt, NULL, NULL); 1069 if ((sp->charcnt - sp->ttis[1].tt_abbrind) == 0) 1070 sp->chars[sp->charcnt++] = '\0'; 1071 sp->ttis[0].tt_gmtoff = - (tzinfo.Bias + tzinfo.StandardBias) 1072 * MINSPERHOUR; 1073 sp->ttis[1].tt_gmtoff = - (tzinfo.Bias + tzinfo.DaylightBias) 1074 * MINSPERHOUR; 1075 sp->ttis[0].tt_isdst = 0; 1076 sp->ttis[1].tt_isdst = 1; 1077 sp->typecnt = (startrule.r_mon == 0 && stoprule.r_mon == 0) ? 1 : 2; 1078 1079 if (sp->typecnt > 1) 1080 (*fill_tzstate_from_rules)(sp, &startrule, &stoprule); 1081 return TRUE; 1082 } 1083 return FALSE; 1084} 1085#endif /* W32_USE_IZ_TIMEZONE */ 1086 1087 1088 1089#ifndef WINDLL 1090/* This replacement getch() function was originally created for Watcom C 1091 * and then additionally used with CYGWIN. Since UnZip 5.4, all other Win32 1092 * ports apply this replacement rather that their supplied getch() (or 1093 * alike) function. There are problems with unabsorbed LF characters left 1094 * over in the keyboard buffer under Win95 (and 98) when ENTER was pressed. 1095 * (Under Win95, ENTER returns two(!!) characters: CR-LF.) This problem 1096 * does not appear when run on a WinNT console prompt! 1097 */ 1098 1099/* Watcom 10.6's getch() does not handle Alt+<digit><digit><digit>. */ 1100/* Note that if PASSWD_FROM_STDIN is defined, the file containing */ 1101/* the password must have a carriage return after the word, not a */ 1102/* Unix-style newline (linefeed only). This discards linefeeds. */ 1103 1104int getch_win32(void) 1105{ 1106 HANDLE stin; 1107 DWORD rc; 1108 unsigned char buf[2]; 1109 int ret = -1; 1110 DWORD odemode = ~(DWORD)0; 1111 1112# ifdef PASSWD_FROM_STDIN 1113 stin = GetStdHandle(STD_INPUT_HANDLE); 1114# else 1115 stin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, 1116 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 1117 if (stin == INVALID_HANDLE_VALUE) 1118 return -1; 1119# endif 1120 if (GetConsoleMode(stin, &odemode)) 1121 SetConsoleMode(stin, ENABLE_PROCESSED_INPUT); /* raw except ^C noticed */ 1122 if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1) 1123 ret = buf[0]; 1124 /* when the user hits return we get CR LF. We discard the LF, not the CR, 1125 * because when we call this for the first time after a previous input 1126 * such as the one for "replace foo? [y]es, ..." the LF may still be in 1127 * the input stream before whatever the user types at our prompt. */ 1128 if (ret == '\n') 1129 if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1) 1130 ret = buf[0]; 1131 if (odemode != ~(DWORD)0) 1132 SetConsoleMode(stin, odemode); 1133# ifndef PASSWD_FROM_STDIN 1134 CloseHandle(stin); 1135# endif 1136 return ret; 1137} 1138 1139 1140 1141/******************************/ 1142/* Function version_local() */ 1143/******************************/ 1144 1145void version_local() 1146{ 1147 static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s.\n\n"; 1148#if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DJGPP__)) 1149 char buf[80]; 1150#if (defined(_MSC_VER) && (_MSC_VER > 900)) 1151 char buf2[80]; 1152#endif 1153#endif 1154 1155/* Define the compiler name and version strings */ 1156#if defined(_MSC_VER) /* MSC == MSVC++, including the SDK compiler */ 1157 sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100); 1158# define COMPILER_NAME1 buf 1159# if (_MSC_VER == 800) 1160# define COMPILER_NAME2 "(Visual C++ v1.1)" 1161# elif (_MSC_VER == 850) 1162# define COMPILER_NAME2 "(Windows NT v3.5 SDK)" 1163# elif (_MSC_VER == 900) 1164# define COMPILER_NAME2 "(Visual C++ v2.x)" 1165# elif (_MSC_VER > 900) 1166 sprintf(buf2, "(Visual C++ v%d.%d)", _MSC_VER/100 - 6, _MSC_VER%100/10); 1167# define COMPILER_NAME2 buf2 1168# else 1169# define COMPILER_NAME2 "(bad version)" 1170# endif 1171#elif defined(__WATCOMC__) 1172# if (__WATCOMC__ % 10 > 0) 1173/* We do this silly test because __WATCOMC__ gives two digits for the */ 1174/* minor version, but Watcom packaging prefers to show only one digit. */ 1175 sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100, 1176 __WATCOMC__ % 100); 1177# else 1178 sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100, 1179 (__WATCOMC__ % 100) / 10); 1180# endif /* __WATCOMC__ % 10 > 0 */ 1181# define COMPILER_NAME1 buf 1182# define COMPILER_NAME2 "" 1183#elif defined(__TURBOC__) 1184# ifdef __BORLANDC__ 1185# define COMPILER_NAME1 "Borland C++" 1186# if (__BORLANDC__ == 0x0452) /* __BCPLUSPLUS__ = 0x0320 */ 1187# define COMPILER_NAME2 " 4.0 or 4.02" 1188# elif (__BORLANDC__ == 0x0460) /* __BCPLUSPLUS__ = 0x0340 */ 1189# define COMPILER_NAME2 " 4.5" 1190# elif (__BORLANDC__ == 0x0500) /* __TURBOC__ = 0x0500 */ 1191# define COMPILER_NAME2 " 5.0" 1192# elif (__BORLANDC__ == 0x0520) /* __TURBOC__ = 0x0520 */ 1193# define COMPILER_NAME2 " 5.2 (C++ Builder 1.0)" 1194# elif (__BORLANDC__ == 0x0530) /* __BCPLUSPLUS__ = 0x0530 */ 1195# define COMPILER_NAME2 " 5.3 (C++ Builder 3.0)" 1196# elif (__BORLANDC__ == 0x0540) /* __BCPLUSPLUS__ = 0x0540 */ 1197# define COMPILER_NAME2 " 5.4 (C++ Builder 4.0)" 1198# elif (__BORLANDC__ == 0x0550) /* __BCPLUSPLUS__ = 0x0550 */ 1199# define COMPILER_NAME2 " 5.5 (C++ Builder 5.0)" 1200# elif (__BORLANDC__ == 0x0551) /* __BCPLUSPLUS__ = 0x0551 */ 1201# define COMPILER_NAME2 " 5.5.1 (C++ Builder 5.0.1)" 1202# elif (__BORLANDC__ == 0x0560) /* __BCPLUSPLUS__ = 0x0560 */ 1203# define COMPILER_NAME2 " 5.6 (C++ Builder 6)" 1204# else 1205# define COMPILER_NAME2 " later than 5.6" 1206# endif 1207# else /* !__BORLANDC__ */ 1208# define COMPILER_NAME1 "Turbo C" 1209# if (__TURBOC__ >= 0x0400) /* Kevin: 3.0 -> 0x0401 */ 1210# define COMPILER_NAME2 "++ 3.0 or later" 1211# elif (__TURBOC__ == 0x0295) /* [661] vfy'd by Kevin */ 1212# define COMPILER_NAME2 "++ 1.0" 1213# endif 1214# endif /* __BORLANDC__ */ 1215#elif defined(__GNUC__) 1216# ifdef __RSXNT__ 1217# if (defined(__DJGPP__) && !defined(__EMX__)) 1218 sprintf(buf, "rsxnt(djgpp v%d.%02d) / gcc ", 1219 __DJGPP__, __DJGPP_MINOR__); 1220# define COMPILER_NAME1 buf 1221# elif defined(__DJGPP__) 1222 sprintf(buf, "rsxnt(emx+djgpp v%d.%02d) / gcc ", 1223 __DJGPP__, __DJGPP_MINOR__); 1224# define COMPILER_NAME1 buf 1225# elif (defined(__GO32__) && !defined(__EMX__)) 1226# define COMPILER_NAME1 "rsxnt(djgpp v1.x) / gcc " 1227# elif defined(__GO32__) 1228# define COMPILER_NAME1 "rsxnt(emx + djgpp v1.x) / gcc " 1229# elif defined(__EMX__) 1230# define COMPILER_NAME1 "rsxnt(emx)+gcc " 1231# else 1232# define COMPILER_NAME1 "rsxnt(unknown) / gcc " 1233# endif 1234# elif defined(__CYGWIN__) 1235# define COMPILER_NAME1 "Cygnus win32 / gcc " 1236# elif defined(__MINGW32__) 1237# define COMPILER_NAME1 "mingw32 / gcc " 1238# else 1239# define COMPILER_NAME1 "gcc " 1240# endif 1241# define COMPILER_NAME2 __VERSION__ 1242#elif defined(__LCC__) 1243# define COMPILER_NAME1 "LCC-Win32" 1244# define COMPILER_NAME2 "" 1245#else 1246# define COMPILER_NAME1 "unknown compiler (SDK?)" 1247# define COMPILER_NAME2 "" 1248#endif 1249 1250/* Define the compile date string */ 1251#ifdef __DATE__ 1252# define COMPILE_DATE " on " __DATE__ 1253#else 1254# define COMPILE_DATE "" 1255#endif 1256 1257 printf(CompiledWith, COMPILER_NAME1, COMPILER_NAME2, 1258 "\nWindows 9x / Windows NT", " (32-bit)", COMPILE_DATE); 1259 1260 return; 1261 1262} /* end function version_local() */ 1263#endif /* !WINDLL */ 1264 1265 1266/* --------------------------------------------------- */ 1267/* Large File Support 1268 * 1269 * Moved to Win32i64.c to avoid conflicts in same name functions 1270 * in WiZ using UnZip and Zip libraries. 1271 * 9/25/2003 1272 */ 1273 1274 1275/* --------------------------------------------------- */ 1276/* Unicode Support for Win32 1277 * 1278 */ 1279 1280#ifdef UNICODE_SUPPORT 1281# if 0 1282 1283 /* get the wide command line and convert to argvw */ 1284 /* windows ignores argv and gets argvw separately */ 1285 zchar **get_wide_argv(argv) 1286 char **argv; 1287 { 1288 int i; 1289 int argc; 1290 int size; 1291 zchar **argvw = NULL; 1292 zchar *commandline = NULL; 1293 zchar **a = NULL; 1294 1295 commandline = GetCommandLineW(); 1296 a = CommandLineToArgvW(commandline, &argc); 1297 1298 if (a == NULL) { 1299 /* failed */ 1300 ZIPERR(ZE_COMPERR, "get_wide_argv"); 1301 } 1302 1303 /* copy args so can use free_args() */ 1304 if ((argvw = (zchar **)malloc((argc + 1) * sizeof(zchar *))) == NULL) { 1305 ZIPERR(ZE_MEM, "get_wide_argv"); 1306 } 1307 for (i = 0; i < argc; i++) { 1308 size = zstrlen(a[i]) + 1; 1309 if ((argvw[i] = (zchar *)malloc(size * sizeof(zchar))) == NULL) { 1310 ZIPERR(ZE_MEM, "get_wide_argv"); 1311 } 1312 if ((argvw[i] = copy_zstring(a[i])) == NULL) { 1313 ZIPERR(ZE_MEM, "get_wide_argv"); 1314 } 1315 } 1316 argvw[argc] = L'\0'; 1317 1318 /* free original argvw */ 1319 LocalFree(a); 1320 1321 return argvw; 1322 } 1323# endif 1324 1325 1326/* convert wide character string to multi-byte character string */ 1327/* win32 version */ 1328char *wide_to_local_string(wide_string) 1329 zwchar *wide_string; 1330{ 1331 int i; 1332 wchar_t wc; 1333 int bytes_char; 1334 int default_used; 1335 int wsize = 0; 1336 int max_bytes = 9; 1337 char buf[9]; 1338 char *buffer = NULL; 1339 char *local_string = NULL; 1340 1341 if (wide_string == NULL) 1342 return NULL; 1343 1344 for (wsize = 0; wide_string[wsize]; wsize++) ; 1345 1346 if (max_bytes < MB_CUR_MAX) 1347 max_bytes = MB_CUR_MAX; 1348 1349 if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) { 1350 ZIPERR(ZE_MEM, "wide_to_local_string"); 1351 } 1352 1353 /* convert it */ 1354 buffer[0] = '\0'; 1355 for (i = 0; i < wsize; i++) { 1356 if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) { 1357 /* wchar_t probably 2 bytes */ 1358 /* could do surrogates if state_dependent and wctomb can do */ 1359 wc = zwchar_to_wchar_t_default_char; 1360 } else { 1361 wc = (wchar_t)wide_string[i]; 1362 } 1363 /* Unter some vendor's C-RTL, the Wide-to-MultiByte conversion functions 1364 * (like wctomb() et. al.) do not use the same codepage as the other 1365 * string arguments I/O functions (fopen, mkdir, rmdir etc.). 1366 * Therefore, we have to fall back to the underlying Win32-API call to 1367 * achieve a consistent behaviour for all supported compiler environments. 1368 * Failing RTLs are for example: 1369 * Borland (locale uses OEM-CP as default, but I/O functions expect ANSI 1370 * names) 1371 * Watcom (only "C" locale, wctomb() always uses OEM CP) 1372 * (in other words: all supported environments except the Microsoft RTLs) 1373 */ 1374 bytes_char = WideCharToMultiByte( 1375 CP_ACP, WC_COMPOSITECHECK, 1376 &wc, 1, 1377 (LPSTR)buf, sizeof(buf), 1378 NULL, &default_used); 1379 if (default_used) 1380 bytes_char = -1; 1381 if (unicode_escape_all) { 1382 if (bytes_char == 1 && (uch)buf[0] <= 0x7f) { 1383 /* ASCII */ 1384 strncat(buffer, buf, 1); 1385 } else { 1386 /* use escape for wide character */ 1387 char *e = wide_char_to_escape_string(wide_string[i]); 1388 strcat(buffer, e); 1389 free(e); 1390 } 1391 } else if (bytes_char > 0) { 1392 /* multi-byte char */ 1393 strncat(buffer, buf, bytes_char); 1394 } else { 1395 /* no MB for this wide */ 1396 if (use_wide_to_mb_default) { 1397 /* default character */ 1398 strcat(buffer, wide_to_mb_default_string); 1399 } else { 1400 /* use escape for wide character */ 1401 char *e = wide_char_to_escape_string(wide_string[i]); 1402 strcat(buffer, e); 1403 free(e); 1404 } 1405 } 1406 } 1407 if ((local_string = (char *)realloc(buffer, strlen(buffer) + 1)) == NULL) { 1408 free(buffer); 1409 ZIPERR(ZE_MEM, "wide_to_local_string"); 1410 } 1411 1412 return local_string; 1413} 1414 1415/* convert multi-byte character string to wide character string */ 1416/* win32 version */ 1417zwchar *local_to_wide_string(local_string) 1418 char *local_string; 1419{ 1420 int wsize; 1421 wchar_t *wc_string; 1422 zwchar *wide_string; 1423 1424 /* for now try to convert as string - fails if a bad char in string */ 1425 wsize = MultiByteToWideChar(CP_ACP, 0, 1426 local_string, -1, NULL, 0); 1427 if (wsize == (size_t)-1) { 1428 /* could not convert */ 1429 return NULL; 1430 } 1431 1432 /* convert it */ 1433 if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) { 1434 ZIPERR(ZE_MEM, "local_to_wide_string"); 1435 } 1436 wsize = MultiByteToWideChar(CP_ACP, 0, 1437 local_string, -1, 1438 wc_string, wsize + 1); 1439 wc_string[wsize] = (wchar_t) 0; 1440 1441 /* in case wchar_t is not zwchar */ 1442 if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) { 1443 free(wc_string); 1444 ZIPERR(ZE_MEM, "local_to_wide_string"); 1445 } 1446 for (wsize = 0; (wide_string[wsize] = (zwchar)wc_string[wsize]); wsize++) ; 1447 wide_string[wsize] = (zwchar)0; 1448 free(wc_string); 1449 1450 return wide_string; 1451} 1452#endif /* UNICODE_SUPPORT */ 1453 1454 1455/* 1456# if defined(UNICODE_SUPPORT) || defined(WIN32_OEM) 1457*/ 1458/* convert oem to ansi character string */ 1459char *oem_to_local_string(local_string, oem_string) 1460 char *local_string; 1461 char *oem_string; 1462{ 1463 /* convert OEM to ANSI character set */ 1464 OemToChar(oem_string, local_string); 1465 1466 return local_string; 1467} 1468/* 1469# endif 1470*/ 1471 1472 1473/* 1474#if defined(UNICODE_SUPPORT) || defined(WIN32_OEM) 1475*/ 1476/* convert local to oem character string */ 1477char *local_to_oem_string(oem_string, local_string) 1478 char *oem_string; 1479 char *local_string; 1480{ 1481 /* convert to OEM display character set */ 1482 CharToOem(local_string, oem_string); 1483 return oem_string; 1484} 1485/* 1486#endif 1487*/ 1488 1489