ReactOS 0.4.16-dev-533-gc7d1aa3
extract.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS CabView Shell Extension
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: FDI API wrapper
5 * COPYRIGHT: Copyright 2024 Whindmar Saksit <whindsaks@proton.me>
6 */
7
8#include "precomp.h"
9#include "cabview.h"
10#include "util.h"
11#include <fcntl.h>
12
14{
18};
19
21{
22 UINT cp = Attr & _A_NAME_IS_UTF ? CP_UTF8 : CP_ACP;
23 UINT cchfile = MultiByteToWideChar(cp, 0, File, -1, 0, 0);
24 SIZE_T lendir = lstrlenW(Dir), cch = lendir + 1 + cchfile;
25 LPWSTR path = (LPWSTR)SHAlloc(cch * sizeof(*path));
26 if (path)
27 {
28 lstrcpyW(path, Dir);
29 if (lendir && !IsPathSep(path[lendir - 1]))
30 path[lendir++] = '\\';
31
32 LPWSTR dst = &path[lendir];
33 MultiByteToWideChar(cp, 0, File + IsPathSep(*File), -1, dst, cchfile);
34 for (SIZE_T i = 0; dst[i]; ++i)
35 {
36 if (dst[i] == L':' && lendir) // Don't allow absolute paths
37 dst[i] = L'_';
38 if (dst[i] == L'/') // Normalize
39 dst[i] = L'\\';
40 }
41 }
42 return path;
43}
44
45static HRESULT HResultFrom(const ERF &erf)
46{
47 switch (erf.fError ? erf.erfOper : FDIERROR_NONE)
48 {
49 case FDIERROR_NONE:
50 return erf.fError ? HRESULT_FROM_WIN32(erf.erfType) : S_OK;
54 return E_OUTOFMEMORY;
56 return S_FALSE;
57 default:
58 return erf.erfType ? HRESULT_FROM_WIN32(erf.erfType) : E_FAIL;
59 }
60}
61
62FNFREE(CabMemFree)
63{
64 SHFree(pv);
65}
66
67FNALLOC(CabMemAlloc)
68{
69 return SHAlloc(cb);
70}
71
72FNCLOSE(CabClose)
73{
74 return CloseHandle((HANDLE)hf) ? 0 : -1;
75}
76
78{
79 return (INT_PTR)CreateFileW(path, access, share, NULL, disp, attr, NULL);
80}
81
82FNOPEN(CabOpen)
83{
84 UINT disp = (oflag & _O_CREAT) ? CREATE_ALWAYS : OPEN_EXISTING;
86 if (oflag & _O_RDWR)
88 else if (oflag & _O_WRONLY)
91 WCHAR buf[MAX_PATH * 2];
92 MultiByteToWideChar(CP_UTF8, 0, pszFile, -1, buf, _countof(buf));
94}
95
96FNREAD(CabRead)
97{
98 DWORD dwBytesRead;
99 return ReadFile((HANDLE)hf, pv, cb, &dwBytesRead, NULL) ? dwBytesRead : -1;
100}
101
102FNWRITE(CabWrite)
103{
104 DWORD dwBytesWritten;
105 return WriteFile((HANDLE)hf, pv, cb, &dwBytesWritten, NULL) ? dwBytesWritten : -1;
106}
107
108FNSEEK(CabSeek)
109{
110 return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
111}
112
113static HRESULT Init(HFDI &hfdi, ERF &erf)
114{
115 const int cpu = cpuUNKNOWN;
116 hfdi = FDICreate(CabMemAlloc, CabMemFree, CabOpen, CabRead, CabWrite, CabClose, CabSeek, cpu, &erf);
117 return hfdi ? S_OK : HResultFrom(erf);
118}
119
120FNFDINOTIFY(ExtractCabinetCallback)
121{
125 HRESULT hr;
126 FILETIME ft;
127
128 noti.pfdin = pfdin;
129 switch (fdint)
130 {
131 case fdintCOPY_FILE:
132 hr = ecd.callback(ECM_FILE, noti, ecd.cookie);
133 if (hr == S_OK)
134 {
136 LPWSTR path = BuildPath(ecd.destination, pfdin->psz1, pfdin->attribs);
137 if (path)
138 {
139 // Callee is using SHPPFW_IGNOREFILENAME so we don't need to remove the name.
140 /*LPWSTR file = PathFindFileNameW(path);
141 if (file > path)
142 {
143 file[-1] = L'\0';*/
144 noti.Path = path;
145 ecd.callback(ECM_PREPAREPATH, noti, ecd.cookie);
146 /* file[-1] = L'\\';
147 }*/
148 UINT attr = pfdin->attribs & attrmask;
151 noti.hr = HResultFromWin32(GetLastError());
152 SHFree(path);
153 if (handle != (INT_PTR)-1)
154 return handle;
155 if (ecd.callback(ECM_ERROR, noti, ecd.cookie) != E_NOTIMPL)
156 hr = noti.hr;
157 }
158 }
159 return hr == S_FALSE ? 0 : -1;
160
162 if (DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
163 SetFileTime((HANDLE)(pfdin->hf), NULL, NULL, &ft);
164 return !CabClose(pfdin->hf);
165
167 if (pfdin->fdie && pfdin->fdie != FDIERROR_USER_ABORT)
168 {
169 if (pfdin->fdie == FDIERROR_CABINET_NOT_FOUND)
171 else
173 ecd.callback(ECM_ERROR, noti, ecd.cookie);
174 }
175 return pfdin->fdie ? -1 : 0;
176
178 return 0;
179
181 return 0;
182
183 case fdintENUMERATE:
184 return 0;
185 }
186 return -1;
187}
188
190{
191 BOOL quick = !destination;
192 if (!destination)
193 destination = L"?:"; // Dummy path for callers that enumerate without extracting
196 ERF erf = { };
197 HFDI hfdi;
198 UINT total = 0, files = 0;
199 HRESULT hr = Init(hfdi, erf);
201 return hr;
202
204 INT_PTR hf = quick ? -1 : CabOpenEx(cab, GENERIC_READ, share, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL);
205 if (hf != -1)
206 {
208 if (FDIIsCabinet(hfdi, hf, &ci))
209 {
210 total = ci.cbCabinet;
211 files = ci.cFiles;
212 }
213 CabClose(hf);
214 }
215
217 char buf[MAX_PATH * 2], *name = 0;
218 if (!WideCharToMultiByte(CP_UTF8, 0, cab, -1, buf, _countof(buf), NULL, NULL))
219 {
220 *buf = '\0';
222 }
223 for (UINT i = 0; buf[i]; ++i)
224 {
225 if (buf[i] == '\\' || buf[i] == '/')
226 name = &buf[i + 1];
227 }
228 if (name > buf && *name)
229 {
230 // Format the name the way FDI likes it
231 name[-1] = ANSI_NULL;
232 char namebuf[MAX_PATH];
233 namebuf[0] = '\\';
234 lstrcpyA(namebuf + 1, name);
235 name = namebuf;
236
237 FDINOTIFICATION fdin;
238 fdin.cb = total;
239 fdin.hf = files;
240 noti.Path = cab;
241 noti.pfdin = &fdin;
242 callback(ECM_BEGIN, noti, cookie);
243
244 hr = FDICopy(hfdi, name, buf, 0, ExtractCabinetCallback, NULL, &data) ? S_OK : HResultFrom(erf);
245 }
246 FDIDestroy(hfdi);
247 return hr;
248}
BOOL(CALLBACK * EXTRACTCALLBACK)(const EXTRACTCALLBACKINFO &Info, void *Cookie)
Definition: misc.h:55
@ ECM_ERROR
Definition: cabview.h:16
@ ECM_BEGIN
Definition: cabview.h:16
@ ECM_FILE
Definition: cabview.h:16
@ ECM_PREPAREPATH
Definition: cabview.h:16
Definition: File.h:16
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define NULL
Definition: types.h:112
static bool IsPathSep(T c)
Definition: util.h:16
#define _O_RDWR
Definition: cabinet.h:39
#define _O_CREAT
Definition: cabinet.h:46
#define _O_WRONLY
Definition: cabinet.h:38
HFDI __cdecl FDICreate(PFNALLOC pfnalloc, PFNFREE pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, PERF perf)
Definition: fdi.c:412
BOOL __cdecl FDIIsCabinet(HFDI hfdi, INT_PTR hf, PFDICABINETINFO pfdici)
Definition: fdi.c:696
BOOL __cdecl FDICopy(HFDI hfdi, char *pszCabinet, char *pszCabPath, int flags, PFNFDINOTIFY pfnfdin, PFNFDIDECRYPT pfnfdid, void *pvUser)
Definition: fdi.c:2431
BOOL __cdecl FDIDestroy(HFDI hfdi)
Definition: fdi.c:2831
#define CloseHandle
Definition: compat.h:739
#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 GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define CreateFileW
Definition: compat.h:741
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define lstrcpyW
Definition: compat.h:749
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define FILE_SHARE_READ
Definition: compat.h:136
#define lstrlenW
Definition: compat.h:750
#define FAILED_UNEXPECTEDLY(hr)
Definition: precomp.h:121
BOOL WINAPI SetFileTime(IN HANDLE hFile, CONST FILETIME *lpCreationTime OPTIONAL, CONST FILETIME *lpLastAccessTime OPTIONAL, CONST FILETIME *lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:948
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
BOOL WINAPI DosDateTimeToFileTime(IN WORD wFatDate, IN WORD wFatTime, OUT LPFILETIME lpFileTime)
Definition: time.c:75
void WINAPI SHFree(LPVOID pv)
Definition: shellole.c:326
LPVOID WINAPI SHAlloc(SIZE_T len)
Definition: shellole.c:304
switch(r->id)
Definition: btrfs.c:3046
static HRESULT HResultFrom(const ERF &erf)
Definition: extract.cpp:45
HRESULT ExtractCabinet(LPCWSTR cab, LPCWSTR destination, EXTRACTCALLBACK callback, LPVOID cookie)
Definition: extract.cpp:189
static LPWSTR BuildPath(LPCWSTR Dir, LPCSTR File, UINT Attr)
Definition: extract.cpp:20
static INT_PTR CabOpenEx(LPCWSTR path, UINT access, UINT share, UINT disp, UINT attr)
Definition: extract.cpp:77
#define _A_NAME_IS_UTF
Definition: fci.h:131
#define FNSEEK(fn)
Definition: fdi.h:221
@ FDIERROR_USER_ABORT
Definition: fdi.h:126
@ FDIERROR_NONE
Definition: fdi.h:115
@ FDIERROR_ALLOC_FAIL
Definition: fdi.h:120
@ FDIERROR_CABINET_NOT_FOUND
Definition: fdi.h:116
#define FNALLOC(fn)
Definition: fdi.h:203
#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
#define FNREAD(fn)
Definition: fdi.h:212
#define FNFDINOTIFY(fn)
Definition: fdi.h:257
#define FNWRITE(fn)
Definition: fdi.h:215
#define cpuUNKNOWN
Definition: fdi.h:269
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
size_t total
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLenum dst
Definition: glext.h:6340
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
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 GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define S_OK
Definition: intsafe.h:52
LPSTR WINAPI lstrcpyA(LPSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:100
POINT cp
Definition: magnifier.c:59
double __cdecl erf(double)
#define CREATE_ALWAYS
Definition: disk.h:72
#define CREATE_NEW
Definition: disk.h:69
#define FILE_FLAG_SEQUENTIAL_SCAN
Definition: disk.h:43
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
static IPrintDialogCallback callback
Definition: printdlg.c:326
static DWORD DWORD void LPSTR DWORD cch
Definition: str.c:202
static HMODULE MODULEINFO DWORD cb
Definition: module.c:33
unsigned int UINT
Definition: ndis.h:50
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
#define FILE_ATTRIBUTE_ARCHIVE
Definition: nt_native.h:706
#define GENERIC_WRITE
Definition: nt_native.h:90
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
#define ANSI_NULL
#define L(x)
Definition: ntvdm.h:50
#define CP_UTF8
Definition: nls.h:20
HRESULT HResultFromWin32(DWORD hr)
Definition: shellutils.h:70
HRESULT hr
Definition: shlfolder.c:183
#define _countof(array)
Definition: sndvol32.h:70
Definition: fci.h:44
EXTRACTCALLBACK callback
Definition: extract.cpp:16
const FDINOTIFICATION * pfdin
Definition: cabview.h:20
USHORT cFiles
Definition: fdi.h:148
LONG cbCabinet
Definition: fdi.h:146
INT_PTR hf
Definition: fdi.h:233
LONG cb
Definition: fdi.h:227
Definition: cookie.c:202
Definition: cookie.c:34
Definition: name.c:39
int32_t INT_PTR
Definition: typedefs.h:64
ULONG_PTR SIZE_T
Definition: typedefs.h:80
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define S_FALSE
Definition: winerror.h:2357
#define HRESULT_FROM_WIN32(x)
Definition: winerror.h:92
#define ERROR_INVALID_DATA
Definition: winerror.h:116
const char * LPCSTR
Definition: xmlstorage.h:183
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185