diff --git a/base/applications/rapps/CMakeLists.txt b/base/applications/rapps/CMakeLists.txt index cdbb6f97dcf..ce8ba3a0ba7 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 04e5005e5a3..f92644f48a4 100644 --- a/base/applications/rapps/available.cpp +++ b/base/applications/rapps/available.cpp @@ -38,7 +38,7 @@ VOID CAvailableApplicationInfo::RetrieveGeneralInfo() { m_Parser = new CConfigParser(m_sFileName); - m_Category = m_Parser->GetInt(L"Category"); + m_Parser->GetInt(L"Category", m_Category); if (!GetString(L"Name", m_szName) || !GetString(L"URLDownload", m_szUrlDownload)) @@ -51,15 +51,16 @@ VOID CAvailableApplicationInfo::RetrieveGeneralInfo() GetString(L"Version", m_szVersion); GetString(L"License", m_szLicense); GetString(L"Description", m_szDesc); - GetString(L"Size", m_szSize); GetString(L"URLSite", m_szUrlSite); GetString(L"CDPath", m_szCDPath); GetString(L"Language", m_szRegName); GetString(L"SHA1", m_szSHA1); + RetrieveSize(); RetrieveLicenseType(); RetrieveLanguages(); RetrieveInstalledStatus(); + if (m_IsInstalled) { RetrieveInstalledVersion(); @@ -128,7 +129,9 @@ VOID CAvailableApplicationInfo::RetrieveLanguages() VOID CAvailableApplicationInfo::RetrieveLicenseType() { - INT IntBuffer = m_Parser->GetInt(L"LicenseType"); + INT IntBuffer; + + m_Parser->GetInt(L"LicenseType", IntBuffer); if (IsLicenseType(IntBuffer)) { @@ -140,6 +143,17 @@ VOID CAvailableApplicationInfo::RetrieveLicenseType() } } +VOID CAvailableApplicationInfo::RetrieveSize() +{ + INT iSizeBytes; + + if (!m_Parser->GetInt(L"SizeBytes", iSizeBytes)) + return; + + StrFormatByteSizeW(iSizeBytes, m_szSize.GetBuffer(MAX_PATH), MAX_PATH); + m_szSize.ReleaseBuffer(); +} + BOOL CAvailableApplicationInfo::FindInLanguages(LCID what) const { if (!m_HasLanguageInfo) @@ -213,7 +227,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 +298,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 00000000000..b5e08a5ab79 --- /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@reactos.org) +*/ +#include "rapps.h" + +#include +#include + +/* + * 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 782f960be89..c0b0f2017fb 100644 --- a/base/applications/rapps/include/available.h +++ b/base/applications/rapps/include/available.h @@ -75,6 +75,7 @@ private: VOID RetrieveInstalledVersion(); VOID RetrieveLanguages(); VOID RetrieveLicenseType(); + VOID RetrieveSize(); inline BOOL FindInLanguages(LCID what) const; }; @@ -86,6 +87,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 02bbd5738d9..00000000000 --- 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 b3f30630019..143d9769b72 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 @@ -37,6 +41,6 @@ class CConfigParser public: CConfigParser(const ATL::CStringW& FileName = ""); - UINT GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString); - UINT GetInt(const ATL::CStringW& KeyName); + BOOL GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString); + BOOL GetInt(const ATL::CStringW& KeyName, INT& iResult); }; diff --git a/base/applications/rapps/include/resource.h b/base/applications/rapps/include/resource.h index 9f4c4b15dec..7d5a9b9ebfa 100644 --- a/base/applications/rapps/include/resource.h +++ b/base/applications/rapps/include/resource.h @@ -154,6 +154,9 @@ #define IDS_AINFO_URLDOWNLOAD 355 #define IDS_AINFO_AVAILABLEVERSION 356 #define IDS_AINFO_LANGUAGES 357 +#define IDS_AINFO_KILOBYTE_EXT 358 +#define IDS_AINFO_MEGABYTE_EXT 359 +#define IDS_AINFO_GIGABYTE_EXT 360 /* Names of categories */ diff --git a/base/applications/rapps/misc.cpp b/base/applications/rapps/misc.cpp index 1a527317afa..cc1dc6541fa 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) @@ -408,7 +354,7 @@ VOID CConfigParser::CacheINILocale() m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale + m_szLocaleID.Right(2); } -UINT CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString) +BOOL CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString) { DWORD dwResult; @@ -446,10 +392,12 @@ UINT CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& Resul return (dwResult != 0 ? TRUE : FALSE); } -UINT CConfigParser::GetInt(const ATL::CStringW& KeyName) +BOOL CConfigParser::GetInt(const ATL::CStringW& KeyName, INT& iResult) { ATL::CStringW Buffer; + iResult = 0; + // grab the text version of our entry if (!GetString(KeyName, Buffer)) return FALSE; @@ -458,8 +406,9 @@ UINT CConfigParser::GetInt(const ATL::CStringW& KeyName) return FALSE; // convert it to an actual integer - INT result = StrToIntW(Buffer.GetString()); + iResult = StrToIntW(Buffer.GetString()); - return (UINT) (result <= 0) ? 0 : result; + // we only care about values > 0 + return (iResult > 0); } // CConfigParser