Archive-Unzip-Burst

 view release on metacpan or  search on metacpan

unzip-6.0/wince/intrface.cpp  view on Meta::CPAN

//                         Adapted to UnZip 5.41 (Version 1.1)
// 12/01/02  Chr. Spieler  Updated interface for UnZip 5.50
// 02/23/05  Chr. Spieler  Modified and optimized utimeToFileTime() to support
//                         the NO_W32TIMES_IZFIX compilation option
// 11/01/09  Chr. Spieler  Added wide_to_local_string() conversion function
//                         from win32.c, which is currently needed for the
//                         new UTF-8 names support (until we manage to port
//                         the complete UnZip code to native wide-char support).
//
//*****************************************************************************


//*****************************************************************************
// 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_EAS
//
//    USE_SMITH_CODE       (optional - See INSTALL document)
//    LZW_CLEAN            (optional - See INSTALL document)
//    NO_W32TIMES_IZFIX    (optional - See INSTALL 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)
//
//****************************************************************************/

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

#ifdef POCKET_UNZIP

//******************************************************************************
//***** "Local" Global Variables
//******************************************************************************

static USERFUNCTIONS  g_uf;
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
//******************************************************************************

// Internal functions of the GUI interface.
static Uz_Globs* InitGlobals(LPCSTR szZipFile);
static void FreeGlobals(Uz_Globs *pG);

#ifdef _WIN32_WCE
static DWORD WINAPI ExtractOrTestFilesThread(LPVOID lpv);
#else
static unsigned __stdcall ExtractOrTestFilesThread(void *lpv);
#endif

static void SetCurrentFile(__GPRO);

#endif // POCKET_UNZIP

// Internal helper functions for the UnZip core.
static int IsFileOrDirectory(LPCTSTR szPath);
static BOOL SmartCreateDirectory(__GPRO__ LPCSTR szDirectory, BOOL *pNewDir);
static void utimeToFileTime(time_t ut, FILETIME *pft, BOOL fOldFileSystem);
static int GetFileTimes(Uz_Globs *pG, FILETIME *pftCreated,
                        FILETIME *pftAccessed, FILETIME *pftModified);

// Check for FAT, VFAT, HPFS, etc.
static BOOL IsOldFileSystem(char *szPath);

#ifdef POCKET_UNZIP

