which included commits to RCS files with non-trunk default branches. git-svn-id: svn://10.65.10.50/trunk@5403 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1569 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1569 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| //******************************************************************************
 | |
| //
 | |
| // File:        INTRFACE.CPP
 | |
| //
 | |
| // Description: This module acts as the interface between the Info-ZIP code and
 | |
| //              our Windows code in WINMAIN.CPP.  We expose the needed
 | |
| //              functions to query a file list, test file(s), extract file(s),
 | |
| //              and display a zip file comment.  The windows code is never
 | |
| //              bothered with understanding the Globals structure.
 | |
| //
 | |
| //              This module also catches all the callbacks from the Info-ZIP
 | |
| //              code, cleans up the data provided in the callback, and then
 | |
| //              forwards the information to the appropriate function in the
 | |
| //              windows code.  These callbacks include status messages, file
 | |
| //              lists, comments, password prompt, and file overwrite prompts.
 | |
| //
 | |
| //              Finally, this module implements the few functions that the
 | |
| //              Info-ZIP code expects the port to implement. These functions are
 | |
| //              OS dependent and are mostly related to validating file names and
 | |
| //              directoies, and setting file attributes and dates of saved files.
 | |
| //
 | |
| // Copyright:   All the source files for Pocket UnZip, except for components
 | |
| //              written by the Info-ZIP group, are copyrighted 1997 by Steve P.
 | |
| //              Miller.  The product "Pocket UnZip" itself is property of the
 | |
| //              author and cannot be altered in any way without written consent
 | |
| //              from Steve P. Miller.
 | |
| //
 | |
| // Disclaimer:  All project files are provided "as is" with no guarantee of
 | |
| //              their correctness.  The authors are not liable for any outcome
 | |
| //              that is the result of using this source.  The source for Pocket
 | |
| //              UnZip has been placed in the public domain to help provide an
 | |
| //              understanding of its implementation.  You are hereby granted
 | |
| //              full permission to use this source in any way you wish, except
 | |
| //              to alter Pocket UnZip itself.  For comments, suggestions, and
 | |
| //              bug reports, please write to stevemil@pobox.com.
 | |
| //
 | |
| // Functions:   DoListFiles
 | |
| //              DoExtractOrTestFiles
 | |
| //              DoGetComment
 | |
| //              SetExtractToDirectory
 | |
| //              InitGlobals
 | |
| //              FreeGlobals
 | |
| //              IsFileOrDirectory
 | |
| //              SmartCreateDirectory
 | |
| //              ExtractOrTestFilesThread
 | |
| //              CheckForAbort
 | |
| //              SetCurrentFile
 | |
| //              UzpMessagePrnt2
 | |
| //              UzpInput2
 | |
| //              UzpMorePause
 | |
| //              UzpPassword
 | |
| //              UzpReplace
 | |
| //              UzpSound
 | |
| //              SendAppMsg
 | |
| //              win_fprintf
 | |
| //              mapattr
 | |
| //              utimeToFileTime
 | |
| //              GetFileTimes
 | |
| //              close_outfile
 | |
| //              do_wild
 | |
| //              mapname
 | |
| //              test_NT
 | |
| //              checkdir
 | |
| //              match
 | |
| //              iswild
 | |
| //              IsOldFileSystem
 | |
| //
 | |
| //
 | |
| // Date      Name          History
 | |
| // --------  ------------  -----------------------------------------------------
 | |
| // 02/01/97  Steve Miller  Created (Version 1.0 using Info-ZIP UnZip 5.30)
 | |
| //
 | |
| //******************************************************************************
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| #if 0 // The following information and structure are here just for reference
 | |
| //******************************************************************************
 | |
| //
 | |
| // The Windows CE version of Unzip builds with the following defines set:
 | |
| //
 | |
| //
 | |
| //    WIN32
 | |
| //    _WINDOWS
 | |
| //    UNICODE
 | |
| //    _UNICODE
 | |
| //    WIN32_LEAN_AND_MEAN
 | |
| //    STRICT
 | |
| //
 | |
| //    POCKET_UNZIP         (Main define - Always set)
 | |
| //
 | |
| //    UNZIP_INTERNAL
 | |
| //    WINDLL
 | |
| //    DLL
 | |
| //    REENTRANT
 | |
| //    USE_EF_UT_TIME
 | |
| //    NO_ZIPINFO
 | |
| //    NO_STDDEF_H
 | |
| //    NO_NTSD_WITH_RSXNT
 | |
| //
 | |
| //    USE_SMITH_CODE       (optional - See COPYING document) 
 | |
| //    USE_UNSHRINK         (optional - See COPYING document) 
 | |
| //
 | |
| //    DEBUG                (When building for Debug)
 | |
| //    _DEBUG               (When building for Debug)
 | |
| //    NDEBUG               (When building for Retail)
 | |
| //    _NDEBUG              (When building for Retail)
 | |
| //
 | |
| //    _WIN32_WCE=100       (When building for Windows CE native)
 | |
| //
 | |
| // This causes our Globals structure to look like the following.  The only
 | |
| // things we care about is this Globals structure, the process_zipfiles()
 | |
| // function, and a few callback functions.  The Info-ZIP code has not been
 | |
| // been modified in any way.
 | |
| //
 | |
| 
 | |
| struct Globals {
 | |
|    int            zipinfo_mode;         // behave like ZipInfo or like normal UnZip?
 | |
|    int            aflag;                // -a: do ASCII-EBCDIC and/or end-of-line translation
 | |
|    int            cflag;                // -c: output to stdout
 | |
|    int            C_flag;               // -C: match filenames case-insensitively
 | |
|    int            dflag;                // -d: all args are files/dirs to be extracted
 | |
|    int            fflag;                // -f: "freshen" (extract only newer files)
 | |
|    int            hflag;                // -h: header line (zipinfo)
 | |
|    int            jflag;                // -j: junk pathnames (unzip)
 | |
|    int            lflag;                // -12slmv: listing format (zipinfo)
 | |
|    int            L_flag;               // -L: convert filenames from some OSes to lowercase
 | |
|    int            overwrite_none;       // -n: never overwrite files (no prompting)
 | |
|    int            overwrite_all;        // -o: OK to overwrite files without prompting
 | |
|    int            P_flag;               // -P: give password on command line (ARGH!)
 | |
|    int            qflag;                // -q: produce a lot less output
 | |
|    int            sflag;                // -s: convert spaces in filenames to underscores
 | |
|    int            volflag;              // -$: extract volume labels
 | |
|    int            tflag;                // -t: test (unzip) or totals line (zipinfo)
 | |
|    int            T_flag;               // -T: timestamps (unzip) or dec. time fmt (zipinfo)
 | |
|    int            uflag;                // -u: "update" (extract only newer/brand-new files)
 | |
|    int            vflag;                // -v: (verbosely) list directory
 | |
|    int            V_flag;               // -V: don't strip VMS version numbers
 | |
|    int            X_flag;               // -X: restore owner/protection or UID/GID or ACLs
 | |
|    int            zflag;                // -z: display the zipfile comment (only, for unzip)
 | |
|    int            filespecs;            // number of real file specifications to be matched
 | |
|    int            xfilespecs;           // number of excluded filespecs to be matched
 | |
|    int            process_all_files;
 | |
|    int            create_dirs;          // used by main(), mapname(), checkdir()
 | |
|    int            extract_flag;
 | |
|    int            newzip;               // reset in extract.c; used in crypt.c
 | |
|    LONGINT        real_ecrec_offset;
 | |
|    LONGINT        expect_ecrec_offset;
 | |
|    long           csize;                // used by decompr. (NEXTBYTE): must be signed
 | |
|    long           ucsize;               // used by unReduce(), explode()
 | |
|    long           used_csize;           // used by extract_or_test_member(), explode()
 | |
|    int            filenotfound;
 | |
|    int            redirect_data;        // redirect data to memory buffer
 | |
|    int            redirect_text;        // redirect text output to buffer
 | |
|    unsigned       _wsize;
 | |
|    int            stem_len;
 | |
|    int            putchar_idx;
 | |
|    uch           *redirect_pointer;
 | |
|    uch           *redirect_buffer;
 | |
|    unsigned       redirect_size;
 | |
|    char         **pfnames;
 | |
|    char         **pxnames;
 | |
|    char           sig[5];
 | |
|    char           answerbuf[10];
 | |
|    min_info       info[DIR_BLKSIZ];
 | |
|    min_info      *pInfo;
 | |
|    union work     area;                 // see unzpriv.h for definition of work
 | |
|    ulg near      *crc_32_tab;
 | |
|    ulg            crc32val;             // CRC shift reg. (was static in funzip)
 | |
|    uch           *inbuf;                // input buffer (any size is OK)
 | |
|    uch           *inptr;                // pointer into input buffer
 | |
|    int            incnt;
 | |
|    ulg            bitbuf;
 | |
|    int            bits_left;            // unreduce and unshrink only
 | |
|    int            zipeof;
 | |
|    char          *argv0;                // used for NT and EXE_EXTENSION
 | |
|    char          *wildzipfn;
 | |
|    char          *zipfn;                // GRR:  MSWIN:  must nuke any malloc'd zipfn...
 | |
|    int            zipfd;                // zipfile file handle
 | |
|    LONGINT        ziplen;
 | |
|    LONGINT        cur_zipfile_bufstart; // extract_or_test, readbuf, ReadByte
 | |
|    LONGINT        extra_bytes;          // used in unzip.c, misc.c
 | |
|    uch           *extra_field;          // Unix, VMS, Mac, OS/2, Acorn, ...
 | |
|    uch           *hold;
 | |
|    char           local_hdr_sig[5];     // initialize sigs at runtime so unzip
 | |
|    char           central_hdr_sig[5];   //  executable won't look like a zipfile
 | |
|    char           end_central_sig[5];
 | |
| 
 | |
|    local_file_hdr lrec;                 // used in unzip.c, extract.c
 | |
|    cdir_file_hdr  crec;                 // used in unzip.c, extract.c, misc.c
 | |
|    ecdir_rec      ecrec;                // used in unzip.c, extract.c
 | |
|    struct stat    statbuf;              // used by main, mapname, check_for_newer
 | |
| 
 | |
|    int            mem_mode;
 | |
|    uch           *outbufptr;            // extract.c static
 | |
|    ulg            outsize;              // extract.c static
 | |
|    int            reported_backslash;   // extract.c static
 | |
|    int            disk_full;
 | |
|    int            newfile;
 | |
| 
 | |
|    int            didCRlast;            // fileio static
 | |
|    ulg            numlines;             // fileio static: number of lines printed
 | |
|    int            sol;                  // fileio static: at start of line
 | |
|    int            no_ecrec;             // process static
 | |
|    FILE          *outfile;
 | |
|    uch           *outbuf;
 | |
|    uch           *realbuf;
 | |
|                   
 | |
|    uch           *outbuf2;              //  main() (never changes); else malloc'd
 | |
|    uch           *outptr;
 | |
|    ulg            outcnt;               // number of chars stored in outbuf
 | |
|    char          *filename;
 | |
| 
 | |
|    char          *pwdarg;               // pointer to command-line password (-P option)
 | |
|    int            nopwd;                // crypt static
 | |
|    ulg            keys[3];              // crypt static: keys defining pseudo-random sequence
 | |
|    char          *key;                  // crypt static: decryption password or NULL
 | |
| 
 | |
|    unsigned       hufts;                // track memory usage
 | |
| 
 | |
|    struct huft   *fixed_tl;             // inflate static
 | |
|    struct huft   *fixed_td;             // inflate static
 | |
|    int            fixed_bl
 | |
|    int            fixed_bd;             // inflate static
 | |
|    unsigned       wp;                   // inflate static: current position in slide
 | |
|    ulg            bb;                   // inflate static: bit buffer
 | |
|    unsigned       bk;                   // inflate static: bits in bit buffer
 | |
|    MsgFn         *message;
 | |
|    InputFn       *input;
 | |
|    PauseFn       *mpause;
 | |
|    PasswdFn      *decr_passwd;
 | |
|    ReplaceFn     *replace;
 | |
|    SoundFn       *sound;
 | |
| 
 | |
|    int            incnt_leftover;       // so improved NEXTBYTE does not waste input
 | |
|    uch           *inptr_leftover;
 | |
| 
 | |
|    // These are defined in PUNZIP.H.
 | |
|    char           matchname[FILNAMSIZ]; // used by do_wild()
 | |
|    int            notfirstcall;         // used by do_wild()
 | |
|    char          *zipfnPtr;
 | |
|    char          *wildzipfnPtr;
 | |
| };
 | |
