aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/cabutil.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2017-09-03 11:22:38 -0700
committerRob Mensching <rob@firegiant.com>2017-09-03 13:33:33 -0700
commit5d8375007754101ff2889d0e79486c8f9b7cf5ab (patch)
treea76d6fb6a38dd9f04a93ffcfd9d64e76779b3414 /src/dutil/cabutil.cpp
parent8e8da6dbc051ec884b5d439bb4f44dc027d05bbf (diff)
downloadwix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.tar.gz
wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.tar.bz2
wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.zip
Initial commit
Diffstat (limited to 'src/dutil/cabutil.cpp')
-rw-r--r--src/dutil/cabutil.cpp567
1 files changed, 567 insertions, 0 deletions
diff --git a/src/dutil/cabutil.cpp b/src/dutil/cabutil.cpp
new file mode 100644
index 00000000..e0efb717
--- /dev/null
+++ b/src/dutil/cabutil.cpp
@@ -0,0 +1,567 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5// external prototypes
6typedef BOOL (FAR DIAMONDAPI *PFNFDIDESTROY)(VOID*);
7typedef HFDI (FAR DIAMONDAPI *PFNFDICREATE)(PFNALLOC, PFNFREE, PFNOPEN, PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF);
8typedef BOOL (FAR DIAMONDAPI *PFNFDIISCABINET)(HFDI, INT_PTR, PFDICABINETINFO);
9typedef BOOL (FAR DIAMONDAPI *PFNFDICOPY)(HFDI, char *, char *, int, PFNFDINOTIFY, PFNFDIDECRYPT, void *);
10
11
12//
13// static globals
14//
15static HMODULE vhCabinetDll = NULL;
16
17static HFDI vhfdi = NULL;
18static PFNFDICREATE vpfnFDICreate = NULL;
19static PFNFDICOPY vpfnFDICopy = NULL;
20static PFNFDIISCABINET vpfnFDIIsCabinet = NULL;
21static PFNFDIDESTROY vpfnFDIDestroy = NULL;
22static ERF verf;
23
24static DWORD64 vdw64EmbeddedOffset = 0;
25
26//
27// structs
28//
29struct CAB_CALLBACK_STRUCT
30{
31 BOOL fStopExtracting; // flag set when no more files are needed
32 LPCWSTR pwzExtract; // file to extract ("*" means extract all)
33 LPCWSTR pwzExtractDir; // directory to extract files to
34
35 // possible user data
36 CAB_CALLBACK_PROGRESS pfnProgress;
37 LPVOID pvContext;
38};
39
40//
41// prototypes
42//
43static __callback LPVOID DIAMONDAPI CabExtractAlloc(__in DWORD dwSize);
44static __callback void DIAMONDAPI CabExtractFree(__in LPVOID pvData);
45static __callback INT_PTR FAR DIAMONDAPI CabExtractOpen(__in_z PSTR pszFile, __in int oflag, __in int pmode);
46static __callback UINT FAR DIAMONDAPI CabExtractRead(__in INT_PTR hf, __out void FAR *pv, __in UINT cb);
47static __callback UINT FAR DIAMONDAPI CabExtractWrite(__in INT_PTR hf, __in void FAR *pv, __in UINT cb);
48static __callback int FAR DIAMONDAPI CabExtractClose(__in INT_PTR hf);
49static __callback long FAR DIAMONDAPI CabExtractSeek(__in INT_PTR hf, __in long dist, __in int seektype);
50static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE iNotification, __inout FDINOTIFICATION *pFDINotify);
51static HRESULT DAPI CabOperation(__in LPCWSTR wzCabinet, __in LPCWSTR wzExtractFile, __in_opt LPCWSTR wzExtractDir, __in_opt CAB_CALLBACK_PROGRESS pfnProgress, __in_opt LPVOID pvContext, __in_opt STDCALL_PFNFDINOTIFY pfnNotify, __in DWORD64 dw64EmbeddedOffset);
52
53static STDCALL_PFNFDINOTIFY v_pfnNetFx11Notify = NULL;
54
55
56inline HRESULT LoadCabinetDll()
57{
58 HRESULT hr = S_OK;
59 if (!vhCabinetDll)
60 {
61 hr = LoadSystemLibrary(L"cabinet.dll", &vhCabinetDll);
62 ExitOnFailure(hr, "failed to load cabinet.dll");
63
64 // retrieve all address functions
65 vpfnFDICreate = reinterpret_cast<PFNFDICREATE>(::GetProcAddress(vhCabinetDll, "FDICreate"));
66 ExitOnNullWithLastError(vpfnFDICreate, hr, "failed to import FDICreate from CABINET.DLL");
67 vpfnFDICopy = reinterpret_cast<PFNFDICOPY>(::GetProcAddress(vhCabinetDll, "FDICopy"));
68 ExitOnNullWithLastError(vpfnFDICopy, hr, "failed to import FDICopy from CABINET.DLL");
69 vpfnFDIIsCabinet = reinterpret_cast<PFNFDIISCABINET>(::GetProcAddress(vhCabinetDll, "FDIIsCabinet"));
70 ExitOnNullWithLastError(vpfnFDIIsCabinet, hr, "failed to import FDIIsCabinetfrom CABINET.DLL");
71 vpfnFDIDestroy = reinterpret_cast<PFNFDIDESTROY>(::GetProcAddress(vhCabinetDll, "FDIDestroy"));
72 ExitOnNullWithLastError(vpfnFDIDestroy, hr, "failed to import FDIDestroyfrom CABINET.DLL");
73
74 vhfdi = vpfnFDICreate(CabExtractAlloc, CabExtractFree, CabExtractOpen, CabExtractRead, CabExtractWrite, CabExtractClose, CabExtractSeek, cpuUNKNOWN, &verf);
75 ExitOnNull(vhfdi, hr, E_FAIL, "failed to initialize cabinet.dll");
76 }
77
78LExit:
79 if (FAILED(hr) && vhCabinetDll)
80 {
81 ::FreeLibrary(vhCabinetDll);
82 vhCabinetDll = NULL;
83 }
84
85 return hr;
86}
87
88
89/********************************************************************
90 CabInitialize - initializes internal static variables
91
92********************************************************************/
93extern "C" HRESULT DAPI CabInitialize(
94 __in BOOL fDelayLoad
95 )
96{
97 HRESULT hr = S_OK;
98
99 if (!fDelayLoad)
100 {
101 hr = LoadCabinetDll();
102 ExitOnFailure(hr, "failed to load CABINET.DLL");
103 }
104
105LExit:
106 return hr;
107}
108
109
110/********************************************************************
111 CabUninitialize - initializes internal static variables
112
113********************************************************************/
114extern "C" void DAPI CabUninitialize(
115 )
116{
117 if (vhfdi)
118 {
119 if (vpfnFDIDestroy)
120 {
121 vpfnFDIDestroy(vhfdi);
122 }
123 vhfdi = NULL;
124 }
125
126 vpfnFDICreate = NULL;
127 vpfnFDICopy =NULL;
128 vpfnFDIIsCabinet = NULL;
129 vpfnFDIDestroy = NULL;
130
131 if (vhCabinetDll)
132 {
133 ::FreeLibrary(vhCabinetDll);
134 vhCabinetDll = NULL;
135 }
136}
137
138/********************************************************************
139 CabEnumerate - list files inside cabinet
140
141 NOTE: wzCabinet must be full path to cabinet file
142 pfnNotify is callback function to get notified for each file
143 in the cabinet
144********************************************************************/
145extern "C" HRESULT DAPI CabEnumerate(
146 __in LPCWSTR wzCabinet,
147 __in LPCWSTR wzEnumerateFile,
148 __in STDCALL_PFNFDINOTIFY pfnNotify,
149 __in DWORD64 dw64EmbeddedOffset
150 )
151{
152 return CabOperation(wzCabinet, wzEnumerateFile, NULL, NULL, NULL, pfnNotify, dw64EmbeddedOffset);
153}
154
155/********************************************************************
156 CabExtract - extracts one or all files from a cabinet
157
158 NOTE: wzCabinet must be full path to cabinet file
159 wzExtractFile can be a single file id or "*" to extract all files
160 wzExttractDir must be normalized (end in a "\")
161 if pfnBeginFile is NULL pfnEndFile must be NULL and vice versa
162********************************************************************/
163extern "C" HRESULT DAPI CabExtract(
164 __in LPCWSTR wzCabinet,
165 __in LPCWSTR wzExtractFile,
166 __in LPCWSTR wzExtractDir,
167 __in_opt CAB_CALLBACK_PROGRESS pfnProgress,
168 __in_opt LPVOID pvContext,
169 __in DWORD64 dw64EmbeddedOffset
170 )
171{
172 return CabOperation(wzCabinet, wzExtractFile, wzExtractDir, pfnProgress, pvContext, NULL, dw64EmbeddedOffset);
173}
174
175//
176// private
177//
178/********************************************************************
179 FDINotify -- wrapper that converts call convention from __cdecl to __stdcall.
180
181 NOTE: Since netfx 1.1 supports only function pointers (delegates)
182 with __stdcall calling convention and cabinet api uses
183 __cdecl calling convention, we need this wrapper function.
184 netfx 2.0 will work with [UnmanagedFunctionPointer(CallingConvention.Cdecl)] attribute on the delegate.
185 TODO: remove this when upgrading to netfx 2.0.
186********************************************************************/
187static __callback INT_PTR DIAMONDAPI FDINotify(
188 __in FDINOTIFICATIONTYPE iNotification,
189 __inout FDINOTIFICATION *pFDINotify
190 )
191{
192 if (NULL != v_pfnNetFx11Notify)
193 {
194 return v_pfnNetFx11Notify(iNotification, pFDINotify);
195 }
196 else
197 {
198 return (INT_PTR)0;
199 }
200}
201
202
203/********************************************************************
204 CabOperation - helper function that enumerates or extracts files
205 from cabinet
206
207 NOTE: wzCabinet must be full path to cabinet file
208 wzExtractFile can be a single file id or "*" to extract all files
209 wzExttractDir must be normalized (end in a "\")
210 if pfnBeginFile is NULL pfnEndFile must be NULL and vice versa
211 pfnNotify is callback function to get notified for each file
212 in the cabinet. If it's NULL, files will be extracted.
213********************************************************************/
214static HRESULT DAPI CabOperation(
215 __in LPCWSTR wzCabinet,
216 __in LPCWSTR wzExtractFile,
217 __in_opt LPCWSTR wzExtractDir,
218 __in_opt CAB_CALLBACK_PROGRESS pfnProgress,
219 __in_opt LPVOID pvContext,
220 __in_opt STDCALL_PFNFDINOTIFY pfnNotify,
221 __in DWORD64 dw64EmbeddedOffset
222 )
223{
224 HRESULT hr = S_OK;
225 BOOL fResult;
226
227 LPWSTR sczCabinet = NULL;
228 LPWSTR pwz = NULL;
229 CHAR szCabDirectory[MAX_PATH * 4]; // Make sure these are big enough for UTF-8 strings
230 CHAR szCabFile[MAX_PATH * 4];
231
232 CAB_CALLBACK_STRUCT ccs;
233 PFNFDINOTIFY pfnFdiNotify;
234
235 //
236 // ensure the cabinet.dll is loaded
237 //
238 if (!vhfdi)
239 {
240 hr = LoadCabinetDll();
241 ExitOnFailure(hr, "failed to load CABINET.DLL");
242 }
243
244 hr = StrAllocString(&sczCabinet, wzCabinet, 0);
245 ExitOnFailure(hr, "Failed to make copy of cabinet name:%ls", wzCabinet);
246
247 //
248 // split the cabinet full path into directory and filename and convert to multi-byte (ick!)
249 //
250 pwz = FileFromPath(sczCabinet);
251 ExitOnNull(pwz, hr, E_INVALIDARG, "failed to process cabinet path: %ls", wzCabinet);
252
253 if (!::WideCharToMultiByte(CP_UTF8, 0, pwz, -1, szCabFile, countof(szCabFile), NULL, NULL))
254 {
255 ExitWithLastError(hr, "failed to convert cabinet filename to ASCII: %ls", pwz);
256 }
257
258 *pwz = '\0';
259
260 // If a full path was not provided, use the relative current directory.
261 if (wzCabinet == pwz)
262 {
263 hr = ::StringCchCopyA(szCabDirectory, countof(szCabDirectory), ".\\");
264 ExitOnFailure(hr, "Failed to copy relative current directory as cabinet directory.");
265 }
266 else
267 {
268 if (!::WideCharToMultiByte(CP_UTF8, 0, sczCabinet, -1, szCabDirectory, countof(szCabDirectory), NULL, NULL))
269 {
270 ExitWithLastError(hr, "failed to convert cabinet directory to ASCII: %ls", sczCabinet);
271 }
272 }
273
274 //
275 // iterate through files in cabinet extracting them to the callback function
276 //
277 ccs.fStopExtracting = FALSE;
278 ccs.pwzExtract = wzExtractFile;
279 ccs.pwzExtractDir = wzExtractDir;
280 ccs.pfnProgress = pfnProgress;
281 ccs.pvContext = pvContext;
282
283 vdw64EmbeddedOffset = dw64EmbeddedOffset;
284
285 // if pfnNotify is given, use it, otherwise use default callback
286 if (NULL == pfnNotify)
287 {
288 pfnFdiNotify = CabExtractCallback;
289 }
290 else
291 {
292 v_pfnNetFx11Notify = pfnNotify;
293 pfnFdiNotify = FDINotify;
294 }
295 fResult = vpfnFDICopy(vhfdi, szCabFile, szCabDirectory, 0, pfnFdiNotify, NULL, static_cast<void*>(&ccs));
296 if (!fResult && !ccs.fStopExtracting) // if something went wrong and it wasn't us just stopping the extraction, then return a failure
297 {
298 ExitWithLastError(hr, "failed to extract cabinet file: %ls", sczCabinet);
299 }
300
301LExit:
302 ReleaseStr(sczCabinet);
303 v_pfnNetFx11Notify = NULL;
304
305 return hr;
306}
307
308/****************************************************************************
309 default extract routines
310
311****************************************************************************/
312static __callback LPVOID DIAMONDAPI CabExtractAlloc(__in DWORD dwSize)
313{
314 return MemAlloc(dwSize, FALSE);
315}
316
317
318static __callback void DIAMONDAPI CabExtractFree(__in LPVOID pvData)
319{
320 MemFree(pvData);
321}
322
323
324static __callback INT_PTR FAR DIAMONDAPI CabExtractOpen(__in_z PSTR pszFile, __in int oflag, __in int pmode)
325{
326 HRESULT hr = S_OK;
327 INT_PTR pFile = -1;
328 LPWSTR sczCabFile = NULL;
329
330 // if FDI asks for some unusual mode (in low memory situation it could ask for a scratch file) fail
331 if ((oflag != (/*_O_BINARY*/ 0x8000 | /*_O_RDONLY*/ 0x0000)) || (pmode != (_S_IREAD | _S_IWRITE)))
332 {
333 hr = E_OUTOFMEMORY;
334 ExitOnFailure(hr, "FDI asked for a scratch file to be created, which is unsupported");
335 }
336
337 hr = StrAllocStringAnsi(&sczCabFile, pszFile, 0, CP_UTF8);
338 ExitOnFailure(hr, "Failed to convert UTF8 cab file name to wide character string");
339
340 pFile = reinterpret_cast<INT_PTR>(::CreateFileW(sczCabFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
341 if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(pFile))
342 {
343 ExitWithLastError(hr, "failed to open file: %ls", sczCabFile);
344 }
345
346 if (vdw64EmbeddedOffset)
347 {
348 hr = CabExtractSeek(pFile, 0, 0);
349 ExitOnFailure(hr, "Failed to seek to embedded offset %I64d", vdw64EmbeddedOffset);
350 }
351
352LExit:
353 ReleaseStr(sczCabFile);
354
355 return FAILED(hr) ? -1 : pFile;
356}
357
358
359static __callback UINT FAR DIAMONDAPI CabExtractRead(__in INT_PTR hf, __out void FAR *pv, __in UINT cb)
360{
361 HRESULT hr = S_OK;
362 DWORD cbRead = 0;
363
364 ExitOnNull(hf, hr, E_INVALIDARG, "Failed to read file during cabinet extraction - no file given to read");
365 if (!::ReadFile(reinterpret_cast<HANDLE>(hf), pv, cb, &cbRead, NULL))
366 {
367 ExitWithLastError(hr, "failed to read during cabinet extraction");
368 }
369
370LExit:
371 return FAILED(hr) ? -1 : cbRead;
372}
373
374
375static __callback UINT FAR DIAMONDAPI CabExtractWrite(__in INT_PTR hf, __in void FAR *pv, __in UINT cb)
376{
377 HRESULT hr = S_OK;
378 DWORD cbWrite = 0;
379
380 ExitOnNull(hf, hr, E_INVALIDARG, "Failed to write file during cabinet extraction - no file given to write");
381 if (!::WriteFile(reinterpret_cast<HANDLE>(hf), pv, cb, &cbWrite, NULL))
382 {
383 ExitWithLastError(hr, "failed to write during cabinet extraction");
384 }
385
386LExit:
387 return FAILED(hr) ? -1 : cbWrite;
388}
389
390
391static __callback long FAR DIAMONDAPI CabExtractSeek(__in INT_PTR hf, __in long dist, __in int seektype)
392{
393 HRESULT hr = S_OK;
394 DWORD dwMoveMethod;
395 LONG lMove = 0;
396
397 switch (seektype)
398 {
399 case 0: // SEEK_SET
400 dwMoveMethod = FILE_BEGIN;
401 dist += static_cast<long>(vdw64EmbeddedOffset);
402 break;
403 case 1: /// SEEK_CUR
404 dwMoveMethod = FILE_CURRENT;
405 break;
406 case 2: // SEEK_END
407 dwMoveMethod = FILE_END;
408 break;
409 default :
410 dwMoveMethod = 0;
411 hr = E_UNEXPECTED;
412 ExitOnFailure(hr, "unexpected seektype in FDISeek(): %d", seektype);
413 }
414
415 // SetFilePointer returns -1 if it fails (this will cause FDI to quit with an FDIERROR_USER_ABORT error.
416 // (Unless this happens while working on a cabinet, in which case FDI returns FDIERROR_CORRUPT_CABINET)
417 lMove = ::SetFilePointer(reinterpret_cast<HANDLE>(hf), dist, NULL, dwMoveMethod);
418 if (0xFFFFFFFF == lMove)
419 {
420 ExitWithLastError(hr, "failed to move file pointer %d bytes", dist);
421 }
422
423LExit:
424 return FAILED(hr) ? -1 : lMove - static_cast<long>(vdw64EmbeddedOffset);
425}
426
427
428static __callback int FAR DIAMONDAPI CabExtractClose(__in INT_PTR hf)
429{
430 HRESULT hr = S_OK;
431
432 if (!::CloseHandle(reinterpret_cast<HANDLE>(hf)))
433 {
434 ExitWithLastError(hr, "failed to close file during cabinet extraction");
435 }
436
437LExit:
438 return FAILED(hr) ? -1 : 0;
439}
440
441
442static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE iNotification, __inout FDINOTIFICATION *pFDINotify)
443{
444 Assert(pFDINotify->pv);
445
446 HRESULT hr = S_OK;
447 INT_PTR ipResult = 0; // result to return on success
448
449 CAB_CALLBACK_STRUCT* pccs = static_cast<CAB_CALLBACK_STRUCT*>(pFDINotify->pv);
450 LPCSTR sz;
451 WCHAR wz[MAX_PATH];
452 FILETIME ft;
453
454 switch (iNotification)
455 {
456 case fdintCOPY_FILE: // begin extracting a resource from cabinet
457 ExitOnNull(pFDINotify->psz1, hr, E_INVALIDARG, "No cabinet file ID given to convert");
458 ExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided");
459
460 if (pccs->fStopExtracting)
461 {
462 ExitFunction1(hr = S_FALSE); // no more extracting
463 }
464
465 // convert params to useful variables
466 sz = static_cast<LPCSTR>(pFDINotify->psz1);
467 if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz)))
468 {
469 ExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz);
470 }
471
472 if (pccs->pfnProgress)
473 {
474 hr = pccs->pfnProgress(TRUE, wz, pccs->pvContext);
475 if (S_OK != hr)
476 {
477 ExitFunction();
478 }
479 }
480
481 if (L'*' == *pccs->pwzExtract || 0 == lstrcmpW(pccs->pwzExtract, wz))
482 {
483 // get the created date for the resource in the cabinet
484 FILETIME ftLocal;
485 if (!::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ftLocal))
486 {
487 ExitWithLastError(hr, "failed to get time for resource: %ls", wz);
488 }
489 ::LocalFileTimeToFileTime(&ftLocal, &ft);
490
491
492 WCHAR wzPath[MAX_PATH];
493 hr = ::StringCchCopyW(wzPath, countof(wzPath), pccs->pwzExtractDir);
494 ExitOnFailure(hr, "failed to copy in extract directory: %ls for file: %ls", pccs->pwzExtractDir, wz);
495 hr = ::StringCchCatW(wzPath, countof(wzPath), wz);
496 ExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", wzPath, wz);
497
498 ipResult = reinterpret_cast<INT_PTR>(::CreateFileW(wzPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
499 if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(ipResult))
500 {
501 ExitWithLastError(hr, "failed to create file: %s", wzPath);
502 }
503
504 ::SetFileTime(reinterpret_cast<HANDLE>(ipResult), &ft, &ft, &ft); // try to set the file time (who cares if it fails)
505
506 if (::SetFilePointer(reinterpret_cast<HANDLE>(ipResult), pFDINotify->cb, NULL, FILE_BEGIN)) // try to set the end of the file (don't worry if this fails)
507 {
508 if (::SetEndOfFile(reinterpret_cast<HANDLE>(ipResult)))
509 {
510 ::SetFilePointer(reinterpret_cast<HANDLE>(ipResult), 0, NULL, FILE_BEGIN); // reset the file pointer
511 }
512 }
513 }
514 else // resource wasn't requested, skip it
515 {
516 hr = S_OK;
517 ipResult = 0;
518 }
519
520 break;
521 case fdintCLOSE_FILE_INFO: // resource extraction complete
522 Assert(pFDINotify->hf && pFDINotify->psz1);
523 ExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided");
524
525 // convert params to useful variables
526 sz = static_cast<LPCSTR>(pFDINotify->psz1);
527 ExitOnNull(sz, hr, E_INVALIDARG, "Failed to convert cabinet file id, because no cabinet file id was provided");
528
529 if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz)))
530 {
531 ExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz);
532 }
533
534 if (NULL != pFDINotify->hf) // just close the file
535 {
536 ::CloseHandle(reinterpret_cast<HANDLE>(pFDINotify->hf));
537 }
538
539 if (pccs->pfnProgress)
540 {
541 hr = pccs->pfnProgress(FALSE, wz, pccs->pvContext);
542 }
543
544 if (S_OK == hr && L'*' == *pccs->pwzExtract) // if everything is okay and we're extracting all files, keep going
545 {
546 ipResult = TRUE;
547 }
548 else // something went wrong or we only needed to extract one file
549 {
550 hr = S_OK;
551 ipResult = FALSE;
552 pccs->fStopExtracting = TRUE;
553 }
554
555 break;
556 case fdintPARTIAL_FILE: __fallthrough; // no action needed for these messages, fall through
557 case fdintNEXT_CABINET: __fallthrough;
558 case fdintENUMERATE: __fallthrough;
559 case fdintCABINET_INFO:
560 break;
561 default:
562 AssertSz(FALSE, "CabExtractCallback() - unknown FDI notification command");
563 };
564
565LExit:
566 return (S_OK == hr) ? ipResult : -1;
567}