extern "C" {

// Local variants of callbacks from Info-ZIP code.
// (These functions are not referenced by name outside this source module.)
int UZ_EXP UzpMessagePrnt2(zvoid *pG, uch *buffer, ulg size, int flag);
int UZ_EXP UzpInput2(zvoid *pG, uch *buffer, int *size, int flag);
int UZ_EXP CheckForAbort2(zvoid *pG, int fnflag, ZCONST char *zfn,
                          ZCONST char *efn, ZCONST zvoid *details);
int WINAPI UzpReplace(LPSTR szFile, unsigned nbufsiz);
void WINAPI UzpSound(void);
#ifdef Z_UINT8_DEFINED
void WINAPI SendAppMsg(z_uint8 uzSize, z_uint8 uzCompressedSize,
#else

unzip-6.0/wince/intrface.cpp  view on Meta::CPAN


//******************************************************************************
//***** 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.
   Uz_Globs *pG = InitGlobals(szZipFile);
   if (!pG) {
      return PK_MEM;
   }

   pG->UzO.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 EXTRACT_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.
   Uz_Globs *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 szZipFile) {

   int result;

   // Create our Globals struct and fill it in with some default values.
   Uz_Globs *pG = InitGlobals(szZipFile);
   if (!pG) {
      return PK_MEM;
   }

   pG->UzO.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')))) {

unzip-6.0/wince/intrface.cpp  view on Meta::CPAN

   pG->message      = UzpMessagePrnt2;
   pG->input        = UzpInput2;
   pG->mpause       = UzpMorePause;
   pG->statreportcb = CheckForAbort2;
   pG->lpUserFunctions->replace                = UzpReplace;
   pG->lpUserFunctions->sound                  = UzpSound;
   pG->lpUserFunctions->SendApplicationMessage = SendAppMsg;
   pG->lpUserFunctions->SendApplicationMessage_i32 = NULL;

#if CRYPT
   pG->decr_passwd = UzpPassword;
#endif

   // Match filenames case-sensitively.  We can do this since we can guarantee
   // exact case because the user can only select files via our UI.
   pG->UzO.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;
}

//******************************************************************************
static void FreeGlobals(Uz_Globs *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();
}

//******************************************************************************
#ifdef _WIN32_WCE

// On WinCE, we declare our thread function the way CreateThread() likes it.
static DWORD WINAPI ExtractOrTestFilesThread(LPVOID lpv)

#else

// On WinNT, we declare our thread function the way _beginthreadex likes it.
static unsigned __stdcall ExtractOrTestFilesThread(void *lpv)

#endif
{
   Uz_Globs *pG = (Uz_Globs*)lpv;

   if (g_pExtractInfo->fExtract) {

      pG->extract_flag = TRUE;

      switch (g_pExtractInfo->overwriteMode) {

         case OM_NEWER:         // Update (extract only newer/brand-new files)
            pG->UzO.uflag = TRUE;
            break;

         case OM_ALWAYS:        // OK to overwrite files without prompting
            pG->UzO.overwrite_all = TRUE;
            break;

         case OM_NEVER:         // Never overwrite files (no prompting)
            pG->UzO.overwrite_none = TRUE;
            break;

         default:               // Force a prompt
            pG->UzO.overwrite_all = FALSE;
            pG->UzO.overwrite_none = FALSE;
            pG->UzO.uflag = FALSE;
            break;
      }

      // Throw away paths if requested.
      pG->UzO.jflag = !g_pExtractInfo->fRestorePaths;

   } else {
      pG->UzO.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;
   }

   // Invalidate our file offset to show that we are starting a new operation.
   g_pExtractInfo->uzFileOffset = ~(zusz_t)0;

   // 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;
}

//******************************************************************************
static void SetCurrentFile(__GPRO)
{
   // Reset all our counters as we about to process a new file.
   g_pExtractInfo->uzFileOffset = (zusz_t)G.pInfo->offset;
   g_pExtractInfo->dwFile++;
   g_pExtractInfo->uzBytesWrittenThisFile = 0;
   g_pExtractInfo->uzBytesWrittenPreviousFiles += g_pExtractInfo->uzBytesTotalThisFile;
   g_pExtractInfo->uzBytesTotalThisFile = G.lrec.ucsize;
   g_pExtractInfo->szFile = G.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.
}
#endif // POCKET_UNZIP

//******************************************************************************
static 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);
}

//******************************************************************************
static BOOL SmartCreateDirectory(__GPRO__ LPCSTR szDirectory, BOOL *pNewDir)
{
   // Copy path to a UNICODE buffer.
   TCHAR szBuffer[_MAX_PATH];
   MBSTOTSTR(szBuffer, szDirectory, countof(szBuffer));

   switch (IsFileOrDirectory(szBuffer)) {
      case 0:
         // Create the directory if it does not exist.
         if (!CreateDirectory(szBuffer, NULL)) {
            Info(slide, 1, ((char *)slide, "error creating directory: %s\n",
              FnFilter1( szDirectory)));
            return FALSE;
         }
         if (pNewDir != NULL) *pNewDir = TRUE;
         break;

      case 1:
         // If there is a file with the same name, then display an error.
         Info(slide, 1, ((char *)slide,
              "cannot create %s as a file with same name already exists.\n",
              FnFilter1(szDirectory)));
         return FALSE;
   }

   // If the directory already exists or was created, then return success.
   return TRUE;
}


#ifdef POCKET_UNZIP
//******************************************************************************
//***** Callbacks from Info-ZIP code.
//******************************************************************************

int UZ_EXP UzpMessagePrnt2(zvoid *pG, uch *buffer, ulg size, int flag)
{

unzip-6.0/wince/intrface.cpp  view on Meta::CPAN

      // 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 UZ_EXP UzpInput2(zvoid *pG, uch *buffer, int *size, int flag)
{
   DebugOut(TEXT("WARNING: UzpInput2(...) called"));
   return 0;
}

//******************************************************************************
void UZ_EXP UzpMorePause(zvoid *pG, const char *szPrompt, int flag)
{
   DebugOut(TEXT("WARNING: UzpMorePause(...) called"));
}

//******************************************************************************
int UZ_EXP 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 IZ_PW_CANCELALL;
#endif
}