| 
 | |
| #endif // #if 0 - This struct is here just for reference
 | |
| 
 | |
| //******************************************************************************
 | |
| 
 | |
| extern "C" {
 | |
| #define __INTRFACE_CPP__
 | |
| #define UNZIP_INTERNAL
 | |
| #include "unzip.h"
 | |
| #include "crypt.h"     // Needed to pick up CRYPT define
 | |
| #include <commctrl.h>
 | |
| #include "intrface.h"
 | |
| #include "winmain.h"
 | |
| 
 | |
| #ifndef _WIN32_WCE
 | |
| #include <process.h>   // _beginthreadex() and _endthreadex()
 | |
| #endif
 | |
| 
 | |
| }
 | |
| #include <tchar.h> // Must be outside of extern "C" block
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** "Local" Global Variables
 | |
| //******************************************************************************
 | |
| 
 | |
| static USERFUNCTIONS  g_uf;
 | |
| static DCL            g_dcl;
 | |
| static EXTRACT_INFO  *g_pExtractInfo = NULL;
 | |
| static FILE_NODE     *g_pFileLast    = NULL;
 | |
| static CHAR           g_szExtractToDirectory[_MAX_PATH];
 | |
| static BOOL           g_fOutOfMemory;
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Local Function Prototypes
 | |
| //******************************************************************************
 | |
| 
 | |
| extern "C" {
 | |
| 
 | |
| // Our exposed interface functions to the Info-ZIP core.
 | |
| BOOL DoListFiles(LPCSTR szZipFile);
 | |
| BOOL DoExtractOrTestFiles(LPCSTR szZipFile, EXTRACT_INFO *pei);
 | |
| BOOL DoGetComment(LPCSTR szFile);
 | |
| BOOL SetExtractToDirectory(LPTSTR szDirectory);
 | |
| 
 | |
| // Internal functions.
 | |
| struct Globals* InitGlobals(LPCSTR szZipFile);
 | |
| void FreeGlobals(Globals *pG);
 | |
| int IsFileOrDirectory(LPCTSTR szPath);
 | |
| BOOL SmartCreateDirectory(struct Globals *pG, LPCSTR szDirectory);
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| DWORD WINAPI ExtractOrTestFilesThread(LPVOID lpv);
 | |
| #else
 | |
| unsigned __stdcall ExtractOrTestFilesThread(void *lpv);
 | |
| #endif
 | |
| 
 | |
| void CheckForAbort(struct Globals *pG);
 | |
| void SetCurrentFile(struct Globals *pG);
 | |
| 
 | |
| // Callbacks from Info-ZIP code.
 | |
| int UzpMessagePrnt2(zvoid *pG, uch *buffer, ulg size, int flag);
 | |
| int UzpInput2(zvoid *pG, uch *buffer, int *size, int flag);
 | |
| void UzpMorePause(zvoid *pG, const char *szPrompt, int flag);
 | |
| int UzpPassword(zvoid *pG, int *pcRetry, char *szPassword, int nSize, 
 | |
|                 const char *szZipFile, const char *szFile);
 | |
| int WINAPI UzpReplace(char *szFile);
 | |
| void WINAPI UzpSound(void);
 | |
| void WINAPI SendAppMsg(ulg dwSize, ulg dwCompressedSize, int ratio, int month, 
 | |
|                        int day, int year, int hour, int minute, int uppercase,
 | |
|                        char *szPath, char *szMethod, ulg dwCRC);
 | |
| int win_fprintf(FILE *file, unsigned int dwCount, char far *buffer);
 | |
| 
 | |
| // Functions that Info-ZIP expects the port to write and export.
 | |
| void utimeToFileTime(time_t ut, FILETIME *pft, BOOL fOldFileSystem);
 | |
| int GetFileTimes(struct Globals *pG, FILETIME *pftCreated, FILETIME *pftAccessed,
 | |
|                  FILETIME *pftModified);
 | |
| int mapattr(struct Globals *pG);
 | |
| void close_outfile(struct Globals *pG);
 | |
| char* do_wild(struct Globals *pG, char *wildspec);
 | |
| int mapname(struct Globals *pG, int renamed);
 | |
| int test_NT(struct Globals *pG, uch *eb, unsigned eb_size);
 | |
| int checkdir(struct Globals *pG, char *pathcomp, int flag);
 | |
| 
 | |
| // Check for FAT, VFAT, HPFS, etc.
 | |
| BOOL IsOldFileSystem(char *szPath);
 | |
| 
 | |
| } // extern "C"
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Our exposed interface functions to the Info-ZIP core
 | |
| //******************************************************************************
 | |
| 
 | |
