James Hawkins : cabinet: Implement Extract on top of FDI.

Alexandre Julliard julliard at wine.codeweavers.com
Tue Jan 10 14:13:52 CST 2006


Module: wine
Branch: refs/heads/master
Commit: 54565b72fd07e6b295601ee17eb483ecf25772b4
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=54565b72fd07e6b295601ee17eb483ecf25772b4

Author: James Hawkins <truiken at gmail.com>
Date:   Tue Jan 10 12:13:07 2006 +0100

cabinet: Implement Extract on top of FDI.

---

 dlls/cabinet/cabinet_main.c |  266 ++++++++++++++++++++++++++++++++++++-------
 1 files changed, 224 insertions(+), 42 deletions(-)

diff --git a/dlls/cabinet/cabinet_main.c b/dlls/cabinet/cabinet_main.c
index 0be8ed4..08eeb5c 100644
--- a/dlls/cabinet/cabinet_main.c
+++ b/dlls/cabinet/cabinet_main.c
@@ -37,6 +37,14 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
 
+/* the following defintions are copied from msvcrt/fcntl.h */
+
+#define _O_RDONLY      0
+#define _O_WRONLY      1
+#define _O_RDWR        2
+#define _O_ACCMODE     (_O_RDONLY|_O_WRONLY|_O_RDWR)
+
+
 /***********************************************************************
  * DllGetVersion (CABINET.2)
  *
@@ -66,6 +74,195 @@ HRESULT WINAPI DllGetVersion (DLLVERSION
   return S_OK;
 }
 
+/* FDI callback functions */
+
+static void *mem_alloc(ULONG cb)
+{
+    return HeapAlloc(GetProcessHeap(), 0, cb);
+}
+
+static void mem_free(void *memory)
+{
+    HeapFree(GetProcessHeap(), 0, memory);
+}
+
+static INT_PTR fdi_open(char *pszFile, int oflag, int pmode)
+{
+    HANDLE handle;
+    DWORD dwAccess = 0;
+    DWORD dwShareMode = 0;
+    DWORD dwCreateDisposition = OPEN_EXISTING;
+
+    switch (oflag & _O_ACCMODE)
+    {
+        case _O_RDONLY:
+            dwAccess = GENERIC_READ;
+            dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
+            break;
+        case _O_WRONLY:
+            dwAccess = GENERIC_WRITE;
+            dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+            break;
+        case _O_RDWR:
+            dwAccess = GENERIC_READ | GENERIC_WRITE;
+            dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+            break;
+    }
+
+    if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
+        dwCreateDisposition = OPEN_EXISTING;
+    else
+        dwCreateDisposition = CREATE_NEW;
+
+    handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
+                         dwCreateDisposition, 0, NULL);
+
+    return (INT_PTR) handle;
+}
+
+static UINT fdi_read(INT_PTR hf, void *pv, UINT cb)
+{
+    HANDLE handle = (HANDLE) hf;
+    DWORD dwRead;
+    
+    if (ReadFile(handle, pv, cb, &dwRead, NULL))
+        return dwRead;
+
+    return 0;
+}
+
+static UINT fdi_write(INT_PTR hf, void *pv, UINT cb)
+{
+    HANDLE handle = (HANDLE) hf;
+    DWORD dwWritten;
+
+    if (WriteFile(handle, pv, cb, &dwWritten, NULL))
+        return dwWritten;
+
+    return 0;
+}
+
+static int fdi_close(INT_PTR hf)
+{
+    HANDLE handle = (HANDLE) hf;
+    return CloseHandle(handle) ? 0 : -1;
+}
+
+static long fdi_seek(INT_PTR hf, long dist, int seektype)
+{
+    HANDLE handle = (HANDLE) hf;
+    return SetFilePointer(handle, dist, NULL, seektype);
+}
+
+static void fill_file_node(struct ExtractFileList *pNode, LPSTR szFilename)
+{
+    pNode->next = NULL;
+    pNode->unknown = TRUE;
+
+    pNode->filename = HeapAlloc(GetProcessHeap(), 0, strlen(szFilename) + 1);
+    lstrcpyA(pNode->filename, szFilename);
+}
+
+static BOOL file_in_list(struct ExtractFileList *pNode, LPSTR szFilename)
+{
+    while (pNode)
+    {
+        if (!lstrcmpiA(pNode->filename, szFilename))
+            return TRUE;
+
+        pNode = pNode->next;
+    }
+
+    return FALSE;
+}
+
+static INT_PTR fdi_notify_extract(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
+{
+    switch (fdint)
+    {
+        case fdintCOPY_FILE:
+        {
+            struct ExtractFileList **fileList;
+            EXTRACTdest *pDestination = pfdin->pv;
+            LPSTR szFullPath, szDirectory;
+            HANDLE hFile = 0;
+            DWORD dwSize;
+
+            dwSize = lstrlenA(pDestination->directory) +
+                    lstrlenA("\\") + lstrlenA(pfdin->psz1) + 1;
+            szFullPath = HeapAlloc(GetProcessHeap(), 0, dwSize);
+
+            lstrcpyA(szFullPath, pDestination->directory);
+            lstrcatA(szFullPath, "\\");
+            lstrcatA(szFullPath, pfdin->psz1);
+
+            /* pull out the destination directory string from the full path */
+            dwSize = strrchr(szFullPath, '\\') - szFullPath + 1;
+            szDirectory = HeapAlloc(GetProcessHeap(), 0, dwSize);
+            lstrcpynA(szDirectory, szFullPath, dwSize);
+
+            if (pDestination->flags & EXTRACT_FILLFILELIST)
+            {
+                fileList = &pDestination->filelist;
+
+                while (*fileList)
+                    fileList = &((*fileList)->next);
+
+                *fileList = HeapAlloc(GetProcessHeap(), 0,
+                                      sizeof(struct ExtractFileList));
+
+                fill_file_node(*fileList, pfdin->psz1);
+                lstrcpyA(pDestination->lastfile, szFullPath);
+                pDestination->filecount++;
+            }
+
+            if (pDestination->flags & EXTRACT_EXTRACTFILES)
+            {
+                /* skip this file it it's not in the file list */
+                if (!file_in_list(pDestination->filelist, pfdin->psz1))
+                    return 0;
+
+                /* create the destination directory if it doesn't exist */
+                if (GetFileAttributesA(szDirectory) == INVALID_FILE_ATTRIBUTES)
+                    CreateDirectoryA(szDirectory, NULL);
+
+                hFile = CreateFileA(szFullPath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                                    CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+
+                if (hFile == INVALID_HANDLE_VALUE)
+                    hFile = 0;
+            }
+
+            HeapFree(GetProcessHeap(), 0, szFullPath);
+            HeapFree(GetProcessHeap(), 0, szDirectory);
+
+            return (INT_PTR) hFile;
+        }
+
+        case fdintCLOSE_FILE_INFO:
+        {
+            FILETIME ft;
+            FILETIME ftLocal;
+            HANDLE handle = (HANDLE) pfdin->hf;
+
+            if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
+                return FALSE;
+
+            if (!LocalFileTimeToFileTime(&ft, &ftLocal))
+                return FALSE;
+
+            if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
+                return FALSE;
+
+            CloseHandle(handle);
+            return TRUE;
+        }
+
+        default:
+            return 0;
+    }
+}
+
 /***********************************************************************
  * Extract (CABINET.3)
  *
@@ -103,48 +300,33 @@ HRESULT WINAPI DllGetVersion (DLLVERSION
  */
 HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR szCabName)
 {
-#define DUMPC(idx)      idx >= sizeof(EXTRACTdest) ? ' ' : \
-                        ((unsigned char*) dest)[idx] >= 0x20 ? \
-                        ((unsigned char*) dest)[idx] : '.'
-
-#define DUMPH(idx)      idx >= sizeof(EXTRACTdest) ? 0x55 : ((unsigned char*) dest)[idx]
-
-  LPSTR dir;
-  unsigned int i;
-
-  TRACE("(dest == %0lx, szCabName == %s)\n", (long) dest, debugstr_a(szCabName));
-
-  if (!dest) {
-    /* win2k will crash here */
-    FIXME("called without valid parameter dest!\n");
-    return E_OUTOFMEMORY;
-  }
-  for (i=0; i < sizeof(EXTRACTdest); i+=8)
-    TRACE( "dest[%04x]:%02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c\n",
-           i,
-           DUMPH(i+0), DUMPH(i+1), DUMPH(i+2), DUMPH(i+3),
-           DUMPH(i+4), DUMPH(i+5), DUMPH(i+6), DUMPH(i+7),
-           DUMPC(i+0), DUMPC(i+1), DUMPC(i+2), DUMPC(i+3),
-           DUMPC(i+4), DUMPC(i+5), DUMPC(i+6), DUMPC(i+7));
-
-  dir = LocalAlloc(LPTR, strlen(dest->directory)+1); 
-  if (!dir) return E_OUTOFMEMORY;
-  lstrcpyA(dir, dest->directory);
-  dest->filecount=0;
-  dest->filelist = NULL;
-
-  TRACE("extracting to dir: %s\n", debugstr_a(dir));
-
-  /* FIXME: what to do on failure? */
-  if (!process_cabinet(szCabName, dir, FALSE, FALSE, dest)) {
-    LocalFree(dir);
-    return E_OUTOFMEMORY;
-  }
+    HRESULT res = S_OK;
+    HFDI hfdi;
+    ERF erf;
+
+    TRACE("(%p, %s)\n", dest, szCabName);
+
+    hfdi = FDICreate(mem_alloc,
+                     mem_free,
+                     fdi_open,
+                     fdi_read,
+                     fdi_write,
+                     fdi_close,
+                     fdi_seek,
+                     cpuUNKNOWN,
+                     &erf);
+
+    if (!hfdi)
+        return E_FAIL;
+
+    if (GetFileAttributesA(dest->directory) == INVALID_FILE_ATTRIBUTES)
+        return S_OK;
+
+    if (!FDICopy(hfdi, (LPSTR)szCabName, "", 0,
+         fdi_notify_extract, NULL, dest))
+        res = E_FAIL;
 
-  LocalFree(dir);
+    FDIDestroy(hfdi);
 
-  TRACE("filecount %08lx,lastfile %s\n",
-         dest->filecount, debugstr_a(dest->lastfile));
-
-  return S_OK;
+    return res;
 }




More information about the wine-cvs mailing list