Release 9.12.
[wine.git] / dlls / urlmon / file.c
blobda71991129bf51bcfc88888cfb157fb65f5c18f0
1 /*
2 * Copyright 2005 Jacek Caban
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "urlmon_main.h"
20 #include "winreg.h"
21 #include "shlwapi.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
27 typedef struct {
28 IUnknown IUnknown_inner;
29 IInternetProtocolEx IInternetProtocolEx_iface;
30 IInternetPriority IInternetPriority_iface;
32 IUnknown *outer;
34 HANDLE file;
35 ULONG size;
36 LONG priority;
38 LONG ref;
39 } FileProtocol;
41 static inline FileProtocol *impl_from_IUnknown(IUnknown *iface)
43 return CONTAINING_RECORD(iface, FileProtocol, IUnknown_inner);
46 static inline FileProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
48 return CONTAINING_RECORD(iface, FileProtocol, IInternetProtocolEx_iface);
51 static inline FileProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
53 return CONTAINING_RECORD(iface, FileProtocol, IInternetPriority_iface);
56 static HRESULT WINAPI FileProtocolUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
58 FileProtocol *This = impl_from_IUnknown(iface);
60 *ppv = NULL;
61 if(IsEqualGUID(&IID_IUnknown, riid)) {
62 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
63 *ppv = &This->IUnknown_inner;
64 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
65 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
66 *ppv = &This->IInternetProtocolEx_iface;
67 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
68 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
69 *ppv = &This->IInternetProtocolEx_iface;
70 }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
71 TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
72 *ppv = &This->IInternetProtocolEx_iface;
73 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
74 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
75 *ppv = &This->IInternetPriority_iface;
78 if(*ppv) {
79 IUnknown_AddRef((IUnknown*)*ppv);
80 return S_OK;
83 WARN("not supported interface %s\n", debugstr_guid(riid));
84 return E_NOINTERFACE;
87 static ULONG WINAPI FileProtocolUnk_AddRef(IUnknown *iface)
89 FileProtocol *This = impl_from_IUnknown(iface);
90 LONG ref = InterlockedIncrement(&This->ref);
91 TRACE("(%p) ref=%ld\n", This, ref);
92 return ref;
95 static ULONG WINAPI FileProtocolUnk_Release(IUnknown *iface)
97 FileProtocol *This = impl_from_IUnknown(iface);
98 LONG ref = InterlockedDecrement(&This->ref);
100 TRACE("(%p) ref=%ld\n", This, ref);
102 if(!ref) {
103 if(This->file != INVALID_HANDLE_VALUE)
104 CloseHandle(This->file);
105 free(This);
107 URLMON_UnlockModule();
110 return ref;
113 static const IUnknownVtbl FileProtocolUnkVtbl = {
114 FileProtocolUnk_QueryInterface,
115 FileProtocolUnk_AddRef,
116 FileProtocolUnk_Release
119 static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
121 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
122 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
123 return IUnknown_QueryInterface(This->outer, riid, ppv);
126 static ULONG WINAPI FileProtocol_AddRef(IInternetProtocolEx *iface)
128 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
129 TRACE("(%p)\n", This);
130 return IUnknown_AddRef(This->outer);
133 static ULONG WINAPI FileProtocol_Release(IInternetProtocolEx *iface)
135 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
136 TRACE("(%p)\n", This);
137 return IUnknown_Release(This->outer);
140 static HRESULT WINAPI FileProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
141 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
142 DWORD grfPI, HANDLE_PTR dwReserved)
144 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
145 IUri *uri;
146 HRESULT hres;
148 TRACE("(%p)->(%s %p %p %08lx %Ix)\n", This, debugstr_w(szUrl), pOIProtSink,
149 pOIBindInfo, grfPI, dwReserved);
151 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
152 if(FAILED(hres))
153 return hres;
155 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
156 pOIBindInfo, grfPI, (HANDLE*)dwReserved);
158 IUri_Release(uri);
159 return hres;
162 static HRESULT WINAPI FileProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
164 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
165 FIXME("(%p)->(%p)\n", This, pProtocolData);
166 return E_NOTIMPL;
169 static HRESULT WINAPI FileProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
170 DWORD dwOptions)
172 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
173 FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
174 return E_NOTIMPL;
177 static HRESULT WINAPI FileProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
179 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
181 TRACE("(%p)->(%08lx)\n", This, dwOptions);
183 return S_OK;
186 static HRESULT WINAPI FileProtocol_Suspend(IInternetProtocolEx *iface)
188 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
189 FIXME("(%p)\n", This);
190 return E_NOTIMPL;
193 static HRESULT WINAPI FileProtocol_Resume(IInternetProtocolEx *iface)
195 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
196 FIXME("(%p)\n", This);
197 return E_NOTIMPL;
200 static HRESULT WINAPI FileProtocol_Read(IInternetProtocolEx *iface, void *pv,
201 ULONG cb, ULONG *pcbRead)
203 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
204 DWORD read = 0;
206 TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
208 if (pcbRead)
209 *pcbRead = 0;
211 if(This->file == INVALID_HANDLE_VALUE)
212 return INET_E_DATA_NOT_AVAILABLE;
214 if (!ReadFile(This->file, pv, cb, &read, NULL))
215 return INET_E_DOWNLOAD_FAILURE;
217 if(pcbRead)
218 *pcbRead = read;
220 return cb == read ? S_OK : S_FALSE;
223 static HRESULT WINAPI FileProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
224 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
226 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
227 FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
228 return E_NOTIMPL;
231 static HRESULT WINAPI FileProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
233 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
235 TRACE("(%p)->(%08lx)\n", This, dwOptions);
237 return S_OK;
240 static HRESULT WINAPI FileProtocol_UnlockRequest(IInternetProtocolEx *iface)
242 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
244 TRACE("(%p)\n", This);
246 return S_OK;
249 static inline HRESULT report_result(IInternetProtocolSink *protocol_sink, HRESULT hres, DWORD res)
251 IInternetProtocolSink_ReportResult(protocol_sink, hres, res, NULL);
252 return hres;
255 static HRESULT WINAPI FileProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
256 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
257 DWORD grfPI, HANDLE *dwReserved)
259 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
260 WCHAR path[MAX_PATH], *ptr;
261 LARGE_INTEGER file_size;
262 HANDLE file_handle;
263 BINDINFO bindinfo;
264 DWORD grfBINDF = 0;
265 DWORD scheme, size;
266 LPWSTR mime = NULL;
267 BSTR ext;
268 HRESULT hres;
270 TRACE("(%p)->(%p %p %p %08lx %p)\n", This, pUri, pOIProtSink,
271 pOIBindInfo, grfPI, dwReserved);
273 if(!pUri)
274 return E_INVALIDARG;
276 scheme = 0;
277 hres = IUri_GetScheme(pUri, &scheme);
278 if(FAILED(hres))
279 return hres;
280 if(scheme != URL_SCHEME_FILE)
281 return E_INVALIDARG;
283 memset(&bindinfo, 0, sizeof(bindinfo));
284 bindinfo.cbSize = sizeof(BINDINFO);
285 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
286 if(FAILED(hres)) {
287 WARN("GetBindInfo failed: %08lx\n", hres);
288 return hres;
291 ReleaseBindInfo(&bindinfo);
293 if(!(grfBINDF & BINDF_FROMURLMON))
294 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DIRECTBIND, NULL);
296 if(This->file != INVALID_HANDLE_VALUE) {
297 IInternetProtocolSink_ReportData(pOIProtSink,
298 BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
299 This->size, This->size);
300 return S_OK;
303 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, L"");
305 size = 0;
306 hres = CoInternetParseIUri(pUri, PARSE_PATH_FROM_URL, 0, path, ARRAY_SIZE(path), &size, 0);
307 if(FAILED(hres)) {
308 WARN("CoInternetParseIUri failed: %08lx\n", hres);
309 return report_result(pOIProtSink, hres, 0);
312 file_handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
313 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
314 if(file_handle == INVALID_HANDLE_VALUE && (ptr = wcsrchr(path, '#'))) {
315 /* If path contains fragment part, try without it. */
316 *ptr = 0;
317 file_handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
318 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
320 if(file_handle == INVALID_HANDLE_VALUE)
321 return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, GetLastError());
323 if(!GetFileSizeEx(file_handle, &file_size)) {
324 CloseHandle(file_handle);
325 return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, GetLastError());
328 This->file = file_handle;
329 This->size = file_size.u.LowPart;
330 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_CACHEFILENAMEAVAILABLE, path);
332 hres = IUri_GetExtension(pUri, &ext);
333 if(SUCCEEDED(hres)) {
334 if(hres == S_OK && *ext) {
335 if((ptr = wcschr(ext, '#')))
336 *ptr = 0;
337 hres = find_mime_from_ext(ext, &mime);
338 if(SUCCEEDED(hres)) {
339 IInternetProtocolSink_ReportProgress(pOIProtSink,
340 (grfBINDF & BINDF_FROMURLMON) ?
341 BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE,
342 mime);
343 CoTaskMemFree(mime);
346 SysFreeString(ext);
349 IInternetProtocolSink_ReportData(pOIProtSink,
350 BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
351 This->size, This->size);
353 return report_result(pOIProtSink, S_OK, 0);
356 static const IInternetProtocolExVtbl FileProtocolExVtbl = {
357 FileProtocol_QueryInterface,
358 FileProtocol_AddRef,
359 FileProtocol_Release,
360 FileProtocol_Start,
361 FileProtocol_Continue,
362 FileProtocol_Abort,
363 FileProtocol_Terminate,
364 FileProtocol_Suspend,
365 FileProtocol_Resume,
366 FileProtocol_Read,
367 FileProtocol_Seek,
368 FileProtocol_LockRequest,
369 FileProtocol_UnlockRequest,
370 FileProtocol_StartEx
373 static HRESULT WINAPI FilePriority_QueryInterface(IInternetPriority *iface,
374 REFIID riid, void **ppv)
376 FileProtocol *This = impl_from_IInternetPriority(iface);
377 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
380 static ULONG WINAPI FilePriority_AddRef(IInternetPriority *iface)
382 FileProtocol *This = impl_from_IInternetPriority(iface);
383 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
386 static ULONG WINAPI FilePriority_Release(IInternetPriority *iface)
388 FileProtocol *This = impl_from_IInternetPriority(iface);
389 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
392 static HRESULT WINAPI FilePriority_SetPriority(IInternetPriority *iface, LONG nPriority)
394 FileProtocol *This = impl_from_IInternetPriority(iface);
396 TRACE("(%p)->(%ld)\n", This, nPriority);
398 This->priority = nPriority;
399 return S_OK;
402 static HRESULT WINAPI FilePriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
404 FileProtocol *This = impl_from_IInternetPriority(iface);
406 TRACE("(%p)->(%p)\n", This, pnPriority);
408 *pnPriority = This->priority;
409 return S_OK;
412 static const IInternetPriorityVtbl FilePriorityVtbl = {
413 FilePriority_QueryInterface,
414 FilePriority_AddRef,
415 FilePriority_Release,
416 FilePriority_SetPriority,
417 FilePriority_GetPriority
420 HRESULT FileProtocol_Construct(IUnknown *outer, LPVOID *ppobj)
422 FileProtocol *ret;
424 TRACE("(%p %p)\n", outer, ppobj);
426 URLMON_LockModule();
428 ret = malloc(sizeof(FileProtocol));
430 ret->IUnknown_inner.lpVtbl = &FileProtocolUnkVtbl;
431 ret->IInternetProtocolEx_iface.lpVtbl = &FileProtocolExVtbl;
432 ret->IInternetPriority_iface.lpVtbl = &FilePriorityVtbl;
433 ret->file = INVALID_HANDLE_VALUE;
434 ret->priority = 0;
435 ret->ref = 1;
436 ret->outer = outer ? outer : &ret->IUnknown_inner;
438 *ppobj = &ret->IUnknown_inner;
439 return S_OK;