| int DoListFiles(LPCSTR szZipFile) {
 | |
| 
 | |
|    int result;
 | |
| 
 | |
|    // Create our Globals struct and fill it in whith some default values.
 | |
|    struct Globals *pG = InitGlobals(szZipFile);
 | |
|    if (!pG) {
 | |
|       return PK_MEM;
 | |
|    }
 | |
| 
 | |
|    pG->vflag = 1; // verbosely: list directory (for WIN32 it is 0 or 1)
 | |
|    pG->process_all_files = TRUE; // improves speed
 | |
| 
 | |
|    g_pFileLast = NULL;
 | |
|    g_fOutOfMemory = FALSE;
 | |
| 
 | |
|    // We wrap some exception handling around the entire Info-ZIP engine to be
 | |
|    // safe.  Since we are running on a device with tight memory configurations,
 | |
|    // all sorts of problems can arise when we run out of memory.
 | |
|    __try {
 | |
| 
 | |
|       // Call the unzip routine.  We will catch the file information in a
 | |
|       // callback to SendAppMsg().
 | |
|       result = process_zipfiles(pG);
 | |
| 
 | |
|       // Make sure we didn't run out of memory in the process.
 | |
|       if (g_fOutOfMemory) {
 | |
|          result = PK_MEM;
 | |
|       }
 | |
| 
 | |
|    } __except(EXCEPTION_EXECUTE_HANDLER) {
 | |
| 
 | |
|       // Catch any exception here.
 | |
|       DebugOut(TEXT("Exception 0x%08X occurred in DoListFiles()"),
 | |
|                GetExceptionCode());
 | |
|       result = PK_EXCEPTION;
 | |
|    }
 | |
| 
 | |
|    g_pFileLast = NULL;
 | |
| 
 | |
|    // It is possible that the ZIP engine change the file name a bit (like adding
 | |
|    // a ".zip" if needed).  If so, we will pick up the new name.
 | |
|    if ((result != PK_EXCEPTION) && pG->zipfn && *pG->zipfn) {
 | |
|       strcpy(g_szZipFile, pG->zipfn);
 | |
|    }
 | |
| 
 | |
|    // Free our globals.
 | |
|    FreeGlobals(pG);
 | |
| 
 | |
|    return result;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| BOOL DoExtractOrTestFiles(LPCSTR szZipFile, EXTRACT_INFO *pei) {
 | |
| 
 | |
|    // WARNING!!!  This functions hands the EXTRACT_INFO structure of to a thread
 | |
|    // to perform the actual extraction/test.  When the thread is done, it will
 | |
|    // send a message to the progress dialog.  The calling function must not
 | |
|    // delete the EXTRAT_INFO structure until it receives the message.  Currently,
 | |
|    // this is not a problem for us since the structure lives on the stack of the
 | |
|    // calling thread.  The calling thread then displays a dialog that blocks the
 | |
|    // calling thread from clearing the stack until the dialog is dismissed, which
 | |
|    // occurs when the dialog receives the message.
 | |
| 
 | |
|    // Create our globals so we can store the file name.
 | |
|    struct Globals *pG = InitGlobals(szZipFile);
 | |
|    if (!pG) {
 | |
|       pei->result = PK_MEM;
 | |
|       SendMessage(g_hDlgProgress, WM_PRIVATE, MSG_OPERATION_COMPLETE, (LPARAM)pei);
 | |
|       return FALSE;
 | |
|    }
 | |
| 
 | |
|    // Store a global pointer to the Extract structure so it can be reached from
 | |
|    // our thread and callback functions.
 | |
|    g_pExtractInfo = pei;
 | |
| 
 | |
|    // Spawn our thread
 | |
|    DWORD dwThreadId;
 | |
|    HANDLE hThread;
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| 
 | |
|    // On CE, we use good old CreateThread() since the WinCE CRT does not 
 | |
|    // allocate per-thread storage.
 | |
|    hThread = CreateThread(NULL, 0, ExtractOrTestFilesThread, pG, 0, &dwThreadId);
 | |
| 
 | |
| #else
 | |
| 
 | |
|    // On NT, we need use the CRT's thread function so that we don't leak any
 | |
|    // CRT allocated memory when the thread exits.
 | |
|    hThread = (HANDLE)_beginthreadex(NULL, 0, ExtractOrTestFilesThread, pG, 0,
 | |
|                                     (unsigned*)&dwThreadId);
 | |
| 
 | |
| #endif
 | |
| 
 | |
|    // Bail out if our thread failed to create.
 | |
|    if (!hThread) {
 | |
| 
 | |
|       DebugOut(TEXT("CreateThread() failed [%u]"), GetLastError());
 | |
| 
 | |
|       // Set our error as a memory error.
 | |
|       g_pExtractInfo->result = PK_MEM;
 | |
| 
 | |
|       // Free our globals.
 | |
|       FreeGlobals(pG);
 | |
| 
 | |
|       // Tell the progress dialog that we are done.
 | |
|       SendMessage(g_hDlgProgress, WM_PRIVATE, MSG_OPERATION_COMPLETE, (LPARAM)pei);
 | |
| 
 | |
|       g_pExtractInfo = NULL;
 | |
|       return FALSE;
 | |
|    }
 | |
| 
 | |
|    // Close our thread handle since we have no use for it.
 | |
|    CloseHandle(hThread);
 | |
|    return TRUE;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| int DoGetComment(LPCSTR szFile) {
 | |
| 
 | |
|    int result;
 | |
| 
 | |
|    // Create our Globals struct and fill it in whith some default values.
 | |
|    struct Globals *pG = InitGlobals(szFile);
 | |
|    if (!pG) {
 | |
|       return PK_MEM;
 | |
|    }
 | |
| 
 | |
|    pG->zflag = TRUE; // display the zipfile comment
 | |
| 
 | |
|    // We wrap some exception handling around the entire Info-ZIP engine to be
 | |
|    // safe.  Since we are running on a device with tight memory configurations,
 | |
|    // all sorts of problems can arise when we run out of memory.
 | |
|    __try {
 | |
| 
 | |
|       // Call the unzip routine.  We will catch the comment string in a callback
 | |
|       // to win_fprintf().
 | |
|       result = process_zipfiles(pG);
 | |
| 
 | |
|    } __except(EXCEPTION_EXECUTE_HANDLER) {
 | |
| 
 | |
|       // Catch any exception here.
 | |
|       DebugOut(TEXT("Exception 0x%08X occurred in DoGetComment()"),
 | |
|                GetExceptionCode());
 | |
|       result = PK_EXCEPTION;
 | |
|    }
 | |
| 
 | |
|    // Free our globals.
 | |
|    FreeGlobals(pG);
 | |
| 
 | |
|    return result;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| BOOL SetExtractToDirectory(LPTSTR szDirectory) {
 | |
| 
 | |
|    BOOL fNeedToAddWack = FALSE;
 | |
| 
 | |
|    // Remove any trailing wack from the path.
 | |
|    int length = _tcslen(szDirectory);
 | |
|    if ((length > 0) && (szDirectory[length - 1] == TEXT('\\'))) {
 | |
|       szDirectory[--length] = TEXT('\0');
 | |
|       fNeedToAddWack = TRUE;
 | |
|    }
 | |
| 
 | |
| #ifndef _WIN32_WCE
 | |
|    
 | |
|    // Check to see if a root directory was specified.
 | |
|    if ((length == 2) && isalpha(szDirectory[0]) && (szDirectory[1] == ':')) {
 | |
| 
 | |
|       // If just a root is specified, we need to only verify the drive letter.
 | |
|       if (!(GetLogicalDrives() & (1 << (tolower(szDirectory[0]) - (int)'a')))) {
 | |
| 
 | |
|          // This drive does not exist.  Bail out with a failure.
 | |
|          return FALSE;
 | |
|       }
 | |
| 
 | |
|    } else
 | |
| 
 | |
| #endif
 | |
| 
 | |
|    // We only verify path if length is >0 since we know "\" is valid.
 | |
|    if (length > 0) {
 | |
| 
 | |
|       // Verify the the path exists and that it is a directory.
 | |
|       if (IsFileOrDirectory(szDirectory) != 2) {
 | |
|          return FALSE;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Store the directory for when we do an extract.
 | |
|    wcstombs(g_szExtractToDirectory, szDirectory, countof(g_szExtractToDirectory));
 | |
| 
 | |
|    // We always want a wack at the end of our path.
 | |
|    strcat(g_szExtractToDirectory, "\\");
 | |
|    
 | |
|    // Add the wack back to the end of the path.
 | |
|    if (fNeedToAddWack) {
 | |
|       _tcscat(szDirectory, TEXT("\\"));
 | |
|    }
 | |
| 
 | |
|    return TRUE;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Internal functions
 | |
| //******************************************************************************
 | |
| 
 | |
| struct Globals* InitGlobals(LPCSTR szZipFile) {
 | |
| 
 | |
|    // Store a global pointer to our USERFUNCTIONS structure so that LIST.C,
 | |
|    // PROCESS.C, and WINMAIN can access it.
 | |
|    lpUserFunctions = &g_uf;
 | |
| 
 | |
|    // Clear our USERFUNCTIONS structure and assign our SendAppMsg() function.
 | |
|    ZeroMemory(&g_uf, sizeof(g_uf));
 | |
|    g_uf.SendApplicationMessage = SendAppMsg;
 | |
|    
 | |
|    // Store a global pointer to our DCL structure so that EXTRACT.C can access it.
 | |
|    lpDCL = &g_dcl;
 | |
| 
 | |
|    // Clear our DCL structure.
 | |
|    ZeroMemory(&g_dcl, sizeof(g_dcl));
 | |
| 
 | |
|    // Create our global structure - pG
 | |
|    CONSTRUCTGLOBALS();
 | |
| 
 | |
|    // Bail out if we failed to allocate our Globals structure.
 | |
|    if (!pG) {
 | |
|       return NULL;
 | |
|    }
 | |
| 
 | |
|    // Fill in all our callback functions.
 | |
|    pG->message     = UzpMessagePrnt2;
 | |
|    pG->input       = UzpInput2;
 | |
|    pG->mpause      = UzpMorePause;
 | |
|    pG->replace     = UzpReplace;
 | |
|    pG->sound       = UzpSound;
 | |
| 
 | |
| #if CRYPT
 | |
|    pG->decr_passwd = UzpPassword;
 | |
| #endif
 | |
| 
 | |
|    // Match filenames case-sensitively.  We can do this since we can guarentee
 | |
|    // exact case because the user can only select files via our UI.
 | |
|    pG->C_flag = FALSE;
 | |
| 
 | |
|    // Allocate and store the ZIP file name in pG->zipfn
 | |
|    if (!(pG->zipfnPtr = new char[FILNAMSIZ])) {
 | |
|       FreeGlobals(pG);
 | |
|       return NULL;
 | |
|    }
 | |
|    pG->zipfn = pG->zipfnPtr;
 | |
|    strcpy(pG->zipfn, szZipFile);
 | |
| 
 | |
|    // Allocate and store the ZIP file name in pG->zipfn.  This needs to done
 | |
|    // so that do_wild() does not wind up clearing out the zip file name when
 | |
|    // it returns in process.c
 | |
|    if (!(pG->wildzipfnPtr = new char[FILNAMSIZ])) {
 | |
|       FreeGlobals(pG);
 | |
|       return NULL;
 | |
|    }
 | |
|    pG->wildzipfn = pG->wildzipfnPtr;
 | |
|    strcpy(pG->wildzipfn, szZipFile);
 | |
| 
 | |
|    return pG;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void FreeGlobals(Globals *pG) {
 | |
| 
 | |
|    // Free our ZIP file name
 | |
|    if (pG->zipfnPtr) {
 | |
|       delete[] pG->zipfnPtr;
 | |
|       pG->zipfnPtr = pG->zipfn = NULL;
 | |
|    }
 | |
| 
 | |
|    // Free our wild name buffer
 | |
|    if (pG->wildzipfnPtr) {
 | |
|       delete[] pG->wildzipfnPtr;
 | |
|       pG->wildzipfnPtr = pG->wildzipfn = NULL;
 | |
|    }
 | |
| 
 | |
|    // Free everything else.
 | |
|    DESTROYGLOBALS()
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| int IsFileOrDirectory(LPCTSTR szPath) {
 | |
| 
 | |
|    // Geth the attributes of the item.
 | |
|    DWORD dwAttribs = GetFileAttributes(szPath);
 | |
| 
 | |
|    // Bail out now if we could not find the path at all.
 | |
|    if (dwAttribs == 0xFFFFFFFF) {
 | |
|       return 0;
 | |
|    }
 | |
| 
 | |
|    // Return 1 for file and 2 for directory.
 | |
|    return ((dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 1);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| BOOL SmartCreateDirectory(struct Globals *pG, LPCSTR szDirectory) {
 | |
| 
 | |
|    // Copy path to a UNICODE buffer.
 | |
|    TCHAR szBuffer[_MAX_PATH];
 | |
|    mbstowcs(szBuffer, szDirectory, countof(szBuffer));
 | |
| 
 | |
|    int x = IsFileOrDirectory(szBuffer);
 | |
| 
 | |
|    // Create the directory if it does not exist.
 | |
|    if (x == 0) {
 | |
|       if (!CreateDirectory(szBuffer, NULL)) {
 | |
|          Info(slide, 1, ((char *)slide, "error creating directory: %s\n", szDirectory));
 | |
|          return FALSE;
 | |
|       }
 | |
| 
 | |
|    // If there is a file with the same name, then display an error.
 | |
|    } else if (x == 1) {
 | |
|       Info(slide, 1, ((char *)slide, 
 | |
|            "cannot create %s as a file with same name already exists.\n",
 | |
|            szDirectory));
 | |
|       return FALSE;
 | |
|    }
 | |
| 
 | |
|    // If the directory already exists or was created, then return success.
 | |
|    return TRUE;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| #ifdef _WIN32_WCE
 | |
| 
 | |
| // On WinCE, we declare our thread function the way CreateThread() likes it.
 | |
| DWORD WINAPI ExtractOrTestFilesThread(LPVOID lpv) {
 | |
| 
 | |
| #else
 | |
| 
 | |
| // On WinNT, we declare our thread function the way _beginthreadex likes it.
 | |
| unsigned __stdcall ExtractOrTestFilesThread(void *lpv) {
 | |
| 
 | |
| #endif
 | |
| 
 | |
|    struct Globals *pG = (struct Globals*)lpv;
 | |
| 
 | |
|    if (g_pExtractInfo->fExtract) {
 | |
| 
 | |
|       pG->extract_flag = TRUE;
 | |
| 
 | |
|       switch (g_pExtractInfo->overwriteMode) {
 | |
| 
 | |
|          case OM_NEWER:
 | |
|             pG->uflag = TRUE; // Update (extract only newer/brand-new files)
 | |
|             break;
 | |
| 
 | |
|          case OM_ALWAYS:
 | |
|             pG->overwrite_all = TRUE; // OK to overwrite files without prompting
 | |
|             break;
 | |
| 
 | |
|          case OM_NEVER:
 | |
|             pG->overwrite_none = TRUE; // Never overwrite files (no prompting)
 | |
|             break;
 | |
| 
 | |
|          default:
 | |
|             g_dcl.PromptToOverwrite = TRUE; // Force a prompt
 | |
|             break;
 | |
|       }
 | |
| 
 | |
|       // Throw away paths if requested.
 | |
|       pG->jflag = !g_pExtractInfo->fRestorePaths;
 | |
| 
 | |
|    } else {
 | |
|       pG->tflag = TRUE;
 | |
|    }
 | |
| 
 | |
|    if (g_pExtractInfo->szFileList) {
 | |
|       pG->filespecs = g_pExtractInfo->dwFileCount;
 | |
|       pG->pfnames = g_pExtractInfo->szFileList;
 | |
|    } else {
 | |
|       // Improves performance if all files are being extracted.
 | |
|       pG->process_all_files = TRUE;
 | |
|    }
 | |
| 
 | |
|    // All args are files/dirs to be extracted.
 | |
|    pG->dflag = TRUE;                    
 | |
| 
 | |
|    // Invalidate our file offset to show that we are starting a new operation.
 | |
|    g_pExtractInfo->dwFileOffset = 0xFFFFFFFF;
 | |
| 
 | |
|    // We wrap some exception handling around the entire Info-ZIP engine to be
 | |
|    // safe.  Since we are running on a device with tight memory configurations,
 | |
|    // all sorts of problems can arise when we run out of memory.
 | |
|    __try {
 | |
| 
 | |
|       // Put a jump marker on our stack so the user can abort.
 | |
|       int error = setjmp(dll_error_return);
 | |
| 
 | |
|       // If setjmp() returns 0, then we just set our jump marker and we can
 | |
|       // continue with the operation.  If setjmp() returned something else,
 | |
|       // then we reached this point because the operation was aborted and 
 | |
|       // set our instruction pointer back here.
 | |
| 
 | |
|       if (error > 0) {
 | |
|          // We already called process_zipfiles() and were thrown back here.
 | |
|          g_pExtractInfo->result = (error == 1) ? PK_BADERR : error;
 | |
| 
 | |
|       } else {
 | |
|          // Entering Info-ZIP... close your eyes.
 | |
|          g_pExtractInfo->result = process_zipfiles(pG);
 | |
|       }
 | |
| 
 | |
|    } __except(EXCEPTION_EXECUTE_HANDLER) {
 | |
| 
 | |
|       // Catch any exception here.
 | |
|       DebugOut(TEXT("Exception 0x%08X occurred in ExtractOrTestFilesThread()"),
 | |
|                GetExceptionCode());
 | |
|       g_pExtractInfo->result = PK_EXCEPTION;
 | |
|    }
 | |
| 
 | |
|    // Free our globals.
 | |
|    FreeGlobals(pG);
 | |
| 
 | |
|    // Tell the progress dialog that we are done.
 | |
|    SendMessage(g_hDlgProgress, WM_PRIVATE, MSG_OPERATION_COMPLETE, 
 | |
|                (LPARAM)g_pExtractInfo);
 | |
| 
 | |
|    // Clear our global pointer as we are done with it.
 | |
|    g_pExtractInfo = NULL;
 | |
| 
 | |
| #ifndef _WIN32_WCE
 | |
|    // On NT, we need to free any CRT allocated memory.
 | |
|    _endthreadex(0);
 | |
| #endif
 | |
| 
 | |
|    return 0;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void CheckForAbort(struct Globals *pG) {
 | |
|    if (g_pExtractInfo->fAbort) {
 | |
|       
 | |
|       // Add a newline to our log if we are in the middle of a line of text.
 | |
|       if (!g_pExtractInfo->fNewLineOfText) {
 | |
|          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)"\n");
 | |
|       }
 | |
| 
 | |
|       // Make sure whatever file we are currently processing gets closed.
 | |
|       if (((int)pG->outfile != 0) && ((int)pG->outfile != -1)) {
 | |
|          if (g_pExtractInfo->fExtract && *pG->filename) {
 | |
| 
 | |
|             // Make sure the user is aware that this file is screwed.
 | |
|             SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
 | |
|                         (LPARAM)"warning: ");
 | |
|             SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
 | |
|                         (LPARAM)pG->filename);
 | |
|             SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
 | |
|                         (LPARAM)" is probably truncated.\n");
 | |
|          }
 | |
| 
 | |
|          // Close the file.
 | |
|          close_outfile(pG);
 | |
|       }
 | |
| 
 | |
|       // Display an aborted message in the log
 | |
|       SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, 
 | |
|                   (LPARAM)"Operation aborted by user.\n");
 | |
| 
 | |
|       // I hate to do this... Take a giant step out of here.
 | |
|       longjmp(dll_error_return, PK_ABORTED);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void SetCurrentFile(struct Globals *pG) {
 | |
| 
 | |
|    // Reset all our counters as we about to process a new file.
 | |
|    g_pExtractInfo->dwFileOffset = (DWORD)pG->pInfo->offset;
 | |
|    g_pExtractInfo->dwFile++;
 | |
|    g_pExtractInfo->dwBytesWrittenThisFile = 0;
 | |
|    g_pExtractInfo->dwBytesWrittenPreviousFiles += g_pExtractInfo->dwBytesTotalThisFile;
 | |
|    g_pExtractInfo->dwBytesTotalThisFile = pG->ucsize;
 | |
|    g_pExtractInfo->szFile = pG->filename;
 | |
|    g_pExtractInfo->fNewLineOfText = TRUE;
 | |
| 
 | |
|    // Pass control to our GUI thread to do a full update our progress dialog.
 | |
|    SendMessage(g_hWndMain, WM_PRIVATE, MSG_UPDATE_PROGRESS_COMPLETE,
 | |
|                (LPARAM)g_pExtractInfo);
 | |
| 
 | |
|    // Check our abort flag.
 | |
|    CheckForAbort(pG);
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Callbacks from Info-ZIP code.
 | |
| //******************************************************************************
 | |
| 
 | |
| int UzpMessagePrnt2(zvoid *pG, uch *buffer, ulg size, int flag) {
 | |
| 
 | |
|    // Some ZIP files cause us to get called during DoListFiles(). We only handle
 | |
|    // messages while processing DoExtractFiles().
 | |
|    if (!g_pExtractInfo) {
 | |
|       if (g_hWndEdit) {
 | |
|          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, 
 | |
|                      (LPARAM)buffer);
 | |
|       } else {
 | |
|          DebugOut(TEXT("Unhandled call to UzpMessagePrnt2(\"%S\")"), buffer);
 | |
|       }
 | |
|       return 0;
 | |
|    }
 | |
| 
 | |
|    // When extracting, mapname() will get called for every file which in turn
 | |
|    // will call SetCurrentFile().  For testing though, mapname() never gets
 | |
|    // called so we need to be on the lookout for a new file.
 | |
|    if (g_pExtractInfo->dwFileOffset != (DWORD)((struct Globals*)pG)->pInfo->offset) {
 | |
|       SetCurrentFile((struct Globals*)pG);
 | |
|    }
 | |
| 
 | |
|    // Make sure this message was inteded for us to display.
 | |
|    if (!MSG_NO_WGUI(flag) && !MSG_NO_WDLL(flag)) {
 | |
| 
 | |
|       // Insert a leading newline if requested to do so.
 | |
|       if (MSG_LNEWLN(flag) && !g_pExtractInfo->fNewLineOfText) {
 | |
|          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)"\n");
 | |
|          g_pExtractInfo->fNewLineOfText = TRUE;
 | |
|       }
 | |
| 
 | |
|       // Since we use a proportional font, we need to do a little cleanup of the
 | |
|       // text we are passed since it assumes a fixed font and adds padding to try
 | |
|       // to line things up.  We remove leading whitespace on any new line of text.
 | |
|       if (g_pExtractInfo->fNewLineOfText) {
 | |
|          while (*buffer == ' ') {
 | |
|             buffer++;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       // We always remove trailing whitespace.
 | |
|       LPSTR psz = (LPSTR)buffer + strlen((LPSTR)buffer) - 1;
 | |
|       while ((psz >= (LPSTR)buffer) && (*psz == ' ')) {
 | |
|          *(psz--) = '\0';
 | |
|       }
 | |
| 
 | |
|       // Determine if the next line of text will be a new line of text.
 | |
|       g_pExtractInfo->fNewLineOfText = ((*psz == '\r') || (*psz == '\n'));
 | |
| 
 | |
|       // Change all forward slashes to back slashes in the buffer
 | |
|       ForwardSlashesToBackSlashesA((LPSTR)buffer);
 | |
| 
 | |
|       // Add the cleaned-up text to our extraction log edit control.
 | |
|       SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)buffer);
 | |
| 
 | |
|       // Append a trailing newline if requested to do so.
 | |
|       if (MSG_TNEWLN(flag) || MSG_MNEWLN(flag) && !g_pExtractInfo->fNewLineOfText) {
 | |
|          SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)"\n");
 | |
|          g_pExtractInfo->fNewLineOfText = TRUE;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    return 0;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| int UzpInput2(zvoid *pG, uch *buffer, int *size, int flag) {
 | |
|    DebugOut(TEXT("WARNING: UzpInput2(...) called"));
 | |
|    return 0;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void UzpMorePause(zvoid *pG, const char *szPrompt, int flag) {
 | |
|    DebugOut(TEXT("WARNING: UzpMorePause(...) called"));
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| int UzpPassword(zvoid *pG, int *pcRetry, char *szPassword, int nSize, 
 | |
|                 const char *szZipFile, const char *szFile)
 | |
| {
 | |
|    // Return Values:
 | |
|    //    IZ_PW_ENTERED    got some PWD string, use/try it
 | |
|    //    IZ_PW_CANCEL     no password available (for this entry)
 | |
|    //    IZ_PW_CANCELALL  no password, skip any further PWD request
 | |
|    //    IZ_PW_ERROR      failure (no mem, no tty, ...)
 | |
| 
 | |
| #if CRYPT
 | |
| 
 | |
|    // Build the data structure for our dialog.
 | |
|    DECRYPT_INFO di;
 | |
|    di.retry      = *pcRetry;
 | |
|    di.szPassword = szPassword;
 | |
|    di.nSize      = nSize;
 | |
|    di.szFile     = szFile;
 | |
| 
 | |
|    // Clear the password to be safe.
 | |
|    *di.szPassword = '\0';
 | |
| 
 | |
|    // On our first call for a file, *pcRetry == 0.  If we would like to allow
 | |
|    // for retries, then we set the value of *pcRetry to the number of retries we
 | |
|    // are willing to allow.  We will be recalled as neccessary, each time with
 | |
|    // *pcRetry being decremented once.  1 is the last retry we will get.
 | |
|    *pcRetry = (*pcRetry == 0) ? MAX_PASSWORD_RETRIES : (*pcRetry - 1);
 | |
| 
 | |
|    // Pass control to our GUI thread which will prompt the user for a password.
 | |
|    return SendMessage(g_hWndMain, WM_PRIVATE, MSG_PROMPT_FOR_PASSWORD, (LPARAM)&di);
 | |
| 
 | |
| #else
 | |
|    return -2;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| int WINAPI UzpReplace(char *szFile) {
 | |
|    // Pass control to our GUI thread which will prompt the user to overwrite.
 | |
|    return SendMessage(g_hWndMain, WM_PRIVATE, MSG_PROMPT_TO_REPLACE, (LPARAM)szFile);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void WINAPI UzpSound(void) {
 | |
|    // Do nothing.
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| // Called from LIST.C
 | |
| void WINAPI SendAppMsg(ulg dwSize, ulg dwCompressedSize, int ratio, int month, 
 | |
|                        int day, int year, int hour, int minute, int uppercase,
 | |
|                        char *szPath, char *szMethod, ulg dwCRC)
 | |
| {
 | |
|    // If we are out of memory, then just bail since we will only make things worse.
 | |
|    if (g_fOutOfMemory) {
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // We get our Globals structure and then retrieve the real file name.
 | |
|    GETGLOBALS()
 | |
|    szPath = pG->filename;
 | |
| 
 | |
|    // Allocate a FILE_NODE large enough to hold this file.
 | |
|    int length = strlen(szPath) + strlen(szMethod);
 | |
|    g_pFileLast = (FILE_NODE*)new BYTE[sizeof(FILE_NODE) + (sizeof(TCHAR) * length)];
 | |
| 
 | |
|    // Bail out if we failed to allocate the node.
 | |
|    if (!g_pFileLast) {
 | |
|       DebugOut(TEXT("Failed to create a FILE_NODE for \"%S\"."), szPath);
 | |
|       g_fOutOfMemory = TRUE;
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // Fill in our node.
 | |
|    g_pFileLast->dwSize           = dwSize;
 | |
|    g_pFileLast->dwCompressedSize = dwCompressedSize;
 | |
|    g_pFileLast->dwCRC            = dwCRC;
 | |
|    g_pFileLast->szComment        = NULL;
 | |
|    g_pFileLast->szType           = NULL;
 | |
| 
 | |
|    // Fix the year value to contain the real year.
 | |
|    year += 1900;
 | |
| 
 | |
|    // Year:   0 - 4095 (12) 1111 1111 1111 0000 0000 0000 0000 0000 (0xFFF00000)
 | |
|    // Month:  1 -   12 ( 4) 0000 0000 0000 1111 0000 0000 0000 0000 (0x000F0000)
 | |
|    // Day:    1 -   31 ( 5) 0000 0000 0000 0000 1111 1000 0000 0000 (0x0000F800)
 | |
|    // Hour:   0 -   23 ( 5) 0000 0000 0000 0000 0000 0111 1100 0000 (0x000007C0)
 | |
|    // Minute: 0 -   59 ( 6) 0000 0000 0000 0000 0000 0000 0011 1111 (0x0000003F)
 | |
| 
 | |
|    // Do some bit shifting to make the date and time fit in a DWORD.
 | |
|    g_pFileLast->dwModified = (((DWORD)(year   & 0x0FFF) << 20) |
 | |
|                               ((DWORD)(month  & 0x000F) << 16) |
 | |
|                               ((DWORD)(day    & 0x001F) << 11) |
 | |
|                               ((DWORD)(hour   & 0x001F) <<  6) |
 | |
|                               ((DWORD)(minute & 0x003F)));
 | |
|    
 | |
|    // We need to get our globals structure to determine our attributes and
 | |
|    // encryption information.
 | |
|    g_pFileLast->dwAttributes = (pG->crec.external_file_attributes & 0xFF);
 | |
|    if (pG->crec.general_purpose_bit_flag & 1) {
 | |
|       g_pFileLast->dwAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
 | |
|    }
 | |
| 
 | |
|    // Store the path and method in our string buffer.
 | |
|    strcpy(g_pFileLast->szPathAndMethod, szPath);
 | |
|    strcpy(g_pFileLast->szPathAndMethod + strlen(szPath) + 1, szMethod);
 | |
| 
 | |
|    // Pass the file object to our windows code to have it added to our list.
 | |
|    AddFileToListView(g_pFileLast);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| int win_fprintf(FILE *file, unsigned int dwCount, char far *buffer) {
 | |
| 
 | |
|    // win_fprintf() is used within Info-ZIP to write to a file as well as log 
 | |
|    // information.  If the "file" is a real file handle (not stdout or stderr),
 | |
|    // then we write the data to the file and return.
 | |
| 
 | |
|    if ((file != stdout) && (file != stderr)) {
 | |
| 
 | |
|       DWORD dwBytesWriten = 0;
 | |
| #ifdef _WIN32_WCE
 | |
|       // On WinCE all FILEs are really HANDLEs.  See WINCE.CPP for more info.
 | |
|       WriteFile((HANDLE)file, buffer, dwCount, &dwBytesWriten, NULL);
 | |
| #else
 | |
|       dwBytesWriten = fwrite(buffer, 1, dwCount, file);
 | |
| #endif
 | |
| 
 | |
|       // Update our bytes written count.
 | |
|       g_pExtractInfo->dwBytesWrittenThisFile += dwBytesWriten;
 | |
| 
 | |
|       // Pass control to our GUI thread to do a partial update our progress dialog.
 | |
|       SendMessage(g_hWndMain, WM_PRIVATE, MSG_UPDATE_PROGRESS_PARTIAL,
 | |
|                   (LPARAM)g_pExtractInfo);
 | |
| 
 | |
|       // Check our abort flag.
 | |
|       GETGLOBALS();
 | |
|       CheckForAbort(pG);
 | |
| 
 | |
|       return dwBytesWriten;
 | |
|    }
 | |
| 
 | |
|    // Check to see if we are expecting a extraction progress string
 | |
|    if (g_pExtractInfo) {
 | |
| 
 | |
|       // Most of our progress strings come to our UzpMessagePrnt2() callback,
 | |
|       // but we occasionally get one here.  We will just forward it to 
 | |
|       // UzpMessagePrnt2() as if it never came here.  To do this, we need to
 | |
|       // get a pointer to our Globals struct.  Calling GETGLOBALS() sort of
 | |
|       // breaks us from be REENTRANT, but we don't support that anyway.
 | |
|       GETGLOBALS();
 | |
|       UzpMessagePrnt2(pG, (uch*)buffer, dwCount, 0);
 | |
|       return dwCount;
 | |
|    }
 | |
| 
 | |
|    // Check to see if we are expecting a zip file comment string.
 | |
|    if (g_hWndEdit) {
 | |
| 
 | |
|       // Change all forward slashes to back slashes in the buffer
 | |
|       ForwardSlashesToBackSlashesA((LPSTR)buffer);
 | |
| 
 | |
|       SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT, (LPARAM)buffer);
 | |
|       return dwCount;
 | |
|    }
 | |
| 
 | |
|    // Check to see if we are expecting a compressed file comment string.
 | |
|    if (g_pFileLast) {
 | |
| 
 | |
|       // Calcalute the size of the buffer we will need to store this comment.
 | |
|       // We are going to convert all ASC values 0 - 31 (excpet tab, new line,
 | |
|       // and CR) to ^char.
 | |
|       int size = 1;
 | |
|       for (char *p2, *p1 = buffer; *p1; p1++) {
 | |
|          size += ((*p1 >= 32) || (*p1 == '\t') || (*p1 == '\r') || (*p1 == '\n')) ? 1 : 2;
 | |
|       }
 | |
| 
 | |
|       // Allocate a comment buffer and assign it to the last file node we saw.
 | |
|       if (g_pFileLast->szComment = new CHAR[size]) {
 | |
| 
 | |
|          // Copy while formatting.
 | |
|          for (p1 = buffer, p2 = (char*)g_pFileLast->szComment; *p1; p1++) {
 | |
|             if ((*p1 >= 32) || (*p1 == '\t') || (*p1 == '\r') || (*p1 == '\n')) {
 | |
|                *(p2++) = *p1;
 | |
|             } else {
 | |
|                *(p2++) = '^';
 | |
|                *(p2++) = 64 + *p1;
 | |
|             }
 | |
|          }
 | |
|          *p2 = '\0';
 | |
|       }
 | |
| 
 | |
|       // Update the attributes of the file node to incldue the comment attribute.
 | |
|       g_pFileLast->dwAttributes |= FILE_ATTRIBUTE_COMMENT;
 | |
| 
 | |
|       // Clear the file node so we don't try to add another bogus comment to it.
 | |
|       g_pFileLast = NULL;
 | |
| 
 | |
|       return dwCount;
 | |
|    }
 | |
| 
 | |
|    if (dwCount >= _MAX_PATH) {
 | |
|       buffer[_MAX_PATH] = '\0';
 | |
|    }
 | |
|    DebugOut(TEXT("Unhandled call to win_fprintf(\"%S\")"), buffer);
 | |
|    return dwCount;
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Functions that Info-ZIP expects the port to write and export.
 | |
| //***** Some of this code was stolen from the WIN32 port and highly modified.
 | |
| //******************************************************************************
 | |
| 
 | |
| int mapattr(struct Globals *pG) {
 | |
| 
 | |
|    // Check to see if we are extracting this file for viewing.  Currently, we do
 | |
|    // this by checking the szMappedPath member of our extract info stucture
 | |
|    // since we know OnActionView() is the only one who sets this member.
 | |
| 
 | |
|    if (g_pExtractInfo && g_pExtractInfo->szMappedPath) {
 | |
| 
 | |
|       // If we are extracting for view only, then we ignore the file's real
 | |
|       // attributes and force the file to create as read-only.  We make the file
 | |
|       // read-only to help prevent the user from making changes to the temporary
 | |
|       // file and then trying to save the changes back to a file that we will
 | |
|       // eventually delete.
 | |
|       pG->pInfo->file_attr = FILE_ATTRIBUTE_READONLY;
 | |
| 
 | |
|    } else {
 | |
| 
 | |
|       // Store the attribute exactly as it appears for normal extraction/test.
 | |
|       pG->pInfo->file_attr = (unsigned)pG->crec.external_file_attributes & 0xff;
 | |
|    }
 | |
|    return PK_OK;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void utimeToFileTime(time_t ut, FILETIME *pft, BOOL fOldFileSystem) {
 | |
| 
 | |
|    // time_t    is a 32-bit value for the seconds since January 1, 1970
 | |
|    // FILETIME  is a 64-bit value for the number of 100-nanosecond intervals since 
 | |
|    //           January 1, 1601
 | |
|    // DWORDLONG is a 64-bit int that we can use to perform large math operations.
 | |
| 
 | |
| 
 | |
|    // time_t has minimum of 1/1/1970.  Many file systems, such as FAT, have a
 | |
|    // minimum date of 1/1/1980.  If extracting to one of those file systems and
 | |
|    // out time_t is less than 1980, then we make it 1/1/1980.
 | |
|    // (365 days/yr * 10 yrs + 3 leap yr days) * (60 secs * 60 mins * 24 hrs).
 | |
|    if (fOldFileSystem && (ut < 0x12CFF780)) {
 | |
|       ut = 0x12CFF780;
 | |
|    }
 | |
| 
 | |
|    // Compute the FILETIME for the given time_t.
 | |
|    DWORDLONG dwl = ((DWORDLONG)116444736000000000 + 
 | |
|                    ((DWORDLONG)ut * (DWORDLONG)10000000));
 | |
| 
 | |
|    // Store the return value.
 | |
|    *pft = *(FILETIME*)&dwl;
 | |
| 
 | |
|    // Now for the next fix for old file systems.  If we are in Daylight Savings
 | |
|    // Time (DST) and the file is not in DST, then we need subtract off the DST
 | |
|    // bias from the filetime.  This is due to a bug in Windows (NT, CE, and 95)
 | |
|    // that causes the DST bias to be added to all file times when the system
 | |
|    // is in DST, even if the file is not in DST.  This only effects old file
 | |
|    // systems since they store local times instead of UTC times.  Newer file
 | |
|    // systems like NTFS and CEFS store UTC times.
 | |
| 
 | |
|    if (fOldFileSystem) {
 | |
| 
 | |
|       // We use the CRT's localtime() and Win32's FileTimeToLocalTime()
 | |
|       // functions to compute the DST bias.  This works because localtime()
 | |
|       // correctly adds the DST bias only if the file time is in DST.
 | |
|       // FileTimeToLocalTime() always adds the DST bias to the time.
 | |
|       // Therefore, if the functions return different results, we know we
 | |
|       // are dealing with a non-DST file during a system DST.
 | |
| 
 | |
|       FILETIME ftCRT, ftWin32;
 | |
| 
 | |
|       // Get the CRT result - result is a "tm" struct.
 | |
|       struct tm *ptmCRT = localtime(&ut);
 | |
| 
 | |
|       // Convert the "tm" struct to a FILETIME.
 | |
|       SYSTEMTIME stCRT;
 | |
|       ZeroMemory(&stCRT, sizeof(stCRT));
 | |
|       stCRT.wYear   = ptmCRT->tm_year + 1900;
 | |
|       stCRT.wMonth  = ptmCRT->tm_mon + 1;
 | |
|       stCRT.wDay    = ptmCRT->tm_mday;
 | |
|       stCRT.wHour   = ptmCRT->tm_hour;
 | |
|       stCRT.wMinute = ptmCRT->tm_min;
 | |
|       stCRT.wSecond = ptmCRT->tm_sec;
 | |
|       SystemTimeToFileTime(&stCRT, &ftCRT);
 | |
| 
 | |
|       // Get the Win32 result - result is a FILETIME.
 | |
|       if (FileTimeToLocalFileTime(pft, &ftWin32)) {
 | |
| 
 | |
|          // Subtract the difference from our current filetime.
 | |
|          *(DWORDLONG*)pft -= *(DWORDLONG*)&ftWin32 - *(DWORDLONG*)&ftCRT;
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| int GetFileTimes(struct Globals *pG, FILETIME *pftCreated, FILETIME *pftAccessed,
 | |
|                  FILETIME *pftModified)
 | |
| {
 | |
|    // We need to check to see if this file system is limited.  This includes
 | |
|    // FAT, VFAT, and HPFS.  It does not include NTFS and CEFS.  The limited
 | |
|    // file systems can not support dates < 1980 and they store file local times
 | |
|    // for files as opposed to UTC times.
 | |
|    BOOL fOldFileSystem = IsOldFileSystem(pG->filename);
 | |
| 
 | |
| #ifdef USE_EF_UT_TIME  // Always true for WinCE build
 | |
| 
 | |
|    if (pG->extra_field) {
 | |
| 
 | |
|       // Structure for Unix style actime, modtime, creatime
 | |
|       iztimes z_utime;
 | |
| 
 | |
|       // Get any date/time we can.  This can return 0 to 3 unix time fields.
 | |
|       unsigned eb_izux_flg = ef_scan_for_izux(pG->extra_field, 
 | |
|                                               pG->lrec.extra_field_length,
 | |
|                                               0, &z_utime, NULL);
 | |
| 
 | |
|       // We require at least a modified time.
 | |
|       if (eb_izux_flg & EB_UT_FL_MTIME) {
 | |
| 
 | |
|          // We know we have a modified time, so get it first.
 | |
|          utimeToFileTime(z_utime.mtime, pftModified, fOldFileSystem);
 | |
| 
 | |
|          // Get the accessed time if we have one.
 | |
|          if (eb_izux_flg & EB_UT_FL_ATIME) {
 | |
|             utimeToFileTime(z_utime.atime, pftAccessed, fOldFileSystem);
 | |
|          }
 | |
| 
 | |
|          // Get the created time if we have one.
 | |
|          if (eb_izux_flg & EB_UT_FL_CTIME) {
 | |
|             utimeToFileTime(z_utime.ctime, pftCreated, fOldFileSystem);
 | |
|          }
 | |
| 
 | |
|          // Return our flags.
 | |
|          return (int)eb_izux_flg;
 | |
|       }
 | |
|    }
 | |
| 
 | |
| #endif // USE_EF_UT_TIME
 | |
| 
 | |
|    // If all else fails, we can resort to using the DOS date and time data.
 | |
|    time_t ux_modtime = dos_to_unix_time(G.lrec.last_mod_file_date,
 | |
|                                         G.lrec.last_mod_file_time);
 | |
|    utimeToFileTime(ux_modtime, pftModified, fOldFileSystem);
 | |
| 
 | |
|    *pftAccessed = *pftModified;
 | |
| 
 | |
|    return (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void close_outfile(struct Globals *pG) {
 | |
| 
 | |
|    // Get the 3 time stamps for the file.
 | |
|    FILETIME ftCreated, ftAccessed, ftModified;
 | |
|    int timeFlags = GetFileTimes(pG, &ftCreated, &ftAccessed, &ftModified);
 | |
| 
 | |
|    TCHAR szFile[_MAX_PATH];
 | |
|    mbstowcs(szFile, pG->filename, countof(szFile));
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
|    
 | |
|    // Cast the outfile to a HANDLE (since that is really what it is), and
 | |
|    // flush the file.  We need to flush, because any unsaved data that is
 | |
|    // written to the file during CloseHandle() will step on the work done
 | |
|    // by SetFileTime().
 | |
|    HANDLE hFile = (HANDLE)pG->outfile;
 | |
|    FlushFileBuffers(hFile);
 | |
| 
 | |
| #else
 | |
| 
 | |
|    // Close the file and then re-open it using the Win32 CreateFile() call.
 | |
|    // SetFileTime() requires a Win32 file HANDLE created with GENERIC_WRITE
 | |
|    // access.
 | |
|    fclose(pG->outfile);
 | |
|    HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
 | |
|                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 | |
| 
 | |
| #endif
 | |
| 
 | |
|    // Set the file's date and time.
 | |
|    if (hFile != INVALID_HANDLE_VALUE) {
 | |
| 
 | |
|       // Make sure we retrieved some valid time stamp(s)
 | |
|       if (timeFlags) {
 | |
| 
 | |
|          // Set the various date and time fields.
 | |
|          if (!SetFileTime(hFile, 
 | |
|                  (timeFlags & EB_UT_FL_CTIME) ? &ftCreated  : NULL,
 | |
|                  (timeFlags & EB_UT_FL_ATIME) ? &ftAccessed : NULL,
 | |
|                  (timeFlags & EB_UT_FL_MTIME) ? &ftModified : NULL))
 | |
|          {
 | |
|             DebugOut(TEXT("SetFileTime() failed [%u]"), GetLastError());
 | |
|          }
 | |
| 
 | |
|       } else {
 | |
|          DebugOut(TEXT("GetFileTimes() failed"));
 | |
|       }
 | |
| 
 | |
|       // Close out file.
 | |
|       CloseHandle(hFile);
 | |
| 
 | |
|    } else {
 | |
|       DebugOut(TEXT("CreateFile() failed [%u]"), GetLastError());
 | |
|    }
 | |
| 
 | |
|    // If the file was successfully written, then set the attributes.
 | |
|    if (!pG->disk_full && !g_pExtractInfo->fAbort) {
 | |
|       if (!SetFileAttributes(szFile, G.pInfo->file_attr & 0x7F)) {
 | |
|          DebugOut(TEXT("SetFileAttributes() failed [%u]"), GetLastError());
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Clear outfile so we know it is closed.
 | |
|    pG->outfile = 0;
 | |
| 
 | |
|    return;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| // Called by PROCESS.C
 | |
| char* do_wild(struct Globals *pG, char *wildspec) {
 | |
| 
 | |
|    // This is a very slimmed down version of do_wild() taken from WIN32.C.
 | |
|    // Since we don't support wildcards, we basically just return the wildspec
 | |
|    // passed in as the filename.
 | |
|    
 | |
|    // First call - must initialize everything.
 | |
|    if (!pG->notfirstcall) {
 | |
|       pG->notfirstcall = TRUE;
 | |
|       return strcpy(pG->matchname, wildspec);
 | |
|    }
 | |
| 
 | |
|    // Last time through - reset for new wildspec.
 | |
|    pG->notfirstcall = FALSE;    
 | |
| 
 | |
|    return (char*)NULL;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| // Called from EXTRACT.C
 | |
| //
 | |
| // returns:  1 - (on APPEND_NAME) truncated filename
 | |
| //           2 - path doesn't exist, not allowed to create
 | |
| //           3 - path doesn't exist, tried to create and failed; or
 | |
| //               path exists and is not a directory, but is supposed to be
 | |
| //           4 - path is too long
 | |
| //          10 - can't allocate memory for filename buffers
 | |
| //
 | |
| // IZ_VOL_LABEL   - Path was a volume label, skip it.
 | |
| // IZ_CREATED_DIR - Created a directory.
 | |
| //
 | |
| int mapname(struct Globals *pG, int renamed) {
 | |
| 
 | |
|    // mapname() is a great place to reset all our status counters for the next
 | |
|    // file to be processed since it is called for every zip file member before
 | |
|    // any work is done with that member.
 | |
|    SetCurrentFile(pG);
 | |
| 
 | |
|    // If Volume Label, skip the "extraction" quietly
 | |
|    if (pG->pInfo->vollabel) {
 | |
|       return IZ_VOL_LABEL;
 | |
|    }
 | |
| 
 | |
|    CHAR szBuffer[countof(pG->filename)] = "", *pIn, *pOut, *pLastSemi = NULL;
 | |
| 
 | |
|    // Initialize file path buffer with our "extract to" path.
 | |
|    strcpy(szBuffer, g_szExtractToDirectory);
 | |
|    pOut = szBuffer + strlen(szBuffer);
 | |
| 
 | |
|    // Point pIn to beginning of our internal pathname.
 | |
|    // If we are junking paths, then locate the file portion of the path.
 | |
|    pIn = (pG->jflag) ? (CHAR*)GetFileFromPath(pG->filename) : pG->filename;
 | |
| 
 | |
|    // Begin main loop through characters in filename.
 | |
|    for ( ; *pIn; pIn++) {
 | |
| 
 | |
|       // Make sure we don't overflow our output buffer.
 | |
|       if (pOut >= (szBuffer + countof(szBuffer) - 2)) {
 | |
|          Info(slide, 1, ((char*)slide, "path too long: %s\n", pG->filename));
 | |
|          return 4;
 | |
|       }
 | |
| 
 | |
|       // Examine the next character in our input buffer.
 | |
|       switch (*pIn) {
 | |
| 
 | |
|          // Check for a directory wack.
 | |
|          case '/':
 | |
|          case '\\':
 | |
|             *pOut = '\0';
 | |
|             if (!SmartCreateDirectory(pG, szBuffer)) {
 | |
|                Info(slide, 1, ((char*)slide, "failure extracting: %s\n",
 | |
|                     pG->filename));
 | |
|                return 3;
 | |
|             }
 | |
|             *(pOut++) = '\\';
 | |
|             pLastSemi = NULL;  // Leave any directory semi-colons alone
 | |
|             break;
 | |
| 
 | |
|          // Check for illegal characters and replace with underscore.
 | |
|          case ':':
 | |
|          case '*':
 | |
|          case '?':
 | |
|          case '"': 
 | |
|          case '<':
 | |
|          case '>':
 | |
|          case '|':
 | |
|             *(pOut++) = '_';
 | |
|             break;
 | |
| 
 | |
|          // Check for start of VMS version.
 | |
|          case ';':
 | |
|             pLastSemi = pOut;  // Make note as to where we are.
 | |
|             *(pOut++) = *pIn;  // Leave the semi-colon alone for now.
 | |
|             break;
 | |
| 
 | |
|          default:
 | |
|             // Allow European characters and spaces in filenames.
 | |
|             *(pOut++) = ((*pIn >= 0x20) ? *pIn : '_');
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Done with output buffer, terminate it.
 | |
|    *pOut = '\0';
 | |
| 
 | |
|    // Remove any VMS version numbers if found (appended ";###").
 | |
|    if (pLastSemi) {
 | |
|       
 | |
|       // Walk over all digits following the semi-colon.
 | |
|       for (pOut = pLastSemi + 1; (*pOut >= '0') && (*pOut <= '9'); pOut++) {
 | |
|       }
 | |
| 
 | |
|       // If we reached the end, then nuke the semi-colon and digits.
 | |
|       if (!*pOut) {
 | |
|          *pLastSemi = '\0';
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Copy the mapped name back to the internal path buffer
 | |
|    strcpy(pG->filename, szBuffer);
 | |
| 
 | |
|    // Fill in the mapped name buffer if the original caller requested us to.
 | |
|    if (g_pExtractInfo->szMappedPath) {
 | |
|       strcpy(g_pExtractInfo->szMappedPath, szBuffer);
 | |
|    }
 | |
| 
 | |
|    // If it is a directory, then display the "creating" status text.
 | |
|    if ((pOut > szBuffer) && (pOut[-1] == TEXT('\\'))) {
 | |
|       Info(slide, 0, ((char *)slide, "creating: %s\n", pG->filename));
 | |
|       return IZ_CREATED_DIR;
 | |
|    }
 | |
| 
 | |
|    return PK_OK;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| // Called from EXTRACT.C
 | |
| int test_NT(struct Globals *pG, uch *eb, unsigned eb_size) {
 | |
|    // This function is called when an NT security descriptor is found in the
 | |
|    // extra field.  We have nothing to do, so we just return success.
 | |
|    return PK_OK;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| // Called from PROCESS.C
 | |
| int checkdir(struct Globals *pG, char *pathcomp, int flag) {
 | |
|    // This function is only called by free_G_buffers() from PROCESS.C with the
 | |
|    // flag set to END.  We have nothing to do, so we just return success.
 | |
|    return PK_OK;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| // Called from EXTRACT.C and LIST.C
 | |
| int match(char *string, char *pattern, int ignore_case) {
 | |
|    // match() for the other ports compares a file in the Zip file with some
 | |
|    // command line file pattern.  In our case, we always pass in exact matches,
 | |
|    // so we can simply do a string compare to see if we have a match.
 | |
|    return (strcmp(string, pattern) == 0);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| // Called from PROCESS.C
 | |
| int iswild(char *pattern) {
 | |
|    // Our file patterns never contain wild characters.  They are always exact
 | |
|    // matches of file names in our Zip file.
 | |
|    return FALSE;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Functions to correct time stamp bugs on old file systems.
 | |
| //******************************************************************************
 | |
| 
 | |
| //******************************************************************************
 | |
| // Borrowed/Modified from win32.c
 | |
| BOOL IsOldFileSystem(char *szPath) {
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
|    
 | |
|    char szRoot[10];
 | |
| 
 | |
|    // Get the first nine characters of the path.
 | |
|    strncpy(szRoot, szPath, 9);
 | |
|    szRoot[9] = '\0';
 | |
| 
 | |
|    // Convert to uppercase to help with compare.
 | |
|    _strupr(szRoot);
 | |
| 
 | |
|    // PC Cards are mounted off the root in a directory called "\PC Cards".
 | |
|    // PC Cards are FAT, no CEOS.  We need to check if the file is being
 | |
|    // extracted to the PC card.
 | |
|    return !strcmp(szRoot, "\\PC CARD\\");
 | |
| 
 | |
| #else
 | |
| 
 | |
|    char szRoot[_MAX_PATH] = "\0\0\0", szFS[64];
 | |
| 
 | |
|    // Check to see if our path contains a drive letter.
 | |
|    if (isalpha(szPath[0]) && (szPath[1] == ':') && (szPath[2] == '\\')) {
 | |
| 
 | |
|       // If so, then just copy the drive letter, colon, and wack to our root path.
 | |
|       strncpy(szRoot, szPath, 3);
 | |
| 
 | |
|    } else {
 | |
| 
 | |
|       // Expand the path so we can get a drive letter.
 | |
|       GetFullPathNameA(szPath, sizeof(szRoot), szRoot, NULL);
 | |
| 
 | |
|       // Make sure we actually got a drive letter back in our root path buffer..
 | |
|       if (!isalpha(szRoot[0]) || (szRoot[1] != ':') || (szRoot[2] != '\\')) {
 | |
| 
 | |
|          // When in doubt, return TRUE.
 | |
|          return TRUE;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // NULL terminate after the wack to ensure we have just the root path.
 | |
|    szRoot[3] = '\0';
 | |
| 
 | |
|    // Get the file system type string.
 | |
|    GetVolumeInformationA(szRoot, NULL, 0, NULL, NULL, NULL, szFS, sizeof(szFS));
 | |
| 
 | |
|    // Ensure that the file system type string is uppercase.
 | |
|    strupr(szFS);
 | |
| 
 | |
|    // Return true for (V)FAT and (OS/2) HPFS format.
 | |
|    return !strncmp(szFS, "FAT",  3) ||
 | |
|           !strncmp(szFS, "VFAT", 4) ||
 | |
|           !strncmp(szFS, "HPFS", 4);
 | |
| 
 | |
| #endif // _WIN32_WCE
 | |
| }
 |