//******************************************************************************
int UZ_EXP CheckForAbort2(zvoid *pG, int fnflag, ZCONST char *zfn,
                    ZCONST char *efn, ZCONST zvoid *details)
{
   int rval = UZ_ST_CONTINUE;

   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)((Uz_Globs *)pG)->outfile != 0) &&
          ((int)((Uz_Globs *)pG)->outfile != -1)) {
         if (g_pExtractInfo->fExtract && *efn) {

            // 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)efn);
            SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
                        (LPARAM)" is probably truncated.\n");
         }
      }

      // Display an aborted message in the log
      SendMessage(g_hWndMain, WM_PRIVATE, MSG_ADD_TEXT_TO_EDIT,
                  (LPARAM)"Operation aborted by user.\n");

      // Signal "Immediate Cancel" back to the UnZip engine.
      rval = UZ_ST_BREAK;
   }

   return rval;
}

//******************************************************************************
int WINAPI UzpReplace(LPSTR szFile, unsigned nbufsiz) {
   // Pass control to our GUI thread which will prompt the user to overwrite.
   // The nbufsiz parameter is not needed here, because this program does not
   // (yet?) contain support for renaming the extraction target.
   return SendMessage(g_hWndMain, WM_PRIVATE, MSG_PROMPT_TO_REPLACE,
                      (LPARAM)szFile);
}

//******************************************************************************
void WINAPI UzpSound(void) {
   // Do nothing.
}

//******************************************************************************
// Called from LIST.C
#ifdef Z_UINT8_DEFINED
void WINAPI SendAppMsg(z_uint8 uzSize, z_uint8 uzCompressedSize,
#else
void WINAPI SendAppMsg(ulg uzSize, ulg uzCompressedSize,
#endif
                       unsigned ratio,
                       unsigned month, unsigned day, unsigned year,
                       unsigned hour, unsigned minute, char uppercase,
                       LPCSTR szPath, LPCSTR szMethod, ulg dwCRC,
                       char chCrypt)
{
   // 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.
   GETGLOBALS();

   // 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(CHAR) * length)];

   // Bail out if we failed to allocate the node.
   if (!g_pFileLast) {
#ifdef UNICODE
      DebugOut(TEXT("Failed to create a FILE_NODE for \"%S\"."), szPath);
#else
      DebugOut(TEXT("Failed to create a FILE_NODE for \"%s\"."), szPath);
#endif
      g_fOutOfMemory = TRUE;
      return;
   }

   // Fill in our node.
   g_pFileLast->uzSize           = (zusz_t)uzSize;
   g_pFileLast->uzCompressedSize = (zusz_t)uzCompressedSize;
   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 (chCrypt == 'E') {
      g_pFileLast->dwAttributes |= ZFILE_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(zvoid *pG, 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 dwBytesWritten = 0;
#if (defined(_WIN32_WCE) && (_WIN32_WCE < 211))
      // On WinCE all FILEs are really HANDLEs.  See WINCE.CPP for more info.
      WriteFile((HANDLE)file, buffer, dwCount, &dwBytesWritten, NULL);
#else
      dwBytesWritten = fwrite(buffer, 1, dwCount, file);
#endif

      // Update our bytes written count.
      g_pExtractInfo->uzBytesWrittenThisFile += dwBytesWritten;

      // 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);

      return dwBytesWritten;
   }

   // 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.
      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) {
      char *p1, *p2;

      // Calcalute the size of the buffer we will need to store this comment.
      // We are going to convert all ASC values 0 - 31 (except tab, new line,
      // and CR) to ^char.
      int size = 1;
      for (p1 = buffer; *p1; INCSTR(p1)) {
         size += ((*p1 >= 32) || (*p1 == '\t') ||
                  (*p1 == '\r') || (*p1 == '\n')) ? CLEN(p1) : 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; INCSTR(p1)) {
            if ((*p1 >= 32) || (*p1 == '\t') ||
                (*p1 == '\r') || (*p1 == '\n')) {
               memcpy(p2, p1, CLEN(p1));
               p2 += CLEN(p1);
            } else {
               *(p2++) = '^';
               *(p2++) = 64 + *p1;
            }
         }
         *p2 = '\0';
      }

      // Update the attributes of the file node to include the comment attribute.
      g_pFileLast->dwAttributes |= ZFILE_ATTRIBUTE_COMMENT;

      // Clear the file node so we don't try to add another bogus comment to it.



( run in 1.428 second using v1.01-cache-2.11-cpan-d8267643d1d )