Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.   Copyright (c) 1990-2003 Info-ZIP.  All rights reserved.
  3.  
  4.   See the accompanying file LICENSE, version 2000-Apr-09 or later
  5.   (the contents of which are also included in unzip.h) for terms of use.
  6.   If, for some reason, all these files are missing, the Info-ZIP license
  7.   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
  8. */
  9. //******************************************************************************
  10. //
  11. // File:        WINCE.CPP
  12. //
  13. // Description: This file implements all the Win32 APIs and C runtime functions
  14. //              that the Info-ZIP code calls, but are not implemented natively
  15. //              on Windows CE.
  16. //
  17. // Copyright:   All the source files for Pocket UnZip, except for components
  18. //              written by the Info-ZIP group, are copyrighted 1997 by Steve P.
  19. //              Miller.  The product "Pocket UnZip" itself is property of the
  20. //              author and cannot be altered in any way without written consent
  21. //              from Steve P. Miller.
  22. //
  23. // Disclaimer:  All project files are provided "as is" with no guarantee of
  24. //              their correctness.  The authors are not liable for any outcome
  25. //              that is the result of using this source.  The source for Pocket
  26. //              UnZip has been placed in the public domain to help provide an
  27. //              understanding of its implementation.  You are hereby granted
  28. //              full permission to use this source in any way you wish, except
  29. //              to alter Pocket UnZip itself.  For comments, suggestions, and
  30. //              bug reports, please write to stevemil@pobox.com.
  31. //
  32. // Functions:   DebugOut
  33. //              chmod
  34. //              close
  35. //              isatty
  36. //              lseek
  37. //              open
  38. //              read
  39. //              setmode
  40. //              unlink
  41. //              fflush
  42. //              fgets
  43. //              fileno
  44. //              fopen
  45. //              fprintf
  46. //              fclose
  47. //              putc
  48. //              sprintf
  49. //              _stricmp
  50. //              _strupr
  51. //              strrchr                 (non-_MBCS only)
  52. //              isupper
  53. //              stat
  54. //              localtime
  55. //
  56. // Internal helper functions:
  57. //              SafeGetTimeZoneInformation
  58. //              GetTransitionTimeT
  59. //              IsDST
  60. //
  61. //
  62. // Date      Name          History
  63. // --------  ------------  -----------------------------------------------------
  64. // 02/01/97  Steve Miller  Created (Version 1.0 using Info-ZIP UnZip 5.30)
  65. //
  66. //******************************************************************************
  67.  
  68.  
  69. extern "C" {
  70. #define __WINCE_CPP
  71. #define UNZIP_INTERNAL
  72. #include "unzip.h"
  73. }
  74. #include <tchar.h> // Must be outside of extern "C" block
  75.  
  76.  
  77. //******************************************************************************
  78. //***** For all platforms - Our debug output function
  79. //******************************************************************************
  80.  
  81. #ifdef DEBUG // RETAIL version is __inline and does not generate any code.
  82.  
  83. void DebugOut(LPCTSTR szFormat, ...) {
  84.    TCHAR szBuffer[512] = TEXT("PUNZIP: ");
  85.  
  86.    va_list pArgs;
  87.    va_start(pArgs, szFormat);
  88.    _vsntprintf(szBuffer + 8, countof(szBuffer) - 10, szFormat, pArgs);
  89.    va_end(pArgs);
  90.  
  91.    TCHAR *psz = szBuffer;
  92.    while (psz = _tcschr(psz, TEXT('\n'))) {
  93.       *psz = TEXT('|');
  94.    }
  95.    psz = szBuffer;
  96.    while (psz = _tcschr(psz, TEXT('\r'))) {
  97.       *psz = TEXT('|');
  98.    }
  99.  
  100.    _tcscat(szBuffer, TEXT("\r\n"));
  101.  
  102.    OutputDebugString(szBuffer);
  103. }
  104.  
  105. #endif // DEBUG
  106.  
  107.  
  108. //******************************************************************************
  109. //***** Windows CE Native
  110. //******************************************************************************
  111.  
  112. #if defined(_WIN32_WCE)
  113.  
  114. //******************************************************************************
  115. //***** Local Function Prototyopes
  116. //******************************************************************************
  117.  
  118. static void SafeGetTimeZoneInformation(TIME_ZONE_INFORMATION *ptzi);
  119. static time_t GetTransitionTimeT(TIME_ZONE_INFORMATION *ptzi,
  120.                                  int year, BOOL fStartDST);
  121. static BOOL IsDST(TIME_ZONE_INFORMATION *ptzi, time_t localTime);
  122.  
  123. //******************************************************************************
  124. //***** IO.H functions
  125. //******************************************************************************
  126.  
  127. //-- Called from fileio.c
  128. int __cdecl chmod(const char *filename, int pmode) {
  129.    // Called before unlink() to delete read-only files.
  130.  
  131.    DWORD dwAttribs = (pmode & _S_IWRITE) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_READONLY;
  132.  
  133.    TCHAR szPath[_MAX_PATH];
  134.    MBSTOTSTR(szPath, filename, countof(szPath));
  135.    return (SetFileAttributes(szPath, dwAttribs) ? 0 : -1);
  136. }
  137.  
  138. //******************************************************************************
  139. //-- Called from process.c
  140. int __cdecl close(int handle) {
  141.    return (CloseHandle((HANDLE)handle) ? 0 : -1);
  142. }
  143.  
  144. //******************************************************************************
  145. //-- Called from fileio.c
  146. int __cdecl isatty(int handle) {
  147.    // returns TRUE if handle is a terminal, console, printer, or serial port
  148.    // called with 1 (stdout) and 2 (stderr)
  149.    return 0;
  150. }
  151.  
  152. //******************************************************************************
  153. //-- Called from extract.c, fileio.c, process.c
  154. long __cdecl lseek(int handle, long offset, int origin) {
  155.    // SEEK_SET, SEEK_CUR, SEEK_END are equal to FILE_BEGIN, FILE_CURRENT, FILE_END
  156.    return SetFilePointer((HANDLE)handle, offset, NULL, origin);
  157. }
  158.  
  159. //******************************************************************************
  160. //-- Called from fileio.c
  161. int __cdecl open(const char *filename, int oflags, ...) {
  162.  
  163.    // The Info-Zip code currently only opens existing ZIP files for read
  164.    // using open().
  165.  
  166.    DWORD dwAccess = 0;
  167.    DWORD dwCreate = 0;
  168.  
  169.    switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
  170.       case _O_RDONLY:
  171.          dwAccess = GENERIC_READ;
  172.          break;
  173.       case _O_WRONLY:
  174.          dwAccess = GENERIC_WRITE;
  175.          break;
  176.       case _O_RDWR:
  177.          dwAccess = GENERIC_READ | GENERIC_WRITE;
  178.          break;
  179.    }
  180.    switch (oflags & (O_CREAT | O_TRUNC)) {
  181.       case _O_CREAT:
  182.          dwCreate = OPEN_ALWAYS;
  183.          break;
  184.       case _O_CREAT | _O_TRUNC:
  185.          dwCreate = CREATE_ALWAYS;
  186.          break;
  187.       default:
  188.          dwCreate = OPEN_EXISTING;
  189.          break;
  190.    }
  191.  
  192.    TCHAR szPath[_MAX_PATH];
  193.    MBSTOTSTR(szPath, filename, countof(szPath));
  194.    HANDLE hFile = CreateFile(szPath, dwAccess,
  195.                              FILE_SHARE_READ | FILE_SHARE_WRITE,
  196.                              NULL, dwCreate, FILE_ATTRIBUTE_NORMAL, NULL);
  197.    if ((hFile != INVALID_HANDLE_VALUE) && ((oflags & O_APPEND) == O_APPEND)) {
  198.       SetFilePointer(hFile, 0, NULL, FILE_END);
  199.    }
  200.    return ((hFile == INVALID_HANDLE_VALUE) ? -1 : (int)hFile);
  201. }
  202.  
  203. //******************************************************************************
  204. //-- Called from extract.c, fileio.c, process.c
  205. int __cdecl read(int handle, void *buffer, unsigned int count) {
  206.    DWORD dwRead = 0;
  207.    return (ReadFile((HANDLE)handle, buffer, count, &dwRead, NULL) ? dwRead : -1);
  208. }
  209.  
  210. #if _WIN32_WCE < 211
  211. //******************************************************************************
  212. //-- Called from extract.c
  213. int __cdecl setmode(int handle, int mode) {
  214.    //TEXT/BINARY translation - currently always called with O_BINARY.
  215.    return O_BINARY;
  216. }
  217. #endif
  218.  
  219. //******************************************************************************
  220. //-- Called from fileio.c
  221. int __cdecl unlink(const char *filename) {
  222.  
  223.    // Called to delete files before an extract overwrite.
  224.  
  225.    TCHAR szPath[_MAX_PATH];
  226.    MBSTOTSTR(szPath, filename, countof(szPath));
  227.    return (DeleteFile(szPath) ? 0: -1);
  228. }
  229.  
  230. //******************************************************************************
  231. //***** STDIO.H functions
  232. //******************************************************************************
  233. #if _WIN32_WCE < 211
  234. // Old versions of Win CE prior to 2.11 do not support stdio library functions.
  235. // We provide simplyfied replacements that are more or less copies of the
  236. // UNIX style low level I/O API functions. Only unbuffered I/O in binary mode
  237. // is supported.
  238. //-- Called from fileio.c
  239. int __cdecl fflush(FILE *stream) {
  240.    return (FlushFileBuffers((HANDLE)stream) ? 0 : EOF);
  241. }
  242.  
  243. //******************************************************************************
  244. //-- Called from extract.c
  245. char * __cdecl fgets(char *string, int n, FILE *stream) {
  246.    // stream always equals "stdin" and fgets() should never be called.
  247.    DebugOut(TEXT("WARNING: fgets(0x%08X, %d, %08X) called."), string, n, stream);
  248.    return NULL;
  249. }
  250.  
  251. //******************************************************************************
  252. //-- Called from extract.c
  253. int __cdecl fileno(FILE *stream) {
  254.    return (int)stream;
  255. }
  256.  
  257. //******************************************************************************
  258. //-- Called from fileio.c
  259. FILE * __cdecl fopen(const char *filename, const char *mode) {
  260.  
  261.    // fopen() is used to create all extracted files.
  262.  
  263.    DWORD dwAccess = 0;
  264.    DWORD dwCreate = 0;
  265.    BOOL  fAppend  = FALSE;
  266.  
  267.    if (strstr(mode, "r+")) {
  268.       dwAccess = GENERIC_READ | GENERIC_WRITE;
  269.       dwCreate = OPEN_EXISTING;
  270.    } else if (strstr(mode, "w+")) {
  271.       dwAccess = GENERIC_READ | GENERIC_WRITE;
  272.       dwCreate = CREATE_ALWAYS;
  273.    } else if (strstr(mode, "a+")) {
  274.       dwAccess = GENERIC_READ | GENERIC_WRITE;
  275.       dwCreate = OPEN_ALWAYS;
  276.       fAppend = TRUE;
  277.    } else if (strstr(mode, "r")) {
  278.       dwAccess = GENERIC_READ;
  279.       dwCreate = OPEN_EXISTING;
  280.    } else if (strstr(mode, "w")) {
  281.       dwAccess = GENERIC_WRITE;
  282.       dwCreate = CREATE_ALWAYS;
  283.    } else if (strstr(mode, "a")) {
  284.       dwAccess = GENERIC_WRITE;
  285.       dwCreate = OPEN_ALWAYS;
  286.       fAppend  = TRUE;
  287.    }
  288.  
  289.    TCHAR szPath[_MAX_PATH];
  290.    MBSTOTSTR(szPath, filename, countof(szPath));
  291.    HANDLE hFile = CreateFile(szPath, dwAccess,
  292.                              FILE_SHARE_READ | FILE_SHARE_WRITE,
  293.                              NULL, dwCreate, FILE_ATTRIBUTE_NORMAL, NULL);
  294.  
  295.    if (hFile == INVALID_HANDLE_VALUE) {
  296.       return NULL;
  297.    }
  298.  
  299.    if (fAppend) {
  300.       SetFilePointer(hFile, 0, NULL, FILE_END);
  301.    }
  302.  
  303.    return (FILE*)hFile;
  304. }
  305.  
  306. //******************************************************************************
  307. //-- Called from many sources when compiled for DEBUG
  308. int __cdecl fprintf(FILE *stream, const char *format, ...) {
  309.  
  310.    // All standard output/error in Info-ZIP is handled through fprintf()
  311.    if ((stream == stdout) || (stream == stderr)) {
  312.       return 1;
  313.    }
  314.  
  315.    // "stream" always equals "stderr" or "stdout" - log error if we see otherwise.
  316. #ifdef UNICODE
  317.    DebugOut(TEXT("WARNING: fprintf(0x%08X, \"%S\", ...) called."), stream, format);
  318. #else
  319.    DebugOut(TEXT("WARNING: fprintf(0x%08X, \"%s\", ...) called."), stream, format);
  320. #endif
  321.    return 0;
  322. }
  323.  
  324. //******************************************************************************
  325. //-- Called from fileio.c
  326. int __cdecl fclose(FILE *stream) {
  327.    return (CloseHandle((HANDLE)stream) ? 0 : EOF);
  328. }
  329.  
  330. //******************************************************************************
  331. //-- Called from fileio.c
  332. int __cdecl putc(int c, FILE *stream) {
  333.    DebugOut(TEXT("WARNING: putc(%d, 0x%08X) called."), c, stream);
  334.    return 0;
  335. }
  336.  
  337. //******************************************************************************
  338. //-- Called from intrface.cpp, extract.c, fileio.c, list.c, process.c
  339. int __cdecl sprintf(char *buffer, const char *format, ...) {
  340.  
  341.    WCHAR wszBuffer[512], wszFormat[512];
  342.  
  343.    MBSTOTSTR(wszFormat, format, countof(wszFormat));
  344.    BOOL fPercent = FALSE;
  345.    for (WCHAR *pwsz = wszFormat; *pwsz; pwsz++) {
  346.       if (*pwsz == L'%') {
  347.          fPercent = !fPercent;
  348.       } else if (fPercent && (((*pwsz >= L'a') && (*pwsz <= L'z')) ||
  349.                               ((*pwsz >= L'A') && (*pwsz <= L'Z'))))
  350.       {
  351.          if (*pwsz == L's') {
  352.             *pwsz = L'S';
  353.          } else if (*pwsz == L'S') {
  354.             *pwsz = L's';
  355.          }
  356.          fPercent = FALSE;
  357.       }
  358.    }
  359.  
  360.    va_list pArgs;
  361.    va_start(pArgs, format);
  362.    _vsntprintf(wszBuffer, countof(wszBuffer), wszFormat, pArgs);
  363.    va_end(pArgs);
  364.  
  365.    TSTRTOMBS(buffer, wszBuffer, countof(wszBuffer));
  366.  
  367.    return 0;
  368. }
  369. #endif /* _WIN32_WCE < 211 */
  370.  
  371. #ifndef POCKET_UNZIP
  372. //******************************************************************************
  373. //-- Called from unzip.c
  374. void __cdecl perror(const char* errorText)
  375. {
  376.     OutputDebugString((LPCTSTR)errorText);
  377. }
  378. #endif // !POCKET_UNZIP
  379.  
  380. #ifdef USE_FWRITE
  381. //******************************************************************************
  382. //-- Called from fileio.c
  383. void __cdecl setbuf(FILE *, char *)
  384. {
  385.     // We are using fwrite and the call to setbuf was to set the stream
  386.     // unbuffered which is the default behaviour, we have nothing to do.
  387. }
  388. #endif // USE_FWRITE
  389.  
  390. //******************************************************************************
  391. //***** STDLIB.H functions
  392. //******************************************************************************
  393.  
  394. #ifdef _MBCS
  395. int __cdecl mblen(const char *mbc, size_t mbszmax)
  396. {
  397.     // very simple cooked-down version of mblen() without any error handling
  398.     // (Windows CE does not support multibyte charsets with a maximum char
  399.     // length > 2 bytes)
  400.     return (IsDBCSLeadByte((BYTE)*mbc) ? 2 : 1);
  401. }
  402. #endif /* _MBCS */
  403.  
  404. //******************************************************************************
  405. //***** STRING.H functions
  406. //******************************************************************************
  407.  
  408. //-- Called from winmain.cpp
  409. int __cdecl _stricmp(const char *string1, const char *string2) {
  410.    while (*string1 && ((*string1 | 0x20) == (*string2 | 0x20))) {
  411.       string1++;
  412.       string2++;
  413.    }
  414.    return (*string1 - *string2);
  415. }
  416.  
  417. //******************************************************************************
  418. //-- Called from intrface.cpp and winmain.cpp
  419. char* __cdecl _strupr(char *string) {
  420.    while (*string) {
  421.       if ((*string >= 'a') && (*string <= 'z')) {
  422.          *string -= 'a' - 'A';
  423.       }
  424.       string++;
  425.    }
  426.    return string;
  427. }
  428.  
  429. //******************************************************************************
  430. //-- Called from fileio.c ("open_input_file()")
  431. char* __cdecl strerror(int errnum) {
  432.    return "[errmsg not available]";
  433. }
  434.  
  435. #ifndef _MBCS
  436. //******************************************************************************
  437. //-- Called from winmain.cpp
  438. char* __cdecl strrchr(const char *string, int c) {
  439.  
  440.    // Walk to end of string.
  441.    for (char *p = (char*)string; *p; p++) {
  442.    }
  443.  
  444.    // Walk backwards looking for character.
  445.    for (p--; p >= string; p--) {
  446.       if ((int)*p == c) {
  447.          return p;
  448.       }
  449.    }
  450.  
  451.    return NULL;
  452. }
  453. #endif /* !_MBCS */
  454.  
  455. //******************************************************************************
  456. //***** CTYPE.H functions
  457. //******************************************************************************
  458.  
  459. #if _WIN32_WCE < 300
  460. int __cdecl isupper(int c) {
  461.    return ((c >= 'A') && (c <= 'Z'));
  462. }
  463. #endif
  464.  
  465. //******************************************************************************
  466. //***** STAT.H functions
  467. //******************************************************************************
  468.  
  469. //-- Called fileio.c, process.c, intrface.cpp
  470. int __cdecl stat(const char *path, struct stat *buffer) {
  471.  
  472.    // stat() is called on both the ZIP files and extracted files.
  473.  
  474.    // Clear our stat buffer to be safe.
  475.    ZeroMemory(buffer, sizeof(struct stat));
  476.  
  477.    // Find the file/direcotry and fill in a WIN32_FIND_DATA structure.
  478.    WIN32_FIND_DATA w32fd;
  479.    ZeroMemory(&w32fd, sizeof(w32fd));
  480.  
  481.    TCHAR szPath[_MAX_PATH];
  482.    MBSTOTSTR(szPath, path, countof(szPath));
  483.    HANDLE hFind = FindFirstFile(szPath, &w32fd);
  484.  
  485.    // Bail out now if we could not find the file/directory.
  486.    if (hFind == INVALID_HANDLE_VALUE) {
  487.       return -1;
  488.    }
  489.  
  490.    // Close the find.
  491.    FindClose(hFind);
  492.  
  493.    // Mode flags that are currently used: S_IWRITE, S_IFMT, S_IFDIR, S_IEXEC
  494.    if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  495.       buffer->st_mode = _S_IFDIR | _S_IREAD | _S_IEXEC;
  496.    } else {
  497.       buffer->st_mode = _S_IFREG | _S_IREAD;
  498.    }
  499.    if (!(w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
  500.       buffer->st_mode |= _S_IWRITE;
  501.    }
  502.  
  503.    // Store the file size.
  504.    buffer->st_size  = (_off_t)w32fd.nFileSizeLow;
  505.  
  506.    // Convert the modified FILETIME to a time_t and store it.
  507.    DWORDLONG dwl = *(DWORDLONG*)&w32fd.ftLastWriteTime;
  508.    buffer->st_mtime = (time_t)((dwl - (DWORDLONG)116444736000000000) / (DWORDLONG)10000000);
  509.  
  510.    return 0;
  511. }
  512.  
  513. //******************************************************************************
  514. //***** TIME.H functions
  515. //******************************************************************************
  516.  
  517. // Evaluates to TRUE if 'y' is a leap year, otherwise FALSE
  518. // #define IS_LEAP_YEAR(y) ((((y) % 4 == 0) && ((y) % 100 != 0)) || ((y) % 400 == 0))
  519.  
  520. // The macro below is a reduced version of the above macro.  It is valid for
  521. // years between 1901 and 2099 which easily includes all years representable
  522. // by the current implementation of time_t.
  523. #define IS_LEAP_YEAR(y) (((y) & 3) == 0)
  524.  
  525. #define BASE_DOW          4                  // 1/1/1970 was a Thursday.
  526. #define SECONDS_IN_A_DAY  (24L * 60L * 60L)  // Number of seconds in one day.
  527.  
  528. // Month to Year Day conversion array.
  529. int M2YD[] = {
  530.    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
  531. };
  532.  
  533. // Month to Leap Year Day conversion array.
  534. int M2LYD[] = {
  535.    0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
  536. };
  537.  
  538. //******************************************************************************
  539. //-- Called from list.c
  540. struct tm * __cdecl localtime(const time_t *timer) {
  541.  
  542.    // Return value for localtime().  Source currently never references
  543.    // more than one "tm" at a time, so the single return structure is ok.
  544.    static struct tm g_tm;
  545.    ZeroMemory(&g_tm, sizeof(g_tm));
  546.  
  547.    // Get our time zone information.
  548.    TIME_ZONE_INFORMATION tzi;
  549.    SafeGetTimeZoneInformation(&tzi);
  550.  
  551.    // Create a time_t that has been corrected for our time zone.
  552.    time_t localTime = *timer - (tzi.Bias * 60L);
  553.  
  554.    // Decide if value is in Daylight Savings Time.
  555.    if (g_tm.tm_isdst = (int)IsDST(&tzi, localTime)) {
  556.       localTime -= tzi.DaylightBias * 60L; // usually 60 minutes
  557.    } else {
  558.       localTime -= tzi.StandardBias * 60L; // usually  0 minutes
  559.    }
  560.  
  561.    // time_t   is a 32-bit value for the seconds since January 1, 1970
  562.    // FILETIME is a 64-bit value for the number of 100-nanosecond intervals
  563.    //          since January 1, 1601
  564.  
  565.    // Compute the FILETIME for the given local time.
  566.    DWORDLONG dwl = ((DWORDLONG)116444736000000000 +
  567.                    ((DWORDLONG)localTime * (DWORDLONG)10000000));
  568.    FILETIME ft = *(FILETIME*)&dwl;
  569.  
  570.    // Convert the FILETIME to a SYSTEMTIME.
  571.    SYSTEMTIME st;
  572.    ZeroMemory(&st, sizeof(st));
  573.    FileTimeToSystemTime(&ft, &st);
  574.  
  575.    // Finish filling in our "tm" structure.
  576.    g_tm.tm_sec  = (int)st.wSecond;
  577.    g_tm.tm_min  = (int)st.wMinute;
  578.    g_tm.tm_hour = (int)st.wHour;
  579.    g_tm.tm_mday = (int)st.wDay;
  580.    g_tm.tm_mon  = (int)st.wMonth - 1;
  581.    g_tm.tm_year = (int)st.wYear - 1900;
  582.  
  583.    return &g_tm;
  584. }
  585.  
  586. //******************************************************************************
  587. static void SafeGetTimeZoneInformation(TIME_ZONE_INFORMATION *ptzi)
  588. {
  589.  
  590.    ZeroMemory(ptzi, sizeof(TIME_ZONE_INFORMATION));
  591.  
  592.    // Ask the OS for the standard/daylight rules for the current time zone.
  593.    if ((GetTimeZoneInformation(ptzi) == 0xFFFFFFFF) ||
  594.        (ptzi->StandardDate.wMonth > 12) || (ptzi->DaylightDate.wMonth > 12))
  595.    {
  596.       // If the OS fails us, we default to the United States' rules.
  597.       ZeroMemory(ptzi, sizeof(TIME_ZONE_INFORMATION));
  598.       ptzi->StandardDate.wMonth =  10;  // October
  599.       ptzi->StandardDate.wDay   =   5;  // Last Sunday (DOW == 0)
  600.       ptzi->StandardDate.wHour  =   2;  // At 2:00 AM
  601.       ptzi->DaylightBias        = -60;  // One hour difference
  602.       ptzi->DaylightDate.wMonth =   4;  // April
  603.       ptzi->DaylightDate.wDay   =   1;  // First Sunday (DOW == 0)
  604.       ptzi->DaylightDate.wHour  =   2;  // At 2:00 AM
  605.    }
  606. }
  607.  
  608. //******************************************************************************
  609. static time_t GetTransitionTimeT(TIME_ZONE_INFORMATION *ptzi,
  610.                                  int year, BOOL fStartDST)
  611. {
  612.    // We only handle years within the range that time_t supports.  We need to
  613.    // handle the very end of 1969 since the local time could be up to 13 hours
  614.    // into the previous year.  In this case, our code will actually return a
  615.    // negative value, but it will be compared to another negative value and is
  616.    // handled correctly.  The same goes for the 13 hours past a the max time_t
  617.    // value of 0x7FFFFFFF (in the year 2038).  Again, these values are handled
  618.    // correctly as well.
  619.  
  620.    if ((year < 1969) || (year > 2038)) {
  621.       return (time_t)0;
  622.    }
  623.  
  624.    SYSTEMTIME *pst = fStartDST ? &ptzi->DaylightDate : &ptzi->StandardDate;
  625.  
  626.    // WORD wYear          Year (0000 == 0)
  627.    // WORD wMonth         Month (January == 1)
  628.    // WORD wDayOfWeek     Day of week (Sunday == 0)
  629.    // WORD wDay           Month day (1 - 31)
  630.    // WORD wHour          Hour (0 - 23)
  631.    // WORD wMinute        Minute (0 - 59)
  632.    // WORD wSecond        Second (0 - 59)
  633.    // WORD wMilliseconds  Milliseconds (0 - 999)
  634.  
  635.    // Compute the number of days since 1/1/1970 to the beginning of this year.
  636.    long daysToYear = ((year - 1970) * 365) // Tally up previous years.
  637.                    + ((year - 1969) >> 2); // Add few extra for the leap years.
  638.  
  639.    // Compute the number of days since the beginning of this year to the
  640.    // beginning of the month.  We will add to this value to get the actual
  641.    // year day.
  642.    long yearDay = IS_LEAP_YEAR(year) ? M2LYD[pst->wMonth - 1] :
  643.                                        M2YD [pst->wMonth - 1];
  644.  
  645.    // Check for day-in-month format.
  646.    if (pst->wYear == 0) {
  647.  
  648.       // Compute the week day for the first day of the month (Sunday == 0).
  649.       long monthDOW = (daysToYear + yearDay + BASE_DOW) % 7;
  650.  
  651.       // Add the day offset of the transition day to the year day.
  652.       if (monthDOW < pst->wDayOfWeek) {
  653.          yearDay += (pst->wDayOfWeek - monthDOW) + (pst->wDay - 1) * 7;
  654.       } else {
  655.          yearDay += (pst->wDayOfWeek - monthDOW) + pst->wDay * 7;
  656.       }
  657.  
  658.       // It is possible that we overshot the month, especially if pst->wDay
  659.       // is 5 (which means the last instance of the day in the month). Check
  660.       // if the year-day has exceeded the month and adjust accordingly.
  661.       if ((pst->wDay == 5) &&
  662.           (yearDay >= (IS_LEAP_YEAR(year) ? M2LYD[pst->wMonth] :
  663.                                             M2YD [pst->wMonth])))
  664.       {
  665.          yearDay -= 7;
  666.       }
  667.  
  668.    // If not day-in-month format, then we assume an absolute date.
  669.    } else {
  670.  
  671.       // Simply add the month day to the current year day.
  672.       yearDay += pst->wDay - 1;
  673.    }
  674.  
  675.    // Tally up all our days, hours, minutes, and seconds since 1970.
  676.    long seconds = ((SECONDS_IN_A_DAY * (daysToYear + yearDay)) +
  677.                    (3600L * (long)pst->wHour) +
  678.                    (60L * (long)pst->wMinute) +
  679.                    (long)pst->wSecond);
  680.  
  681.    // If we are checking for the end of DST, then we need to add the DST bias
  682.    // since we are in DST when we chack this time stamp.
  683.    if (!fStartDST) {
  684.       seconds += ptzi->DaylightBias * 60L;
  685.    }
  686.  
  687.    return (time_t)seconds;
  688. }
  689.  
  690. //******************************************************************************
  691. static BOOL IsDST(TIME_ZONE_INFORMATION *ptzi, time_t localTime) {
  692.  
  693.    // If either of the months is 0, then this usually means that the time zone
  694.    // does not use DST.  Unfortunately, Windows CE since it has a bug where it
  695.    // never really fills in these fields with the correct values, so it appears
  696.    // like we are never in DST.  This is supposed to be fixed in future releases,
  697.    // so hopefully this code will get some use then.
  698.    if ((ptzi->StandardDate.wMonth == 0) || (ptzi->DaylightDate.wMonth == 0)) {
  699.       return FALSE;
  700.    }
  701.  
  702.    // time_t   is a 32-bit value for the seconds since January 1, 1970
  703.    // FILETIME is a 64-bit value for the number of 100-nanosecond intervals
  704.    //          since January 1, 1601
  705.  
  706.    // Compute the FILETIME for the given local time.
  707.    DWORDLONG dwl = ((DWORDLONG)116444736000000000 +
  708.                    ((DWORDLONG)localTime * (DWORDLONG)10000000));
  709.    FILETIME ft = *(FILETIME*)&dwl;
  710.  
  711.    // Convert the FILETIME to a SYSTEMTIME.
  712.    SYSTEMTIME st;
  713.    ZeroMemory(&st, sizeof(st));
  714.    FileTimeToSystemTime(&ft, &st);
  715.  
  716.    // Get our start and end daylight savings times.
  717.    time_t timeStart = GetTransitionTimeT(ptzi, (int)st.wYear, TRUE);
  718.    time_t timeEnd   = GetTransitionTimeT(ptzi, (int)st.wYear, FALSE);
  719.  
  720.    // Check what hemisphere we are in.
  721.    if (timeStart < timeEnd) {
  722.  
  723.       // Northern hemisphere ordering.
  724.       return ((localTime >= timeStart) && (localTime < timeEnd));
  725.  
  726.    } else if (timeStart > timeEnd) {
  727.  
  728.       // Southern hemisphere ordering.
  729.       return ((localTime < timeEnd) || (localTime >= timeStart));
  730.    }
  731.  
  732.    // If timeStart equals timeEnd then this time zone does not support DST.
  733.    return FALSE;
  734. }
  735.  
  736. #endif // _WIN32_WCE
  737.  
  738. //******************************************************************************
  739. //***** Functions to supply timezone information from the Windows registry to
  740. //***** Info-ZIP's private RTL "localtime() et al." replacements in timezone.c.
  741. //******************************************************************************
  742.  
  743. //******************************************************************************
  744. // Copied from win32.c
  745. #ifdef W32_USE_IZ_TIMEZONE
  746. #include "timezone.h"
  747. #define SECSPERMIN      60
  748. #define MINSPERHOUR     60
  749. #define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
  750. static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule);
  751.  
  752. static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule)
  753. {
  754.     if (lpw32tm->wYear != 0) {
  755.         ptrule->r_type = JULIAN_DAY;
  756.         ptrule->r_day = ydays[lpw32tm->wMonth - 1] + lpw32tm->wDay;
  757.     } else {
  758.         ptrule->r_type = MONTH_NTH_DAY_OF_WEEK;
  759.         ptrule->r_mon = lpw32tm->wMonth;
  760.         ptrule->r_day = lpw32tm->wDayOfWeek;
  761.         ptrule->r_week = lpw32tm->wDay;
  762.     }
  763.     ptrule->r_time = (long)lpw32tm->wHour * SECSPERHOUR +
  764.                      (long)(lpw32tm->wMinute * SECSPERMIN) +
  765.                      (long)lpw32tm->wSecond;
  766. }
  767.  
  768. int GetPlatformLocalTimezone(register struct state * ZCONST sp,
  769.         void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
  770.                                         ZCONST struct rule * ZCONST start,
  771.                                         ZCONST struct rule * ZCONST end))
  772. {
  773.     TIME_ZONE_INFORMATION tzinfo;
  774.     DWORD res;
  775.  
  776.     /* read current timezone settings from registry if TZ envvar missing */
  777.     res = GetTimeZoneInformation(&tzinfo);
  778.     if (res != TIME_ZONE_ID_INVALID)
  779.     {
  780.         struct rule startrule, stoprule;
  781.  
  782.         conv_to_rule(&(tzinfo.StandardDate), &stoprule);
  783.         conv_to_rule(&(tzinfo.DaylightDate), &startrule);
  784.         sp->timecnt = 0;
  785.         sp->ttis[0].tt_abbrind = 0;
  786.         if ((sp->charcnt =
  787.              WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1,
  788.                                  sp->chars, sizeof(sp->chars), NULL, NULL))
  789.             == 0)
  790.             sp->chars[sp->charcnt++] = '\0';
  791.         sp->ttis[1].tt_abbrind = sp->charcnt;
  792.         sp->charcnt +=
  793.             WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1,
  794.                                 sp->chars + sp->charcnt,
  795.                                 sizeof(sp->chars) - sp->charcnt, NULL, NULL);
  796.         if ((sp->charcnt - sp->ttis[1].tt_abbrind) == 0)
  797.             sp->chars[sp->charcnt++] = '\0';
  798.         sp->ttis[0].tt_gmtoff = - (tzinfo.Bias + tzinfo.StandardBias)
  799.                                 * MINSPERHOUR;
  800.         sp->ttis[1].tt_gmtoff = - (tzinfo.Bias + tzinfo.DaylightBias)
  801.                                 * MINSPERHOUR;
  802.         sp->ttis[0].tt_isdst = 0;
  803.         sp->ttis[1].tt_isdst = 1;
  804.         sp->typecnt = (startrule.r_mon == 0 && stoprule.r_mon == 0) ? 1 : 2;
  805.  
  806.         if (sp->typecnt > 1)
  807.             (*fill_tzstate_from_rules)(sp, &startrule, &stoprule);
  808.         return TRUE;
  809.     }
  810.     return FALSE;
  811. }
  812. #endif /* W32_USE_IZ_TIMEZONE */
  813.