home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip531.zip / wince / intrface.cpp < prev    next >
C/C++ Source or Header  |  1997-04-27  |  57KB  |  1,569 lines

  1. //******************************************************************************
  2. //
  3. // File:        INTRFACE.CPP
  4. //
  5. // Description: This module acts as the interface between the Info-ZIP code and
  6. //              our Windows code in WINMAIN.CPP.  We expose the needed
  7. //              functions to query a file list, test file(s), extract file(s),
  8. //              and display a zip file comment.  The windows code is never
  9. //              bothered with understanding the Globals structure.
  10. //
  11. //              This module also catches all the callbacks from the Info-ZIP
  12. //              code, cleans up the data provided in the callback, and then
  13. //              forwards the information to the appropriate function in the
  14. //              windows code.  These callbacks include status messages, file
  15. //              lists, comments, password prompt, and file overwrite prompts.
  16. //
  17. //              Finally, this module implements the few functions that the
  18. //              Info-ZIP code expects the port to implement. These functions are
  19. //              OS dependent and are mostly related to validating file names and
  20. //              directoies, and setting file attributes and dates of saved files.
  21. //
  22. // Copyright:   All the source files for Pocket UnZip, except for components
  23. //              written by the Info-ZIP group, are copyrighted 1997 by Steve P.
  24. //              Miller.  The product "Pocket UnZip" itself is property of the
  25. //              author and cannot be altered in any way without written consent
  26. //              from Steve P. Miller.
  27. //
  28. // Disclaimer:  All project files are provided "as is" with no guarantee of
  29. //              their correctness.  The authors are not liable for any outcome
  30. //              that is the result of using this source.  The source for Pocket
  31. //              UnZip has been placed in the public domain to help provide an
  32. //              understanding of its implementation.  You are hereby granted
  33. //              full permission to use this source in any way you wish, except
  34. //              to alter Pocket UnZip itself.  For comments, suggestions, and
  35. //              bug reports, please write to stevemil@pobox.com.
  36. //
  37. // Functions:   DoListFiles
  38. //              DoExtractOrTestFiles
  39. //              DoGetComment
  40. //              SetExtractToDirectory
  41. //              InitGlobals
  42. //              FreeGlobals
  43. //              IsFileOrDirectory
  44. //              SmartCreateDirectory
  45. //              ExtractOrTestFilesThread
  46. //              CheckForAbort
  47. //              SetCurrentFile
  48. //              UzpMessagePrnt2
  49. //              UzpInput2
  50. //              UzpMorePause
  51. //              UzpPassword
  52. //              UzpReplace
  53. //              UzpSound
  54. //              SendAppMsg
  55. //              win_fprintf
  56. //              mapattr
  57. //              utimeToFileTime
  58. //              GetFileTimes
  59. //              close_outfile
  60. //              do_wild
  61. //              mapname
  62. //              test_NT
  63. //              checkdir
  64. //              match
  65. //              iswild
  66. //              IsOldFileSystem
  67. //
  68. //
  69. // Date      Name          History
  70. // --------  ------------  -----------------------------------------------------
  71. // 02/01/97  Steve Miller  Created (Version 1.0 using Info-ZIP UnZip 5.30)
  72. //
  73. //******************************************************************************
  74.  
  75.  
  76. //******************************************************************************
  77. #if 0 // The following information and structure are here just for reference
  78. //******************************************************************************
  79. //
  80. // The Windows CE version of Unzip builds with the following defines set:
  81. //
  82. //
  83. //    WIN32
  84. //    _WINDOWS
  85. //    UNICODE
  86. //    _UNICODE
  87. //    WIN32_LEAN_AND_MEAN
  88. //    STRICT
  89. //
  90. //    POCKET_UNZIP         (Main define - Always set)
  91. //
  92. //    UNZIP_INTERNAL
  93. //    WINDLL
  94. //    DLL
  95. //    REENTRANT
  96. //    USE_EF_UT_TIME
  97. //    NO_ZIPINFO
  98. //    NO_STDDEF_H
  99. //    NO_NTSD_WITH_RSXNT
  100. //
  101. //    USE_SMITH_CODE       (optional - See COPYING document) 
  102. //    USE_UNSHRINK         (optional - See COPYING document) 
  103. //
  104. //    DEBUG                (When building for Debug)
  105. //    _DEBUG               (When building for Debug)
  106. //    NDEBUG               (When building for Retail)
  107. //    _NDEBUG              (When building for Retail)
  108. //
  109. //    _WIN32_WCE=100       (When building for Windows CE native)
  110. //
  111. // This causes our Globals structure to look like the following.  The only
  112. // things we care about is this Globals structure, the process_zipfiles()
  113. // function, and a few callback functions.  The Info-ZIP code has not been
  114. // been modified in any way.
  115. //
  116.  
  117. struct Globals {
  118.    int            zipinfo_mode;         // behave like ZipInfo or like normal UnZip?
  119.    int            aflag;                // -a: do ASCII-EBCDIC and/or end-of-line translation
  120.    int            cflag;                // -c: output to stdout
  121.    int            C_flag;               // -C: match filenames case-insensitively
  122.    int            dflag;                // -d: all args are files/dirs to be extracted
  123.    int            fflag;                // -f: "freshen" (extract only newer files)
  124.    int            hflag;                // -h: header line (zipinfo)
  125.    int            jflag;                // -j: junk pathnames (unzip)
  126.    int            lflag;                // -12slmv: listing format (zipinfo)
  127.    int            L_flag;               // -L: convert filenames from some OSes to lowercase
  128.    int            overwrite_none;       // -n: never overwrite files (no prompting)
  129.    int            overwrite_all;        // -o: OK to overwrite files without prompting
  130.    int            P_flag;               // -P: give password on command line (ARGH!)
  131.    int            qflag;                // -q: produce a lot less output
  132.    int            sflag;                // -s: convert spaces in filenames to underscores
  133.    int            volflag;              // -$: extract volume labels
  134.    int            tflag;                // -t: test (unzip) or totals line (zipinfo)
  135.    int            T_flag;               // -T: timestamps (unzip) or dec. time fmt (zipinfo)
  136.    int            uflag;                // -u: "update" (extract only newer/brand-new files)
  137.    int            vflag;                // -v: (verbosely) list directory
  138.    int            V_flag;               // -V: don't strip VMS version numbers
  139.    int            X_flag;               // -X: restore owner/protection or UID/GID or ACLs
  140.    int            zflag;                // -z: display the zipfile comment (only, for unzip)
  141.    int            filespecs;            // number of real file specifications to be matched
  142.    int            xfilespecs;           // number of excluded filespecs to be matched
  143.    int            process_all_files;
  144.    int            create_dirs;          // used by main(), mapname(), checkdir()
  145.    int            extract_flag;
  146.    int            newzip;               // reset in extract.c; used in crypt.c
  147.    LONGINT        real_ecrec_offset;
  148.    LONGINT        expect_ecrec_offset;
  149.    long           csize;                // used by decompr. (NEXTBYTE): must be signed
  150.    long           ucsize;               // used by unReduce(), explode()
  151.    long           used_csize;           // used by extract_or_test_member(), explode()
  152.    int            filenotfound;
  153.    int            redirect_data;        // redirect data to memory buffer
  154.    int            redirect_text;        // redirect text output to buffer
  155.    unsigned       _wsize;
  156.    int            stem_len;
  157.    int            putchar_idx;
  158.    uch           *redirect_pointer;
  159.    uch           *redirect_buffer;
  160.    unsigned       redirect_size;
  161.    char         **pfnames;
  162.    char         **pxnames;
  163.    char           sig[5];
  164.    char           answerbuf[10];
  165.    min_info       info[DIR_BLKSIZ];
  166.    min_info      *pInfo;
  167.    union work     area;                 // see unzpriv.h for definition of work
  168.    ulg near      *crc_32_tab;
  169.    ulg            crc32val;             // CRC shift reg. (was static in funzip)
  170.    uch           *inbuf;                // input buffer (any size is OK)
  171.    uch           *inptr;                // pointer into input buffer
  172.    int            incnt;
  173.    ulg            bitbuf;
  174.    int            bits_left;            // unreduce and unshrink only
  175.    int            zipeof;
  176.    char          *argv0;                // used for NT and EXE_EXTENSION
  177.    char          *wildzipfn;
  178.    char          *zipfn;                // GRR:  MSWIN:  must nuke any malloc'd zipfn...
  179.    int            zipfd;                // zipfile file handle
  180.    LONGINT        ziplen;
  181.    LONGINT        cur_zipfile_bufstart; // extract_or_test, readbuf, ReadByte
  182.    LONGINT        extra_bytes;          // used in unzip.c, misc.c
  183.    uch           *extra_field;          // Unix, VMS, Mac, OS/2, Acorn, ...
  184.    uch           *hold;
  185.    char           local_hdr_sig[5];     // initialize sigs at runtime so unzip
  186.    char           central_hdr_sig[5];   //  executable won't look like a zipfile
  187.    char           end_central_sig[5];
  188.  
  189.    local_file_hdr lrec;                 // used in unzip.c, extract.c
  190.    cdir_file_hdr  crec;                 // used in unzip.c, extract.c, misc.c
  191.    ecdir_rec      ecrec;                // used in unzip.c, extract.c
  192.    struct stat    statbuf;              // used by main, mapname, check_for_newer
  193.  
  194.    int            mem_mode;
  195.    uch           *outbufptr;            // extract.c static
  196.    ulg            outsize;              // extract.c static
  197.    int            reported_backslash;   // extract.c static
  198.    int            disk_full;
  199.    int            newfile;
  200.  
  201.    int            didCRlast;            // fileio static
  202.    ulg            numlines;             // fileio static: number of lines printed
  203.    int            sol;                  // fileio static: at start of line
  204.    int            no_ecrec;             // process static
  205.    FILE          *outfile;
  206.    uch           *outbuf;
  207.    uch           *realbuf;
  208.                   
  209.    uch           *outbuf2;              //  main() (never changes); else malloc'd
  210.    uch           *outptr;
  211.    ulg            outcnt;               // number of chars stored in outbuf
  212.    char          *filename;
  213.  
  214.    char          *pwdarg;               // pointer to command-line password (-P option)
  215.    int            nopwd;                // crypt static
  216.    ulg            keys[3];              // crypt static: keys defining pseudo-random sequence
  217.    char          *key;                  // crypt static: decryption password or NULL
  218.  
  219.    unsigned       hufts;                // track memory usage
  220.  
  221.    struct huft   *fixed_tl;             // inflate static
  222.    struct huft   *fixed_td;             // inflate static
  223.    int            fixed_bl
  224.    int            fixed_bd;             // inflate static
  225.    unsigned       wp;                   // inflate static: current position in slide
  226.    ulg            bb;                   // inflate static: bit buffer
  227.    unsigned       bk;                   // inflate static: bits in bit buffer
  228.    MsgFn         *message;
  229.    InputFn       *input;
  230.    PauseFn       *mpause;
  231.    PasswdFn      *decr_passwd;
  232.    ReplaceFn     *replace;
  233.    SoundFn       *sound;
  234.  
  235.    int            incnt_leftover;       // so improved NEXTBYTE does not waste input
  236.    uch           *inptr_leftover;
  237.  
  238.    // These are defined in PUNZIP.H.
  239.    char           matchname[FILNAMSIZ]; // used by do_wild()
  240.    int            notfirstcall;         // used by do_wild()
  241.    char          *zipfnPtr;
  242.    char          *wildzipfnPtr;
  243. };
  244.  
  245. #endif // #if 0 - This struct is here just for reference
  246.  
  247. //******************************************************************************
  248.  
  249. extern "C" {
  250. #define __INTRFACE_CPP__
  251. #define UNZIP_INTERNAL
  252. #include "unzip.h"
  253. #include "crypt.h"     // Needed to pick up CRYPT define
  254. #include <commctrl.h>
  255. #include "intrface.h"
  256. #include "winmain.h"
  257.  
  258. #ifndef _WIN32_WCE
  259. #include <process.h>   // _beginthreadex() and _endthreadex()
  260. #endif
  261.  
  262. }
  263. #include <tchar.h> // Must be outside of extern "C" block
  264.  
  265.  
  266. //******************************************************************************
  267. //***** "Local" Global Variables
  268. //******************************************************************************
  269.  
  270. static USERFUNCTIONS  g_uf;
  271. static DCL            g_dcl;
  272. static EXTRACT_INFO  *g_pExtractInfo = NULL;
  273. static FILE_NODE     *g_pFileLast    = NULL;
  274. static CHAR           g_szExtractToDirectory[_MAX_PATH];
  275. static BOOL           g_fOutOfMemory;
  276.  
  277. //******************************************************************************
  278. //***** Local Function Prototypes
  279. //******************************************************************************
  280.  
  281. extern "C" {
  282.  
  283. // Our exposed interface functions to the Info-ZIP core.
  284. BOOL DoListFiles(LPCSTR szZipFile);
  285. BOOL DoExtractOrTestFiles(LPCSTR szZipFile, EXTRACT_INFO *pei);
  286. BOOL DoGetComment(LPCSTR szFile);
  287. BOOL SetExtractToDirectory(LPTSTR szDirectory);
  288.  
  289. // Internal functions.
  290. struct Globals* InitGlobals(LPCSTR szZipFile);
  291. void FreeGlobals(Globals *pG);
  292. int IsFileOrDirectory(LPCTSTR szPath);
  293. BOOL SmartCreateDirectory(struct Globals *pG, LPCSTR szDirectory);
  294.  
  295. #ifdef _WIN32_WCE
  296. DWORD WINAPI ExtractOrTestFilesThread(LPVOID lpv);
  297. #else
  298. unsigned __stdcall ExtractOrTestFilesThread(void *lpv);
  299. #endif
  300.  
  301. void CheckForAbort(struct Globals *pG);
  302. void SetCurrentFile(struct Globals *pG);
  303.  
  304. // Callbacks from Info-ZIP code.
  305. int UzpMessagePrnt2(zvoid *pG, uch *buffer, ulg size, int flag);
  306. int UzpInput2(zvoid *pG, uch *buffer, int *size, int flag);
  307. void UzpMorePause(zvoid *pG, const char *szPrompt, int flag);
  308. int UzpPassword(zvoid *pG, int *pcRetry, char *szPassword, int nSize, 
  309.                 const char *szZipFile, const char *szFile);
  310. int WINAPI UzpReplace(char *szFile);
  311. void WINAPI UzpSound(void);
  312. void WINAPI SendAppMsg(ulg dwSize, ulg dwCompressedSize, int ratio, int month, 
  313.                        int day, int year, int hour, int minute, int uppercase,
  314.                        char *szPath, char *szMethod, ulg dwCRC);
  315. int win_fprintf(FILE *file, unsigned int dwCount, char far *buffer);
  316.  
  317. // Functions that Info-ZIP expects the port to write and export.
  318. void utimeToFileTime(time_t ut, FILETIME *pft, BOOL fOldFileSystem);
  319. int GetFileTimes(struct Globals *pG, FILETIME *pftCreated, FILETIME *pftAccessed,
  320.                  FILETIME *pftModified);
  321. int mapattr(struct Globals *pG);
  322. void close_outfile(struct Globals *pG);
  323. char* do_wild(struct Globals *pG, char *wildspec);
  324. int mapname(struct Globals *pG, int renamed);
  325. int test_NT(struct Globals *pG, uch *eb, unsigned eb_size);
  326. int checkdir(struct Globals *pG, char *pathcomp, int flag);
  327.  
  328. // Check for FAT, VFAT, HPFS, etc.
  329. BOOL IsOldFileSystem(char *szPath);
  330.  
  331. } // extern "C"
  332.  
  333.  
  334. //******************************************************************************
  335. //***** Our exposed interface functions to the Info-ZIP core
  336. //******************************************************************************
  337.  
  338. int DoListFiles(LPCSTR szZipFile) {
  339.  
  340.    int result;
  341.  
  342.    // Create our Globals struct and fill it in whith some default values.
  343.    struct Globals *pG = InitGlobals(szZipFile);
  344.    if (!pG) {
  345.       return PK_MEM;
  346.    }
  347.  
  348.    pG->vflag = 1; // verbosely: list directory (for WIN32 it is 0 or 1)
  349.    pG->process_all_files = TRUE; // improves speed
  350.  
  351.    g_pFileLast = NULL;
  352.    g_fOutOfMemory = FALSE;
  353.  
  354.    // We wrap some exception handling around the entire Info-ZIP engine to be
  355.    // safe.  Since we are running on a device with tight memory configurations,
  356.    // all sorts of problems can arise when we run out of memory.
  357.    __try {
  358.  
  359.       // Call the unzip routine.  We will catch the file information in a
  360.       // callback to SendAppMsg().
  361.       result = process_zipfiles(pG);
  362.  
  363.       // Make sure we didn't run out of memory in the process.
  364.       if (g_fOutOfMemory) {
  365.          result = PK_MEM;
  366.       }
  367.  
  368.    } __except(EXCEPTION_EXECUTE_HANDLER) {
  369.  
  370.       // Catch any exception here.
  371.       DebugOut(TEXT("Exception 0x%08X occurred in DoListFiles()"),
  372.                GetExceptionCode());
  373.       result = PK_EXCEPTION;
  374.    }
  375.  
  376.    g_pFileLast = NULL;
  377.  
  378.    // It is possible that the ZIP engine change the file name a bit (like adding
  379.    // a ".zip" if needed).  If so, we will pick up the new name.
  380.    if ((result != PK_EXCEPTION) && pG->zipfn && *pG->zipfn) {
  381.       strcpy(g_szZipFile, pG->zipfn);
  382.    }
  383.  
  384.    // Free our globals.
  385.    FreeGlobals(pG);
  386.  
  387.    return result;
  388. }
  389.  
  390. //******************************************************************************
  391. BOOL DoExtractOrTestFiles(LPCSTR szZipFile, EXTRACT_INFO *pei) {
  392.  
  393.    // WARNING!!!  This functions hands the EXTRACT_INFO structure of to a thread
  394.    // to perform the actual extraction/test.  When the thread is done, it will
  395.    // send a message to the progress dialog.  The calling function must not
  396.    // delete the EXTRAT_INFO structure until it receives the message.  Currently,
  397.    // this is not a problem for us since the structure lives on the stack of the
  398.    // calling thread.  The calling thread then displays a dialog that blocks the
  399.    // calling thread from clearing the stack until the dialog is dismissed, which
  400.    // occurs when the dialog receives the message.
  401.  
  402.    // Create our globals so we can store the file name.
  403.    struct Globals *pG = InitGlobals(szZipFile);
  404.    if (!pG) {
  405.       pei->result = PK_MEM;
  406.       SendMessage(g_hDlgProgress, WM_PRIVATE, MSG_OPERATION_COMPLETE, (LPARAM)pei);
  407.       return FALSE;
  408.    }
  409.  
  410.    // Store a global pointer to the Extract structure so it can be reached from
  411.    // our thread and callback functions.
  412.    g_pExtractInfo = pei;
  413.  
  414.    // Spawn our thread
  415.    DWORD dwThreadId;
  416.    HANDLE hThread;
  417.  
  418. #ifdef _WIN32_WCE
  419.  
  420.    // On CE, we use good old CreateThread() since the WinCE CRT does not 
  421.    // allocate per-thread storage.
  422.    hThread = CreateThread(NULL, 0, ExtractOrTestFilesThread, pG, 0, &dwThreadId);
  423.  
  424. #else
  425.  
  426.    // On NT, we need use the CRT's thread function so that we don't leak any
  427.    // CRT allocated memory when the thread exits.
  428.    hThread = (HANDLE)_beginthreadex(NULL, 0, ExtractOrTestFilesThread, pG, 0,
  429.                                     (unsigned*)&dwThreadId);
  430.  
  431. #endif
  432.  
  433.    // Bail out if our thread failed to create.
  434.    if (!hThread) {
  435.  
  436.       DebugOut(TEXT("CreateThread() failed [%u]"), GetLastError());
  437.  
  438.       // Set our error as a memory error.
  439.       g_pExtractInfo->result = PK_MEM;
  440.  
  441.       // Free our globals.
  442.       FreeGlobals(pG);
  443.  
  444.       // Tell the progress dialog that we are done.
  445.       SendMessage(g_hDlgProgress, WM_PRIVATE, MSG_OPERATION_COMPLETE, (LPARAM)pei);
  446.  
  447.       g_pExtractInfo = NULL;
  448.       return FALSE;
  449.    }
  450.  
  451.    // Close our thread handle since we have no use for it.
  452.    CloseHandle(hThread);
  453.    return TRUE;
  454. }
  455.  
  456. //******************************************************************************
  457. int DoGetComment(LPCSTR szFile) {
  458.  
  459.    int result;
  460.  
  461.    // Create our Globals struct and fill it in whith some default values.
  462.    struct Globals *pG = InitGlobals(szFile);
  463.    if (!pG) {
  464.       return PK_MEM;
  465.    }
  466.  
  467.    pG->zflag = TRUE; // display the zipfile comment
  468.  
  469.    // We wrap some exception handling around the entire Info-ZIP engine to be
  470.    // safe.  Since we are running on a device with tight memory configurations,
  471.    // all sorts of problems can arise when we run out of memory.
  472.    __try {
  473.  
  474.       // Call the unzip routine.  We will catch the comment string in a callback
  475.       // to win_fprintf().
  476.       result = process_zipfiles(pG);
  477.  
  478.    } __except(EXCEPTION_EXECUTE_HANDLER) {
  479.  
  480.       // Catch any exception here.
  481.       DebugOut(TEXT("Exception 0x%08X occurred in DoGetComment()"),
  482.                GetExceptionCode());
  483.       result = PK_EXCEPTION;
  484.    }
  485.  
  486.    // Free our globals.
  487.    FreeGlobals(pG);
  488.  
  489.    return result;
  490. }
  491.  
  492. //******************************************************************************
  493. BOOL SetExtractToDirectory(LPTSTR szDirectory) {
  494.  
  495.    BOOL fNeedToAddWack = FALSE;
  496.  
  497.    // Remove any trailing wack from the path.
  498.    int length = _tcslen(szDirectory);
  499.    if ((length > 0) && (szDirectory[length - 1] == TEXT('\\'))) {
  500.       szDirectory[--length] = TEXT('\0');
  501.       fNeedToAddWack = TRUE;
  502.    }
  503.  
  504. #ifndef _WIN32_WCE
  505.    
  506.    // Check to see if a root directory was specified.
  507.    if ((length == 2) && isalpha(szDirectory[0]) && (szDirectory[1] == ':')) {
  508.  
  509.       // If just a root is specified, we need to only verify the drive letter.
  510.       if (!(GetLogicalDrives() & (1 << (tolower(szDirectory[0]) - (int)'a')))) {
  511.  
  512.          // This drive does not exist.  Bail out with a failure.
  513.          return FALSE;
  514.       }
  515.  
  516.    } else
  517.  
  518. #endif
  519.  
  520.    // We only verify path if length is >0 since we know "\" is valid.
  521.    if (length > 0) {
  522.  
  523.       // Verify the the path exists and that it is a directory.
  524.       if (IsFileOrDirectory(szDirectory) != 2) {
  525.          return FALSE;
  526.       }
  527.    }
  528.  
  529.    // Store the directory for when we do an extract.
  530.    wcstombs(g_szExtractToDirectory, szDirectory, countof(g_szExtractToDirectory));
  531.  
  532.    // We always want a wack at the end of our path.
  533.    strcat(g_szExtractToDirectory, "\\");
  534.    
  535.    // Add the wack back to the end of the path.
  536.    if (fNeedToAddWack) {
  537.       _tcscat(szDirectory, TEXT("\\"));
  538.    }
  539.  
  540.    return TRUE;
  541. }
  542.  
  543. //******************************************************************************
  544. //***** Internal functions
  545. //******************************************************************************
  546.  
  547. struct Globals* InitGlobals(LPCSTR szZipFile) {
  548.  
  549.    // Store a global pointer to our USERFUNCTIONS structure so that LIST.C,
  550.    // PROCESS.C, and WINMAIN can access it.
  551.    lpUserFunctions = &g_uf;
  552.  
  553.    // Clear our USERFUNCTIONS structure and assign our SendAppMsg() function.
  554.    ZeroMemory(&g_uf, sizeof(g_uf));
  555.    g_uf.SendApplicationMessage = SendAppMsg;
  556.    
  557.    // Store a global pointer to our DCL structure so that EXTRACT.C can access it.
  558.    lpDCL = &g_dcl;
  559.  
  560.    // Clear our DCL structure.
  561.    ZeroMemory(&g_dcl, sizeof(g_dcl));
  562.  
  563.    // Create our global structure - pG
  564.    CONSTRUCTGLOBALS();
  565.  
  566.    // Bail out if we failed to allocate our Globals structure.
  567.    if (!pG) {
  568.       return NULL;
  569.    }
  570.  
  571.    // Fill in all our callback functions.
  572.    pG->message     = UzpMessagePrnt2;
  573.    pG->input       = UzpInput2;
  574.    pG->mpause      = UzpMorePause;
  575.    pG->replace     = UzpReplace;
  576.    pG->sound       = UzpSound;
  577.  
  578. #if CRYPT
  579.    pG->decr_passwd = UzpPassword;
  580. #endif
  581.  
  582.    // Match filenames case-sensitively.  We can do this since we can guarentee
  583.    // exact case because the user can only select files via our UI.
  584.    pG->C_flag = FALSE;
  585.  
  586.    // Allocate and store the ZIP file name in pG->zipfn
  587.    if (!(pG->zipfnPtr = new char[FILNAMSIZ])) {
  588.       FreeGlobals(pG);
  589.       return NULL;
  590.    }
  591.    pG->zipfn = pG->zipfnPtr;
  592.    strcpy(pG->zipfn, szZipFile);
  593.  
  594.    // Allocate and store the ZIP file name in pG->zipfn.  This needs to done
  595.    // so that do_wild() does not wind up clearing out the zip file name when
  596.    // it returns in process.c
  597.    if (!(pG->wildzipfnPtr = new char[FILNAMSIZ])) {
  598.       FreeGlobals(pG);
  599.       return NULL;
  600.    }
  601.    pG->wildzipfn = pG->wildzipfnPtr;
  602.    strcpy(pG->wildzipfn, szZipFile);
  603.  
  604.    return pG;
  605. }
  606.  
  607. //******************************************************************************
  608. void FreeGlobals(Globals *pG) {
  609.  
  610.    // Free our ZIP file name
  611.    if (pG->zipfnPtr) {
  612.       delete[] pG->zipfnPtr;
  613.       pG->zipfnPtr = pG->zipfn = NULL;
  614.    }
  615.  
  616.    // Free our wild name buffer
  617.    if (pG->wildzipfnPtr) {
  618.       delete[] pG->wildzipfnPtr;
  619.       pG->wildzipfnPtr = pG->wildzipfn = NULL;
  620.    }
  621.  
  622.    // Free everything else.
  623.    DESTROYGLOBALS()
  624. }
  625.  
  626. //******************************************************************************
  627. int IsFileOrDirectory(LPCTSTR szPath) {
  628.  
  629.    // Geth the attributes of the item.
  630.    DWORD dwAttribs = GetFileAttributes(szPath);
  631.  
  632.    // Bail out now if we could not find the path at all.
  633.    if (dwAttribs == 0xFFFFFFFF) {
  634.       return 0;
  635.    }
  636.  
  637.    // Return 1 for file and 2 for directory.
  638.    return ((dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 1);
  639. }
  640.  
  641. //******************************************************************************
  642. BOOL SmartCreateDirectory(struct Globals *pG, LPCSTR szDirectory) {
  643.  
  644.    // Copy path to a UNICODE buffer.
  645.    TCHAR szBuffer[_MAX_PATH];
  646.    mbstowcs(szBuffer, szDirectory, countof(szBuffer));
  647.  
  648.    int x = IsFileOrDirectory(szBuffer);
  649.  
  650.    // Create the directory if it does not exist.
  651.    if (x == 0) {
  652.       if (!CreateDirectory(szBuffer, NULL)) {
  653.          Info(slide, 1, ((char *)slide, "error creating directory: %s\n", szDirectory));
  654.          return FALSE;
  655.       }
  656.  
  657.    // If there is a file with the same name, then display an error.
  658.    } else if (x == 1) {
  659.       Info(slide, 1, ((char *)slide, 
  660.            "cannot create %s as a file with same name already exists.\n",
  661.            szDirectory));
  662.       return FALSE;
  663.    }
  664.  
  665.    // If the directory already exists or was created, then return success.
  666.    return TRUE;
  667. }
  668.  
  669. //******************************************************************************
  670. #ifdef _WIN32_WCE
  671.  
  672. // On WinCE, we declare our thread function the way CreateThread() likes it.
  673. DWORD WINAPI ExtractOrTestFilesThread(LPVOID lpv) {
  674.  
  675. #else
  676.  
  677. // On WinNT, we declare our thread function the way _beginthreadex likes it.
  678. unsigned __stdcall ExtractOrTestFilesThread(void *lpv) {
  679.  
  680. #endif
  681.  
  682.    struct Globals *pG = (struct Globals*)lpv;
  683.  
  684.    if (g_pExtractInfo->fExtract) {
  685.  
  686.       pG->extract_flag = TRUE;
  687.  
  688.       switch (g_pExtractInfo->overwriteMode) {
  689.  
  690.          case OM_NEWER:
  691.             pG->uflag = TRUE; // Update (extract only newer/brand-new files)
  692.             break;
  693.  
  694.          case OM_ALWAYS:
  695.             pG->overwrite_all = TRUE; // OK to overwrite files without prompting
  696.             break;
  697.  
  698.          case OM_NEVER:
  699.             pG->overwrite_none = TRUE; // Never overwrite files (no prompting)
  700.             break;
  701.  
  702.          default:
  703.             g_dcl.PromptToOverwrite = TRUE; // Force a prompt
  704.             break;
  705.       }
  706.  
  707.       // Throw away paths if requested.
  708.       pG->jflag = !g_pExtractInfo->fRestorePaths;
  709.  
  710.    } else {
  711.       pG->tflag = TRUE;
  712.    }
  713.  
  714.    if (g_pExtractInfo->szFileList) {
  715.       pG->filespecs = g_pExtractInfo->dwFileCount;
  716.       pG->pfnames = g_pExtractInfo->szFileList;
  717.    } else {
  718.       // Improves performance if all files are being extracted.
  719.       pG->process_all_files = TRUE;
  720.    }
  721.  
  722.    // All args are files/dirs to be extracted.
  723.    pG->dflag = TRUE;                    
  724.  
  725.    // Invalidate our file offset to show that we are starting a new operation.
  726.    g_pExtractInfo->dwFileOffset = 0xFFFFFFFF;
  727.  
  728.    // We wrap some exception handling around the entire Info-ZIP engine to be
  729.    // safe.  Since we are running on a device with tight memory configurations,
  730.    // all sorts of problems can arise when we run out of memory.
  731.    __try {
  732.  
  733.       // Put a jump marker on our stack so the user can abort.
  734.       int error = setjmp(dll_error_return);
  735.  
  736.       // If setjmp() returns 0, then we just set our jump marker and we can
  737.       // continue with the operation.  If setjmp() returned something else,
  738.       // then we reached this point because the operation was aborted and 
  739.       // set our instruction pointer back here.
  740.  
  741.       if (error > 0) {
  742.          // We already called process_zipfiles() and were thrown back here.
  743.          g_pExtractInfo->result = (error == 1) ? PK_BADERR : error;
  744.  
  745.       } else {
  746.          // Entering Info-ZIP... close your eyes.
  747.          g_pExtractInfo->result = process_zipfiles(pG);
  748.       }
  749.  
  750.    } __except(EXCEPTION_EXECUTE_HANDLER) {
  751.  
  752.       // Catch any exception here.
  753.       DebugOut(TEXT("Exception 0x%08X occurred in ExtractOrTestFilesThread()"),
  754.                GetExceptionCode());
  755.       g_pExtractInfo->result = PK_EXCEPTION;
  756.    }
  757.  
  758.    // Free our globals.
  759.    FreeGlobals(pG);
  760.  
  761.    // Tell the progress dialog that we are done.
  762.    SendMessage(g_hDlgProgress, WM_PRIVATE, MSG_OPERATION_COMPLETE, 
  763.                (LPARAM)g_pExtractInfo);
  764.  
  765.    // Clear our global pointer as we are done with it.
  766.    g_pExtractInfo = NULL;
  767.  
  768. #ifndef _WIN32_WCE
  769.    // On NT, we need to free any CRT allocated memory.
  770.    _endthreadex(0);
  771. #endif
  772.  
  773.    return 0;
  774. }
  775.  
  776. //******************************************************************************
  777. void CheckForAbort(struct Globals *pG) {
  778.    if (g_pExtractInfo->fAbort) {
  779.       
  780.       // Add a newline to our log if we are in the middle of a line of text.
  781.       if (!g_pExtractInfo->fNewLineOfText) {
  782.          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)"\n");
  783.       }
  784.  
  785.       // Make sure whatever file we are currently processing gets closed.
  786.       if (((int)pG->outfile != 0) && ((int)pG->outfile != -1)) {
  787.          if (g_pExtractInfo->fExtract && *pG->filename) {
  788.  
  789.             // Make sure the user is aware that this file is screwed.
  790.             SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
  791.                         (LPARAM)"warning: ");
  792.             SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
  793.                         (LPARAM)pG->filename);
  794.             SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
  795.                         (LPARAM)" is probably truncated.\n");
  796.          }
  797.  
  798.          // Close the file.
  799.          close_outfile(pG);
  800.       }
  801.  
  802.       // Display an aborted message in the log
  803.       SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, 
  804.                   (LPARAM)"Operation aborted by user.\n");
  805.  
  806.       // I hate to do this... Take a giant step out of here.
  807.       longjmp(dll_error_return, PK_ABORTED);
  808.    }
  809. }
  810.  
  811. //******************************************************************************
  812. void SetCurrentFile(struct Globals *pG) {
  813.  
  814.    // Reset all our counters as we about to process a new file.
  815.    g_pExtractInfo->dwFileOffset = (DWORD)pG->pInfo->offset;
  816.    g_pExtractInfo->dwFile++;
  817.    g_pExtractInfo->dwBytesWrittenThisFile = 0;
  818.    g_pExtractInfo->dwBytesWrittenPreviousFiles += g_pExtractInfo->dwBytesTotalThisFile;
  819.    g_pExtractInfo->dwBytesTotalThisFile = pG->ucsize;
  820.    g_pExtractInfo->szFile = pG->filename;
  821.    g_pExtractInfo->fNewLineOfText = TRUE;
  822.  
  823.    // Pass control to our GUI thread to do a full update our progress dialog.
  824.    SendMessage(g_hWndMain, WM_PRIVATE, MSG_UPDATE_PROGRESS_COMPLETE,
  825.                (LPARAM)g_pExtractInfo);
  826.  
  827.    // Check our abort flag.
  828.    CheckForAbort(pG);
  829. }
  830.  
  831.  
  832. //******************************************************************************
  833. //***** Callbacks from Info-ZIP code.
  834. //******************************************************************************
  835.  
  836. int UzpMessagePrnt2(zvoid *pG, uch *buffer, ulg size, int flag) {
  837.  
  838.    // Some ZIP files cause us to get called during DoListFiles(). We only handle
  839.    // messages while processing DoExtractFiles().
  840.    if (!g_pExtractInfo) {
  841.       if (g_hWndEdit) {
  842.          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, 
  843.                      (LPARAM)buffer);
  844.       } else {
  845.          DebugOut(TEXT("Unhandled call to UzpMessagePrnt2(\"%S\")"), buffer);
  846.       }
  847.       return 0;
  848.    }
  849.  
  850.    // When extracting, mapname() will get called for every file which in turn
  851.    // will call SetCurrentFile().  For testing though, mapname() never gets
  852.    // called so we need to be on the lookout for a new file.
  853.    if (g_pExtractInfo->dwFileOffset != (DWORD)((struct Globals*)pG)->pInfo->offset) {
  854.       SetCurrentFile((struct Globals*)pG);
  855.    }
  856.  
  857.    // Make sure this message was inteded for us to display.
  858.    if (!MSG_NO_WGUI(flag) && !MSG_NO_WDLL(flag)) {
  859.  
  860.       // Insert a leading newline if requested to do so.
  861.       if (MSG_LNEWLN(flag) && !g_pExtractInfo->fNewLineOfText) {
  862.          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)"\n");
  863.          g_pExtractInfo->fNewLineOfText = TRUE;
  864.       }
  865.  
  866.       // Since we use a proportional font, we need to do a little cleanup of the
  867.       // text we are passed since it assumes a fixed font and adds padding to try
  868.       // to line things up.  We remove leading whitespace on any new line of text.
  869.       if (g_pExtractInfo->fNewLineOfText) {
  870.          while (*buffer == ' ') {
  871.             buffer++;
  872.          }
  873.       }
  874.  
  875.       // We always remove trailing whitespace.
  876.       LPSTR psz = (LPSTR)buffer + strlen((LPSTR)buffer) - 1;
  877.       while ((psz >= (LPSTR)buffer) && (*psz == ' ')) {
  878.          *(psz--) = '\0';
  879.       }
  880.  
  881.       // Determine if the next line of text will be a new line of text.
  882.       g_pExtractInfo->fNewLineOfText = ((*psz == '\r') || (*psz == '\n'));
  883.  
  884.       // Change all forward slashes to back slashes in the buffer
  885.       ForwardSlashesToBackSlashesA((LPSTR)buffer);
  886.  
  887.       // Add the cleaned-up text to our extraction log edit control.
  888.       SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)buffer);
  889.  
  890.       // Append a trailing newline if requested to do so.
  891.       if (MSG_TNEWLN(flag) || MSG_MNEWLN(flag) && !g_pExtractInfo->fNewLineOfText) {
  892.          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)"\n");
  893.          g_pExtractInfo->fNewLineOfText = TRUE;
  894.       }
  895.    }
  896.  
  897.    return 0;
  898. }
  899.  
  900. //******************************************************************************
  901. int UzpInput2(zvoid *pG, uch *buffer, int *size, int flag) {
  902.    DebugOut(TEXT("WARNING: UzpInput2(...) called"));
  903.    return 0;
  904. }
  905.  
  906. //******************************************************************************
  907. void UzpMorePause(zvoid *pG, const char *szPrompt, int flag) {
  908.    DebugOut(TEXT("WARNING: UzpMorePause(...) called"));
  909. }
  910.  
  911. //******************************************************************************
  912. int UzpPassword(zvoid *pG, int *pcRetry, char *szPassword, int nSize, 
  913.                 const char *szZipFile, const char *szFile)
  914. {
  915.    // Return Values:
  916.    //    IZ_PW_ENTERED    got some PWD string, use/try it
  917.    //    IZ_PW_CANCEL     no password available (for this entry)
  918.    //    IZ_PW_CANCELALL  no password, skip any further PWD request
  919.    //    IZ_PW_ERROR      failure (no mem, no tty, ...)
  920.  
  921. #if CRYPT
  922.  
  923.    // Build the data structure for our dialog.
  924.    DECRYPT_INFO di;
  925.    di.retry      = *pcRetry;
  926.    di.szPassword = szPassword;
  927.    di.nSize      = nSize;
  928.    di.szFile     = szFile;
  929.  
  930.    // Clear the password to be safe.
  931.    *di.szPassword = '\0';
  932.  
  933.    // On our first call for a file, *pcRetry == 0.  If we would like to allow
  934.    // for retries, then we set the value of *pcRetry to the number of retries we
  935.    // are willing to allow.  We will be recalled as neccessary, each time with
  936.    // *pcRetry being decremented once.  1 is the last retry we will get.
  937.    *pcRetry = (*pcRetry == 0) ? MAX_PASSWORD_RETRIES : (*pcRetry - 1);
  938.  
  939.    // Pass control to our GUI thread which will prompt the user for a password.
  940.    return SendMessage(g_hWndMain, WM_PRIVATE, MSG_PROMPT_FOR_PASSWORD, (LPARAM)&di);
  941.  
  942. #else
  943.    return -2;
  944. #endif
  945. }
  946.  
  947. //******************************************************************************
  948. int WINAPI UzpReplace(char *szFile) {
  949.    // Pass control to our GUI thread which will prompt the user to overwrite.
  950.    return SendMessage(g_hWndMain, WM_PRIVATE, MSG_PROMPT_TO_REPLACE, (LPARAM)szFile);
  951. }
  952.  
  953. //******************************************************************************
  954. void WINAPI UzpSound(void) {
  955.    // Do nothing.
  956. }
  957.  
  958. //******************************************************************************
  959. // Called from LIST.C
  960. void WINAPI SendAppMsg(ulg dwSize, ulg dwCompressedSize, int ratio, int month, 
  961.                        int day, int year, int hour, int minute, int uppercase,
  962.                        char *szPath, char *szMethod, ulg dwCRC)
  963. {
  964.    // If we are out of memory, then just bail since we will only make things worse.
  965.    if (g_fOutOfMemory) {
  966.       return;
  967.    }
  968.  
  969.    // We get our Globals structure and then retrieve the real file name.
  970.    GETGLOBALS()
  971.    szPath = pG->filename;
  972.  
  973.    // Allocate a FILE_NODE large enough to hold this file.
  974.    int length = strlen(szPath) + strlen(szMethod);
  975.    g_pFileLast = (FILE_NODE*)new BYTE[sizeof(FILE_NODE) + (sizeof(TCHAR) * length)];
  976.  
  977.    // Bail out if we failed to allocate the node.
  978.    if (!g_pFileLast) {
  979.       DebugOut(TEXT("Failed to create a FILE_NODE for \"%S\"."), szPath);
  980.       g_fOutOfMemory = TRUE;
  981.       return;
  982.    }
  983.  
  984.    // Fill in our node.
  985.    g_pFileLast->dwSize           = dwSize;
  986.    g_pFileLast->dwCompressedSize = dwCompressedSize;
  987.    g_pFileLast->dwCRC            = dwCRC;
  988.    g_pFileLast->szComment        = NULL;
  989.    g_pFileLast->szType           = NULL;
  990.  
  991.    // Fix the year value to contain the real year.
  992.    year += 1900;
  993.  
  994.    // Year:   0 - 4095 (12) 1111 1111 1111 0000 0000 0000 0000 0000 (0xFFF00000)
  995.    // Month:  1 -   12 ( 4) 0000 0000 0000 1111 0000 0000 0000 0000 (0x000F0000)
  996.    // Day:    1 -   31 ( 5) 0000 0000 0000 0000 1111 1000 0000 0000 (0x0000F800)
  997.    // Hour:   0 -   23 ( 5) 0000 0000 0000 0000 0000 0111 1100 0000 (0x000007C0)
  998.    // Minute: 0 -   59 ( 6) 0000 0000 0000 0000 0000 0000 0011 1111 (0x0000003F)
  999.  
  1000.    // Do some bit shifting to make the date and time fit in a DWORD.
  1001.    g_pFileLast->dwModified = (((DWORD)(year   & 0x0FFF) << 20) |
  1002.                               ((DWORD)(month  & 0x000F) << 16) |
  1003.                               ((DWORD)(day    & 0x001F) << 11) |
  1004.                               ((DWORD)(hour   & 0x001F) <<  6) |
  1005.                               ((DWORD)(minute & 0x003F)));
  1006.    
  1007.    // We need to get our globals structure to determine our attributes and
  1008.    // encryption information.
  1009.    g_pFileLast->dwAttributes = (pG->crec.external_file_attributes & 0xFF);
  1010.    if (pG->crec.general_purpose_bit_flag & 1) {
  1011.       g_pFileLast->dwAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1012.    }
  1013.  
  1014.    // Store the path and method in our string buffer.
  1015.    strcpy(g_pFileLast->szPathAndMethod, szPath);
  1016.    strcpy(g_pFileLast->szPathAndMethod + strlen(szPath) + 1, szMethod);
  1017.  
  1018.    // Pass the file object to our windows code to have it added to our list.
  1019.    AddFileToListView(g_pFileLast);
  1020. }
  1021.  
  1022. //******************************************************************************
  1023. int win_fprintf(FILE *file, unsigned int dwCount, char far *buffer) {
  1024.  
  1025.    // win_fprintf() is used within Info-ZIP to write to a file as well as log 
  1026.    // information.  If the "file" is a real file handle (not stdout or stderr),
  1027.    // then we write the data to the file and return.
  1028.  
  1029.    if ((file != stdout) && (file != stderr)) {
  1030.  
  1031.       DWORD dwBytesWriten = 0;
  1032. #ifdef _WIN32_WCE
  1033.       // On WinCE all FILEs are really HANDLEs.  See WINCE.CPP for more info.
  1034.       WriteFile((HANDLE)file, buffer, dwCount, &dwBytesWriten, NULL);
  1035. #else
  1036.       dwBytesWriten = fwrite(buffer, 1, dwCount, file);
  1037. #endif
  1038.  
  1039.       // Update our bytes written count.
  1040.       g_pExtractInfo->dwBytesWrittenThisFile += dwBytesWriten;
  1041.  
  1042.       // Pass control to our GUI thread to do a partial update our progress dialog.
  1043.       SendMessage(g_hWndMain, WM_PRIVATE, MSG_UPDATE_PROGRESS_PARTIAL,
  1044.                   (LPARAM)g_pExtractInfo);
  1045.  
  1046.       // Check our abort flag.
  1047.       GETGLOBALS();
  1048.       CheckForAbort(pG);
  1049.  
  1050.       return dwBytesWriten;
  1051.    }
  1052.  
  1053.    // Check to see if we are expecting a extraction progress string
  1054.    if (g_pExtractInfo) {
  1055.  
  1056.       // Most of our progress strings come to our UzpMessagePrnt2() callback,
  1057.       // but we occasionally get one here.  We will just forward it to 
  1058.       // UzpMessagePrnt2() as if it never came here.  To do this, we need to
  1059.       // get a pointer to our Globals struct.  Calling GETGLOBALS() sort of
  1060.       // breaks us from be REENTRANT, but we don't support that anyway.
  1061.       GETGLOBALS();
  1062.       UzpMessagePrnt2(pG, (uch*)buffer, dwCount, 0);
  1063.       return dwCount;
  1064.    }
  1065.  
  1066.    // Check to see if we are expecting a zip file comment string.
  1067.    if (g_hWndEdit) {
  1068.  
  1069.       // Change all forward slashes to back slashes in the buffer
  1070.       ForwardSlashesToBackSlashesA((LPSTR)buffer);
  1071.  
  1072.       SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)buffer);
  1073.       return dwCount;
  1074.    }
  1075.  
  1076.    // Check to see if we are expecting a compressed file comment string.
  1077.    if (g_pFileLast) {
  1078.  
  1079.       // Calcalute the size of the buffer we will need to store this comment.
  1080.       // We are going to convert all ASC values 0 - 31 (excpet tab, new line,
  1081.       // and CR) to ^char.
  1082.       int size = 1;
  1083.       for (char *p2, *p1 = buffer; *p1; p1++) {
  1084.          size += ((*p1 >= 32) || (*p1 == '\t') || (*p1 == '\r') || (*p1 == '\n')) ? 1 : 2;
  1085.       }
  1086.  
  1087.       // Allocate a comment buffer and assign it to the last file node we saw.
  1088.       if (g_pFileLast->szComment = new CHAR[size]) {
  1089.  
  1090.          // Copy while formatting.
  1091.          for (p1 = buffer, p2 = (char*)g_pFileLast->szComment; *p1; p1++) {
  1092.             if ((*p1 >= 32) || (*p1 == '\t') || (*p1 == '\r') || (*p1 == '\n')) {
  1093.                *(p2++) = *p1;
  1094.             } else {
  1095.                *(p2++) = '^';
  1096.                *(p2++) = 64 + *p1;
  1097.             }
  1098.          }
  1099.          *p2 = '\0';
  1100.       }
  1101.  
  1102.       // Update the attributes of the file node to incldue the comment attribute.
  1103.       g_pFileLast->dwAttributes |= FILE_ATTRIBUTE_COMMENT;
  1104.  
  1105.       // Clear the file node so we don't try to add another bogus comment to it.
  1106.       g_pFileLast = NULL;
  1107.  
  1108.       return dwCount;
  1109.    }
  1110.  
  1111.    if (dwCount >= _MAX_PATH) {
  1112.       buffer[_MAX_PATH] = '\0';
  1113.    }
  1114.    DebugOut(TEXT("Unhandled call to win_fprintf(\"%S\")"), buffer);
  1115.    return dwCount;
  1116. }
  1117.  
  1118.  
  1119. //******************************************************************************
  1120. //***** Functions that Info-ZIP expects the port to write and export.
  1121. //***** Some of this code was stolen from the WIN32 port and highly modified.
  1122. //******************************************************************************
  1123.  
  1124. int mapattr(struct Globals *pG) {
  1125.  
  1126.    // Check to see if we are extracting this file for viewing.  Currently, we do
  1127.    // this by checking the szMappedPath member of our extract info stucture
  1128.    // since we know OnActionView() is the only one who sets this member.
  1129.  
  1130.    if (g_pExtractInfo && g_pExtractInfo->szMappedPath) {
  1131.  
  1132.       // If we are extracting for view only, then we ignore the file's real
  1133.       // attributes and force the file to create as read-only.  We make the file
  1134.       // read-only to help prevent the user from making changes to the temporary
  1135.       // file and then trying to save the changes back to a file that we will
  1136.       // eventually delete.
  1137.       pG->pInfo->file_attr = FILE_ATTRIBUTE_READONLY;
  1138.  
  1139.    } else {
  1140.  
  1141.       // Store the attribute exactly as it appears for normal extraction/test.
  1142.       pG->pInfo->file_attr = (unsigned)pG->crec.external_file_attributes & 0xff;
  1143.    }
  1144.    return PK_OK;
  1145. }
  1146.  
  1147. //******************************************************************************
  1148. void utimeToFileTime(time_t ut, FILETIME *pft, BOOL fOldFileSystem) {
  1149.  
  1150.    // time_t    is a 32-bit value for the seconds since January 1, 1970
  1151.    // FILETIME  is a 64-bit value for the number of 100-nanosecond intervals since 
  1152.    //           January 1, 1601
  1153.    // DWORDLONG is a 64-bit int that we can use to perform large math operations.
  1154.  
  1155.  
  1156.    // time_t has minimum of 1/1/1970.  Many file systems, such as FAT, have a
  1157.    // minimum date of 1/1/1980.  If extracting to one of those file systems and
  1158.    // out time_t is less than 1980, then we make it 1/1/1980.
  1159.    // (365 days/yr * 10 yrs + 3 leap yr days) * (60 secs * 60 mins * 24 hrs).
  1160.    if (fOldFileSystem && (ut < 0x12CFF780)) {
  1161.       ut = 0x12CFF780;
  1162.    }
  1163.  
  1164.    // Compute the FILETIME for the given time_t.
  1165.    DWORDLONG dwl = ((DWORDLONG)116444736000000000 + 
  1166.                    ((DWORDLONG)ut * (DWORDLONG)10000000));
  1167.  
  1168.    // Store the return value.
  1169.    *pft = *(FILETIME*)&dwl;
  1170.  
  1171.    // Now for the next fix for old file systems.  If we are in Daylight Savings
  1172.    // Time (DST) and the file is not in DST, then we need subtract off the DST
  1173.    // bias from the filetime.  This is due to a bug in Windows (NT, CE, and 95)
  1174.    // that causes the DST bias to be added to all file times when the system
  1175.    // is in DST, even if the file is not in DST.  This only effects old file
  1176.    // systems since they store local times instead of UTC times.  Newer file
  1177.    // systems like NTFS and CEFS store UTC times.
  1178.  
  1179.    if (fOldFileSystem) {
  1180.  
  1181.       // We use the CRT's localtime() and Win32's FileTimeToLocalTime()
  1182.       // functions to compute the DST bias.  This works because localtime()
  1183.       // correctly adds the DST bias only if the file time is in DST.
  1184.       // FileTimeToLocalTime() always adds the DST bias to the time.
  1185.       // Therefore, if the functions return different results, we know we
  1186.       // are dealing with a non-DST file during a system DST.
  1187.  
  1188.       FILETIME ftCRT, ftWin32;
  1189.  
  1190.       // Get the CRT result - result is a "tm" struct.
  1191.       struct tm *ptmCRT = localtime(&ut);
  1192.  
  1193.       // Convert the "tm" struct to a FILETIME.
  1194.       SYSTEMTIME stCRT;
  1195.       ZeroMemory(&stCRT, sizeof(stCRT));
  1196.       stCRT.wYear   = ptmCRT->tm_year + 1900;
  1197.       stCRT.wMonth  = ptmCRT->tm_mon + 1;
  1198.       stCRT.wDay    = ptmCRT->tm_mday;
  1199.       stCRT.wHour   = ptmCRT->tm_hour;
  1200.       stCRT.wMinute = ptmCRT->tm_min;
  1201.       stCRT.wSecond = ptmCRT->tm_sec;
  1202.       SystemTimeToFileTime(&stCRT, &ftCRT);
  1203.  
  1204.       // Get the Win32 result - result is a FILETIME.
  1205.       if (FileTimeToLocalFileTime(pft, &ftWin32)) {
  1206.  
  1207.          // Subtract the difference from our current filetime.
  1208.          *(DWORDLONG*)pft -= *(DWORDLONG*)&ftWin32 - *(DWORDLONG*)&ftCRT;
  1209.       }
  1210.    }
  1211. }
  1212.  
  1213. //******************************************************************************
  1214. int GetFileTimes(struct Globals *pG, FILETIME *pftCreated, FILETIME *pftAccessed,
  1215.                  FILETIME *pftModified)
  1216. {
  1217.    // We need to check to see if this file system is limited.  This includes
  1218.    // FAT, VFAT, and HPFS.  It does not include NTFS and CEFS.  The limited
  1219.    // file systems can not support dates < 1980 and they store file local times
  1220.    // for files as opposed to UTC times.
  1221.    BOOL fOldFileSystem = IsOldFileSystem(pG->filename);
  1222.  
  1223. #ifdef USE_EF_UT_TIME  // Always true for WinCE build
  1224.  
  1225.    if (pG->extra_field) {
  1226.  
  1227.       // Structure for Unix style actime, modtime, creatime
  1228.       iztimes z_utime;
  1229.  
  1230.       // Get any date/time we can.  This can return 0 to 3 unix time fields.
  1231.       unsigned eb_izux_flg = ef_scan_for_izux(pG->extra_field, 
  1232.                                               pG->lrec.extra_field_length,
  1233.                                               0, &z_utime, NULL);
  1234.  
  1235.       // We require at least a modified time.
  1236.       if (eb_izux_flg & EB_UT_FL_MTIME) {
  1237.  
  1238.          // We know we have a modified time, so get it first.
  1239.          utimeToFileTime(z_utime.mtime, pftModified, fOldFileSystem);
  1240.  
  1241.          // Get the accessed time if we have one.
  1242.          if (eb_izux_flg & EB_UT_FL_ATIME) {
  1243.             utimeToFileTime(z_utime.atime, pftAccessed, fOldFileSystem);
  1244.          }
  1245.  
  1246.          // Get the created time if we have one.
  1247.          if (eb_izux_flg & EB_UT_FL_CTIME) {
  1248.             utimeToFileTime(z_utime.ctime, pftCreated, fOldFileSystem);
  1249.          }
  1250.  
  1251.          // Return our flags.
  1252.          return (int)eb_izux_flg;
  1253.       }
  1254.    }
  1255.  
  1256. #endif // USE_EF_UT_TIME
  1257.  
  1258.    // If all else fails, we can resort to using the DOS date and time data.
  1259.    time_t ux_modtime = dos_to_unix_time(G.lrec.last_mod_file_date,
  1260.                                         G.lrec.last_mod_file_time);
  1261.    utimeToFileTime(ux_modtime, pftModified, fOldFileSystem);
  1262.  
  1263.    *pftAccessed = *pftModified;
  1264.  
  1265.    return (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
  1266. }
  1267.  
  1268. //******************************************************************************
  1269. void close_outfile(struct Globals *pG) {
  1270.  
  1271.    // Get the 3 time stamps for the file.
  1272.    FILETIME ftCreated, ftAccessed, ftModified;
  1273.    int timeFlags = GetFileTimes(pG, &ftCreated, &ftAccessed, &ftModified);
  1274.  
  1275.    TCHAR szFile[_MAX_PATH];
  1276.    mbstowcs(szFile, pG->filename, countof(szFile));
  1277.  
  1278. #ifdef _WIN32_WCE
  1279.    
  1280.    // Cast the outfile to a HANDLE (since that is really what it is), and
  1281.    // flush the file.  We need to flush, because any unsaved data that is
  1282.    // written to the file during CloseHandle() will step on the work done
  1283.    // by SetFileTime().
  1284.    HANDLE hFile = (HANDLE)pG->outfile;
  1285.    FlushFileBuffers(hFile);
  1286.  
  1287. #else
  1288.  
  1289.    // Close the file and then re-open it using the Win32 CreateFile() call.
  1290.    // SetFileTime() requires a Win32 file HANDLE created with GENERIC_WRITE
  1291.    // access.
  1292.    fclose(pG->outfile);
  1293.    HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
  1294.                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1295.  
  1296. #endif
  1297.  
  1298.    // Set the file's date and time.
  1299.    if (hFile != INVALID_HANDLE_VALUE) {
  1300.  
  1301.       // Make sure we retrieved some valid time stamp(s)
  1302.       if (timeFlags) {
  1303.  
  1304.          // Set the various date and time fields.
  1305.          if (!SetFileTime(hFile, 
  1306.                  (timeFlags & EB_UT_FL_CTIME) ? &ftCreated  : NULL,
  1307.                  (timeFlags & EB_UT_FL_ATIME) ? &ftAccessed : NULL,
  1308.                  (timeFlags & EB_UT_FL_MTIME) ? &ftModified : NULL))
  1309.          {
  1310.             DebugOut(TEXT("SetFileTime() failed [%u]"), GetLastError());
  1311.          }
  1312.  
  1313.       } else {
  1314.          DebugOut(TEXT("GetFileTimes() failed"));
  1315.       }
  1316.  
  1317.       // Close out file.
  1318.       CloseHandle(hFile);
  1319.  
  1320.    } else {
  1321.       DebugOut(TEXT("CreateFile() failed [%u]"), GetLastError());
  1322.    }
  1323.  
  1324.    // If the file was successfully written, then set the attributes.
  1325.    if (!pG->disk_full && !g_pExtractInfo->fAbort) {
  1326.       if (!SetFileAttributes(szFile, G.pInfo->file_attr & 0x7F)) {
  1327.          DebugOut(TEXT("SetFileAttributes() failed [%u]"), GetLastError());
  1328.       }
  1329.    }
  1330.  
  1331.    // Clear outfile so we know it is closed.
  1332.    pG->outfile = 0;
  1333.  
  1334.    return;
  1335. }
  1336.  
  1337. //******************************************************************************
  1338. // Called by PROCESS.C
  1339. char* do_wild(struct Globals *pG, char *wildspec) {
  1340.  
  1341.    // This is a very slimmed down version of do_wild() taken from WIN32.C.
  1342.    // Since we don't support wildcards, we basically just return the wildspec
  1343.    // passed in as the filename.
  1344.    
  1345.    // First call - must initialize everything.
  1346.    if (!pG->notfirstcall) {
  1347.       pG->notfirstcall = TRUE;
  1348.       return strcpy(pG->matchname, wildspec);
  1349.    }
  1350.  
  1351.    // Last time through - reset for new wildspec.
  1352.    pG->notfirstcall = FALSE;    
  1353.  
  1354.    return (char*)NULL;
  1355. }
  1356.  
  1357. //******************************************************************************
  1358. // Called from EXTRACT.C
  1359. //
  1360. // returns:  1 - (on APPEND_NAME) truncated filename
  1361. //           2 - path doesn't exist, not allowed to create
  1362. //           3 - path doesn't exist, tried to create and failed; or
  1363. //               path exists and is not a directory, but is supposed to be
  1364. //           4 - path is too long
  1365. //          10 - can't allocate memory for filename buffers
  1366. //
  1367. // IZ_VOL_LABEL   - Path was a volume label, skip it.
  1368. // IZ_CREATED_DIR - Created a directory.
  1369. //
  1370. int mapname(struct Globals *pG, int renamed) {
  1371.  
  1372.    // mapname() is a great place to reset all our status counters for the next
  1373.    // file to be processed since it is called for every zip file member before
  1374.    // any work is done with that member.
  1375.    SetCurrentFile(pG);
  1376.  
  1377.    // If Volume Label, skip the "extraction" quietly
  1378.    if (pG->pInfo->vollabel) {
  1379.       return IZ_VOL_LABEL;
  1380.    }
  1381.  
  1382.    CHAR szBuffer[countof(pG->filename)] = "", *pIn, *pOut, *pLastSemi = NULL;
  1383.  
  1384.    // Initialize file path buffer with our "extract to" path.
  1385.    strcpy(szBuffer, g_szExtractToDirectory);
  1386.    pOut = szBuffer + strlen(szBuffer);
  1387.  
  1388.    // Point pIn to beginning of our internal pathname.
  1389.    // If we are junking paths, then locate the file portion of the path.
  1390.    pIn = (pG->jflag) ? (CHAR*)GetFileFromPath(pG->filename) : pG->filename;
  1391.  
  1392.    // Begin main loop through characters in filename.
  1393.    for ( ; *pIn; pIn++) {
  1394.  
  1395.       // Make sure we don't overflow our output buffer.
  1396.       if (pOut >= (szBuffer + countof(szBuffer) - 2)) {
  1397.          Info(slide, 1, ((char*)slide, "path too long: %s\n", pG->filename));
  1398.          return 4;
  1399.       }
  1400.  
  1401.       // Examine the next character in our input buffer.
  1402.       switch (*pIn) {
  1403.  
  1404.          // Check for a directory wack.
  1405.          case '/':
  1406.          case '\\':
  1407.             *pOut = '\0';
  1408.             if (!SmartCreateDirectory(pG, szBuffer)) {
  1409.                Info(slide, 1, ((char*)slide, "failure extracting: %s\n",
  1410.                     pG->filename));
  1411.                return 3;
  1412.             }
  1413.             *(pOut++) = '\\';
  1414.             pLastSemi = NULL;  // Leave any directory semi-colons alone
  1415.             break;
  1416.  
  1417.          // Check for illegal characters and replace with underscore.
  1418.          case ':':
  1419.          case '*':
  1420.          case '?':
  1421.          case '"': 
  1422.          case '<':
  1423.          case '>':
  1424.          case '|':
  1425.             *(pOut++) = '_';
  1426.             break;
  1427.  
  1428.          // Check for start of VMS version.
  1429.          case ';':
  1430.             pLastSemi = pOut;  // Make note as to where we are.
  1431.             *(pOut++) = *pIn;  // Leave the semi-colon alone for now.
  1432.             break;
  1433.  
  1434.          default:
  1435.             // Allow European characters and spaces in filenames.
  1436.             *(pOut++) = ((*pIn >= 0x20) ? *pIn : '_');
  1437.       }
  1438.    }
  1439.  
  1440.    // Done with output buffer, terminate it.
  1441.    *pOut = '\0';
  1442.  
  1443.    // Remove any VMS version numbers if found (appended ";###").
  1444.    if (pLastSemi) {
  1445.       
  1446.       // Walk over all digits following the semi-colon.
  1447.       for (pOut = pLastSemi + 1; (*pOut >= '0') && (*pOut <= '9'); pOut++) {
  1448.       }
  1449.  
  1450.       // If we reached the end, then nuke the semi-colon and digits.
  1451.       if (!*pOut) {
  1452.          *pLastSemi = '\0';
  1453.       }
  1454.    }
  1455.  
  1456.    // Copy the mapped name back to the internal path buffer
  1457.    strcpy(pG->filename, szBuffer);
  1458.  
  1459.    // Fill in the mapped name buffer if the original caller requested us to.
  1460.    if (g_pExtractInfo->szMappedPath) {
  1461.       strcpy(g_pExtractInfo->szMappedPath, szBuffer);
  1462.    }
  1463.  
  1464.    // If it is a directory, then display the "creating" status text.
  1465.    if ((pOut > szBuffer) && (pOut[-1] == TEXT('\\'))) {
  1466.       Info(slide, 0, ((char *)slide, "creating: %s\n", pG->filename));
  1467.       return IZ_CREATED_DIR;
  1468.    }
  1469.  
  1470.    return PK_OK;
  1471. }
  1472.  
  1473. //******************************************************************************
  1474. // Called from EXTRACT.C
  1475. int test_NT(struct Globals *pG, uch *eb, unsigned eb_size) {
  1476.    // This function is called when an NT security descriptor is found in the
  1477.    // extra field.  We have nothing to do, so we just return success.
  1478.    return PK_OK;
  1479. }
  1480.  
  1481. //******************************************************************************
  1482. // Called from PROCESS.C
  1483. int checkdir(struct Globals *pG, char *pathcomp, int flag) {
  1484.    // This function is only called by free_G_buffers() from PROCESS.C with the
  1485.    // flag set to END.  We have nothing to do, so we just return success.
  1486.    return PK_OK;
  1487. }
  1488.  
  1489. //******************************************************************************
  1490. // Called from EXTRACT.C and LIST.C
  1491. int match(char *string, char *pattern, int ignore_case) {
  1492.    // match() for the other ports compares a file in the Zip file with some
  1493.    // command line file pattern.  In our case, we always pass in exact matches,
  1494.    // so we can simply do a string compare to see if we have a match.
  1495.    return (strcmp(string, pattern) == 0);
  1496. }
  1497.  
  1498. //******************************************************************************
  1499. // Called from PROCESS.C
  1500. int iswild(char *pattern) {
  1501.    // Our file patterns never contain wild characters.  They are always exact
  1502.    // matches of file names in our Zip file.
  1503.    return FALSE;
  1504. }
  1505.  
  1506. //******************************************************************************
  1507. //***** Functions to correct time stamp bugs on old file systems.
  1508. //******************************************************************************
  1509.  
  1510. //******************************************************************************
  1511. // Borrowed/Modified from win32.c
  1512. BOOL IsOldFileSystem(char *szPath) {
  1513.  
  1514. #ifdef _WIN32_WCE
  1515.    
  1516.    char szRoot[10];
  1517.  
  1518.    // Get the first nine characters of the path.
  1519.    strncpy(szRoot, szPath, 9);
  1520.    szRoot[9] = '\0';
  1521.  
  1522.    // Convert to uppercase to help with compare.
  1523.    _strupr(szRoot);
  1524.  
  1525.    // PC Cards are mounted off the root in a directory called "\PC Cards".
  1526.    // PC Cards are FAT, no CEOS.  We need to check if the file is being
  1527.    // extracted to the PC card.
  1528.    return !strcmp(szRoot, "\\PC CARD\\");
  1529.  
  1530. #else
  1531.  
  1532.    char szRoot[_MAX_PATH] = "\0\0\0", szFS[64];
  1533.  
  1534.    // Check to see if our path contains a drive letter.
  1535.    if (isalpha(szPath[0]) && (szPath[1] == ':') && (szPath[2] == '\\')) {
  1536.  
  1537.       // If so, then just copy the drive letter, colon, and wack to our root path.
  1538.       strncpy(szRoot, szPath, 3);
  1539.  
  1540.    } else {
  1541.  
  1542.       // Expand the path so we can get a drive letter.
  1543.       GetFullPathNameA(szPath, sizeof(szRoot), szRoot, NULL);
  1544.  
  1545.       // Make sure we actually got a drive letter back in our root path buffer..
  1546.       if (!isalpha(szRoot[0]) || (szRoot[1] != ':') || (szRoot[2] != '\\')) {
  1547.  
  1548.          // When in doubt, return TRUE.
  1549.          return TRUE;
  1550.       }
  1551.    }
  1552.  
  1553.    // NULL terminate after the wack to ensure we have just the root path.
  1554.    szRoot[3] = '\0';
  1555.  
  1556.    // Get the file system type string.
  1557.    GetVolumeInformationA(szRoot, NULL, 0, NULL, NULL, NULL, szFS, sizeof(szFS));
  1558.  
  1559.    // Ensure that the file system type string is uppercase.
  1560.    strupr(szFS);
  1561.  
  1562.    // Return true for (V)FAT and (OS/2) HPFS format.
  1563.    return !strncmp(szFS, "FAT",  3) ||
  1564.           !strncmp(szFS, "VFAT", 4) ||
  1565.           !strncmp(szFS, "HPFS", 4);
  1566.  
  1567. #endif // _WIN32_WCE
  1568. }
  1569.