[RAPPS] CMainWindow: remove unused functions , and the globals g_MainWindow and hListView
[reactos.git] / base / applications / rapps / cabinet.cpp
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
25 inline BOOL WideToMultiByte(const CStringW& szSource,
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
56 inline BOOL MultiByteToWide(const CStringA& szSource,
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
71 sz = MultiByteToWideChar(CP_UTF8,
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 {
91 HeapFree(GetProcessHeap(), NULL, pv);
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,
129 FILE_SHARE_READ,
130 NULL,
131 dwCreationDisposition,
132 FILE_ATTRIBUTE_NORMAL,
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(),
195 _O_WRONLY | _O_CREAT,
196 0);
197 }
198 break;
199
200 case fdintCLOSE_FILE_INFO:
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
233 typedef HFDI(*fnFDICreate)(PFNALLOC,
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,
248 PFNFDIDECRYPT,
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 */
257 BOOL ExtractFilesFromCab(const ATL::CStringW& szCabName,
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 }