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 #include "winreg.h" 21 #include "shlwapi.h" 22 23 #include "wine/debug.h" 24 25 WINE_DEFAULT_DEBUG_CHANNEL(urlmon); 26 27 typedef struct { 28 IUnknown IUnknown_inner; 29 IInternetProtocolEx IInternetProtocolEx_iface; 30 IInternetPriority IInternetPriority_iface; 31 32 IUnknown *outer; 33 34 HANDLE file; 35 ULONG size; 36 LONG priority; 37 38 LONG ref; 39 } FileProtocol; 40 41 static inline FileProtocol *impl_from_IUnknown(IUnknown *iface) 42 { 43 return CONTAINING_RECORD(iface, FileProtocol, IUnknown_inner); 44 } 45 46 static inline FileProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface) 47 { 48 return CONTAINING_RECORD(iface, FileProtocol, IInternetProtocolEx_iface); 49 } 50 51 static inline FileProtocol *impl_from_IInternetPriority(IInternetPriority *iface) 52 { 53 return CONTAINING_RECORD(iface, FileProtocol, IInternetPriority_iface); 54 } 55 56 static HRESULT WINAPI FileProtocolUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 57 { 58 FileProtocol *This = impl_from_IUnknown(iface); 59 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; 76 } 77 78 if(*ppv) { 79 IUnknown_AddRef((IUnknown*)*ppv); 80 return S_OK; 81 } 82 83 WARN("not supported interface %s\n", debugstr_guid(riid)); 84 return E_NOINTERFACE; 85 } 86 87 static ULONG WINAPI FileProtocolUnk_AddRef(IUnknown *iface) 88 { 89 FileProtocol *This = impl_from_IUnknown(iface); 90 LONG ref = InterlockedIncrement(&This->ref); 91 TRACE("(%p) ref=%d\n", This, ref); 92 return ref; 93 } 94 95 static ULONG WINAPI FileProtocolUnk_Release(IUnknown *iface) 96 { 97 FileProtocol *This = impl_from_IUnknown(iface); 98 LONG ref = InterlockedDecrement(&This->ref); 99 100 TRACE("(%p) ref=%d\n", This, ref); 101 102 if(!ref) { 103 if(This->file != INVALID_HANDLE_VALUE) 104 CloseHandle(This->file); 105 heap_free(This); 106 107 URLMON_UnlockModule(); 108 } 109 110 return ref; 111 } 112 113 static const IUnknownVtbl FileProtocolUnkVtbl = { 114 FileProtocolUnk_QueryInterface, 115 FileProtocolUnk_AddRef, 116 FileProtocolUnk_Release 117 }; 118 119 static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv) 120 { 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); 124 } 125 126 static ULONG WINAPI FileProtocol_AddRef(IInternetProtocolEx *iface) 127 { 128 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 129 TRACE("(%p)\n", This); 130 return IUnknown_AddRef(This->outer); 131 } 132 133 static ULONG WINAPI FileProtocol_Release(IInternetProtocolEx *iface) 134 { 135 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 136 TRACE("(%p)\n", This); 137 return IUnknown_Release(This->outer); 138 } 139 140 static HRESULT WINAPI FileProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl, 141 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, 142 DWORD grfPI, HANDLE_PTR dwReserved) 143 { 144 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 145 IUri *uri; 146 HRESULT hres; 147 148 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, 149 pOIBindInfo, grfPI, dwReserved); 150 151 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri); 152 if(FAILED(hres)) 153 return hres; 154 155 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink, 156 pOIBindInfo, grfPI, (HANDLE*)dwReserved); 157 158 IUri_Release(uri); 159 return hres; 160 } 161 162 static HRESULT WINAPI FileProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData) 163 { 164 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 165 FIXME("(%p)->(%p)\n", This, pProtocolData); 166 return E_NOTIMPL; 167 } 168 169 static HRESULT WINAPI FileProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason, 170 DWORD dwOptions) 171 { 172 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 173 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); 174 return E_NOTIMPL; 175 } 176 177 static HRESULT WINAPI FileProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions) 178 { 179 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 180 181 TRACE("(%p)->(%08x)\n", This, dwOptions); 182 183 return S_OK; 184 } 185 186 static HRESULT WINAPI FileProtocol_Suspend(IInternetProtocolEx *iface) 187 { 188 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 189 FIXME("(%p)\n", This); 190 return E_NOTIMPL; 191 } 192 193 static HRESULT WINAPI FileProtocol_Resume(IInternetProtocolEx *iface) 194 { 195 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 196 FIXME("(%p)\n", This); 197 return E_NOTIMPL; 198 } 199 200 static HRESULT WINAPI FileProtocol_Read(IInternetProtocolEx *iface, void *pv, 201 ULONG cb, ULONG *pcbRead) 202 { 203 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 204 DWORD read = 0; 205 206 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); 207 208 if (pcbRead) 209 *pcbRead = 0; 210 211 if(This->file == INVALID_HANDLE_VALUE) 212 return INET_E_DATA_NOT_AVAILABLE; 213 214 if (!ReadFile(This->file, pv, cb, &read, NULL)) 215 return INET_E_DOWNLOAD_FAILURE; 216 217 if(pcbRead) 218 *pcbRead = read; 219 220 return cb == read ? S_OK : S_FALSE; 221 } 222 223 static HRESULT WINAPI FileProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove, 224 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 225 { 226 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 227 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); 228 return E_NOTIMPL; 229 } 230 231 static HRESULT WINAPI FileProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions) 232 { 233 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 234 235 TRACE("(%p)->(%08x)\n", This, dwOptions); 236 237 return S_OK; 238 } 239 240 static HRESULT WINAPI FileProtocol_UnlockRequest(IInternetProtocolEx *iface) 241 { 242 FileProtocol *This = impl_from_IInternetProtocolEx(iface); 243 244 TRACE("(%p)\n", This); 245 246 return S_OK; 247 } 248 249 static inline HRESULT report_result(IInternetProtocolSink *protocol_sink, HRESULT hres, DWORD res) 250 { 251 IInternetProtocolSink_ReportResult(protocol_sink, hres, res, NULL); 252 return hres; 253 } 254 255 static HRESULT WINAPI FileProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri, 256 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, 257 DWORD grfPI, HANDLE *dwReserved) 258 { 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 WCHAR null_char = 0; 268 BSTR ext; 269 HRESULT hres; 270 271 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, 272 pOIBindInfo, grfPI, dwReserved); 273 274 if(!pUri) 275 return E_INVALIDARG; 276 277 scheme = 0; 278 hres = IUri_GetScheme(pUri, &scheme); 279 if(FAILED(hres)) 280 return hres; 281 if(scheme != URL_SCHEME_FILE) 282 return E_INVALIDARG; 283 284 memset(&bindinfo, 0, sizeof(bindinfo)); 285 bindinfo.cbSize = sizeof(BINDINFO); 286 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo); 287 if(FAILED(hres)) { 288 WARN("GetBindInfo failed: %08x\n", hres); 289 return hres; 290 } 291 292 ReleaseBindInfo(&bindinfo); 293 294 if(!(grfBINDF & BINDF_FROMURLMON)) 295 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DIRECTBIND, NULL); 296 297 if(This->file != INVALID_HANDLE_VALUE) { 298 IInternetProtocolSink_ReportData(pOIProtSink, 299 BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION, 300 This->size, This->size); 301 return S_OK; 302 } 303 304 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, &null_char); 305 306 size = 0; 307 hres = CoInternetParseIUri(pUri, PARSE_PATH_FROM_URL, 0, path, ARRAY_SIZE(path), &size, 0); 308 if(FAILED(hres)) { 309 WARN("CoInternetParseIUri failed: %08x\n", hres); 310 return report_result(pOIProtSink, hres, 0); 311 } 312 313 file_handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, 314 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 315 if(file_handle == INVALID_HANDLE_VALUE && (ptr = wcsrchr(path, '#'))) { 316 /* If path contains fragment part, try without it. */ 317 *ptr = 0; 318 file_handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, 319 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 320 } 321 if(file_handle == INVALID_HANDLE_VALUE) 322 return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, GetLastError()); 323 324 if(!GetFileSizeEx(file_handle, &file_size)) { 325 CloseHandle(file_handle); 326 return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, GetLastError()); 327 } 328 329 This->file = file_handle; 330 This->size = file_size.u.LowPart; 331 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_CACHEFILENAMEAVAILABLE, path); 332 333 hres = IUri_GetExtension(pUri, &ext); 334 if(SUCCEEDED(hres)) { 335 if(hres == S_OK && *ext) { 336 if((ptr = wcschr(ext, '#'))) 337 *ptr = 0; 338 hres = find_mime_from_ext(ext, &mime); 339 if(SUCCEEDED(hres)) { 340 IInternetProtocolSink_ReportProgress(pOIProtSink, 341 (grfBINDF & BINDF_FROMURLMON) ? 342 BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE, 343 mime); 344 CoTaskMemFree(mime); 345 } 346 } 347 SysFreeString(ext); 348 } 349 350 IInternetProtocolSink_ReportData(pOIProtSink, 351 BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION, 352 This->size, This->size); 353 354 return report_result(pOIProtSink, S_OK, 0); 355 } 356 357 static const IInternetProtocolExVtbl FileProtocolExVtbl = { 358 FileProtocol_QueryInterface, 359 FileProtocol_AddRef, 360 FileProtocol_Release, 361 FileProtocol_Start, 362 FileProtocol_Continue, 363 FileProtocol_Abort, 364 FileProtocol_Terminate, 365 FileProtocol_Suspend, 366 FileProtocol_Resume, 367 FileProtocol_Read, 368 FileProtocol_Seek, 369 FileProtocol_LockRequest, 370 FileProtocol_UnlockRequest, 371 FileProtocol_StartEx 372 }; 373 374 static HRESULT WINAPI FilePriority_QueryInterface(IInternetPriority *iface, 375 REFIID riid, void **ppv) 376 { 377 FileProtocol *This = impl_from_IInternetPriority(iface); 378 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv); 379 } 380 381 static ULONG WINAPI FilePriority_AddRef(IInternetPriority *iface) 382 { 383 FileProtocol *This = impl_from_IInternetPriority(iface); 384 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 385 } 386 387 static ULONG WINAPI FilePriority_Release(IInternetPriority *iface) 388 { 389 FileProtocol *This = impl_from_IInternetPriority(iface); 390 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 391 } 392 393 static HRESULT WINAPI FilePriority_SetPriority(IInternetPriority *iface, LONG nPriority) 394 { 395 FileProtocol *This = impl_from_IInternetPriority(iface); 396 397 TRACE("(%p)->(%d)\n", This, nPriority); 398 399 This->priority = nPriority; 400 return S_OK; 401 } 402 403 static HRESULT WINAPI FilePriority_GetPriority(IInternetPriority *iface, LONG *pnPriority) 404 { 405 FileProtocol *This = impl_from_IInternetPriority(iface); 406 407 TRACE("(%p)->(%p)\n", This, pnPriority); 408 409 *pnPriority = This->priority; 410 return S_OK; 411 } 412 413 static const IInternetPriorityVtbl FilePriorityVtbl = { 414 FilePriority_QueryInterface, 415 FilePriority_AddRef, 416 FilePriority_Release, 417 FilePriority_SetPriority, 418 FilePriority_GetPriority 419 }; 420 421 HRESULT FileProtocol_Construct(IUnknown *outer, LPVOID *ppobj) 422 { 423 FileProtocol *ret; 424 425 TRACE("(%p %p)\n", outer, ppobj); 426 427 URLMON_LockModule(); 428 429 ret = heap_alloc(sizeof(FileProtocol)); 430 431 ret->IUnknown_inner.lpVtbl = &FileProtocolUnkVtbl; 432 ret->IInternetProtocolEx_iface.lpVtbl = &FileProtocolExVtbl; 433 ret->IInternetPriority_iface.lpVtbl = &FilePriorityVtbl; 434 ret->file = INVALID_HANDLE_VALUE; 435 ret->priority = 0; 436 ret->ref = 1; 437 ret->outer = outer ? outer : &ret->IUnknown_inner; 438 439 *ppobj = &ret->IUnknown_inner; 440 return S_OK; 441 } 442