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