ReactOS  0.4.12-dev-57-g7050ac4
cabinet.cpp
Go to the documentation of this file.
1 /*
2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * FILE: base/applications/rapps/cabinet.cpp
5 * PURPOSE: Cabinet extraction using FDI API
6 * COPYRIGHT: Copyright 2018 Alexander Shaposhnikov (sanchaez@reactos.org)
7 */
8 #include "rapps.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
26  CStringA& szDest,
27  UINT Codepage)
28 {
29  // determine the needed size
30  INT sz = WideCharToMultiByte(Codepage,
31  0,
32  szSource,
33  -1,
34  NULL,
35  NULL,
36  NULL,
37  NULL);
38  if (!sz)
39  return FALSE;
40 
41  // do the actual conversion
42  sz = WideCharToMultiByte(Codepage,
43  0,
44  szSource,
45  -1,
46  szDest.GetBuffer(sz),
47  sz,
48  NULL,
49  NULL);
50 
51  szDest.ReleaseBuffer();
52  return sz != 0;
53 }
54 
55 // converts CStringA to CStringW using a given codepage
57  CStringW& szDest,
58  UINT Codepage)
59 {
60  // determine the needed size
61  INT sz = MultiByteToWideChar(Codepage,
62  0,
63  szSource,
64  -1,
65  NULL,
66  NULL);
67  if (!sz)
68  return FALSE;
69 
70  // do the actual conversion
72  0,
73  szSource,
74  -1,
75  szDest.GetBuffer(sz),
76  sz);
77 
78  szDest.ReleaseBuffer();
79  return sz != 0;
80 }
81 
82 /* FDICreate callbacks */
83 
84 FNALLOC(fnMemAlloc)
85 {
86  return HeapAlloc(GetProcessHeap(), NULL, cb);
87 }
88 
89 FNFREE(fnMemFree)
90 {
92 }
93 
94 FNOPEN(fnFileOpen)
95 {
96  HANDLE hFile = NULL;
97  DWORD dwDesiredAccess = 0;
98  DWORD dwCreationDisposition = 0;
99  ATL::CStringW szFileName;
100 
101  UNREFERENCED_PARAMETER(pmode);
102 
103  if (oflag & _O_RDWR)
104  {
105  dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
106  }
107  else if (oflag & _O_WRONLY)
108  {
109  dwDesiredAccess = GENERIC_WRITE;
110  }
111  else
112  {
113  dwDesiredAccess = GENERIC_READ;
114  }
115 
116  if (oflag & _O_CREAT)
117  {
118  dwCreationDisposition = CREATE_ALWAYS;
119  }
120  else
121  {
122  dwCreationDisposition = OPEN_EXISTING;
123  }
124 
125  MultiByteToWide(pszFile, szFileName, CP_UTF8);
126 
127  hFile = CreateFileW(szFileName,
128  dwDesiredAccess,
130  NULL,
131  dwCreationDisposition,
133  NULL);
134 
135  return (INT_PTR) hFile;
136 }
137 
138 FNREAD(fnFileRead)
139 {
140  DWORD dwBytesRead = 0;
141 
142  if (ReadFile((HANDLE) hf, pv, cb, &dwBytesRead, NULL) == FALSE)
143  {
144  dwBytesRead = (DWORD) -1L;
145  }
146 
147  return dwBytesRead;
148 }
149 
150 FNWRITE(fnFileWrite)
151 {
152  DWORD dwBytesWritten = 0;
153 
154  if (WriteFile((HANDLE) hf, pv, cb, &dwBytesWritten, NULL) == FALSE)
155  {
156  dwBytesWritten = (DWORD) -1;
157  }
158 
159  return dwBytesWritten;
160 }
161 
162 FNCLOSE(fnFileClose)
163 {
164  return (CloseHandle((HANDLE) hf) != FALSE) ? 0 : -1;
165 }
166 
167 FNSEEK(fnFileSeek)
168 {
169  return SetFilePointer((HANDLE) hf, dist, NULL, seektype);
170 }
171 
172 /* FDICopy callbacks */
173 
174 FNFDINOTIFY(fnNotify)
175 {
176  INT_PTR iResult = 0;
177 
178  switch (fdint)
179  {
180  case fdintCOPY_FILE:
181  {
182  ATL::CStringW szNewFileName, szExtractDir, szCabFileName;
183  ATL::CStringA szFilePathUTF8;
184 
185  // Append the destination directory to the file name.
186  MultiByteToWide((LPCSTR) pfdin->pv, szExtractDir, CP_UTF8);
187  MultiByteToWide(pfdin->psz1, szCabFileName, CP_ACP);
188 
189  szNewFileName = szExtractDir + L"\\" + szCabFileName;
190 
191  WideToMultiByte(szNewFileName, szFilePathUTF8, CP_UTF8);
192 
193  // Copy file
194  iResult = fnFileOpen((LPSTR) szFilePathUTF8.GetString(),
196  0);
197  }
198  break;
199 
201  iResult = !fnFileClose(pfdin->hf);
202  break;
203 
204  case fdintNEXT_CABINET:
205  if (pfdin->fdie != FDIERROR_NONE)
206  {
207  iResult = -1;
208  }
209  break;
210 
211  case fdintPARTIAL_FILE:
212  iResult = 0;
213  break;
214 
215  case fdintCABINET_INFO:
216  iResult = 0;
217  break;
218 
219  case fdintENUMERATE:
220  iResult = 0;
221  break;
222 
223  default:
224  iResult = -1;
225  break;
226  }
227 
228  return iResult;
229 }
230 
231 /* cabinet.dll FDI function pointers */
232 
234  PFNFREE,
235  PFNOPEN,
236  PFNREAD,
237  PFNWRITE,
238  PFNCLOSE,
239  PFNSEEK,
240  int,
241  PERF);
242 
243 typedef BOOL(*fnFDICopy)(HFDI,
244  LPSTR,
245  LPSTR,
246  INT,
247  PFNFDINOTIFY,
249  void FAR *pvUser);
250 
251 typedef BOOL(*fnFDIDestroy)(HFDI);
252 
253 /*
254  * Extraction function
255  * TODO: require only a full path to the cab as an argument
256  */
258  const ATL::CStringW& szCabDir,
259  const ATL::CStringW& szOutputDir)
260 {
261  HINSTANCE hCabinetDll;
262  HFDI ExtractHandler;
263  ERF ExtractErrors;
264  ATL::CStringA szCabNameUTF8, szCabDirUTF8, szOutputDirUTF8;
265  fnFDICreate pfnFDICreate;
266  fnFDICopy pfnFDICopy;
267  fnFDIDestroy pfnFDIDestroy;
268  BOOL bResult;
269 
270  // Load cabinet.dll and extract needed functions
271  hCabinetDll = LoadLibraryW(L"cabinet.dll");
272 
273  if (!hCabinetDll)
274  {
275  return FALSE;
276  }
277 
278  pfnFDICreate = (fnFDICreate) GetProcAddress(hCabinetDll, "FDICreate");
279  pfnFDICopy = (fnFDICopy) GetProcAddress(hCabinetDll, "FDICopy");
280  pfnFDIDestroy = (fnFDIDestroy) GetProcAddress(hCabinetDll, "FDIDestroy");
281 
282  if (!pfnFDICreate || !pfnFDICopy || !pfnFDIDestroy)
283  {
284  FreeLibrary(hCabinetDll);
285  return FALSE;
286  }
287 
288  // Create FDI context
289  ExtractHandler = pfnFDICreate(fnMemAlloc,
290  fnMemFree,
291  fnFileOpen,
292  fnFileRead,
293  fnFileWrite,
294  fnFileClose,
295  fnFileSeek,
296  cpuUNKNOWN,
297  &ExtractErrors);
298 
299  if (!ExtractHandler)
300  {
301  FreeLibrary(hCabinetDll);
302  return FALSE;
303  }
304 
305  // Create output dir
306  bResult = CreateDirectoryW(szOutputDir, NULL);
307 
308  if (bResult || GetLastError() == ERROR_ALREADY_EXISTS)
309  {
310  // Convert wide strings to UTF-8
311  bResult = WideToMultiByte(szCabName, szCabNameUTF8, CP_UTF8);
312  bResult &= WideToMultiByte(szCabDir, szCabDirUTF8, CP_UTF8);
313  bResult &= WideToMultiByte(szOutputDir, szOutputDirUTF8, CP_UTF8);
314  }
315 
316  // Perform extraction
317  if (bResult)
318  {
319  // Add a slash to cab name as required by the api
320  szCabNameUTF8 = "\\" + szCabNameUTF8;
321 
322  bResult = pfnFDICopy(ExtractHandler,
323  (LPSTR) szCabNameUTF8.GetString(),
324  (LPSTR) szCabDirUTF8.GetString(),
325  0,
326  fnNotify,
327  NULL,
328  (void FAR *) szOutputDirUTF8.GetString());
329  }
330 
331  pfnFDIDestroy(ExtractHandler);
332  FreeLibrary(hCabinetDll);
333  return bResult;
334 }
INT_PTR(__cdecl * PFNFDINOTIFY)(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: fdi.h:255
BOOL WINAPI CreateDirectoryW(IN LPCWSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:90
FNREAD(fnFileRead)
Definition: cabinet.cpp:138
BOOL ExtractFilesFromCab(const ATL::CStringW &szCabName, const ATL::CStringW &szCabDir, const ATL::CStringW &szOutputDir)
Definition: cabinet.cpp:257
#define CloseHandle
Definition: compat.h:398
#define WideCharToMultiByte
Definition: compat.h:101
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
BOOL(* fnFDIDestroy)(HFDI)
Definition: cabinet.cpp:251
#define DWORD
Definition: msvc.h:34
#define CP_ACP
Definition: compat.h:99
int(__cdecl * PFNFDIDECRYPT)(PFDIDECRYPT pfdid)
Definition: fdi.h:223
#define _O_CREAT
Definition: cabinet.h:46
void(__cdecl * PFNFREE)(void *pv)
Definition: fdi.h:205
FNOPEN(fnFileOpen)
Definition: cabinet.cpp:94
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
int32_t INT_PTR
Definition: typedefs.h:62
char * LPSTR
Definition: xmlstorage.h:182
int32_t INT
Definition: typedefs.h:56
#define FILE_SHARE_READ
Definition: compat.h:125
BOOL MultiByteToWide(const CStringA &szSource, CStringW &szDest, UINT Codepage)
Definition: cabinet.cpp:56
DWORD WINAPI DECLSPEC_HOTPATCH SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
Definition: fileinfo.c:204
#define _O_RDWR
Definition: cabinet.h:39
void ReleaseBuffer(_In_ int nNewLength=-1)
Definition: atlsimpstr.h:372
#define cpuUNKNOWN
Definition: fdi.h:269
#define CP_UTF8
Definition: nls.h:20
FNALLOC(fnMemAlloc)
Definition: cabinet.cpp:84
HFDI(* fnFDICreate)(PFNALLOC, PFNFREE, PFNOPEN, PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF)
Definition: cabinet.cpp:233
Definition: fci.h:44
#define GENERIC_WRITE
Definition: nt_native.h:90
DWORD void * pv
Definition: msvc.h:87
#define FAR
Definition: guiddef.h:36
int(__cdecl * PFNCLOSE)(INT_PTR hf)
Definition: fdi.h:217
#define INT(a)
Definition: assyntax.h:463
#define LoadLibraryW(x)
Definition: compat.h:404
smooth NULL
Definition: ftsmooth.c:416
const char * LPCSTR
Definition: xmlstorage.h:183
INT_PTR(__cdecl * PFNOPEN)(char *pszFile, int oflag, int pmode)
Definition: fdi.h:208
#define OPEN_EXISTING
Definition: compat.h:426
BOOL WideToMultiByte(const CStringW &szSource, CStringA &szDest, UINT Codepage)
Definition: cabinet.cpp:25
UINT(__cdecl * PFNREAD)(INT_PTR hf, void *pv, UINT cb)
Definition: fdi.h:211
struct ERF * PERF
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
#define FreeLibrary(x)
Definition: compat.h:405
unsigned int BOOL
Definition: ntddk_ex.h:94
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
PCXSTR GetString() const
Definition: atlsimpstr.h:361
unsigned int UINT
Definition: ndis.h:50
unsigned long DWORD
Definition: ntddk_ex.h:95
static DWORD cb
Definition: integrity.c:41
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
static const WCHAR L[]
Definition: oid.c:1087
void *(__cdecl * PFNALLOC)(ULONG cb)
Definition: fdi.h:202
static const WCHAR szSource[]
Definition: automation.c:501
LONG(__cdecl * PFNSEEK)(INT_PTR hf, LONG dist, int seektype)
Definition: fdi.h:220
void * HFDI
Definition: fdi.h:141
#define GENERIC_READ
Definition: compat.h:124
UINT(__cdecl * PFNWRITE)(INT_PTR hf, void *pv, UINT cb)
Definition: fdi.h:214
_In_ HANDLE hFile
Definition: mswsock.h:90
#define _O_WRONLY
Definition: cabinet.h:38
#define CREATE_ALWAYS
Definition: disk.h:72
FNSEEK(fnFileSeek)
Definition: cabinet.cpp:167
#define MultiByteToWideChar
Definition: compat.h:100
#define CreateFileW
Definition: compat.h:400
BOOL(* fnFDICopy)(HFDI, LPSTR, LPSTR, INT, PFNFDINOTIFY, PFNFDIDECRYPT, void FAR *pvUser)
Definition: cabinet.cpp:243
FNCLOSE(fnFileClose)
Definition: cabinet.cpp:162
#define GetProcAddress(x, y)
Definition: compat.h:410
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
FNWRITE(fnFileWrite)
Definition: cabinet.cpp:150
FNFDINOTIFY(fnNotify)
Definition: cabinet.cpp:174
BOOL WINAPI ReadFile(IN HANDLE hFile, IN LPVOID lpBuffer, IN DWORD nNumberOfBytesToRead, OUT LPDWORD lpNumberOfBytesRead OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:123
FNFREE(fnMemFree)
Definition: cabinet.cpp:89
#define BOOL
Definition: msvc.h:23
#define HeapFree(x, y, z)
Definition: compat.h:394
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:29