mirror of
https://github.com/reactos/reactos.git
synced 2025-05-25 12:14:32 +00:00
[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
This commit is contained in:
parent
602db40277
commit
9591550116
7 changed files with 348 additions and 90 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
334
base/applications/rapps/cabinet.cpp
Normal file
334
base/applications/rapps/cabinet.cpp
Normal file
|
@ -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@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;
|
||||
}
|
|
@ -86,6 +86,8 @@ struct AvailableStrings
|
|||
ATL::CStringW szCabPath;
|
||||
ATL::CStringW szAppsPath;
|
||||
ATL::CStringW szSearchPath;
|
||||
ATL::CStringW szCabName;
|
||||
ATL::CStringW szCabDir;
|
||||
|
||||
AvailableStrings();
|
||||
};
|
||||
|
|
|
@ -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);
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue