https://git.reactos.org/?p=reactos.git;a=commitdiff;h=95915501162e727900e07…
commit 95915501162e727900e077d97026a3e2e00f117c
Author: Alexander Shaposhnikov <sanchaez(a)reactos.org>
AuthorDate: Sun Feb 25 15:20:00 2018 +0200
Commit: Alexander Shaposhnikov <sanchaez(a)reactos.org>
CommitDate: Sun Mar 11 21:56:32 2018 +0200
[RAPPS] Replace Extract with FDI for handling .cab
FDI allows to have user-defined callbacks for file handling.
Since it doesn't provide support for Unicode we convert strings to
multi-byte UTF-8 and handle them appropriately in the callbacks. They
are properly null-terminated so FDI won't choke when doing operations
with strings.
Thanks to hbelusca and mjansen for the help.
CORE-14466
---
base/applications/rapps/CMakeLists.txt | 2 +-
base/applications/rapps/available.cpp | 8 +-
base/applications/rapps/cabinet.cpp | 334 ++++++++++++++++++++++++++++
base/applications/rapps/include/available.h | 2 +
base/applications/rapps/include/cabinet.h | 32 ---
base/applications/rapps/include/misc.h | 6 +-
base/applications/rapps/misc.cpp | 54 -----
7 files changed, 348 insertions(+), 90 deletions(-)
diff --git a/base/applications/rapps/CMakeLists.txt
b/base/applications/rapps/CMakeLists.txt
index cdbb6f97dc..ce8ba3a0ba 100644
--- a/base/applications/rapps/CMakeLists.txt
+++ b/base/applications/rapps/CMakeLists.txt
@@ -9,6 +9,7 @@ include_directories(include)
list(APPEND SOURCE
aboutdlg.cpp
available.cpp
+ cabinet.cpp
gui.cpp
installed.cpp
integrity.cpp
@@ -22,7 +23,6 @@ list(APPEND SOURCE
include/gui.h
include/dialogs.h
include/installed.h
- include/cabinet.h
include/crichedit.h
include/defines.h
include/misc.h
diff --git a/base/applications/rapps/available.cpp
b/base/applications/rapps/available.cpp
index 04e5005e5a..5ed7119853 100644
--- a/base/applications/rapps/available.cpp
+++ b/base/applications/rapps/available.cpp
@@ -213,7 +213,9 @@ AvailableStrings::AvailableStrings()
if (GetStorageDirectory(szPath))
{
szAppsPath = szPath + L"\\rapps\\";
- szCabPath = szPath + L"\\rappmgr.cab";
+ szCabName = L"rappmgr.cab";
+ szCabDir = szPath;
+ szCabPath = (szCabDir + L"\\") + szCabName;
szSearchPath = szAppsPath + L"*.txt";
}
}
@@ -282,7 +284,9 @@ BOOL CAvailableApps::UpdateAppsDB()
CDownloadManager::DownloadApplicationsDB(APPLICATION_DATABASE_URL);
- if (!ExtractFilesFromCab(m_Strings.szCabPath, m_Strings.szAppsPath))
+ if (!ExtractFilesFromCab(m_Strings.szCabName,
+ m_Strings.szCabDir,
+ m_Strings.szAppsPath))
{
return FALSE;
}
diff --git a/base/applications/rapps/cabinet.cpp b/base/applications/rapps/cabinet.cpp
new file mode 100644
index 0000000000..11b301ed9c
--- /dev/null
+++ b/base/applications/rapps/cabinet.cpp
@@ -0,0 +1,334 @@
+/*
+* PROJECT: ReactOS Applications Manager
+* LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+)
+* FILE: base/applications/rapps/cabinet.cpp
+* PURPOSE: Cabinet extraction using FDI API
+* COPYRIGHT: Copyright 2018 Alexander Shaposhnikov (sanchaez(a)reactos.org)
+*/
+#include "rapps.h"
+
+#include <fdi.h>
+#include <fcntl.h>
+
+/*
+ * HACK: treat any input strings as Unicode (UTF-8)
+ * cabinet.dll lacks any sort of a Unicode API, but FCI/FDI
+ * provide an ability to use user-defined callbacks for any file or memory
+ * operations. This flexibility and the magic power of C/C++ casting allows
+ * us to treat input as we please.
+ * This is by far the best way to extract .cab using Unicode paths.
+ */
+
+/* String conversion helper functions */
+
+// converts CStringW to CStringA using a given codepage
+inline BOOL WideToMultiByte(const CStringW& szSource,
+ CStringA& szDest,
+ UINT Codepage)
+{
+ // determine the needed size
+ INT sz = WideCharToMultiByte(Codepage,
+ 0,
+ szSource,
+ -1,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (!sz)
+ return FALSE;
+
+ // do the actual conversion
+ sz = WideCharToMultiByte(Codepage,
+ 0,
+ szSource,
+ -1,
+ szDest.GetBuffer(sz),
+ sz,
+ NULL,
+ NULL);
+
+ szDest.ReleaseBuffer();
+ return sz != 0;
+}
+
+// converts CStringA to CStringW using a given codepage
+inline BOOL MultiByteToWide(const CStringA& szSource,
+ CStringW& szDest,
+ UINT Codepage)
+{
+ // determine the needed size
+ INT sz = MultiByteToWideChar(Codepage,
+ 0,
+ szSource,
+ -1,
+ NULL,
+ NULL);
+ if (!sz)
+ return FALSE;
+
+ // do the actual conversion
+ sz = MultiByteToWideChar(CP_UTF8,
+ 0,
+ szSource,
+ -1,
+ szDest.GetBuffer(sz),
+ sz);
+
+ szDest.ReleaseBuffer();
+ return sz != 0;
+}
+
+/* FDICreate callbacks */
+
+FNALLOC(fnMemAlloc)
+{
+ return HeapAlloc(GetProcessHeap(), NULL, cb);
+}
+
+FNFREE(fnMemFree)
+{
+ HeapFree(GetProcessHeap(), NULL, pv);
+}
+
+FNOPEN(fnFileOpen)
+{
+ HANDLE hFile = NULL;
+ DWORD dwDesiredAccess = 0;
+ DWORD dwCreationDisposition = 0;
+ ATL::CStringW szFileName;
+
+ UNREFERENCED_PARAMETER(pmode);
+
+ if (oflag & _O_RDWR)
+ {
+ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
+ }
+ else if (oflag & _O_WRONLY)
+ {
+ dwDesiredAccess = GENERIC_WRITE;
+ }
+ else
+ {
+ dwDesiredAccess = GENERIC_READ;
+ }
+
+ if (oflag & _O_CREAT)
+ {
+ dwCreationDisposition = CREATE_ALWAYS;
+ }
+ else
+ {
+ dwCreationDisposition = OPEN_EXISTING;
+ }
+
+ MultiByteToWide(pszFile, szFileName, CP_UTF8);
+
+ hFile = CreateFileW(szFileName,
+ dwDesiredAccess,
+ FILE_SHARE_READ,
+ NULL,
+ dwCreationDisposition,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ return (INT_PTR) hFile;
+}
+
+FNREAD(fnFileRead)
+{
+ DWORD dwBytesRead = 0;
+
+ if (ReadFile((HANDLE) hf, pv, cb, &dwBytesRead, NULL) == FALSE)
+ {
+ dwBytesRead = (DWORD) -1L;
+ }
+
+ return dwBytesRead;
+}
+
+FNWRITE(fnFileWrite)
+{
+ DWORD dwBytesWritten = 0;
+
+ if (WriteFile((HANDLE) hf, pv, cb, &dwBytesWritten, NULL) == FALSE)
+ {
+ dwBytesWritten = (DWORD) -1;
+ }
+
+ return dwBytesWritten;
+}
+
+FNCLOSE(fnFileClose)
+{
+ return (CloseHandle((HANDLE) hf) != FALSE) ? 0 : -1;
+}
+
+FNSEEK(fnFileSeek)
+{
+ return SetFilePointer((HANDLE) hf, dist, NULL, seektype);
+}
+
+/* FDICopy callbacks */
+
+FNFDINOTIFY(fnNotify)
+{
+ INT_PTR iResult = 0;
+
+ switch (fdint)
+ {
+ case fdintCOPY_FILE:
+ {
+ ATL::CStringW szNewFileName, szExtractDir, szCabFileName;
+ ATL::CStringA szFilePathUTF8;
+
+ // Append the destination directory to the file name.
+ MultiByteToWide((LPCSTR) pfdin->pv, szExtractDir, CP_UTF8);
+ MultiByteToWide(pfdin->psz1, szCabFileName, CP_ACP);
+
+ szNewFileName = szExtractDir + L"\\" + szCabFileName;
+
+ WideToMultiByte(szNewFileName, szFilePathUTF8, CP_UTF8);
+
+ // Copy file
+ iResult = fnFileOpen((LPSTR) szFilePathUTF8.GetString(),
+ _O_WRONLY | _O_CREAT,
+ 0);
+ }
+ break;
+
+ case fdintCLOSE_FILE_INFO:
+ iResult = !fnFileClose(pfdin->hf);
+ break;
+
+ case fdintNEXT_CABINET:
+ if (pfdin->fdie != FDIERROR_NONE)
+ {
+ iResult = -1;
+ }
+ break;
+
+ case fdintPARTIAL_FILE:
+ iResult = 0;
+ break;
+
+ case fdintCABINET_INFO:
+ iResult = 0;
+ break;
+
+ case fdintENUMERATE:
+ iResult = 0;
+ break;
+
+ default:
+ iResult = -1;
+ break;
+ }
+
+ return iResult;
+}
+
+/* cabinet.dll FDI function pointers */
+
+typedef HFDI(*fnFDICreate)(PFNALLOC,
+ PFNFREE,
+ PFNOPEN,
+ PFNREAD,
+ PFNWRITE,
+ PFNCLOSE,
+ PFNSEEK,
+ int,
+ PERF);
+
+typedef BOOL(*fnFDICopy)(HFDI,
+ LPSTR,
+ LPSTR,
+ INT,
+ PFNFDINOTIFY,
+ PFNFDIDECRYPT,
+ void FAR *pvUser);
+
+typedef BOOL(*fnFDIDestroy)(HFDI);
+
+/*
+ * Extraction function
+ * TODO: require only a full path to the cab as an argument
+ */
+BOOL ExtractFilesFromCab(const ATL::CStringW& szCabName,
+ const ATL::CStringW& szCabDir,
+ const ATL::CStringW& szOutputDir)
+{
+ HINSTANCE hCabinetDll;
+ HFDI ExtractHandler;
+ ERF ExtractErrors;
+ ATL::CStringA szCabNameUTF8, szCabDirUTF8, szOutputDirUTF8;
+ fnFDICreate pfnFDICreate;
+ fnFDICopy pfnFDICopy;
+ fnFDIDestroy pfnFDIDestroy;
+ BOOL bResult;
+
+ // Load cabinet.dll and extract needed functions
+ hCabinetDll = LoadLibraryW(L"cabinet.dll");
+
+ if (!hCabinetDll)
+ {
+ return FALSE;
+ }
+
+ pfnFDICreate = (fnFDICreate) GetProcAddress(hCabinetDll, "FDICreate");
+ pfnFDICopy = (fnFDICopy) GetProcAddress(hCabinetDll, "FDICopy");
+ pfnFDIDestroy = (fnFDIDestroy) GetProcAddress(hCabinetDll, "FDIDestroy");
+
+ if (!pfnFDICreate || !pfnFDICopy || !pfnFDIDestroy)
+ {
+ FreeLibrary(hCabinetDll);
+ return FALSE;
+ }
+
+ // Create FDI context
+ ExtractHandler = pfnFDICreate(fnMemAlloc,
+ fnMemFree,
+ fnFileOpen,
+ fnFileRead,
+ fnFileWrite,
+ fnFileClose,
+ fnFileSeek,
+ cpuUNKNOWN,
+ &ExtractErrors);
+
+ if (!ExtractHandler)
+ {
+ FreeLibrary(hCabinetDll);
+ return FALSE;
+ }
+
+ // Create output dir
+ bResult = CreateDirectoryW(szOutputDir, NULL);
+
+ if (bResult || GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ // Convert wide strings to UTF-8
+ bResult = WideToMultiByte(szCabName, szCabNameUTF8, CP_UTF8);
+ bResult &= WideToMultiByte(szCabDir, szCabDirUTF8, CP_UTF8);
+ bResult &= WideToMultiByte(szOutputDir, szOutputDirUTF8, CP_UTF8);
+ }
+
+ // Perform extraction
+ if (bResult)
+ {
+ // Add a slash to cab name as required by the api
+ szCabNameUTF8 = "\\" + szCabNameUTF8;
+
+ bResult = pfnFDICopy(ExtractHandler,
+ (LPSTR) szCabNameUTF8.GetString(),
+ (LPSTR) szCabDirUTF8.GetString(),
+ 0,
+ fnNotify,
+ NULL,
+ (void FAR *) szOutputDirUTF8.GetString());
+ }
+
+ pfnFDIDestroy(ExtractHandler);
+ FreeLibrary(hCabinetDll);
+ return bResult;
+}
diff --git a/base/applications/rapps/include/available.h
b/base/applications/rapps/include/available.h
index 782f960be8..876465fd09 100644
--- a/base/applications/rapps/include/available.h
+++ b/base/applications/rapps/include/available.h
@@ -86,6 +86,8 @@ struct AvailableStrings
ATL::CStringW szCabPath;
ATL::CStringW szAppsPath;
ATL::CStringW szSearchPath;
+ ATL::CStringW szCabName;
+ ATL::CStringW szCabDir;
AvailableStrings();
};
diff --git a/base/applications/rapps/include/cabinet.h
b/base/applications/rapps/include/cabinet.h
deleted file mode 100644
index 02bbd5738d..0000000000
--- a/base/applications/rapps/include/cabinet.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Structs related to .cab extraction
-// FIXME: they should belong to exports of cabinet.dll
-#pragma once
-
-struct ERF
-{
- INT erfOper;
- INT erfType;
- BOOL fError;
-};
-
-struct FILELIST
-{
- LPSTR FileName;
- FILELIST *next;
- BOOL DoExtract;
-};
-
-struct SESSION
-{
- INT FileSize;
- ERF Error;
- FILELIST *FileList;
- INT FileCount;
- INT Operation;
- CHAR Destination[MAX_PATH];
- CHAR CurrentFile[MAX_PATH];
- CHAR Reserved[MAX_PATH];
- FILELIST *FilterList;
-};
-
-typedef HRESULT(WINAPI *fnExtract)(SESSION *dest, LPCSTR szCabName);
diff --git a/base/applications/rapps/include/misc.h
b/base/applications/rapps/include/misc.h
index b3f3063001..738f6746cb 100644
--- a/base/applications/rapps/include/misc.h
+++ b/base/applications/rapps/include/misc.h
@@ -14,12 +14,16 @@ VOID ShowPopupMenu(HWND hwnd, UINT MenuID, UINT DefaultItem);
BOOL StartProcess(ATL::CStringW &Path, BOOL Wait);
BOOL StartProcess(LPWSTR lpPath, BOOL Wait);
BOOL GetStorageDirectory(ATL::CStringW &lpDirectory);
-BOOL ExtractFilesFromCab(LPCWSTR lpCabName, LPCWSTR lpOutputPath);
+
VOID InitLogs();
VOID FreeLogs();
BOOL WriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg);
BOOL GetInstalledVersion(ATL::CStringW *pszVersion, const ATL::CStringW &szRegName);
+BOOL ExtractFilesFromCab(const ATL::CStringW& szCabName,
+ const ATL::CStringW& szCabDir,
+ const ATL::CStringW& szOutputDir);
+
class CConfigParser
{
// Locale names cache
diff --git a/base/applications/rapps/misc.cpp b/base/applications/rapps/misc.cpp
index 1a527317af..db0ae0bf1b 100644
--- a/base/applications/rapps/misc.cpp
+++ b/base/applications/rapps/misc.cpp
@@ -11,11 +11,6 @@
#include "gui.h"
#include "misc.h"
-#include "cabinet.h"
-
- /* SESSION Operation */
-#define EXTRACT_FILLFILELIST 0x00000001
-#define EXTRACT_EXTRACTFILES 0x00000002
static HANDLE hLog = NULL;
@@ -203,55 +198,6 @@ BOOL GetStorageDirectory(ATL::CStringW& Directory)
return (CreateDirectoryW(Directory.GetString(), NULL) || GetLastError() ==
ERROR_ALREADY_EXISTS);
}
-BOOL ExtractFilesFromCab(const ATL::CStringW &CabName, const ATL::CStringW
&OutputPath)
-{
- return ExtractFilesFromCab(CabName.GetString(), OutputPath.GetString());
-}
-
-BOOL ExtractFilesFromCab(LPCWSTR lpCabName, LPCWSTR lpOutputPath)
-{
- HINSTANCE hCabinetDll;
- CHAR szCabName[MAX_PATH];
- SESSION Dest;
- HRESULT Result;
- fnExtract pfnExtract;
-
- hCabinetDll = LoadLibraryW(L"cabinet.dll");
- if (hCabinetDll)
- {
- pfnExtract = (fnExtract) GetProcAddress(hCabinetDll, "Extract");
- if (pfnExtract)
- {
- ZeroMemory(&Dest, sizeof(Dest));
-
- WideCharToMultiByte(CP_ACP, 0, lpOutputPath, -1, Dest.Destination, MAX_PATH,
NULL, NULL);
- WideCharToMultiByte(CP_ACP, 0, lpCabName, -1, szCabName, _countof(szCabName),
NULL, NULL);
- Dest.Operation = EXTRACT_FILLFILELIST;
-
- Result = pfnExtract(&Dest, szCabName);
- if (Result == S_OK)
- {
- Dest.Operation = EXTRACT_EXTRACTFILES;
- CreateDirectoryW(lpOutputPath, NULL);
-
- Result = pfnExtract(&Dest, szCabName);
- if (Result == S_OK)
- {
- FreeLibrary(hCabinetDll);
- return TRUE;
- }
- else
- {
- RemoveDirectoryW(lpOutputPath);
- }
- }
- }
- FreeLibrary(hCabinetDll);
- }
-
- return FALSE;
-}
-
VOID InitLogs()
{
if (!SettingsInfo.bLogEnabled)