ReactOS 0.4.15-dev-8116-gf69e256
cabinet.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Cabinet extraction using FDI API
5 * COPYRIGHT: Copyright 2018 Alexander Shaposhnikov (sanchaez@reactos.org)
6 */
7#include "rapps.h"
8#include <debug.h>
9
10#include <fdi.h>
11#include <fcntl.h>
12
13/*
14 * HACK: treat any input strings as Unicode (UTF-8)
15 * cabinet.dll lacks any sort of a Unicode API, but FCI/FDI
16 * provide an ability to use user-defined callbacks for any file or memory
17 * operations. This flexibility and the magic power of C/C++ casting allows
18 * us to treat input as we please.
19 * This is by far the best way to extract .cab using Unicode paths.
20 */
21
22/* String conversion helper functions */
23
24// converts CStringW to CStringA using a given codepage
25inline BOOL
26WideToMultiByte(const CStringW &szSource, CStringA &szDest, UINT Codepage)
27{
28 // determine the needed size
29 INT sz = WideCharToMultiByte(Codepage, 0, szSource, -1, NULL, NULL, NULL, NULL);
30 if (!sz)
31 return FALSE;
32
33 // do the actual conversion
34 sz = WideCharToMultiByte(Codepage, 0, szSource, -1, szDest.GetBuffer(sz), sz, NULL, NULL);
35
36 szDest.ReleaseBuffer();
37 return sz != 0;
38}
39
40// converts CStringA to CStringW using a given codepage
41inline BOOL
42MultiByteToWide(const CStringA &szSource, CStringW &szDest, UINT Codepage)
43{
44 // determine the needed size
45 INT sz = MultiByteToWideChar(Codepage, 0, szSource, -1, NULL, NULL);
46 if (!sz)
47 return FALSE;
48
49 // do the actual conversion
50 sz = MultiByteToWideChar(CP_UTF8, 0, szSource, -1, szDest.GetBuffer(sz), sz);
51
52 szDest.ReleaseBuffer();
53 return sz != 0;
54}
55
57{
61};
62
63/* FDICreate callbacks */
64
65FNALLOC(fnMemAlloc)
66{
67 return HeapAlloc(GetProcessHeap(), NULL, cb);
68}
69
70FNFREE(fnMemFree)
71{
73}
74
75FNOPEN(fnFileOpen)
76{
78 DWORD dwDesiredAccess = 0;
79 DWORD dwCreationDisposition = 0;
80 CStringW szFileName;
81
83
84 if (oflag & _O_RDWR)
85 {
86 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
87 }
88 else if (oflag & _O_WRONLY)
89 {
90 dwDesiredAccess = GENERIC_WRITE;
91 }
92 else
93 {
94 dwDesiredAccess = GENERIC_READ;
95 }
96
97 if (oflag & _O_CREAT)
98 {
99 dwCreationDisposition = CREATE_ALWAYS;
100 }
101 else
102 {
103 dwCreationDisposition = OPEN_EXISTING;
104 }
105
106 MultiByteToWide(pszFile, szFileName, CP_UTF8);
107
109 szFileName, dwDesiredAccess, FILE_SHARE_READ, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
110
111 return (INT_PTR)hFile;
112}
113
114FNREAD(fnFileRead)
115{
116 DWORD dwBytesRead = 0;
117
118 if (ReadFile((HANDLE)hf, pv, cb, &dwBytesRead, NULL) == FALSE)
119 {
120 dwBytesRead = (DWORD)-1L;
121 }
122
123 return dwBytesRead;
124}
125
126FNWRITE(fnFileWrite)
127{
128 DWORD dwBytesWritten = 0;
129
130 if (WriteFile((HANDLE)hf, pv, cb, &dwBytesWritten, NULL) == FALSE)
131 {
132 dwBytesWritten = (DWORD)-1;
133 }
134
135 return dwBytesWritten;
136}
137
138FNCLOSE(fnFileClose)
139{
140 return (CloseHandle((HANDLE)hf) != FALSE) ? 0 : -1;
141}
142
143FNSEEK(fnFileSeek)
144{
145 return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
146}
147
148/* FDICopy callbacks */
149
150FNFDINOTIFY(fnNotify)
151{
152 INT_PTR iResult = 0;
153 NotifyData *pND = (NotifyData *)pfdin->pv;
154
155 switch (fdint)
156 {
157 case fdintCOPY_FILE:
158 {
159 CStringW szExtractDir, szCabFileName;
160
161 // Append the destination directory to the file name.
162 MultiByteToWide(pND->OutputDir, szExtractDir, CP_UTF8);
163 MultiByteToWide(pfdin->psz1, szCabFileName, CP_ACP);
164
165 if (!NotifyFileExtractCallback(szCabFileName, pfdin->cb, pfdin->attribs,
166 pND->Callback, pND->CallerCookie))
167 {
168 break; // Skip file
169 }
170
171 if (szCabFileName.Find('\\') >= 0)
172 {
173 CStringW szNewDirName = szExtractDir;
174 int nTokenPos = 0;
175 // We do not want to interpret the filename as directory,
176 // so bail out before the last token!
177 while (szCabFileName.Find('\\', nTokenPos) >= 0)
178 {
179 CStringW token = szCabFileName.Tokenize(L"\\", nTokenPos);
180 if (token.IsEmpty())
181 break;
182
183 szNewDirName += L"\\" + token;
184 if (!CreateDirectoryW(szNewDirName, NULL))
185 {
188 {
189 DPRINT1(
190 "ERROR: Unable to create directory %S (err %lu)\n", szNewDirName.GetString(), dwErr);
191 }
192 }
193 }
194 }
195
196 CStringW szNewFileName = szExtractDir + L"\\" + szCabFileName;
197
198 CStringA szFilePathUTF8;
199 WideToMultiByte(szNewFileName, szFilePathUTF8, CP_UTF8);
200
201 // Open the file
202 iResult = fnFileOpen((LPSTR)szFilePathUTF8.GetString(), _O_WRONLY | _O_CREAT, 0);
203 }
204 break;
205
207 iResult = !fnFileClose(pfdin->hf);
208 break;
209
211 if (pfdin->fdie != FDIERROR_NONE)
212 {
213 iResult = -1;
214 }
215 break;
216
218 iResult = 0;
219 break;
220
222 iResult = 0;
223 break;
224
225 case fdintENUMERATE:
226 iResult = 0;
227 break;
228
229 default:
230 iResult = -1;
231 break;
232 }
233
234 return iResult;
235}
236
237/* cabinet.dll FDI function pointers */
238
240
242
244
245/*
246 * Extraction function
247 */
248BOOL
249ExtractFilesFromCab(const CStringW &szCabName, const CStringW &szCabDir, const CStringW &szOutputDir,
251{
252 HINSTANCE hCabinetDll;
253 HFDI ExtractHandler;
254 ERF ExtractErrors;
255 ATL::CStringA szCabNameUTF8, szCabDirUTF8, szOutputDirUTF8;
256 fnFDICreate pfnFDICreate;
257 fnFDICopy pfnFDICopy;
258 fnFDIDestroy pfnFDIDestroy;
259 BOOL bResult;
260 NotifyData nd = { Callback, Cookie };
261
262 // Load cabinet.dll and extract needed functions
263 hCabinetDll = LoadLibraryW(L"cabinet.dll");
264
265 if (!hCabinetDll)
266 {
267 return FALSE;
268 }
269
270 pfnFDICreate = (fnFDICreate)GetProcAddress(hCabinetDll, "FDICreate");
271 pfnFDICopy = (fnFDICopy)GetProcAddress(hCabinetDll, "FDICopy");
272 pfnFDIDestroy = (fnFDIDestroy)GetProcAddress(hCabinetDll, "FDIDestroy");
273
274 if (!pfnFDICreate || !pfnFDICopy || !pfnFDIDestroy)
275 {
276 FreeLibrary(hCabinetDll);
277 return FALSE;
278 }
279
280 // Create FDI context
281 ExtractHandler = pfnFDICreate(
282 fnMemAlloc, fnMemFree, fnFileOpen, fnFileRead, fnFileWrite, fnFileClose, fnFileSeek, cpuUNKNOWN,
283 &ExtractErrors);
284
285 if (!ExtractHandler)
286 {
287 FreeLibrary(hCabinetDll);
288 return FALSE;
289 }
290
291 // Create output dir
292 bResult = CreateDirectoryW(szOutputDir, NULL);
293
294 if (bResult || GetLastError() == ERROR_ALREADY_EXISTS)
295 {
296 // Convert wide strings to UTF-8
297 bResult = WideToMultiByte(szCabName, szCabNameUTF8, CP_UTF8);
298 bResult &= WideToMultiByte(szCabDir, szCabDirUTF8, CP_UTF8);
299 bResult &= WideToMultiByte(szOutputDir, szOutputDirUTF8, CP_UTF8);
300 }
301
302 // Perform extraction
303 if (bResult)
304 {
305 // Add a slash to cab name as required by the api
306 szCabNameUTF8 = "\\" + szCabNameUTF8;
307
308 nd.OutputDir = szOutputDirUTF8.GetString();
309 bResult = pfnFDICopy(
310 ExtractHandler, (LPSTR)szCabNameUTF8.GetString(), (LPSTR)szCabDirUTF8.GetString(), 0, fnNotify, NULL,
311 (void FAR *)&nd);
312 }
313
314 pfnFDIDestroy(ExtractHandler);
315 FreeLibrary(hCabinetDll);
316 return bResult;
317}
318
319BOOL
320ExtractFilesFromCab(LPCWSTR FullCabPath, const CStringW &szOutputDir,
322{
323 CStringW dir, file = SplitFileAndDirectory(FullCabPath, &dir);
324 return ExtractFilesFromCab(file, dir, szOutputDir, Callback, Cookie);
325}
unsigned int dir
Definition: maze.c:112
BOOL(CALLBACK * EXTRACTCALLBACK)(const EXTRACTCALLBACKINFO &Info, void *Cookie)
Definition: misc.h:53
static BOOL NotifyFileExtractCallback(const CStringW &ItemPath, UINT64 UncompressedSize, UINT FileAttributes, EXTRACTCALLBACK Callback, void *Cookie)
Definition: misc.h:56
CStringW SplitFileAndDirectory(LPCWSTR FullPath, CStringW *pDir=NULL)
Definition: misc.cpp:438
#define DPRINT1
Definition: precomp.h:8
DWORD dwErr
Definition: service.c:36
BOOL MultiByteToWide(const CStringA &szSource, CStringW &szDest, UINT Codepage)
Definition: cabinet.cpp:42
BOOL WideToMultiByte(const CStringW &szSource, CStringA &szDest, UINT Codepage)
Definition: cabinet.cpp:26
HFDI(* fnFDICreate)(PFNALLOC, PFNFREE, PFNOPEN, PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF)
Definition: cabinet.cpp:239
BOOL(* fnFDICopy)(HFDI, LPSTR, LPSTR, INT, PFNFDINOTIFY, PFNFDIDECRYPT, void FAR *pvUser)
Definition: cabinet.cpp:241
BOOL ExtractFilesFromCab(const CStringW &szCabName, const CStringW &szCabDir, const CStringW &szOutputDir, EXTRACTCALLBACK Callback, void *Cookie)
Definition: cabinet.cpp:249
BOOL(* fnFDIDestroy)(HFDI)
Definition: cabinet.cpp:243
void ReleaseBuffer(_In_ int nNewLength=-1)
Definition: atlsimpstr.h:387
PXSTR GetString() noexcept
Definition: atlsimpstr.h:367
CStringT Tokenize(_In_z_ PCXSTR pszTokens, _Inout_ int &iStart) const
Definition: cstringt.h:947
int Find(_In_ PCXSTR pszSub, _In_opt_ int iStart=0) const noexcept
Definition: cstringt.h:696
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define _O_RDWR
Definition: cabinet.h:39
#define _O_CREAT
Definition: cabinet.h:46
#define _O_WRONLY
Definition: cabinet.h:38
#define CloseHandle
Definition: compat.h:739
#define GetProcessHeap()
Definition: compat.h:736
#define CP_ACP
Definition: compat.h:109
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define SetFilePointer
Definition: compat.h:743
#define GetProcAddress(x, y)
Definition: compat.h:753
#define HeapAlloc
Definition: compat.h:733
#define FreeLibrary(x)
Definition: compat.h:748
#define GENERIC_READ
Definition: compat.h:135
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CreateFileW
Definition: compat.h:741
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define LoadLibraryW(x)
Definition: compat.h:747
#define FILE_SHARE_READ
Definition: compat.h:136
#define FAR
Definition: zlib.h:34
BOOL WINAPI CreateDirectoryW(IN LPCWSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:90
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
switch(r->id)
Definition: btrfs.c:3046
struct ERF * PERF
#define FNSEEK(fn)
Definition: fdi.h:221
@ FDIERROR_NONE
Definition: fdi.h:115
#define FNALLOC(fn)
Definition: fdi.h:203
UINT(__cdecl * PFNWRITE)(INT_PTR hf, void *pv, UINT cb)
Definition: fdi.h:214
int(__cdecl * PFNCLOSE)(INT_PTR hf)
Definition: fdi.h:217
#define FNOPEN(fn)
Definition: fdi.h:209
@ fdintCABINET_INFO
Definition: fdi.h:247
@ fdintCOPY_FILE
Definition: fdi.h:249
@ fdintPARTIAL_FILE
Definition: fdi.h:248
@ fdintCLOSE_FILE_INFO
Definition: fdi.h:250
@ fdintNEXT_CABINET
Definition: fdi.h:251
@ fdintENUMERATE
Definition: fdi.h:252
#define FNFREE(fn)
Definition: fdi.h:206
#define FNCLOSE(fn)
Definition: fdi.h:218
INT_PTR(__cdecl * PFNFDINOTIFY)(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: fdi.h:255
UINT(__cdecl * PFNREAD)(INT_PTR hf, void *pv, UINT cb)
Definition: fdi.h:211
void(__cdecl * PFNFREE)(void *pv)
Definition: fdi.h:205
void *(__cdecl * PFNALLOC)(ULONG cb)
Definition: fdi.h:202
#define FNREAD(fn)
Definition: fdi.h:212
INT_PTR(__cdecl * PFNOPEN)(char *pszFile, int oflag, int pmode)
Definition: fdi.h:208
LONG(__cdecl * PFNSEEK)(INT_PTR hf, LONG dist, int seektype)
Definition: fdi.h:220
#define FNFDINOTIFY(fn)
Definition: fdi.h:257
#define FNWRITE(fn)
Definition: fdi.h:215
void * HFDI
Definition: fdi.h:141
int(__cdecl * PFNFDIDECRYPT)(PFDIDECRYPT pfdid)
Definition: fdi.h:223
#define cpuUNKNOWN
Definition: fdi.h:269
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat token
Definition: glfuncs.h:210
#define CREATE_ALWAYS
Definition: disk.h:72
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
static HMODULE MODULEINFO DWORD cb
Definition: module.c:33
_In_ HANDLE hFile
Definition: mswsock.h:90
unsigned int UINT
Definition: ndis.h:50
#define BOOL
Definition: nt_native.h:43
#define DWORD
Definition: nt_native.h:44
#define GENERIC_WRITE
Definition: nt_native.h:90
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define L(x)
Definition: ntvdm.h:50
#define INT
Definition: polytest.cpp:20
#define CP_UTF8
Definition: nls.h:20
Definition: fci.h:44
void * CallerCookie
Definition: cabinet.cpp:59
EXTRACTCALLBACK Callback
Definition: cabinet.cpp:58
LPCSTR OutputDir
Definition: cabinet.cpp:60
Definition: fci.c:127
int32_t INT_PTR
Definition: typedefs.h:64
int32_t INT
Definition: typedefs.h:58
_In_ WDFINTERRUPT _In_ PFN_WDF_INTERRUPT_SYNCHRONIZE Callback
Definition: wdfinterrupt.h:458
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_In_opt_ PVOID _Out_ PLARGE_INTEGER Cookie
Definition: cmfuncs.h:14
const char * LPCSTR
Definition: xmlstorage.h:183
char * LPSTR
Definition: xmlstorage.h:182
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185