Sync with trunk r63174.
[reactos.git] / dll / win32 / urlmon / file.c
1 /*
2 * Copyright 2005 Jacek Caban
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include "urlmon_main.h"
20
21 typedef struct {
22 IInternetProtocolEx IInternetProtocolEx_iface;
23 IInternetPriority IInternetPriority_iface;
24
25 HANDLE file;
26 ULONG size;
27 LONG priority;
28
29 LONG ref;
30 } FileProtocol;
31
32 static inline FileProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
33 {
34 return CONTAINING_RECORD(iface, FileProtocol, IInternetProtocolEx_iface);
35 }
36
37 static inline FileProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
38 {
39 return CONTAINING_RECORD(iface, FileProtocol, IInternetPriority_iface);
40 }
41
42 static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
43 {
44 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
45
46 *ppv = NULL;
47 if(IsEqualGUID(&IID_IUnknown, riid)) {
48 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
49 *ppv = &This->IInternetProtocolEx_iface;
50 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
51 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
52 *ppv = &This->IInternetProtocolEx_iface;
53 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
54 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
55 *ppv = &This->IInternetProtocolEx_iface;
56 }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
57 TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
58 *ppv = &This->IInternetProtocolEx_iface;
59 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
60 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
61 *ppv = &This->IInternetPriority_iface;
62 }
63
64 if(*ppv) {
65 IInternetProtocolEx_AddRef(iface);
66 return S_OK;
67 }
68
69 WARN("not supported interface %s\n", debugstr_guid(riid));
70 return E_NOINTERFACE;
71 }
72
73 static ULONG WINAPI FileProtocol_AddRef(IInternetProtocolEx *iface)
74 {
75 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
76 LONG ref = InterlockedIncrement(&This->ref);
77 TRACE("(%p) ref=%d\n", This, ref);
78 return ref;
79 }
80
81 static ULONG WINAPI FileProtocol_Release(IInternetProtocolEx *iface)
82 {
83 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
84 LONG ref = InterlockedDecrement(&This->ref);
85
86 TRACE("(%p) ref=%d\n", This, ref);
87
88 if(!ref) {
89 if(This->file != INVALID_HANDLE_VALUE)
90 CloseHandle(This->file);
91 heap_free(This);
92
93 URLMON_UnlockModule();
94 }
95
96 return ref;
97 }
98
99 static HRESULT WINAPI FileProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
100 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
101 DWORD grfPI, HANDLE_PTR dwReserved)
102 {
103 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
104 IUri *uri;
105 HRESULT hres;
106
107 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
108 pOIBindInfo, grfPI, dwReserved);
109
110 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
111 if(FAILED(hres))
112 return hres;
113
114 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
115 pOIBindInfo, grfPI, (HANDLE*)dwReserved);
116
117 IUri_Release(uri);
118 return hres;
119 }
120
121 static HRESULT WINAPI FileProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
122 {
123 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
124 FIXME("(%p)->(%p)\n", This, pProtocolData);
125 return E_NOTIMPL;
126 }
127
128 static HRESULT WINAPI FileProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
129 DWORD dwOptions)
130 {
131 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
132 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
133 return E_NOTIMPL;
134 }
135
136 static HRESULT WINAPI FileProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
137 {
138 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
139
140 TRACE("(%p)->(%08x)\n", This, dwOptions);
141
142 return S_OK;
143 }
144
145 static HRESULT WINAPI FileProtocol_Suspend(IInternetProtocolEx *iface)
146 {
147 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
148 FIXME("(%p)\n", This);
149 return E_NOTIMPL;
150 }
151
152 static HRESULT WINAPI FileProtocol_Resume(IInternetProtocolEx *iface)
153 {
154 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
155 FIXME("(%p)\n", This);
156 return E_NOTIMPL;
157 }
158
159 static HRESULT WINAPI FileProtocol_Read(IInternetProtocolEx *iface, void *pv,
160 ULONG cb, ULONG *pcbRead)
161 {
162 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
163 DWORD read = 0;
164
165 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
166
167 if (pcbRead)
168 *pcbRead = 0;
169
170 if(This->file == INVALID_HANDLE_VALUE)
171 return INET_E_DATA_NOT_AVAILABLE;
172
173 if (!ReadFile(This->file, pv, cb, &read, NULL))
174 return INET_E_DOWNLOAD_FAILURE;
175
176 if(pcbRead)
177 *pcbRead = read;
178
179 return cb == read ? S_OK : S_FALSE;
180 }
181
182 static HRESULT WINAPI FileProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
183 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
184 {
185 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
186 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
187 return E_NOTIMPL;
188 }
189
190 static HRESULT WINAPI FileProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
191 {
192 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
193
194 TRACE("(%p)->(%08x)\n", This, dwOptions);
195
196 return S_OK;
197 }
198
199 static HRESULT WINAPI FileProtocol_UnlockRequest(IInternetProtocolEx *iface)
200 {
201 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
202
203 TRACE("(%p)\n", This);
204
205 return S_OK;
206 }
207
208 static inline HRESULT report_result(IInternetProtocolSink *protocol_sink, HRESULT hres, DWORD res)
209 {
210 IInternetProtocolSink_ReportResult(protocol_sink, hres, res, NULL);
211 return hres;
212 }
213
214 static HRESULT open_file(FileProtocol *This, const WCHAR *path, IInternetProtocolSink *protocol_sink)
215 {
216 LARGE_INTEGER size;
217 HANDLE file;
218
219 file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
220 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
221 if(file == INVALID_HANDLE_VALUE)
222 return report_result(protocol_sink, INET_E_RESOURCE_NOT_FOUND, GetLastError());
223
224 if(!GetFileSizeEx(file, &size)) {
225 CloseHandle(file);
226 return report_result(protocol_sink, INET_E_RESOURCE_NOT_FOUND, GetLastError());
227 }
228
229 This->file = file;
230 This->size = size.u.LowPart;
231
232 IInternetProtocolSink_ReportProgress(protocol_sink,
233 BINDSTATUS_CACHEFILENAMEAVAILABLE, path);
234 return S_OK;
235 }
236
237 static HRESULT WINAPI FileProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
238 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
239 DWORD grfPI, HANDLE *dwReserved)
240 {
241 FileProtocol *This = impl_from_IInternetProtocolEx(iface);
242 WCHAR path[MAX_PATH];
243 BINDINFO bindinfo;
244 DWORD grfBINDF = 0;
245 DWORD scheme, size;
246 LPWSTR mime = NULL;
247 WCHAR null_char = 0;
248 BSTR url;
249 HRESULT hres;
250
251 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink,
252 pOIBindInfo, grfPI, dwReserved);
253
254 if(!pUri)
255 return E_INVALIDARG;
256
257 scheme = 0;
258 hres = IUri_GetScheme(pUri, &scheme);
259 if(FAILED(hres))
260 return hres;
261 if(scheme != URL_SCHEME_FILE)
262 return E_INVALIDARG;
263
264 memset(&bindinfo, 0, sizeof(bindinfo));
265 bindinfo.cbSize = sizeof(BINDINFO);
266 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
267 if(FAILED(hres)) {
268 WARN("GetBindInfo failed: %08x\n", hres);
269 return hres;
270 }
271
272 ReleaseBindInfo(&bindinfo);
273
274 if(!(grfBINDF & BINDF_FROMURLMON))
275 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DIRECTBIND, NULL);
276
277 if(This->file != INVALID_HANDLE_VALUE) {
278 IInternetProtocolSink_ReportData(pOIProtSink,
279 BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
280 This->size, This->size);
281 return S_OK;
282 }
283
284 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, &null_char);
285
286 size = 0;
287 hres = CoInternetParseIUri(pUri, PARSE_PATH_FROM_URL, 0, path, sizeof(path)/sizeof(WCHAR), &size, 0);
288 if(FAILED(hres)) {
289 WARN("CoInternetParseIUri failed: %08x\n", hres);
290 return report_result(pOIProtSink, hres, 0);
291 }
292
293 hres = open_file(This, path, pOIProtSink);
294 if(FAILED(hres))
295 return hres;
296
297 hres = IUri_GetDisplayUri(pUri, &url);
298 if(hres == S_OK) {
299 hres = FindMimeFromData(NULL, url, NULL, 0, NULL, 0, &mime, 0);
300 SysFreeString(url);
301 if(SUCCEEDED(hres)) {
302 IInternetProtocolSink_ReportProgress(pOIProtSink,
303 (grfBINDF & BINDF_FROMURLMON) ?
304 BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE,
305 mime);
306 CoTaskMemFree(mime);
307 }
308 }
309
310 IInternetProtocolSink_ReportData(pOIProtSink,
311 BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
312 This->size, This->size);
313
314 return report_result(pOIProtSink, S_OK, 0);
315 }
316
317 static const IInternetProtocolExVtbl FileProtocolExVtbl = {
318 FileProtocol_QueryInterface,
319 FileProtocol_AddRef,
320 FileProtocol_Release,
321 FileProtocol_Start,
322 FileProtocol_Continue,
323 FileProtocol_Abort,
324 FileProtocol_Terminate,
325 FileProtocol_Suspend,
326 FileProtocol_Resume,
327 FileProtocol_Read,
328 FileProtocol_Seek,
329 FileProtocol_LockRequest,
330 FileProtocol_UnlockRequest,
331 FileProtocol_StartEx
332 };
333
334 static HRESULT WINAPI FilePriority_QueryInterface(IInternetPriority *iface,
335 REFIID riid, void **ppv)
336 {
337 FileProtocol *This = impl_from_IInternetPriority(iface);
338 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
339 }
340
341 static ULONG WINAPI FilePriority_AddRef(IInternetPriority *iface)
342 {
343 FileProtocol *This = impl_from_IInternetPriority(iface);
344 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
345 }
346
347 static ULONG WINAPI FilePriority_Release(IInternetPriority *iface)
348 {
349 FileProtocol *This = impl_from_IInternetPriority(iface);
350 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
351 }
352
353 static HRESULT WINAPI FilePriority_SetPriority(IInternetPriority *iface, LONG nPriority)
354 {
355 FileProtocol *This = impl_from_IInternetPriority(iface);
356
357 TRACE("(%p)->(%d)\n", This, nPriority);
358
359 This->priority = nPriority;
360 return S_OK;
361 }
362
363 static HRESULT WINAPI FilePriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
364 {
365 FileProtocol *This = impl_from_IInternetPriority(iface);
366
367 TRACE("(%p)->(%p)\n", This, pnPriority);
368
369 *pnPriority = This->priority;
370 return S_OK;
371 }
372
373 static const IInternetPriorityVtbl FilePriorityVtbl = {
374 FilePriority_QueryInterface,
375 FilePriority_AddRef,
376 FilePriority_Release,
377 FilePriority_SetPriority,
378 FilePriority_GetPriority
379 };
380
381 HRESULT FileProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
382 {
383 FileProtocol *ret;
384
385 TRACE("(%p %p)\n", pUnkOuter, ppobj);
386
387 URLMON_LockModule();
388
389 ret = heap_alloc(sizeof(FileProtocol));
390
391 ret->IInternetProtocolEx_iface.lpVtbl = &FileProtocolExVtbl;
392 ret->IInternetPriority_iface.lpVtbl = &FilePriorityVtbl;
393 ret->file = INVALID_HANDLE_VALUE;
394 ret->priority = 0;
395 ret->ref = 1;
396
397 *ppobj = &ret->IInternetProtocolEx_iface;
398 return S_OK;
399 }