Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.   Copyright (c) 1990-2009 Info-ZIP.  All rights reserved.
  3.  
  4.   See the accompanying file LICENSE, version 2009-Jan-02 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:        INTRFACE.CPP
  12. //
  13. // Description: This module acts as the interface between the Info-ZIP code and
  14. //              our Windows code in WINMAIN.CPP.  We expose the needed
  15. //              functions to query a file list, test file(s), extract file(s),
  16. //              and display a zip file comment.  The windows code is never
  17. //              bothered with understanding the Globals structure "Uz_Globs".
  18. //
  19. //              This module also catches all the callbacks from the Info-ZIP
  20. //              code, cleans up the data provided in the callback, and then
  21. //              forwards the information to the appropriate function in the
  22. //              windows code.  These callbacks include status messages, file
  23. //              lists, comments, password prompt, and file overwrite prompts.
  24. //
  25. //              Finally, this module implements the few functions that the
  26. //              Info-ZIP code expects the port to implement. These functions are
  27. //              OS dependent and are mostly related to validating file names and
  28. //              directories, and setting file attributes and dates of saved files.
  29. //
  30. // Copyright:   All the source files for Pocket UnZip, except for components
  31. //              written by the Info-ZIP group, are copyrighted 1997 by Steve P.
  32. //              Miller.  As of June 1999, Steve P. Miller has agreed to apply
  33. //              the Info-ZIP License (see citation on top of this module)
  34. //              to his work.  See the contents of this License for terms
  35. //              and conditon of using the product "Pocket UnZip".
  36. //
  37. // Disclaimer:  All project files are provided "as is" with no guarantee of
  38. //              their correctness.  The authors are not liable for any outcome
  39. //              that is the result of using this source.  The source for Pocket
  40. //              UnZip has been placed in the public domain to help provide an
  41. //              understanding of its implementation.  You are hereby granted
  42. //              full permission to use this source in any way you wish, except
  43. //              to alter Pocket UnZip itself.  For comments, suggestions, and
  44. //              bug reports, please write to stevemil@pobox.com or the Info-ZIP
  45. //              mailing list Zip-Bugs@lists.wku.edu.
  46. //
  47. // Functions:   DoListFiles
  48. //              DoExtractOrTestFiles
  49. //              DoGetComment
  50. //              SetExtractToDirectory
  51. //              InitGlobals
  52. //              FreeGlobals
  53. //              ExtractOrTestFilesThread
  54. //              IsFileOrDirectory
  55. //              SmartCreateDirectory
  56. //              CheckForAbort2
  57. //              SetCurrentFile
  58. //              UzpMessagePrnt2
  59. //              UzpInput2
  60. //              UzpMorePause
  61. //              UzpPassword
  62. //              UzpReplace
  63. //              UzpSound
  64. //              SendAppMsg
  65. //              win_fprintf
  66. //              test_NT
  67. //              utimeToFileTime
  68. //              GetFileTimes
  69. //              IsOldFileSystem
  70. //              SetFileSize
  71. //              close_outfile
  72. //              do_wild
  73. //              mapattr
  74. //              mapname
  75. //              checkdir
  76. //              match
  77. //              iswild
  78. //              conv_to_rule
  79. //              GetPlatformLocalTimezone
  80. //              wide_to_local_string
  81. //
  82. //
  83. // Date      Name          History
  84. // --------  ------------  -----------------------------------------------------
  85. // 02/01/97  Steve Miller  Created (Version 1.0 using Info-ZIP UnZip 5.30)
  86. // 08/01/99  Johnny Lee, Christian Spieler, Steve Miller, and others
  87. //                         Adapted to UnZip 5.41 (Version 1.1)
  88. // 12/01/02  Chr. Spieler  Updated interface for UnZip 5.50
  89. // 02/23/05  Chr. Spieler  Modified and optimized utimeToFileTime() to support
  90. //                         the NO_W32TIMES_IZFIX compilation option
  91. // 11/01/09  Chr. Spieler  Added wide_to_local_string() conversion function
  92. //                         from win32.c, which is currently needed for the
  93. //                         new UTF-8 names support (until we manage to port
  94. //                         the complete UnZip code to native wide-char support).
  95. //
  96. //*****************************************************************************
  97.  
  98.  
  99. //*****************************************************************************
  100. // The following information and structure are here just for reference
  101. //*****************************************************************************
  102. //
  103. // The Windows CE version of Unzip builds with the following defines set:
  104. //
  105. //
  106. //    WIN32
  107. //    _WINDOWS
  108. //    UNICODE
  109. //    _UNICODE
  110. //    WIN32_LEAN_AND_MEAN
  111. //    STRICT
  112. //
  113. //    POCKET_UNZIP         (Main define - Always set)
  114. //
  115. //    UNZIP_INTERNAL
  116. //    WINDLL
  117. //    DLL
  118. //    REENTRANT
  119. //    USE_EF_UT_TIME
  120. //    NO_ZIPINFO
  121. //    NO_STDDEF_H
  122. //    NO_NTSD_EAS
  123. //
  124. //    USE_SMITH_CODE       (optional - See INSTALL document)
  125. //    LZW_CLEAN            (optional - See INSTALL document)
  126. //    NO_W32TIMES_IZFIX    (optional - See INSTALL document)
  127. //
  128. //    DEBUG                (When building for Debug)
  129. //    _DEBUG               (When building for Debug)
  130. //    NDEBUG               (When building for Retail)
  131. //    _NDEBUG              (When building for Retail)
  132. //
  133. //    _WIN32_WCE=100       (When building for Windows CE native)
  134. //
  135. //****************************************************************************/
  136.  
  137. extern "C" {
  138. #define __INTRFACE_CPP__
  139. #define UNZIP_INTERNAL
  140. #include "unzip.h"
  141. #include "crypt.h"     // Needed to pick up CRYPT define
  142. #include <commctrl.h>
  143. #include "intrface.h"
  144. #include "winmain.h"
  145.  
  146. #ifndef _WIN32_WCE
  147. #include <process.h>   // _beginthreadex() and _endthreadex()
  148. #endif
  149.  
  150. }
  151. #include <tchar.h> // Must be outside of extern "C" block
  152.  
  153. #ifdef POCKET_UNZIP
  154.  
  155. //******************************************************************************
  156. //***** "Local" Global Variables
  157. //******************************************************************************
  158.  
  159. static USERFUNCTIONS  g_uf;
  160. static EXTRACT_INFO  *g_pExtractInfo = NULL;
  161. static FILE_NODE     *g_pFileLast    = NULL;
  162. static CHAR           g_szExtractToDirectory[_MAX_PATH];
  163. static BOOL           g_fOutOfMemory;
  164.  
  165. //******************************************************************************
  166. //***** Local Function Prototypes
  167. //******************************************************************************
  168.  
  169. // Internal functions of the GUI interface.
  170. static Uz_Globs* InitGlobals(LPCSTR szZipFile);
  171. static void FreeGlobals(Uz_Globs *pG);
  172.  
  173. #ifdef _WIN32_WCE
  174. static DWORD WINAPI ExtractOrTestFilesThread(LPVOID lpv);
  175. #else
  176. static unsigned __stdcall ExtractOrTestFilesThread(void *lpv);
  177. #endif
  178.  
  179. static void SetCurrentFile(__GPRO);
  180.  
  181. #endif // POCKET_UNZIP
  182.  
  183. // Internal helper functions for the UnZip core.
  184. static int IsFileOrDirectory(LPCTSTR szPath);
  185. static BOOL SmartCreateDirectory(__GPRO__ LPCSTR szDirectory, BOOL *pNewDir);
  186. static void utimeToFileTime(time_t ut, FILETIME *pft, BOOL fOldFileSystem);
  187. static int GetFileTimes(Uz_Globs *pG, FILETIME *pftCreated,
  188.                         FILETIME *pftAccessed, FILETIME *pftModified);
  189.  
  190. // Check for FAT, VFAT, HPFS, etc.
  191. static BOOL IsOldFileSystem(char *szPath);
  192.  
  193. #ifdef POCKET_UNZIP
  194.  
  195. extern "C" {
  196.  
  197. // Local variants of callbacks from Info-ZIP code.
  198. // (These functions are not referenced by name outside this source module.)
  199. int UZ_EXP UzpMessagePrnt2(zvoid *pG, uch *buffer, ulg size, int flag);
  200. int UZ_EXP UzpInput2(zvoid *pG, uch *buffer, int *size, int flag);
  201. int UZ_EXP CheckForAbort2(zvoid *pG, int fnflag, ZCONST char *zfn,
  202.                           ZCONST char *efn, ZCONST zvoid *details);
  203. int WINAPI UzpReplace(LPSTR szFile, unsigned nbufsiz);
  204. void WINAPI UzpSound(void);
  205. #ifdef Z_UINT8_DEFINED
  206. void WINAPI SendAppMsg(z_uint8 uzSize, z_uint8 uzCompressedSize,
  207. #else
  208. void WINAPI SendAppMsg(ulg uzSize, ulg uzCompressedSize,
  209. #endif
  210.                        unsigned ratio,
  211.                        unsigned month, unsigned day, unsigned year,
  212.                        unsigned hour, unsigned minute, char uppercase,
  213.                        LPCSTR szPath, LPCSTR szMethod, ulg dwCRC,
  214.                        char chCrypt);
  215.  
  216. } // extern "C"
  217.  
  218.  
  219. //******************************************************************************
  220. //***** Our exposed interface functions to the Info-ZIP core
  221. //******************************************************************************
  222.  
  223. int DoListFiles(LPCSTR szZipFile) {
  224.  
  225.    int result;
  226.  
  227.    // Create our Globals struct and fill it in whith some default values.
  228.    Uz_Globs *pG = InitGlobals(szZipFile);
  229.    if (!pG) {
  230.       return PK_MEM;
  231.    }
  232.  
  233.    pG->UzO.vflag = 1; // verbosely: list directory (for WIN32 it is 0 or 1)
  234.    pG->process_all_files = TRUE; // improves speed
  235.  
  236.    g_pFileLast = NULL;
  237.    g_fOutOfMemory = FALSE;
  238.  
  239.    // We wrap some exception handling around the entire Info-ZIP engine to be
  240.    // safe.  Since we are running on a device with tight memory configurations,
  241.    // all sorts of problems can arise when we run out of memory.
  242.    __try {
  243.  
  244.       // Call the unzip routine.  We will catch the file information in a
  245.       // callback to SendAppMsg().
  246.       result = process_zipfiles(pG);
  247.  
  248.       // Make sure we didn't run out of memory in the process.
  249.       if (g_fOutOfMemory) {
  250.          result = PK_MEM;
  251.       }
  252.  
  253.    } __except(EXCEPTION_EXECUTE_HANDLER) {
  254.  
  255.       // Catch any exception here.
  256.       DebugOut(TEXT("Exception 0x%08X occurred in DoListFiles()"),
  257.                GetExceptionCode());
  258.       result = PK_EXCEPTION;
  259.    }
  260.  
  261.    g_pFileLast = NULL;
  262.  
  263.    // It is possible that the ZIP engine change the file name a bit (like adding
  264.    // a ".zip" if needed).  If so, we will pick up the new name.
  265.    if ((result != PK_EXCEPTION) && pG->zipfn && *pG->zipfn) {
  266.       strcpy(g_szZipFile, pG->zipfn);
  267.    }
  268.  
  269.    // Free our globals.
  270.    FreeGlobals(pG);
  271.  
  272.    return result;
  273. }
  274.  
  275. //******************************************************************************
  276. BOOL DoExtractOrTestFiles(LPCSTR szZipFile, EXTRACT_INFO *pei) {
  277.  
  278.    // WARNING!!!  This functions hands the EXTRACT_INFO structure of to a thread
  279.    // to perform the actual extraction/test.  When the thread is done, it will
  280.    // send a message to the progress dialog.  The calling function must not
  281.    // delete the EXTRACT_INFO structure until it receives the message.  Currently,
  282.    // this is not a problem for us since the structure lives on the stack of the
  283.    // calling thread.  The calling thread then displays a dialog that blocks the
  284.    // calling thread from clearing the stack until the dialog is dismissed, which
  285.    // occurs when the dialog receives the message.
  286.  
  287.    // Create our globals so we can store the file name.
  288.    Uz_Globs *pG = InitGlobals(szZipFile);
  289.    if (!pG) {
  290.       pei->result = PK_MEM;
  291.       SendMessage(g_hDlgProgress, WM_PRIVATE, MSG_OPERATION_COMPLETE, (LPARAM)pei);
  292.       return FALSE;
  293.    }
  294.  
  295.    // Store a global pointer to the Extract structure so it can be reached from
  296.    // our thread and callback functions.
  297.    g_pExtractInfo = pei;
  298.  
  299.    // Spawn our thread
  300.    DWORD dwThreadId;
  301.    HANDLE hThread;
  302.  
  303. #ifdef _WIN32_WCE
  304.  
  305.    // On CE, we use good old CreateThread() since the WinCE CRT does not
  306.    // allocate per-thread storage.
  307.    hThread = CreateThread(NULL, 0, ExtractOrTestFilesThread, pG, 0,
  308.                           &dwThreadId);
  309.  
  310. #else
  311.  
  312.    // On NT, we need use the CRT's thread function so that we don't leak any
  313.    // CRT allocated memory when the thread exits.
  314.    hThread = (HANDLE)_beginthreadex(NULL, 0, ExtractOrTestFilesThread, pG, 0,
  315.                                     (unsigned*)&dwThreadId);
  316.  
  317. #endif
  318.  
  319.    // Bail out if our thread failed to create.
  320.    if (!hThread) {
  321.  
  322.       DebugOut(TEXT("CreateThread() failed [%u]"), GetLastError());
  323.  
  324.       // Set our error as a memory error.
  325.       g_pExtractInfo->result = PK_MEM;
  326.  
  327.       // Free our globals.
  328.       FreeGlobals(pG);
  329.  
  330.       // Tell the progress dialog that we are done.
  331.       SendMessage(g_hDlgProgress, WM_PRIVATE, MSG_OPERATION_COMPLETE, (LPARAM)pei);
  332.  
  333.       g_pExtractInfo = NULL;
  334.       return FALSE;
  335.    }
  336.  
  337.    // Close our thread handle since we have no use for it.
  338.    CloseHandle(hThread);
  339.    return TRUE;
  340. }
  341.  
  342. //******************************************************************************
  343. int DoGetComment(LPCSTR szZipFile) {
  344.  
  345.    int result;
  346.  
  347.    // Create our Globals struct and fill it in with some default values.
  348.    Uz_Globs *pG = InitGlobals(szZipFile);
  349.    if (!pG) {
  350.       return PK_MEM;
  351.    }
  352.  
  353.    pG->UzO.zflag = TRUE; // display the zipfile comment
  354.  
  355.    // We wrap some exception handling around the entire Info-ZIP engine to be
  356.    // safe.  Since we are running on a device with tight memory configurations,
  357.    // all sorts of problems can arise when we run out of memory.
  358.    __try {
  359.  
  360.       // Call the unzip routine.  We will catch the comment string in a callback
  361.       // to win_fprintf().
  362.       result = process_zipfiles(pG);
  363.  
  364.    } __except(EXCEPTION_EXECUTE_HANDLER) {
  365.  
  366.       // Catch any exception here.
  367.       DebugOut(TEXT("Exception 0x%08X occurred in DoGetComment()"),
  368.                GetExceptionCode());
  369.       result = PK_EXCEPTION;
  370.    }
  371.  
  372.    // Free our globals.
  373.    FreeGlobals(pG);
  374.  
  375.    return result;
  376. }
  377.  
  378. //******************************************************************************
  379. BOOL SetExtractToDirectory(LPTSTR szDirectory) {
  380.  
  381.    BOOL fNeedToAddWack = FALSE;
  382.  
  383.    // Remove any trailing wack from the path.
  384.    int length = _tcslen(szDirectory);
  385.    if ((length > 0) && (szDirectory[length - 1] == TEXT('\\'))) {
  386.       szDirectory[--length] = TEXT('\0');
  387.       fNeedToAddWack = TRUE;
  388.    }
  389.  
  390. #ifndef _WIN32_WCE
  391.  
  392.    // Check to see if a root directory was specified.
  393.    if ((length == 2) && isalpha(szDirectory[0]) && (szDirectory[1] == ':')) {
  394.  
  395.       // If just a root is specified, we need to only verify the drive letter.
  396.       if (!(GetLogicalDrives() & (1 << (tolower(szDirectory[0]) - (int)'a')))) {
  397.  
  398.          // This drive does not exist.  Bail out with a failure.
  399.          return FALSE;
  400.       }
  401.  
  402.    } else
  403.  
  404. #endif
  405.  
  406.    // We only verify path if length is >0 since we know "\" is valid.
  407.    if (length > 0) {
  408.  
  409.       // Verify the the path exists and that it is a directory.
  410.       if (IsFileOrDirectory(szDirectory) != 2) {
  411.          return FALSE;
  412.       }
  413.    }
  414.  
  415.    // Store the directory for when we do an extract.
  416.    TSTRTOMBS(g_szExtractToDirectory, szDirectory, countof(g_szExtractToDirectory));
  417.  
  418.    // We always want a wack at the end of our path.
  419.    strcat(g_szExtractToDirectory, "\\");
  420.  
  421.    // Add the wack back to the end of the path.
  422.    if (fNeedToAddWack) {
  423.       _tcscat(szDirectory, TEXT("\\"));
  424.    }
  425.  
  426.    return TRUE;
  427. }
  428.  
  429. //******************************************************************************
  430. //***** Internal functions
  431. //******************************************************************************
  432.  
  433. static Uz_Globs* InitGlobals(LPCSTR szZipFile)
  434. {
  435.    // Create our global structure - pG
  436.    CONSTRUCTGLOBALS();
  437.  
  438.    // Bail out if we failed to allocate our Globals structure.
  439.    if (!pG) {
  440.       return NULL;
  441.    }
  442.  
  443.    // Clear our USERFUNCTIONS structure
  444.    ZeroMemory(&g_uf, sizeof(g_uf));
  445.  
  446.    // Initialize a global pointer to our USERFUNCTIONS structure that is
  447.    // used by WINMAIN.CPP to access it (without using the pG construction).
  448.    lpUserFunctions = &g_uf;
  449.  
  450.    // Store a global pointer to our USERFUNCTIONS structure in pG so that
  451.    // the generic Info-ZIP code LIST.C and PROCESS.C can access it.
  452.    pG->lpUserFunctions = &g_uf;
  453.  
  454.    // Fill in all our callback functions.
  455.    pG->message      = UzpMessagePrnt2;
  456.    pG->input        = UzpInput2;
  457.    pG->mpause       = UzpMorePause;
  458.    pG->statreportcb = CheckForAbort2;
  459.    pG->lpUserFunctions->replace                = UzpReplace;
  460.    pG->lpUserFunctions->sound                  = UzpSound;
  461.    pG->lpUserFunctions->SendApplicationMessage = SendAppMsg;
  462.    pG->lpUserFunctions->SendApplicationMessage_i32 = NULL;
  463.  
  464. #if CRYPT
  465.    pG->decr_passwd = UzpPassword;
  466. #endif
  467.  
  468.    // Match filenames case-sensitively.  We can do this since we can guarantee
  469.    // exact case because the user can only select files via our UI.
  470.    pG->UzO.C_flag = FALSE;
  471.  
  472.    // Allocate and store the ZIP file name in pG->zipfn
  473.    if (!(pG->zipfnPtr = new char[FILNAMSIZ])) {
  474.       FreeGlobals(pG);
  475.       return NULL;
  476.    }
  477.    pG->zipfn = pG->zipfnPtr;
  478.    strcpy(pG->zipfn, szZipFile);
  479.  
  480.    // Allocate and store the ZIP file name in pG->zipfn.  This needs to done
  481.    // so that do_wild() does not wind up clearing out the zip file name when
  482.    // it returns in process.c
  483.    if (!(pG->wildzipfnPtr = new char[FILNAMSIZ])) {
  484.       FreeGlobals(pG);
  485.       return NULL;
  486.    }
  487.    pG->wildzipfn = pG->wildzipfnPtr;
  488.    strcpy(pG->wildzipfn, szZipFile);
  489.  
  490.    return pG;
  491. }
  492.  
  493. //******************************************************************************
  494. static void FreeGlobals(Uz_Globs *pG)
  495. {
  496.    // Free our ZIP file name
  497.    if (pG->zipfnPtr) {
  498.       delete[] pG->zipfnPtr;
  499.       pG->zipfnPtr = pG->zipfn = NULL;
  500.    }
  501.  
  502.    // Free our wild name buffer
  503.    if (pG->wildzipfnPtr) {
  504.       delete[] pG->wildzipfnPtr;
  505.       pG->wildzipfnPtr = pG->wildzipfn = NULL;
  506.    }
  507.  
  508.    // Free everything else.
  509.    DESTROYGLOBALS();
  510. }
  511.  
  512. //******************************************************************************
  513. #ifdef _WIN32_WCE
  514.  
  515. // On WinCE, we declare our thread function the way CreateThread() likes it.
  516. static DWORD WINAPI ExtractOrTestFilesThread(LPVOID lpv)
  517.  
  518. #else
  519.  
  520. // On WinNT, we declare our thread function the way _beginthreadex likes it.
  521. static unsigned __stdcall ExtractOrTestFilesThread(void *lpv)
  522.  
  523. #endif
  524. {
  525.    Uz_Globs *pG = (Uz_Globs*)lpv;
  526.  
  527.    if (g_pExtractInfo->fExtract) {
  528.  
  529.       pG->extract_flag = TRUE;
  530.  
  531.       switch (g_pExtractInfo->overwriteMode) {
  532.  
  533.          case OM_NEWER:         // Update (extract only newer/brand-new files)
  534.             pG->UzO.uflag = TRUE;
  535.             break;
  536.  
  537.          case OM_ALWAYS:        // OK to overwrite files without prompting
  538.             pG->UzO.overwrite_all = TRUE;
  539.             break;
  540.  
  541.          case OM_NEVER:         // Never overwrite files (no prompting)
  542.             pG->UzO.overwrite_none = TRUE;
  543.             break;
  544.  
  545.          default:               // Force a prompt
  546.             pG->UzO.overwrite_all = FALSE;
  547.             pG->UzO.overwrite_none = FALSE;
  548.             pG->UzO.uflag = FALSE;
  549.             break;
  550.       }
  551.  
  552.       // Throw away paths if requested.
  553.       pG->UzO.jflag = !g_pExtractInfo->fRestorePaths;
  554.  
  555.    } else {
  556.       pG->UzO.tflag = TRUE;
  557.    }
  558.  
  559.    if (g_pExtractInfo->szFileList) {
  560.       pG->filespecs = g_pExtractInfo->dwFileCount;
  561.       pG->pfnames = g_pExtractInfo->szFileList;
  562.    } else {
  563.       // Improves performance if all files are being extracted.
  564.       pG->process_all_files = TRUE;
  565.    }
  566.  
  567.    // Invalidate our file offset to show that we are starting a new operation.
  568.    g_pExtractInfo->uzFileOffset = ~(zusz_t)0;
  569.  
  570.    // We wrap some exception handling around the entire Info-ZIP engine to be
  571.    // safe.  Since we are running on a device with tight memory configurations,
  572.    // all sorts of problems can arise when we run out of memory.
  573.    __try {
  574.  
  575.       // Put a jump marker on our stack so the user can abort.
  576.       int error = setjmp(dll_error_return);
  577.  
  578.       // If setjmp() returns 0, then we just set our jump marker and we can
  579.       // continue with the operation.  If setjmp() returned something else,
  580.       // then we reached this point because the operation was aborted and
  581.       // set our instruction pointer back here.
  582.  
  583.       if (error > 0) {
  584.          // We already called process_zipfiles() and were thrown back here.
  585.          g_pExtractInfo->result = (error == 1) ? PK_BADERR : error;
  586.  
  587.       } else {
  588.          // Entering Info-ZIP... close your eyes.
  589.          g_pExtractInfo->result = process_zipfiles(pG);
  590.       }
  591.  
  592.    } __except(EXCEPTION_EXECUTE_HANDLER) {
  593.  
  594.       // Catch any exception here.
  595.       DebugOut(TEXT("Exception 0x%08X occurred in ExtractOrTestFilesThread()"),
  596.                GetExceptionCode());
  597.       g_pExtractInfo->result = PK_EXCEPTION;
  598.    }
  599.  
  600.    // Free our globals.
  601.    FreeGlobals(pG);
  602.  
  603.    // Tell the progress dialog that we are done.
  604.    SendMessage(g_hDlgProgress, WM_PRIVATE, MSG_OPERATION_COMPLETE,
  605.                (LPARAM)g_pExtractInfo);
  606.  
  607.    // Clear our global pointer as we are done with it.
  608.    g_pExtractInfo = NULL;
  609.  
  610. #ifndef _WIN32_WCE
  611.    // On NT, we need to free any CRT allocated memory.
  612.    _endthreadex(0);
  613. #endif
  614.  
  615.    return 0;
  616. }
  617.  
  618. //******************************************************************************
  619. static void SetCurrentFile(__GPRO)
  620. {
  621.    // Reset all our counters as we about to process a new file.
  622.    g_pExtractInfo->uzFileOffset = (zusz_t)G.pInfo->offset;
  623.    g_pExtractInfo->dwFile++;
  624.    g_pExtractInfo->uzBytesWrittenThisFile = 0;
  625.    g_pExtractInfo->uzBytesWrittenPreviousFiles += g_pExtractInfo->uzBytesTotalThisFile;
  626.    g_pExtractInfo->uzBytesTotalThisFile = G.lrec.ucsize;
  627.    g_pExtractInfo->szFile = G.filename;
  628.    g_pExtractInfo->fNewLineOfText = TRUE;
  629.  
  630.    // Pass control to our GUI thread to do a full update our progress dialog.
  631.    SendMessage(g_hWndMain, WM_PRIVATE, MSG_UPDATE_PROGRESS_COMPLETE,
  632.                (LPARAM)g_pExtractInfo);
  633.  
  634.    // Check our abort flag.
  635. }
  636. #endif // POCKET_UNZIP
  637.  
  638. //******************************************************************************
  639. static int IsFileOrDirectory(LPCTSTR szPath)
  640. {
  641.    // Geth the attributes of the item.
  642.    DWORD dwAttribs = GetFileAttributes(szPath);
  643.  
  644.    // Bail out now if we could not find the path at all.
  645.    if (dwAttribs == 0xFFFFFFFF) {
  646.       return 0;
  647.    }
  648.  
  649.    // Return 1 for file and 2 for directory.
  650.    return ((dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 1);
  651. }
  652.  
  653. //******************************************************************************
  654. static BOOL SmartCreateDirectory(__GPRO__ LPCSTR szDirectory, BOOL *pNewDir)
  655. {
  656.    // Copy path to a UNICODE buffer.
  657.    TCHAR szBuffer[_MAX_PATH];
  658.    MBSTOTSTR(szBuffer, szDirectory, countof(szBuffer));
  659.  
  660.    switch (IsFileOrDirectory(szBuffer)) {
  661.       case 0:
  662.          // Create the directory if it does not exist.
  663.          if (!CreateDirectory(szBuffer, NULL)) {
  664.             Info(slide, 1, ((char *)slide, "error creating directory: %s\n",
  665.               FnFilter1( szDirectory)));
  666.             return FALSE;
  667.          }
  668.          if (pNewDir != NULL) *pNewDir = TRUE;
  669.          break;
  670.  
  671.       case 1:
  672.          // If there is a file with the same name, then display an error.
  673.          Info(slide, 1, ((char *)slide,
  674.               "cannot create %s as a file with same name already exists.\n",
  675.               FnFilter1(szDirectory)));
  676.          return FALSE;
  677.    }
  678.  
  679.    // If the directory already exists or was created, then return success.
  680.    return TRUE;
  681. }
  682.  
  683.  
  684. #ifdef POCKET_UNZIP
  685. //******************************************************************************
  686. //***** Callbacks from Info-ZIP code.
  687. //******************************************************************************
  688.  
  689. int UZ_EXP UzpMessagePrnt2(zvoid *pG, uch *buffer, ulg size, int flag)
  690. {
  691.  
  692.    // Some ZIP files cause us to get called during DoListFiles(). We only handle
  693.    // messages while processing DoExtractFiles().
  694.    if (!g_pExtractInfo) {
  695.       if (g_hWndEdit) {
  696.          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
  697.                      (LPARAM)buffer);
  698.       } else {
  699. #ifdef UNICODE
  700.          DebugOut(TEXT("Unhandled call to UzpMessagePrnt2(\"%S\")"), buffer);
  701. #else
  702.          DebugOut(TEXT("Unhandled call to UzpMessagePrnt2(\"%s\")"), buffer);
  703. #endif
  704.       }
  705.       return 0;
  706.    }
  707.  
  708.    // When extracting, mapname() will get called for every file which in turn
  709.    // will call SetCurrentFile().  For testing though, mapname() never gets
  710.    // called so we need to be on the lookout for a new file.
  711.    if (g_pExtractInfo->uzFileOffset != (zusz_t)((Uz_Globs*)pG)->pInfo->offset) {
  712.       SetCurrentFile((Uz_Globs*)pG);
  713.    }
  714.  
  715.    // Make sure this message was intended for us to display.
  716.    if (!MSG_NO_WGUI(flag) && !MSG_NO_WDLL(flag)) {
  717.  
  718.       // Insert a leading newline if requested to do so.
  719.       if (MSG_LNEWLN(flag) && !g_pExtractInfo->fNewLineOfText) {
  720.          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)"\n");
  721.          g_pExtractInfo->fNewLineOfText = TRUE;
  722.       }
  723.  
  724.       // Since we use a proportional font, we need to do a little cleanup of the
  725.       // text we are passed since it assumes a fixed font and adds padding to try
  726.       // to line things up.  We remove leading whitespace on any new line of text.
  727.       if (g_pExtractInfo->fNewLineOfText) {
  728.          while (*buffer == ' ') {
  729.             buffer++;
  730.          }
  731.       }
  732.  
  733.       // We always remove trailing whitespace.
  734.       LPSTR psz = (LPSTR)buffer;
  735.       LPSTR pszn;
  736.       while ((pszn = MBSCHR(psz, ' ')) != NULL) {
  737.          for (psz = pszn+1; *psz == ' '; psz++);
  738.          if (*psz == '\0') {
  739.             *pszn = '\0';
  740.             break;
  741.          }
  742.       }
  743.  
  744.  
  745.       // Determine if the next line of text will be a new line of text.
  746.       g_pExtractInfo->fNewLineOfText = ((*psz == '\r') || (*psz == '\n'));
  747.  
  748.       // Change all forward slashes to back slashes in the buffer
  749.       ForwardSlashesToBackSlashesA((LPSTR)buffer);
  750.  
  751.       // Add the cleaned-up text to our extraction log edit control.
  752.       SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)buffer);
  753.  
  754.       // Append a trailing newline if requested to do so.
  755.       if (MSG_TNEWLN(flag) || MSG_MNEWLN(flag) && !g_pExtractInfo->fNewLineOfText) {
  756.          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)"\n");
  757.          g_pExtractInfo->fNewLineOfText = TRUE;
  758.       }
  759.    }
  760.  
  761.    return 0;
  762. }
  763.  
  764. //******************************************************************************
  765. int UZ_EXP UzpInput2(zvoid *pG, uch *buffer, int *size, int flag)
  766. {
  767.    DebugOut(TEXT("WARNING: UzpInput2(...) called"));
  768.    return 0;
  769. }
  770.  
  771. //******************************************************************************
  772. void UZ_EXP UzpMorePause(zvoid *pG, const char *szPrompt, int flag)
  773. {
  774.    DebugOut(TEXT("WARNING: UzpMorePause(...) called"));
  775. }
  776.  
  777. //******************************************************************************
  778. int UZ_EXP UzpPassword(zvoid *pG, int *pcRetry, char *szPassword, int nSize,
  779.                        const char *szZipFile, const char *szFile)
  780. {
  781.    // Return Values:
  782.    //    IZ_PW_ENTERED    got some PWD string, use/try it
  783.    //    IZ_PW_CANCEL     no password available (for this entry)
  784.    //    IZ_PW_CANCELALL  no password, skip any further PWD request
  785.    //    IZ_PW_ERROR      failure (no mem, no tty, ...)
  786.  
  787. #if CRYPT
  788.  
  789.    // Build the data structure for our dialog.
  790.    DECRYPT_INFO di;
  791.    di.retry      = *pcRetry;
  792.    di.szPassword = szPassword;
  793.    di.nSize      = nSize;
  794.    di.szFile     = szFile;
  795.  
  796.    // Clear the password to be safe.
  797.    *di.szPassword = '\0';
  798.  
  799.    // On our first call for a file, *pcRetry == 0.  If we would like to allow
  800.    // for retries, then we set the value of *pcRetry to the number of retries we
  801.    // are willing to allow.  We will be recalled as neccessary, each time with
  802.    // *pcRetry being decremented once.  1 is the last retry we will get.
  803.    *pcRetry = (*pcRetry == 0) ? MAX_PASSWORD_RETRIES : (*pcRetry - 1);
  804.  
  805.    // Pass control to our GUI thread which will prompt the user for a password.
  806.    return SendMessage(g_hWndMain, WM_PRIVATE, MSG_PROMPT_FOR_PASSWORD, (LPARAM)&di);
  807.  
  808. #else
  809.    return IZ_PW_CANCELALL;
  810. #endif
  811. }
  812.  
  813. //******************************************************************************
  814. int UZ_EXP CheckForAbort2(zvoid *pG, int fnflag, ZCONST char *zfn,
  815.                     ZCONST char *efn, ZCONST zvoid *details)
  816. {
  817.    int rval = UZ_ST_CONTINUE;
  818.  
  819.    if (g_pExtractInfo->fAbort) {
  820.  
  821.       // Add a newline to our log if we are in the middle of a line of text.
  822.       if (!g_pExtractInfo->fNewLineOfText) {
  823.          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)"\n");
  824.       }
  825.  
  826.       // Make sure whatever file we are currently processing gets closed.
  827.       if (((int)((Uz_Globs *)pG)->outfile != 0) &&
  828.           ((int)((Uz_Globs *)pG)->outfile != -1)) {
  829.          if (g_pExtractInfo->fExtract && *efn) {
  830.  
  831.             // Make sure the user is aware that this file is screwed.
  832.             SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
  833.                         (LPARAM)"warning: ");
  834.             SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
  835.                         (LPARAM)efn);
  836.             SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
  837.                         (LPARAM)" is probably truncated.\n");
  838.          }
  839.       }
  840.  
  841.       // Display an aborted message in the log
  842.       SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
  843.                   (LPARAM)"Operation aborted by user.\n");
  844.  
  845.       // Signal "Immediate Cancel" back to the UnZip engine.
  846.       rval = UZ_ST_BREAK;
  847.    }
  848.  
  849.    return rval;
  850. }
  851.  
  852. //******************************************************************************
  853. int WINAPI UzpReplace(LPSTR szFile, unsigned nbufsiz) {
  854.    // Pass control to our GUI thread which will prompt the user to overwrite.
  855.    // The nbufsiz parameter is not needed here, because this program does not
  856.    // (yet?) contain support for renaming the extraction target.
  857.    return SendMessage(g_hWndMain, WM_PRIVATE, MSG_PROMPT_TO_REPLACE,
  858.                       (LPARAM)szFile);
  859. }
  860.  
  861. //******************************************************************************
  862. void WINAPI UzpSound(void) {
  863.    // Do nothing.
  864. }
  865.  
  866. //******************************************************************************
  867. // Called from LIST.C
  868. #ifdef Z_UINT8_DEFINED
  869. void WINAPI SendAppMsg(z_uint8 uzSize, z_uint8 uzCompressedSize,
  870. #else
  871. void WINAPI SendAppMsg(ulg uzSize, ulg uzCompressedSize,
  872. #endif
  873.                        unsigned ratio,
  874.                        unsigned month, unsigned day, unsigned year,
  875.                        unsigned hour, unsigned minute, char uppercase,
  876.                        LPCSTR szPath, LPCSTR szMethod, ulg dwCRC,
  877.                        char chCrypt)
  878. {
  879.    // If we are out of memory, then just bail since we will only make things worse.
  880.    if (g_fOutOfMemory) {
  881.       return;
  882.    }
  883.  
  884.    // We get our Globals structure.
  885.    GETGLOBALS();
  886.  
  887.    // Allocate a FILE_NODE large enough to hold this file.
  888.    int length = strlen(szPath) + strlen(szMethod);
  889.    g_pFileLast = (FILE_NODE*)new BYTE[sizeof(FILE_NODE) +
  890.                                       (sizeof(CHAR) * length)];
  891.  
  892.    // Bail out if we failed to allocate the node.
  893.    if (!g_pFileLast) {
  894. #ifdef UNICODE
  895.       DebugOut(TEXT("Failed to create a FILE_NODE for \"%S\"."), szPath);
  896. #else
  897.       DebugOut(TEXT("Failed to create a FILE_NODE for \"%s\"."), szPath);
  898. #endif
  899.       g_fOutOfMemory = TRUE;
  900.       return;
  901.    }
  902.  
  903.    // Fill in our node.
  904.    g_pFileLast->uzSize           = (zusz_t)uzSize;
  905.    g_pFileLast->uzCompressedSize = (zusz_t)uzCompressedSize;
  906.    g_pFileLast->dwCRC            = dwCRC;
  907.    g_pFileLast->szComment        = NULL;
  908.    g_pFileLast->szType           = NULL;
  909.  
  910.    // Fix the year value to contain the real year.
  911.    year += 1900;
  912.  
  913.    // Year:   0 - 4095 (12) 1111 1111 1111 0000 0000 0000 0000 0000 (0xFFF00000)
  914.    // Month:  1 -   12 ( 4) 0000 0000 0000 1111 0000 0000 0000 0000 (0x000F0000)
  915.    // Day:    1 -   31 ( 5) 0000 0000 0000 0000 1111 1000 0000 0000 (0x0000F800)
  916.    // Hour:   0 -   23 ( 5) 0000 0000 0000 0000 0000 0111 1100 0000 (0x000007C0)
  917.    // Minute: 0 -   59 ( 6) 0000 0000 0000 0000 0000 0000 0011 1111 (0x0000003F)
  918.  
  919.    // Do some bit shifting to make the date and time fit in a DWORD.
  920.    g_pFileLast->dwModified = (((DWORD)(year   & 0x0FFF) << 20) |
  921.                               ((DWORD)(month  & 0x000F) << 16) |
  922.                               ((DWORD)(day    & 0x001F) << 11) |
  923.                               ((DWORD)(hour   & 0x001F) <<  6) |
  924.                               ((DWORD)(minute & 0x003F)));
  925.  
  926.    // We need to get our globals structure to determine our attributes and
  927.    // encryption information.
  928.    g_pFileLast->dwAttributes = (pG->crec.external_file_attributes & 0xFF);
  929.    if (chCrypt == 'E') {
  930.       g_pFileLast->dwAttributes |= ZFILE_ATTRIBUTE_ENCRYPTED;
  931.    }
  932.  
  933.    // Store the path and method in our string buffer.
  934.    strcpy(g_pFileLast->szPathAndMethod, szPath);
  935.    strcpy(g_pFileLast->szPathAndMethod + strlen(szPath) + 1, szMethod);
  936.  
  937.    // Pass the file object to our windows code to have it added to our list.
  938.    AddFileToListView(g_pFileLast);
  939. }
  940.  
  941. //******************************************************************************
  942. int win_fprintf(zvoid *pG, FILE *file, unsigned int dwCount, char far *buffer)
  943. {
  944.  
  945.    // win_fprintf() is used within Info-ZIP to write to a file as well as log
  946.    // information.  If the "file" is a real file handle (not stdout or stderr),
  947.    // then we write the data to the file and return.
  948.  
  949.    if ((file != stdout) && (file != stderr)) {
  950.  
  951.       DWORD dwBytesWritten = 0;
  952. #if (defined(_WIN32_WCE) && (_WIN32_WCE < 211))
  953.       // On WinCE all FILEs are really HANDLEs.  See WINCE.CPP for more info.
  954.       WriteFile((HANDLE)file, buffer, dwCount, &dwBytesWritten, NULL);
  955. #else
  956.       dwBytesWritten = fwrite(buffer, 1, dwCount, file);
  957. #endif
  958.  
  959.       // Update our bytes written count.
  960.       g_pExtractInfo->uzBytesWrittenThisFile += dwBytesWritten;
  961.  
  962.       // Pass control to our GUI thread to do a partial update our progress dialog.
  963.       SendMessage(g_hWndMain, WM_PRIVATE, MSG_UPDATE_PROGRESS_PARTIAL,
  964.                   (LPARAM)g_pExtractInfo);
  965.  
  966.       return dwBytesWritten;
  967.    }
  968.  
  969.    // Check to see if we are expecting a extraction progress string
  970.    if (g_pExtractInfo) {
  971.  
  972.       // Most of our progress strings come to our UzpMessagePrnt2() callback,
  973.       // but we occasionally get one here.  We will just forward it to
  974.       // UzpMessagePrnt2() as if it never came here.
  975.       UzpMessagePrnt2(pG, (uch*)buffer, dwCount, 0);
  976.       return dwCount;
  977.    }
  978.  
  979.    // Check to see if we are expecting a zip file comment string.
  980.    if (g_hWndEdit) {
  981.  
  982.       // Change all forward slashes to back slashes in the buffer
  983.       ForwardSlashesToBackSlashesA((LPSTR)buffer);
  984.  
  985.       SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)buffer);
  986.       return dwCount;
  987.    }
  988.  
  989.    // Check to see if we are expecting a compressed file comment string.
  990.    if (g_pFileLast) {
  991.       char *p1, *p2;
  992.  
  993.       // Calcalute the size of the buffer we will need to store this comment.
  994.       // We are going to convert all ASC values 0 - 31 (except tab, new line,
  995.       // and CR) to ^char.
  996.       int size = 1;
  997.       for (p1 = buffer; *p1; INCSTR(p1)) {
  998.          size += ((*p1 >= 32) || (*p1 == '\t') ||
  999.                   (*p1 == '\r') || (*p1 == '\n')) ? CLEN(p1) : 2;
  1000.       }
  1001.  
  1002.       // Allocate a comment buffer and assign it to the last file node we saw.
  1003.       if (g_pFileLast->szComment = new CHAR[size]) {
  1004.  
  1005.          // Copy while formatting.
  1006.          for (p1 = buffer, p2 = (char*)g_pFileLast->szComment; *p1; INCSTR(p1)) {
  1007.             if ((*p1 >= 32) || (*p1 == '\t') ||
  1008.                 (*p1 == '\r') || (*p1 == '\n')) {
  1009.                memcpy(p2, p1, CLEN(p1));
  1010.                p2 += CLEN(p1);
  1011.             } else {
  1012.                *(p2++) = '^';
  1013.                *(p2++) = 64 + *p1;
  1014.             }
  1015.          }
  1016.          *p2 = '\0';
  1017.       }
  1018.  
  1019.       // Update the attributes of the file node to include the comment attribute.
  1020.       g_pFileLast->dwAttributes |= ZFILE_ATTRIBUTE_COMMENT;
  1021.  
  1022.       // Clear the file node so we don't try to add another bogus comment to it.
  1023.       g_pFileLast = NULL;
  1024.  
  1025.       return dwCount;
  1026.    }
  1027.  
  1028.    if (dwCount >= _MAX_PATH) {
  1029.       buffer[_MAX_PATH] = '\0';
  1030.    }
  1031. #ifdef UNICODE
  1032.    DebugOut(TEXT("Unhandled call to win_fprintf(\"%S\")"), buffer);
  1033. #else
  1034.    DebugOut(TEXT("Unhandled call to win_fprintf(\"%S\")"), buffer);
  1035. #endif
  1036.    return dwCount;
  1037. }
  1038.  
  1039. //******************************************************************************
  1040. void WINAPI Wiz_NoPrinting(int f) {
  1041.    // Do nothing.
  1042. }
  1043.  
  1044. #endif // POCKET_UNZIP
  1045.  
  1046. //******************************************************************************
  1047. //***** Functions that Info-ZIP expects the port to write and export.
  1048. //***** Some of this code was stolen from the WIN32 port and highly modified.
  1049. //******************************************************************************
  1050.  
  1051. #ifdef NTSD_EAS
  1052. #ifndef SFX
  1053. //******************************************************************************
  1054. // Called from EXTRACT.C
  1055. int test_NTSD(__GPRO__ uch *eb, unsigned eb_size) {
  1056.    // This function is called when an NT security descriptor is found in the
  1057.    // extra field.  We have nothing to do, so we just return success.
  1058.    return PK_OK;
  1059. }
  1060. #endif /* !SFX */
  1061. #endif /* NTSD_EAS */
  1062.  
  1063. static void utimeToFileTime(time_t ut, FILETIME *pft, BOOL fOldFileSystem)
  1064. {
  1065.  
  1066.    // time_t    is a 32-bit value for the seconds since January 1, 1970
  1067.    // FILETIME  is a 64-bit value for the number of 100-nanosecond intervals
  1068.    //           since January 1, 1601
  1069.    // DWORDLONG is a 64-bit unsigned int that we can use to perform large math
  1070.    //           operations.
  1071.  
  1072.  
  1073.    // time_t has minimum of 1/1/1970.  Many file systems, such as FAT, have a
  1074.    // minimum date of 1/1/1980.  If extracting to one of those file systems and
  1075.    // out time_t is less than 1980, then we make it 1/1/1980.
  1076.    // (365 days/yr * 10 yrs + 3 leap yr days) * (60 secs * 60 mins * 24 hrs).
  1077.    if (fOldFileSystem && (ut < 0x12CFF780)) {
  1078.       ut = 0x12CFF780;
  1079.    }
  1080.  
  1081. #ifndef NO_W32TIMES_IZFIX
  1082.    // Now for the next fix for old file systems.  If we are in Daylight Savings
  1083.    // Time (DST) and the file is not in DST, then we need subtract off the DST
  1084.    // bias from the filetime.  This is due to a bug in Windows (NT, CE, and 95)
  1085.    // that causes the DST bias to be added to all file times when the system
  1086.    // is in DST, even if the file is not in DST.  This only effects old file
  1087.    // systems since they store local times instead of UTC times.  Newer file
  1088.    // systems like NTFS and CEFS store UTC times.
  1089.    if (fOldFileSystem)
  1090. #endif
  1091.    {
  1092.       // We use the CRT's localtime() and Win32's LocalTimeToFileTime()
  1093.       // functions to compute a FILETIME value that always shows the correct
  1094.       // local time in Windows' file listings.  This works because localtime()
  1095.       // correctly adds the DST bias only if the file time is in DST.
  1096.       // FileTimeToLocalTime() always adds the DST bias to the time.
  1097.       // Therefore, if the functions return different results, we know we
  1098.       // are dealing with a non-DST file during a system DST.
  1099.  
  1100.       FILETIME lftCRT;
  1101.  
  1102.       // Get the CRT result - result is a "tm" struct.
  1103.       struct tm *ptmCRT = localtime(&ut);
  1104.  
  1105.       // Check if localtime() returned something useful; continue with the
  1106.       // "NewFileSystem" code in case of an error. This failsafe method
  1107.       // should give an "almost" correct filetime result.
  1108.       if (ptmCRT != (struct tm *)NULL) {
  1109.          // Convert the "tm" struct to a FILETIME.
  1110.          SYSTEMTIME stCRT;
  1111.          ZeroMemory(&stCRT, sizeof(stCRT));
  1112.          if (fOldFileSystem && (ptmCRT->tm_year < 80)) {
  1113.             stCRT.wYear   = 1980;
  1114.             stCRT.wMonth  = 1;
  1115.             stCRT.wDay    = 1;
  1116.             stCRT.wHour   = 0;
  1117.             stCRT.wMinute = 0;
  1118.             stCRT.wSecond = 0;
  1119.          } else {
  1120.             stCRT.wYear   = ptmCRT->tm_year + 1900;
  1121.             stCRT.wMonth  = ptmCRT->tm_mon + 1;
  1122.             stCRT.wDay    = ptmCRT->tm_mday;
  1123.             stCRT.wHour   = ptmCRT->tm_hour;
  1124.             stCRT.wMinute = ptmCRT->tm_min;
  1125.             stCRT.wSecond = ptmCRT->tm_sec;
  1126.          }
  1127.          SystemTimeToFileTime(&stCRT, &lftCRT);
  1128.          LocalFileTimeToFileTime(&lftCRT, pft);
  1129.          // we are finished!
  1130.          return;
  1131.       }
  1132.    }
  1133.    // For "Modern" file system that stores timestamps in UTC (or as second
  1134.    // chance in case of localtime() errors) the conversion of time_t into
  1135.    // 64-bit FILETIME is a simple arithmetic rescaling calculation.
  1136.    // Compute the FILETIME for the given time_t.
  1137.    DWORDLONG dwl = ((DWORDLONG)116444736000000000 +
  1138.                    ((DWORDLONG)ut * (DWORDLONG)10000000));
  1139.  
  1140.    // Store the return value.
  1141.    *pft = *(FILETIME*)&dwl;
  1142.  
  1143. }
  1144.  
  1145. //******************************************************************************
  1146. static int GetFileTimes(__GPRO__ FILETIME *pftCreated,
  1147.                         FILETIME *pftAccessed, FILETIME *pftModified)
  1148. {
  1149.    // We need to check to see if this file system is limited.  This includes
  1150.    // FAT, VFAT, and HPFS.  It does not include NTFS and CEFS.  The limited
  1151.    // file systems can not support dates < 1980 and they store file local times
  1152.    // for files as opposed to UTC times.
  1153.    BOOL fOldFileSystem = IsOldFileSystem(G.filename);
  1154.  
  1155. #ifdef USE_EF_UT_TIME  // Always true for WinCE build
  1156.  
  1157. #ifdef IZ_CHECK_TZ
  1158.    if (G.extra_field && G.tz_is_valid) {
  1159. #else
  1160.    if (G.extra_field) {
  1161. #endif
  1162.  
  1163.       // Structure for Unix style actime, modtime, creatime
  1164.       iztimes z_utime;
  1165.  
  1166.       // Get any date/time we can.  This can return 0 to 3 unix time fields.
  1167.       unsigned eb_izux_flg = ef_scan_for_izux(G.extra_field,
  1168.                                               G.lrec.extra_field_length, 0,
  1169.                                               G.lrec.last_mod_dos_datetime,
  1170.                                               &z_utime, NULL);
  1171.  
  1172.       // We require at least a modified time.
  1173.       if (eb_izux_flg & EB_UT_FL_MTIME) {
  1174.  
  1175.          // We know we have a modified time, so get it first.
  1176.          utimeToFileTime(z_utime.mtime, pftModified, fOldFileSystem);
  1177.  
  1178.          // Get the accessed time if we have one.
  1179.          if (eb_izux_flg & EB_UT_FL_ATIME) {
  1180.             utimeToFileTime(z_utime.atime, pftAccessed, fOldFileSystem);
  1181.          }
  1182.  
  1183.          // Get the created time if we have one.
  1184.          if (eb_izux_flg & EB_UT_FL_CTIME) {
  1185.             utimeToFileTime(z_utime.ctime, pftCreated, fOldFileSystem);
  1186.          }
  1187.  
  1188.          // Return our flags.
  1189.          return (int)eb_izux_flg;
  1190.       }
  1191.    }
  1192.  
  1193. #endif // USE_EF_UT_TIME
  1194.  
  1195.    // If all else fails, we can resort to using the DOS date and time data.
  1196.    time_t ux_modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  1197.    utimeToFileTime(ux_modtime, pftModified, fOldFileSystem);
  1198.  
  1199.    *pftAccessed = *pftModified;
  1200.  
  1201.    return (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
  1202. }
  1203.  
  1204. //******************************************************************************
  1205. //***** Functions to correct time stamp bugs on old file systems.
  1206. //******************************************************************************
  1207.  
  1208. //******************************************************************************
  1209. // Borrowed/Modified from win32.c
  1210. static BOOL IsOldFileSystem(char *szPath) {
  1211.  
  1212. #ifdef _WIN32_WCE
  1213.  
  1214.    char szRoot[10];
  1215.  
  1216.    // Get the first nine characters of the path.
  1217.    strncpy(szRoot, szPath, 9);
  1218.    szRoot[9] = '\0';
  1219.  
  1220.    // Convert to uppercase to help with compare.
  1221.    _strupr(szRoot);
  1222.  
  1223.    // PC Cards are mounted off the root in a directory called "\PC Cards".
  1224.    // PC Cards are FAT, no CEOS.  We need to check if the file is being
  1225.    // extracted to the PC card.
  1226.    return !strcmp(szRoot, "\\PC CARD\\");
  1227.  
  1228. #else
  1229.  
  1230.    char szRoot[_MAX_PATH] = "\0\0\0", szFS[64];
  1231.  
  1232.    // Check to see if our path contains a drive letter.
  1233.    if (isalpha(szPath[0]) && (szPath[1] == ':') && (szPath[2] == '\\')) {
  1234.  
  1235.       // If so, then just copy the drive letter, colon, and wack to our root path.
  1236.       strncpy(szRoot, szPath, 3);
  1237.  
  1238.    } else {
  1239.  
  1240.       // Expand the path so we can get a drive letter.
  1241.       GetFullPathNameA(szPath, sizeof(szRoot), szRoot, NULL);
  1242.  
  1243.       // Make sure we actually got a drive letter back in our root path buffer..
  1244.       if (!isalpha(szRoot[0]) || (szRoot[1] != ':') || (szRoot[2] != '\\')) {
  1245.  
  1246.          // When in doubt, return TRUE.
  1247.          return TRUE;
  1248.       }
  1249.    }
  1250.  
  1251.    // NULL terminate after the wack to ensure we have just the root path.
  1252.    szRoot[3] = '\0';
  1253.  
  1254.    // Get the file system type string.
  1255.    GetVolumeInformationA(szRoot, NULL, 0, NULL, NULL, NULL, szFS, sizeof(szFS));
  1256.  
  1257.    // Ensure that the file system type string is uppercase.
  1258.    _strupr(szFS);
  1259.  
  1260.    // Return true for (V)FAT and (OS/2) HPFS format.
  1261.    return !strncmp(szFS, "FAT",  3) ||
  1262.           !strncmp(szFS, "VFAT", 4) ||
  1263.           !strncmp(szFS, "HPFS", 4);
  1264.  
  1265. #endif // _WIN32_WCE
  1266. }
  1267.  
  1268. //******************************************************************************
  1269. int SetFileSize(FILE *file, zusz_t filesize)
  1270. {
  1271. #if (defined(_WIN32_WCE) || defined(__RSXNT__))
  1272.     // For native Windows CE, it is not known whether the API supports
  1273.     // presetting a file's size.
  1274.     // RSXNT environment lacks a translation function from C file pointer
  1275.     // to Win32-API file handle.
  1276.     // So, simply do nothing.
  1277.     return 0;
  1278. #else /* !(_WIN32_WCE || __RSXNT__) */
  1279.     /* not yet verified, if that really creates an unfragmented file
  1280.       rommel@ars.de
  1281.      */
  1282.     HANDLE os_fh;
  1283. #ifdef Z_UINT8_DEFINED
  1284.     LARGE_INTEGER fsbuf;
  1285. #endif
  1286.  
  1287.     /* Win9x supports FAT file system, only; presetting file size does
  1288.        not help to prevent fragmentation. */
  1289.     if ((long)GetVersion() < 0) return 0;
  1290.  
  1291.     /* Win32-API calls require access to the Win32 file handle.
  1292.        The interface function used to retrieve the Win32 handle for
  1293.        a file opened by the C rtl is non-standard and may not be
  1294.        available for every Win32 compiler environment.
  1295.        (see also win32/win32.c of the Zip distribution)
  1296.      */
  1297.     os_fh = (HANDLE)_get_osfhandle(fileno(file));
  1298.     /* move file pointer behind the last byte of the expected file size */
  1299. #ifdef Z_UINT8_DEFINED
  1300.     fsbuf.QuadPart = filesize;
  1301.     if ((SetFilePointer(os_fh, fsbuf.LowPart, &fsbuf.HighPart, FILE_BEGIN)
  1302.          == 0xFFFFFFFF) && GetLastError() != NO_ERROR)
  1303. #else
  1304.     if (SetFilePointer(os_fh, filesize, 0, FILE_BEGIN) == 0xFFFFFFFF)
  1305. #endif
  1306.         return -1;
  1307.     /* extend/truncate file to the current position */
  1308.     if (SetEndOfFile(os_fh) == 0)
  1309.         return -1;
  1310.     /* move file position pointer back to the start of the file! */
  1311.     return (SetFilePointer(os_fh, 0, 0, FILE_BEGIN) == 0xFFFFFFFF) ? -1 : 0;
  1312. #endif /* ?(_WIN32_WCE || __RSXNT__) */
  1313. } /* end function SetFileSize() */
  1314.  
  1315. //******************************************************************************
  1316. void close_outfile(__GPRO)
  1317. {
  1318.    HANDLE hFile;
  1319.  
  1320.    TCHAR szFile[_MAX_PATH];
  1321.    MBSTOTSTR(szFile, G.filename, countof(szFile));
  1322.  
  1323.    /* skip restoring time stamps on user's request */
  1324.    if (uO.D_flag <= 1) {
  1325.       // Get the 3 time stamps for the file.
  1326.       FILETIME ftCreated, ftAccessed, ftModified;
  1327.       int timeFlags = GetFileTimes(__G__ &ftCreated, &ftAccessed, &ftModified);
  1328.  
  1329. #if (defined(_WIN32_WCE) && (_WIN32_WCE < 211))
  1330.  
  1331.       // Cast the outfile to a HANDLE (since that is really what it is), and
  1332.       // flush the file.  We need to flush, because any unsaved data that is
  1333.       // written to the file during CloseHandle() will step on the work done
  1334.       // by SetFileTime().
  1335.       hFile = (HANDLE)G.outfile;
  1336.       FlushFileBuffers(hFile);
  1337.  
  1338. #else
  1339.  
  1340.       // Close the file and then re-open it using the Win32 CreateFile() call.
  1341.       // SetFileTime() requires a Win32 file HANDLE created with GENERIC_WRITE
  1342.       // access.
  1343.       fclose(G.outfile);
  1344.       hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
  1345.                          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1346.  
  1347. #endif
  1348.  
  1349.       // Set the file's date and time.
  1350.       if (hFile != INVALID_HANDLE_VALUE) {
  1351.  
  1352.          // Make sure we retrieved some valid time stamp(s)
  1353.          if (timeFlags) {
  1354.  
  1355.             // Set the various date and time fields.
  1356.             if (!SetFileTime(hFile,
  1357.                     (timeFlags & EB_UT_FL_CTIME) ? &ftCreated  : NULL,
  1358.                     (timeFlags & EB_UT_FL_ATIME) ? &ftAccessed : NULL,
  1359.                     (timeFlags & EB_UT_FL_MTIME) ? &ftModified : NULL))
  1360.             {
  1361.                DebugOut(TEXT("SetFileTime() failed [%u]"), GetLastError());
  1362.             }
  1363.  
  1364.          } else {
  1365.             DebugOut(TEXT("GetFileTimes() failed"));
  1366.          }
  1367.  
  1368.          // Close out file.
  1369.          CloseHandle(hFile);
  1370.  
  1371.       } else {
  1372.          DebugOut(TEXT("CreateFile() failed [%u]"), GetLastError());
  1373.       }
  1374.    }
  1375.  
  1376.    // If the file was successfully written, then set the attributes.
  1377. #ifdef POCKET_UNZIP
  1378.    if (!G.disk_full && !g_pExtractInfo->fAbort) {
  1379. #else
  1380.    if (!G.disk_full) {
  1381. #endif
  1382.       if (!SetFileAttributes(szFile, G.pInfo->file_attr & 0x7F)) {
  1383.          DebugOut(TEXT("SetFileAttributes() failed [%u]"), GetLastError());
  1384.       }
  1385.    }
  1386.  
  1387.    // Clear outfile so we know it is closed.
  1388.    G.outfile = 0;
  1389.  
  1390.    return;
  1391. }
  1392.  
  1393. //******************************************************************************
  1394. // Called by PROCESS.C
  1395. char* do_wild(__GPRO__ ZCONST char *wildspec)
  1396. {
  1397.    // This is a very slimmed down version of do_wild() taken from WIN32.C.
  1398.    // Since we don't support wildcards, we basically just return the wildspec
  1399.    // passed in as the filename.
  1400.  
  1401. #ifndef POCKET_UNZIP
  1402.    // Delete allocated storage for the match name
  1403.    if (G.matchname != NULL)
  1404.    {
  1405.       delete G.matchname;
  1406.       G.matchname = NULL;
  1407.    }
  1408. #endif
  1409.  
  1410.    // First call - must initialize everything.
  1411.    if (!G.notfirstcall) {
  1412.       G.notfirstcall = TRUE;
  1413. #ifdef POCKET_UNZIP
  1414.       return strcpy(G.matchname, wildspec);
  1415. #else
  1416.       // allocate some storage for the match name
  1417.       G.matchname = new char[strlen(wildspec) + 1];
  1418.       if (G.matchname != NULL)
  1419.          return strcpy(G.matchname, wildspec);
  1420. #endif
  1421.    }
  1422.  
  1423.    // Last time through - reset for new wildspec.
  1424.    G.notfirstcall = FALSE;
  1425.  
  1426.    return (char *)NULL;
  1427. }
  1428.  
  1429. //******************************************************************************
  1430. // Called from EXTRACT.C
  1431. int mapattr(__GPRO)
  1432. {
  1433. #ifdef POCKET_UNZIP
  1434.    // Check to see if we are extracting this file for viewing.  Currently, we do
  1435.    // this by checking the szMappedPath member of our extract info stucture
  1436.    // since we know OnActionView() is the only one who sets this member.
  1437.  
  1438.    if (g_pExtractInfo && g_pExtractInfo->szMappedPath) {
  1439.  
  1440.       // If we are extracting for view only, then we ignore the file's real
  1441.       // attributes and force the file to create as read-only.  We make the file
  1442.       // read-only to help prevent the user from making changes to the temporary
  1443.       // file and then trying to save the changes back to a file that we will
  1444.       // eventually delete.
  1445.       G.pInfo->file_attr = FILE_ATTRIBUTE_READONLY;
  1446.  
  1447.    } else
  1448. #endif
  1449.    {
  1450.       /* set archive bit for file entries (file is not backed up): */
  1451.       G.pInfo->file_attr = ((unsigned)G.crec.external_file_attributes |
  1452.         (G.crec.external_file_attributes & FILE_ATTRIBUTE_DIRECTORY ?
  1453.          0 : FILE_ATTRIBUTE_ARCHIVE)) & 0xff;
  1454.    }
  1455.    return 0;
  1456. } /* end function mapattr() */
  1457.  
  1458. //******************************************************************************
  1459. // Called from EXTRACT.C
  1460. //
  1461. // returns:
  1462. //  MPN_OK          - no problem detected
  1463. //  MPN_INF_TRUNC   - (on APPEND_NAME) truncated filename
  1464. //  MPN_INF_SKIP    - path doesn't exist, not allowed to create
  1465. //  MPN_ERR_SKIP    - path doesn't exist, tried to create and failed; or path
  1466. //                    exists and is not a directory, but is supposed to be
  1467. //  MPN_ERR_TOOLONG - path is too long
  1468. //  MPN_NOMEM       - can't allocate memory for filename buffers
  1469. //
  1470. //  MPN_VOL_LABEL   - Path was a volume label, skip it.
  1471. //  MPN_CREATED_DIR - Created a directory.
  1472. //
  1473. int mapname(__GPRO__ int renamed)
  1474. {
  1475.     int error = MPN_OK;
  1476.     CHAR szBuffer[countof(G.filename)] = "";
  1477.     CHAR *pIn = NULL, *pOut, *pLastSemi = NULL;
  1478.     CHAR *pPathComp, workch;
  1479.     BOOL killed_ddot = FALSE, renamed_fullpath = FALSE, created_dir = FALSE;
  1480.  
  1481. #ifdef POCKET_UNZIP
  1482.     // mapname() is a great place to reset all our status counters for the next
  1483.     // file to be processed since it is called for every zip file member before
  1484.     // any work is done with that member.
  1485.     SetCurrentFile(__G);
  1486. #endif
  1487.  
  1488.     // If Volume Label, skip the "extraction" quietly
  1489.     if (G.pInfo->vollabel) {
  1490.        return MPN_VOL_LABEL;
  1491.     }
  1492.  
  1493. #ifndef POCKET_UNZIP // The GUI interface does not support renaming...
  1494.     if (renamed) {
  1495.         pIn = G.filename;   // point to beginning of renamed name...
  1496.         if (*pIn) do {
  1497.             if (*pIn == '\\')   // convert backslashes to forward
  1498.                 *pIn = '/';
  1499.         } while (*PREINCSTR(pIn));
  1500.         pIn = G.filename;
  1501.         // use temporary rootpath if user gave full pathname
  1502.         if (G.filename[0] == '/') {
  1503.             renamed_fullpath = TRUE;
  1504.             szBuffer[0] = '\\'; // copy the '/' and terminate
  1505.             szBuffer[1] = '\0';
  1506.             ++pIn;
  1507.         } else if (isalpha((uch)G.filename[0]) && G.filename[1] == ':') {
  1508.             renamed_fullpath = TRUE;
  1509.             pOut = szBuffer;
  1510.             *pOut++ = *pIn++;   // copy the "d:" (+ '/', possibly)
  1511.             *pOut++ = *pIn++;
  1512.             if (*pIn == '/') {
  1513.                 *pOut++ = '\\';
  1514.                 pIn++;          // otherwise add "./"?
  1515.             }
  1516.             *pOut = '\0';
  1517.         }
  1518.     }
  1519. #endif
  1520.  
  1521.     // Initialize file path buffer with our "extract to" path.
  1522.     if (!renamed_fullpath) {
  1523. #ifdef POCKET_UNZIP
  1524.         strcpy(szBuffer, g_szExtractToDirectory);
  1525. #else
  1526.         strcpy(szBuffer, G.rootpath);
  1527. #endif
  1528.         pOut = szBuffer + strlen(szBuffer);
  1529.     }
  1530.     pPathComp = pOut;
  1531.  
  1532.     if (!renamed) {
  1533.         // Point pIn to beginning of our internal pathname.
  1534.         // If we are junking paths, then locate the file portion of the path.
  1535.         if (uO.jflag)
  1536.             pIn = (CHAR*)MBSRCHR(G.filename, '/');
  1537.         if (pIn == NULL)
  1538.             pIn = G.filename;
  1539.         else
  1540.             ++pIn;
  1541.     }
  1542.  
  1543.     // Begin main loop through characters in filename.
  1544.     for ( ; (workch = *pIn) != '\0'; INCSTR(pIn)) {
  1545.  
  1546.         // Make sure we don't overflow our output buffer.
  1547.         if (pOut >= (szBuffer + countof(szBuffer) - 2)) {
  1548.             Info(slide, 1, ((char*)slide, "path too long: %s\n",
  1549.               FnFilter1(G.filename)));
  1550.             return MPN_ERR_TOOLONG;
  1551.         }
  1552.  
  1553.         // Examine the next character in our input buffer.
  1554.         switch (workch) {
  1555.  
  1556.           // Check for a directory wack.
  1557.           case '/':
  1558.             *pOut = '\0';
  1559.             // Skip dir traversals unless they are explicitly allowed.
  1560.             if (strcmp(pPathComp, ".") == 0) {
  1561.                 // don't bother appending "./" to the path
  1562.                 *pPathComp = '\0';
  1563.             } else if (!uO.ddotflag && strcmp(pPathComp, "..") == 0) {
  1564.                 // "../" dir traversal detected, skip over it
  1565.                 *pPathComp = '\0';
  1566.                 killed_ddot = TRUE;     // set "show message" flag
  1567.             }
  1568.             // When path component is not empty, append it now.
  1569.             if (*pPathComp == '\0') {
  1570.                 // Reset insert pos to start of path component.
  1571.                 pOut = pPathComp;
  1572.             } else {
  1573.                 if (!SmartCreateDirectory(__G__ szBuffer, &created_dir)) {
  1574.                    Info(slide, 1, ((char*)slide, "failure extracting: %s\n",
  1575.                         FnFilter1(G.filename)));
  1576.                    return MPN_ERR_SKIP;
  1577.                 }
  1578.                 *(pOut++) = '\\';
  1579.                 pPathComp = pOut;  // Remember start pos of new path component
  1580.             }
  1581.             pLastSemi = NULL;  // Leave any directory semi-colons alone
  1582.             break;
  1583.  
  1584.           // Check for illegal characters and replace with underscore.
  1585.           case ':':
  1586.           case '\\':
  1587.           case '*':
  1588.           case '?':
  1589.           case '"':
  1590.           case '<':
  1591.           case '>':
  1592.           case '|':
  1593.             *(pOut++) = '_';
  1594.             break;
  1595.  
  1596.           // Check for start of VMS version.
  1597.           case ';':
  1598.             pLastSemi = pOut;  // Make note as to where we are.
  1599.             *(pOut++) = ';';   // Leave the semi-colon alone for now.
  1600.             break;
  1601.  
  1602.           default:
  1603.             // Allow European characters and spaces in filenames.
  1604. #ifdef _MBCS
  1605.             if ((UCHAR)workch >= 0x20) {
  1606.                 memcpy(pOut, pIn, CLEN(pIn));
  1607.                 INCSTR(pOut);
  1608.             } else {
  1609.                 *(pOut++) = '_';
  1610.             }
  1611. #else
  1612.             *(pOut++) = (((UCHAR)workch >= 0x20) ? workch : '_');
  1613. #endif
  1614.        }
  1615.     }
  1616.  
  1617.     // Show warning when stripping insecure "parent dir" path components
  1618.     if (killed_ddot && QCOND2) {
  1619.         Info(slide, 0, ((char *)slide,
  1620.           "warning:  skipped \"../\" path component(s) in %s\n",
  1621.           FnFilter1(G.filename)));
  1622.         if (!(error & ~MPN_MASK))
  1623.             error = (error & MPN_MASK) | PK_WARN;
  1624.     }
  1625.  
  1626.     // Done with output buffer, terminate it.
  1627.     *pOut = '\0';
  1628.  
  1629.     // Remove any VMS version numbers if found (appended ";###").
  1630.     if (pLastSemi) {
  1631.  
  1632.         // Walk over all digits following the semi-colon.
  1633.         for (pOut = pLastSemi + 1; (*pOut >= '0') && (*pOut <= '9'); pOut++);
  1634.  
  1635.         // If we reached the end, then nuke the semi-colon and digits.
  1636.         if (!*pOut)
  1637.            *pLastSemi = '\0';
  1638.     }
  1639.  
  1640.     // Copy the mapped name back to the internal path buffer
  1641.     strcpy(G.filename, szBuffer);
  1642.  
  1643. #ifdef POCKET_UNZIP
  1644.     // Fill in the mapped name buffer if the original caller requested us to.
  1645.     if (g_pExtractInfo->szMappedPath) {
  1646.         strcpy(g_pExtractInfo->szMappedPath, szBuffer);
  1647.     }
  1648. #endif
  1649.  
  1650.     // If it is a directory, then display the "creating" status text.
  1651.     if ((pOut > szBuffer) && (lastchar(szBuffer, pOut-szBuffer) == '\\')) {
  1652.         if (created_dir) {
  1653. #ifdef UNICODE
  1654.             TCHAR szFile[_MAX_PATH];
  1655.  
  1656.             MBSTOTSTR(szFile, G.filename, countof(szFile));
  1657. #           define T_Fname  szFile
  1658. #else
  1659. #           define T_Fname  G.filename
  1660. #endif
  1661.             if (QCOND2) {
  1662.                 Info(slide, 0, ((char *)slide, "   creating: %-22s\n",
  1663.                   FnFilter1(G.filename)));
  1664.             }
  1665.  
  1666.             // set file attributes:
  1667.             // The default for newly created directories is "DIR attribute
  1668.             // flags set", so there is no need to change attributes unless
  1669.             // one of the DOS style attribute flags is set. There is no need
  1670.             // to mask the readonly attribute, because it does not prevent
  1671.             // modifications in the new directory.
  1672.             if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
  1673.                 if (!SetFileAttributes(T_Fname, G.pInfo->file_attr & 0x7F))
  1674.                     Info(slide, 1, ((char *)slide,
  1675.                       "\nwarning (%d): could not set file attributes for %s\n",
  1676.                       (int)GetLastError(), FnFilter1(G.filename)));
  1677.             }
  1678.  
  1679.             /* set dir time (note trailing '/') */
  1680.             return (error & ~MPN_MASK) | MPN_CREATED_DIR;
  1681.         }
  1682.         /* dir existed already; don't look for data to extract */
  1683.         return (error & ~MPN_MASK) | MPN_INF_SKIP;
  1684.     }
  1685.  
  1686.     return error;
  1687. }
  1688.  
  1689. //******************************************************************************
  1690. // Called from PROCESS.C
  1691. int checkdir(__GPRO__ char *pathcomp, int flag) {
  1692. #ifdef POCKET_UNZIP
  1693.  
  1694.     // This function is only called by free_G_buffers() from PROCESS.C with the
  1695.     // flag set to END.  We have nothing to do, so we just return success.
  1696.     return MPN_OK;
  1697.  
  1698. #else // !POCKET_UNZIP
  1699.  
  1700. #   define FN_MASK 7
  1701. #   define FUNCTION (flag & FN_MASK)
  1702.     int rc = MPN_OK;
  1703.  
  1704.     switch (FUNCTION) {
  1705.     case ROOT:
  1706.       {
  1707.         // User specified a root path. save the root without separator
  1708.         char* pathcompStart;
  1709.  
  1710.         if (pathcomp == NULL) {
  1711.             G.rootlen = 0;      // trivial NULL clause...
  1712.             break;
  1713.         }
  1714.         if (G.rootlen > 0)
  1715.             break;              // nothing to do, rootpath was already set
  1716.  
  1717.         G.rootlen = strlen(pathcomp);
  1718.         pathcompStart = pathcomp;
  1719.         // Strip the drive if given. CE does not support Drive
  1720.         if (pathcomp[1] == ':') {
  1721.             G.rootlen -= 2;
  1722.             pathcompStart += 2;
  1723.         }
  1724.         // Check for trailing separator, Strip if given
  1725.         // accomodate it if required.
  1726.         if (pathcomp[G.rootlen - 1] == '/' || pathcomp[G.rootlen - 1] == '\\')
  1727.             G.rootlen--;
  1728.         // Save the root
  1729.         memcpy(G.rootpath, pathcompStart, G.rootlen);
  1730.         G.rootpath[G.rootlen] = '\0';
  1731.  
  1732.         // Check if directory exists and try to create when neccessary.
  1733.         if (!SmartCreateDirectory(__G__ G.rootpath, NULL)) {
  1734.             rc = MPN_ERR_SKIP; // Create directory failed
  1735.         }
  1736.  
  1737.         // Add trailing path separator
  1738.         G.rootpath[G.rootlen++] = '\\';
  1739.         G.rootpath[G.rootlen] = '\0';
  1740.         break;
  1741.      }
  1742.  
  1743.     case END:
  1744.         Trace((stderr, "freeing rootpath\n"));
  1745.         if (G.rootlen > 0) {
  1746.             G.rootlen = 0;
  1747.             G.rootpath[0] = '\0';
  1748.         }
  1749.         break;
  1750.  
  1751.     default:
  1752.         rc = MPN_INVALID;       /* should never reach */
  1753.         break;
  1754.     }
  1755.     return rc;
  1756.  
  1757. #endif // !POCKET_UNZIP
  1758. } /* end function checkdir() */
  1759.  
  1760. #ifdef POCKET_UNZIP
  1761. //******************************************************************************
  1762. // Called from EXTRACT.C and LIST.C
  1763. int match(ZCONST char *string, ZCONST char *pattern, int ignore_case __WDLPRO)
  1764. {
  1765.    // match() for the other ports compares a file in the Zip file with some
  1766.    // command line file pattern.  In our case, we always pass in exact matches,
  1767.    // so we can simply do a string compare to see if we have a match.
  1768.    return (strcmp(string, pattern) == 0);
  1769. }
  1770.  
  1771. //******************************************************************************
  1772. // Called from PROCESS.C
  1773. int iswild(ZCONST char *pattern) {
  1774.    // Our file patterns never contain wild characters.  They are always exact
  1775.    // matches of file names in our Zip file.
  1776.    return FALSE;
  1777. }
  1778.  
  1779. #else // !POCKET_UNZIP
  1780.  
  1781. /************************/
  1782. /*  Function version()  */
  1783. /************************/
  1784.  
  1785. void version(__GPRO)
  1786. {
  1787.     // Dummy function, does nothing.
  1788. }
  1789.  
  1790. #ifndef WINDLL
  1791. /* Console input not supported on CE so just return -1 */
  1792. int getch_win32(void)
  1793. {
  1794.   return -1;
  1795. }
  1796. #endif /* !WINDLL */
  1797. #endif // !POCKET_UNZIP
  1798.  
  1799. #if (defined(UNICODE_SUPPORT))
  1800. /* convert wide character string to multi-byte character string */
  1801. char *wide_to_local_string(ZCONST zwchar *wide_string,
  1802.                            int escape_all)
  1803. {
  1804.   int i;
  1805.   wchar_t wc;
  1806.   int bytes_char;
  1807.   int default_used;
  1808.   int wsize = 0;
  1809.   int max_bytes = 9;
  1810.   char buf[9];
  1811.   char *buffer = NULL;
  1812.   char *local_string = NULL;
  1813.  
  1814.   for (wsize = 0; wide_string[wsize]; wsize++) ;
  1815.  
  1816.   if (max_bytes < MB_CUR_MAX)
  1817.     max_bytes = MB_CUR_MAX;
  1818.  
  1819.   if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
  1820.     return NULL;
  1821.   }
  1822.  
  1823.   /* convert it */
  1824.   buffer[0] = '\0';
  1825.   for (i = 0; i < wsize; i++) {
  1826.     if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
  1827.       /* wchar_t probably 2 bytes */
  1828.       /* could do surrogates if state_dependent and wctomb can do */
  1829.       wc = zwchar_to_wchar_t_default_char;
  1830.     } else {
  1831.       wc = (wchar_t)wide_string[i];
  1832.     }
  1833.     /* The C-RTL under WinCE does not support the generic C-style
  1834.      * Wide-to-MultiByte conversion functions (like wctomb() et. al.).
  1835.      * Therefore, we have to fall back to the underlying WinCE-API call to
  1836.      * get WCHAR-to-ANSI translation done.
  1837.      */
  1838.     bytes_char = WideCharToMultiByte(
  1839.                           CP_ACP, WC_COMPOSITECHECK,
  1840.                           &wc, 1,
  1841.                           (LPSTR)buf, sizeof(buf),
  1842.                           NULL, &default_used);
  1843.     if (default_used)
  1844.       bytes_char = -1;
  1845.     if (escape_all) {
  1846.       if (bytes_char == 1 && (uch)buf[0] <= 0x7f) {
  1847.         /* ASCII */
  1848.         strncat(buffer, buf, 1);
  1849.       } else {
  1850.         /* use escape for wide character */
  1851.         char *escape_string = wide_to_escape_string(wide_string[i]);
  1852.         strcat(buffer, escape_string);
  1853.         free(escape_string);
  1854.       }
  1855.     } else if (bytes_char > 0) {
  1856.       /* multi-byte char */
  1857.       strncat(buffer, buf, bytes_char);
  1858.     } else {
  1859.       /* no MB for this wide */
  1860.       /* use escape for wide character */
  1861.       char *escape_string = wide_to_escape_string(wide_string[i]);
  1862.       strcat(buffer, escape_string);
  1863.       free(escape_string);
  1864.     }
  1865.   }
  1866.   if ((local_string = (char *)realloc(buffer, strlen(buffer) + 1)) == NULL) {
  1867.     free(buffer);
  1868.     return NULL;
  1869.   }
  1870.  
  1871.   return local_string;
  1872. }
  1873. #endif /* UNICODE_SUPPORT */
  1874.