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 "mshtml_private.h" 20 21 /******************************************************************** 22 * common ProtocolFactory implementation 23 */ 24 25 typedef struct { 26 IInternetProtocolInfo IInternetProtocolInfo_iface; 27 IClassFactory IClassFactory_iface; 28 } ProtocolFactory; 29 30 static inline ProtocolFactory *impl_from_IInternetProtocolInfo(IInternetProtocolInfo *iface) 31 { 32 return CONTAINING_RECORD(iface, ProtocolFactory, IInternetProtocolInfo_iface); 33 } 34 35 static HRESULT WINAPI InternetProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv) 36 { 37 ProtocolFactory *This = impl_from_IInternetProtocolInfo(iface); 38 39 *ppv = NULL; 40 if(IsEqualGUID(&IID_IUnknown, riid)) { 41 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 42 *ppv = &This->IInternetProtocolInfo_iface; 43 }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) { 44 TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv); 45 *ppv = &This->IInternetProtocolInfo_iface; 46 }else if(IsEqualGUID(&IID_IClassFactory, riid)) { 47 TRACE("(%p)->(IID_IClassFactory %p)\n", This, ppv); 48 *ppv = &This->IClassFactory_iface; 49 } 50 51 if(!*ppv) { 52 WARN("unknown interface %s\n", debugstr_guid(riid)); 53 return E_NOINTERFACE; 54 } 55 56 IInternetProtocolInfo_AddRef(iface); 57 return S_OK; 58 } 59 60 static ULONG WINAPI InternetProtocolInfo_AddRef(IInternetProtocolInfo *iface) 61 { 62 TRACE("(%p)\n", iface); 63 return 2; 64 } 65 66 static ULONG WINAPI InternetProtocolInfo_Release(IInternetProtocolInfo *iface) 67 { 68 TRACE("(%p)\n", iface); 69 return 1; 70 } 71 72 static HRESULT WINAPI InternetProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, 73 LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, 74 DWORD cchResult, DWORD* pcchResult, DWORD dwReserved) 75 { 76 TRACE("%p)->(%s %s %08x %p %d %p %d)\n", iface, debugstr_w(pwzBaseUrl), 77 debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult, 78 pcchResult, dwReserved); 79 80 return INET_E_USE_DEFAULT_PROTOCOLHANDLER; 81 } 82 83 static HRESULT WINAPI InternetProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1, 84 LPCWSTR pwzUrl2, DWORD dwCompareFlags) 85 { 86 TRACE("%p)->(%s %s %08x)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags); 87 return E_NOTIMPL; 88 } 89 90 static inline ProtocolFactory *impl_from_IClassFactory(IClassFactory *iface) 91 { 92 return CONTAINING_RECORD(iface, ProtocolFactory, IClassFactory_iface); 93 } 94 95 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) 96 { 97 ProtocolFactory *This = impl_from_IClassFactory(iface); 98 return IInternetProtocolInfo_QueryInterface(&This->IInternetProtocolInfo_iface, riid, ppv); 99 } 100 101 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) 102 { 103 ProtocolFactory *This = impl_from_IClassFactory(iface); 104 return IInternetProtocolInfo_AddRef(&This->IInternetProtocolInfo_iface); 105 } 106 107 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) 108 { 109 ProtocolFactory *This = impl_from_IClassFactory(iface); 110 return IInternetProtocolInfo_Release(&This->IInternetProtocolInfo_iface); 111 } 112 113 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) 114 { 115 TRACE("(%p)->(%x)\n", iface, dolock); 116 return S_OK; 117 } 118 119 /******************************************************************** 120 * AboutProtocol implementation 121 */ 122 123 typedef struct { 124 IInternetProtocol IInternetProtocol_iface; 125 126 LONG ref; 127 128 BYTE *data; 129 ULONG data_len; 130 ULONG cur; 131 132 IUnknown *pUnkOuter; 133 } AboutProtocol; 134 135 static inline AboutProtocol *AboutProtocol_from_IInternetProtocol(IInternetProtocol *iface) 136 { 137 return CONTAINING_RECORD(iface, AboutProtocol, IInternetProtocol_iface); 138 } 139 140 static HRESULT WINAPI AboutProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) 141 { 142 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 143 144 *ppv = NULL; 145 146 if(IsEqualGUID(&IID_IUnknown, riid)) { 147 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv); 148 if(This->pUnkOuter) 149 return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv); 150 *ppv = &This->IInternetProtocol_iface; 151 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) { 152 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv); 153 *ppv = &This->IInternetProtocol_iface; 154 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) { 155 TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv); 156 *ppv = &This->IInternetProtocol_iface; 157 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { 158 FIXME("IServiceProvider is not implemented\n"); 159 return E_NOINTERFACE; 160 } 161 162 if(!*ppv) { 163 TRACE("unknown interface %s\n", debugstr_guid(riid)); 164 return E_NOINTERFACE; 165 } 166 167 IInternetProtocol_AddRef(iface); 168 return S_OK; 169 } 170 171 static ULONG WINAPI AboutProtocol_AddRef(IInternetProtocol *iface) 172 { 173 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 174 ULONG ref = InterlockedIncrement(&This->ref); 175 TRACE("(%p) ref=%d\n", iface, ref); 176 return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref; 177 } 178 179 static ULONG WINAPI AboutProtocol_Release(IInternetProtocol *iface) 180 { 181 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 182 IUnknown *pUnkOuter = This->pUnkOuter; 183 ULONG ref = InterlockedDecrement(&This->ref); 184 185 TRACE("(%p) ref=%x\n", iface, ref); 186 187 if(!ref) { 188 heap_free(This->data); 189 heap_free(This); 190 } 191 192 return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref; 193 } 194 195 static HRESULT WINAPI AboutProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, 196 IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo, 197 DWORD grfPI, HANDLE_PTR dwReserved) 198 { 199 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 200 BINDINFO bindinfo; 201 DWORD grfBINDF = 0; 202 LPCWSTR text = NULL; 203 DWORD data_len; 204 BYTE *data; 205 HRESULT hres; 206 207 static const WCHAR html_begin[] = {0xfeff,'<','H','T','M','L','>',0}; 208 static const WCHAR html_end[] = {'<','/','H','T','M','L','>',0}; 209 static const WCHAR wszBlank[] = {'b','l','a','n','k',0}; 210 static const WCHAR wszAbout[] = {'a','b','o','u','t',':'}; 211 static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0}; 212 213 /* NOTE: 214 * the about protocol seems not to work as I would expect. It creates html document 215 * for a given url, eg. about:some_text -> <HTML>some_text</HTML> except for the case when 216 * some_text = "blank", when document is blank (<HTML></HMTL>). The same happens 217 * when the url does not have "about:" in the beginning. 218 */ 219 220 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, 221 pOIBindInfo, grfPI, dwReserved); 222 223 memset(&bindinfo, 0, sizeof(bindinfo)); 224 bindinfo.cbSize = sizeof(BINDINFO); 225 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo); 226 if(FAILED(hres)) 227 return hres; 228 ReleaseBindInfo(&bindinfo); 229 230 TRACE("bindf %x\n", grfBINDF); 231 232 if(strlenW(szUrl)>=sizeof(wszAbout)/sizeof(WCHAR) && !memcmp(wszAbout, szUrl, sizeof(wszAbout))) { 233 text = szUrl + sizeof(wszAbout)/sizeof(WCHAR); 234 if(!strcmpW(wszBlank, text)) 235 text = NULL; 236 } 237 238 data_len = sizeof(html_begin)+sizeof(html_end)-sizeof(WCHAR) 239 + (text ? strlenW(text)*sizeof(WCHAR) : 0); 240 data = heap_alloc(data_len); 241 if(!data) 242 return E_OUTOFMEMORY; 243 244 heap_free(This->data); 245 This->data = data; 246 This->data_len = data_len; 247 248 memcpy(This->data, html_begin, sizeof(html_begin)); 249 if(text) 250 strcatW((LPWSTR)This->data, text); 251 strcatW((LPWSTR)This->data, html_end); 252 253 This->cur = 0; 254 255 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml); 256 257 IInternetProtocolSink_ReportData(pOIProtSink, 258 BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, 259 This->data_len, This->data_len); 260 261 IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL); 262 263 return S_OK; 264 } 265 266 static HRESULT WINAPI AboutProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData) 267 { 268 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 269 FIXME("(%p)->(%p)\n", This, pProtocolData); 270 return E_NOTIMPL; 271 } 272 273 static HRESULT WINAPI AboutProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, 274 DWORD dwOptions) 275 { 276 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 277 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); 278 return E_NOTIMPL; 279 } 280 281 static HRESULT WINAPI AboutProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) 282 { 283 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 284 TRACE("(%p)->(%08x)\n", This, dwOptions); 285 return S_OK; 286 } 287 288 static HRESULT WINAPI AboutProtocol_Suspend(IInternetProtocol *iface) 289 { 290 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 291 FIXME("(%p)\n", This); 292 return E_NOTIMPL; 293 } 294 295 static HRESULT WINAPI AboutProtocol_Resume(IInternetProtocol *iface) 296 { 297 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 298 FIXME("(%p)\n", This); 299 return E_NOTIMPL; 300 } 301 302 static HRESULT WINAPI AboutProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead) 303 { 304 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 305 306 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); 307 308 if(!This->data) 309 return E_FAIL; 310 311 *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb); 312 313 if(!*pcbRead) 314 return S_FALSE; 315 316 memcpy(pv, This->data+This->cur, *pcbRead); 317 This->cur += *pcbRead; 318 319 return S_OK; 320 } 321 322 static HRESULT WINAPI AboutProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, 323 DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) 324 { 325 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 326 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); 327 return E_NOTIMPL; 328 } 329 330 static HRESULT WINAPI AboutProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) 331 { 332 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 333 334 TRACE("(%p)->(%d)\n", This, dwOptions); 335 336 return S_OK; 337 } 338 339 static HRESULT WINAPI AboutProtocol_UnlockRequest(IInternetProtocol *iface) 340 { 341 AboutProtocol *This = AboutProtocol_from_IInternetProtocol(iface); 342 343 TRACE("(%p)\n", This); 344 345 return S_OK; 346 } 347 348 static const IInternetProtocolVtbl AboutProtocolVtbl = { 349 AboutProtocol_QueryInterface, 350 AboutProtocol_AddRef, 351 AboutProtocol_Release, 352 AboutProtocol_Start, 353 AboutProtocol_Continue, 354 AboutProtocol_Abort, 355 AboutProtocol_Terminate, 356 AboutProtocol_Suspend, 357 AboutProtocol_Resume, 358 AboutProtocol_Read, 359 AboutProtocol_Seek, 360 AboutProtocol_LockRequest, 361 AboutProtocol_UnlockRequest 362 }; 363 364 static HRESULT WINAPI AboutProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, 365 REFIID riid, void **ppv) 366 { 367 AboutProtocol *ret; 368 HRESULT hres = S_OK; 369 370 TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv); 371 372 ret = heap_alloc(sizeof(AboutProtocol)); 373 ret->IInternetProtocol_iface.lpVtbl = &AboutProtocolVtbl; 374 ret->ref = 0; 375 376 ret->data = NULL; 377 ret->data_len = 0; 378 ret->cur = 0; 379 ret->pUnkOuter = pUnkOuter; 380 381 if(pUnkOuter) { 382 ret->ref = 1; 383 if(IsEqualGUID(&IID_IUnknown, riid)) 384 *ppv = &ret->IInternetProtocol_iface; 385 else 386 hres = E_INVALIDARG; 387 }else { 388 hres = IInternetProtocol_QueryInterface(&ret->IInternetProtocol_iface, riid, ppv); 389 } 390 391 if(FAILED(hres)) 392 heap_free(ret); 393 394 return hres; 395 } 396 397 static HRESULT WINAPI AboutProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, 398 PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, 399 DWORD* pcchResult, DWORD dwReserved) 400 { 401 TRACE("%p)->(%s %d %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), ParseAction, 402 dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved); 403 404 if(ParseAction == PARSE_SECURITY_URL) { 405 unsigned int len = strlenW(pwzUrl)+1; 406 407 *pcchResult = len; 408 if(len > cchResult) 409 return S_FALSE; 410 411 memcpy(pwzResult, pwzUrl, len*sizeof(WCHAR)); 412 return S_OK; 413 } 414 415 if(ParseAction == PARSE_DOMAIN) { 416 if(!pcchResult) 417 return E_POINTER; 418 419 if(pwzUrl) 420 *pcchResult = strlenW(pwzUrl)+1; 421 else 422 *pcchResult = 1; 423 return E_FAIL; 424 } 425 426 return INET_E_DEFAULT_ACTION; 427 } 428 429 static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, 430 QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf, 431 DWORD dwReserved) 432 { 433 TRACE("%p)->(%s %08x %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer, 434 cbBuffer, pcbBuf, dwReserved); 435 436 switch(QueryOption) { 437 case QUERY_CAN_NAVIGATE: 438 return INET_E_USE_DEFAULT_PROTOCOLHANDLER; 439 440 case QUERY_USES_NETWORK: 441 if(!pBuffer || cbBuffer < sizeof(DWORD)) 442 return E_FAIL; 443 444 *(DWORD*)pBuffer = 0; 445 if(pcbBuf) 446 *pcbBuf = sizeof(DWORD); 447 448 break; 449 450 case QUERY_IS_CACHED: 451 FIXME("Unsupported option QUERY_IS_CACHED\n"); 452 return E_NOTIMPL; 453 case QUERY_IS_INSTALLEDENTRY: 454 FIXME("Unsupported option QUERY_IS_INSTALLEDENTRY\n"); 455 return E_NOTIMPL; 456 case QUERY_IS_CACHED_OR_MAPPED: 457 FIXME("Unsupported option QUERY_IS_CACHED_OR_MAPPED\n"); 458 return E_NOTIMPL; 459 case QUERY_IS_SECURE: 460 FIXME("Unsupported option QUERY_IS_SECURE\n"); 461 return E_NOTIMPL; 462 case QUERY_IS_SAFE: 463 FIXME("Unsupported option QUERY_IS_SAFE\n"); 464 return E_NOTIMPL; 465 case QUERY_USES_HISTORYFOLDER: 466 FIXME("Unsupported option QUERY_USES_HISTORYFOLDER\n"); 467 return E_FAIL; 468 case QUERY_IS_CACHED_AND_USABLE_OFFLINE: 469 FIXME("Unsupported option QUERY_IS_CACHED_AND_USABLE_OFFLINE\n"); 470 return E_NOTIMPL; 471 default: 472 return E_FAIL; 473 } 474 475 return S_OK; 476 } 477 478 static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = { 479 InternetProtocolInfo_QueryInterface, 480 InternetProtocolInfo_AddRef, 481 InternetProtocolInfo_Release, 482 AboutProtocolInfo_ParseUrl, 483 InternetProtocolInfo_CombineUrl, 484 InternetProtocolInfo_CompareUrl, 485 AboutProtocolInfo_QueryInfo 486 }; 487 488 static const IClassFactoryVtbl AboutProtocolFactoryVtbl = { 489 ClassFactory_QueryInterface, 490 ClassFactory_AddRef, 491 ClassFactory_Release, 492 AboutProtocolFactory_CreateInstance, 493 ClassFactory_LockServer 494 }; 495 496 static ProtocolFactory AboutProtocolFactory = { 497 { &AboutProtocolInfoVtbl }, 498 { &AboutProtocolFactoryVtbl } 499 }; 500 501 /******************************************************************** 502 * ResProtocol implementation 503 */ 504 505 typedef struct { 506 IInternetProtocol IInternetProtocol_iface; 507 LONG ref; 508 509 BYTE *data; 510 ULONG data_len; 511 ULONG cur; 512 513 IUnknown *pUnkOuter; 514 } ResProtocol; 515 516 static inline ResProtocol *ResProtocol_from_IInternetProtocol(IInternetProtocol *iface) 517 { 518 return CONTAINING_RECORD(iface, ResProtocol, IInternetProtocol_iface); 519 } 520 521 static HRESULT WINAPI ResProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) 522 { 523 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 524 525 *ppv = NULL; 526 527 if(IsEqualGUID(&IID_IUnknown, riid)) { 528 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv); 529 if(This->pUnkOuter) 530 return IUnknown_QueryInterface(This->pUnkOuter, &IID_IUnknown, ppv); 531 *ppv = &This->IInternetProtocol_iface; 532 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) { 533 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv); 534 *ppv = &This->IInternetProtocol_iface; 535 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) { 536 TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv); 537 *ppv = &This->IInternetProtocol_iface; 538 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { 539 FIXME("IServiceProvider is not implemented\n"); 540 return E_NOINTERFACE; 541 } 542 543 if(!*ppv) { 544 TRACE("unknown interface %s\n", debugstr_guid(riid)); 545 return E_NOINTERFACE; 546 } 547 548 IInternetProtocol_AddRef(iface); 549 return S_OK; 550 } 551 552 static ULONG WINAPI ResProtocol_AddRef(IInternetProtocol *iface) 553 { 554 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 555 ULONG ref = InterlockedIncrement(&This->ref); 556 TRACE("(%p) ref=%d\n", iface, ref); 557 return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref; 558 } 559 560 static ULONG WINAPI ResProtocol_Release(IInternetProtocol *iface) 561 { 562 ResProtocol *This = (ResProtocol*)iface; 563 IUnknown *pUnkOuter = This->pUnkOuter; 564 ULONG ref = InterlockedDecrement(&This->ref); 565 566 TRACE("(%p) ref=%x\n", iface, ref); 567 568 if(!ref) { 569 heap_free(This->data); 570 heap_free(This); 571 } 572 573 return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref; 574 } 575 576 static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, 577 IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo, 578 DWORD grfPI, HANDLE_PTR dwReserved) 579 { 580 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 581 WCHAR *url_dll, *url_file, *url, *mime, *res_type = (LPWSTR)RT_HTML, *ptr; 582 DWORD grfBINDF = 0, len; 583 BINDINFO bindinfo; 584 HMODULE hdll; 585 HRSRC src; 586 HRESULT hres; 587 588 static const WCHAR wszRes[] = {'r','e','s',':','/','/'}; 589 590 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, 591 pOIBindInfo, grfPI, dwReserved); 592 593 memset(&bindinfo, 0, sizeof(bindinfo)); 594 bindinfo.cbSize = sizeof(BINDINFO); 595 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo); 596 if(FAILED(hres)) 597 return hres; 598 ReleaseBindInfo(&bindinfo); 599 600 len = strlenW(szUrl)+16; 601 url = heap_alloc(len*sizeof(WCHAR)); 602 hres = CoInternetParseUrl(szUrl, PARSE_ENCODE, 0, url, len, &len, 0); 603 if(FAILED(hres)) { 604 WARN("CoInternetParseUrl failed: %08x\n", hres); 605 heap_free(url); 606 IInternetProtocolSink_ReportResult(pOIProtSink, hres, 0, NULL); 607 return hres; 608 } 609 610 if(len < sizeof(wszRes)/sizeof(wszRes[0]) || memcmp(url, wszRes, sizeof(wszRes))) { 611 WARN("Wrong protocol of url: %s\n", debugstr_w(url)); 612 IInternetProtocolSink_ReportResult(pOIProtSink, E_INVALIDARG, 0, NULL); 613 heap_free(url); 614 return E_INVALIDARG; 615 } 616 617 url_dll = url + sizeof(wszRes)/sizeof(wszRes[0]); 618 if(!(res_type = strchrW(url_dll, '/'))) { 619 WARN("wrong url: %s\n", debugstr_w(url)); 620 IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL); 621 heap_free(url); 622 return MK_E_SYNTAX; 623 } 624 625 *res_type++ = 0; 626 if ((url_file = strchrW(res_type, '/'))) { 627 *url_file++ = 0; 628 }else { 629 url_file = res_type; 630 res_type = (LPWSTR)RT_HTML; 631 } 632 633 /* Ignore query and hash parts. */ 634 if((ptr = strchrW(url_file, '?'))) 635 *ptr = 0; 636 if(*url_file && (ptr = strchrW(url_file+1, '#'))) 637 *ptr = 0; 638 639 hdll = LoadLibraryExW(url_dll, NULL, LOAD_LIBRARY_AS_DATAFILE); 640 if(!hdll) { 641 WARN("Could not open dll: %s\n", debugstr_w(url_dll)); 642 IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL); 643 heap_free(url); 644 return HRESULT_FROM_WIN32(GetLastError()); 645 } 646 647 TRACE("trying to find resource type %s, name %s\n", debugstr_w(res_type), debugstr_w(url_file)); 648 649 src = FindResourceW(hdll, url_file, res_type); 650 if(!src) { 651 LPWSTR endpoint = NULL; 652 DWORD file_id = strtolW(url_file, &endpoint, 10); 653 if(endpoint == url_file+strlenW(url_file)) 654 src = FindResourceW(hdll, MAKEINTRESOURCEW(file_id), res_type); 655 656 if(!src) { 657 WARN("Could not find resource\n"); 658 IInternetProtocolSink_ReportResult(pOIProtSink, 659 HRESULT_FROM_WIN32(GetLastError()), 0, NULL); 660 heap_free(url); 661 return HRESULT_FROM_WIN32(GetLastError()); 662 } 663 } 664 665 if(This->data) { 666 WARN("data already loaded\n"); 667 heap_free(This->data); 668 } 669 670 This->data_len = SizeofResource(hdll, src); 671 This->data = heap_alloc(This->data_len); 672 memcpy(This->data, LoadResource(hdll, src), This->data_len); 673 This->cur = 0; 674 675 FreeLibrary(hdll); 676 677 hres = FindMimeFromData(NULL, url_file, This->data, This->data_len, NULL, 0, &mime, 0); 678 heap_free(url); 679 if(SUCCEEDED(hres)) { 680 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime); 681 CoTaskMemFree(mime); 682 } 683 684 IInternetProtocolSink_ReportData(pOIProtSink, 685 BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, 686 This->data_len, This->data_len); 687 688 IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL); 689 690 return S_OK; 691 } 692 693 static HRESULT WINAPI ResProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData) 694 { 695 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 696 FIXME("(%p)->(%p)\n", This, pProtocolData); 697 return E_NOTIMPL; 698 } 699 700 static HRESULT WINAPI ResProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, 701 DWORD dwOptions) 702 { 703 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 704 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); 705 return E_NOTIMPL; 706 } 707 708 static HRESULT WINAPI ResProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) 709 { 710 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 711 712 TRACE("(%p)->(%08x)\n", This, dwOptions); 713 714 /* test show that we don't have to do anything here */ 715 return S_OK; 716 } 717 718 static HRESULT WINAPI ResProtocol_Suspend(IInternetProtocol *iface) 719 { 720 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 721 FIXME("(%p)\n", This); 722 return E_NOTIMPL; 723 } 724 725 static HRESULT WINAPI ResProtocol_Resume(IInternetProtocol *iface) 726 { 727 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 728 FIXME("(%p)\n", This); 729 return E_NOTIMPL; 730 } 731 732 static HRESULT WINAPI ResProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead) 733 { 734 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 735 736 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); 737 738 if(!This->data) 739 return E_FAIL; 740 741 *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb); 742 743 if(!*pcbRead) 744 return S_FALSE; 745 746 memcpy(pv, This->data+This->cur, *pcbRead); 747 This->cur += *pcbRead; 748 749 return S_OK; 750 } 751 752 static HRESULT WINAPI ResProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, 753 DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) 754 { 755 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 756 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); 757 return E_NOTIMPL; 758 } 759 760 static HRESULT WINAPI ResProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) 761 { 762 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 763 764 TRACE("(%p)->(%d)\n", This, dwOptions); 765 766 /* test show that we don't have to do anything here */ 767 return S_OK; 768 } 769 770 static HRESULT WINAPI ResProtocol_UnlockRequest(IInternetProtocol *iface) 771 { 772 ResProtocol *This = ResProtocol_from_IInternetProtocol(iface); 773 774 TRACE("(%p)\n", This); 775 776 /* test show that we don't have to do anything here */ 777 return S_OK; 778 } 779 780 static const IInternetProtocolVtbl ResProtocolVtbl = { 781 ResProtocol_QueryInterface, 782 ResProtocol_AddRef, 783 ResProtocol_Release, 784 ResProtocol_Start, 785 ResProtocol_Continue, 786 ResProtocol_Abort, 787 ResProtocol_Terminate, 788 ResProtocol_Suspend, 789 ResProtocol_Resume, 790 ResProtocol_Read, 791 ResProtocol_Seek, 792 ResProtocol_LockRequest, 793 ResProtocol_UnlockRequest 794 }; 795 796 static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, 797 REFIID riid, void **ppv) 798 { 799 ResProtocol *ret; 800 HRESULT hres = S_OK; 801 802 TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv); 803 804 ret = heap_alloc(sizeof(ResProtocol)); 805 ret->IInternetProtocol_iface.lpVtbl = &ResProtocolVtbl; 806 ret->ref = 0; 807 ret->data = NULL; 808 ret->data_len = 0; 809 ret->cur = 0; 810 ret->pUnkOuter = pUnkOuter; 811 812 if(pUnkOuter) { 813 ret->ref = 1; 814 if(IsEqualGUID(&IID_IUnknown, riid)) 815 *ppv = &ret->IInternetProtocol_iface; 816 else 817 hres = E_FAIL; 818 }else { 819 hres = IInternetProtocol_QueryInterface(&ret->IInternetProtocol_iface, riid, ppv); 820 } 821 822 if(FAILED(hres)) 823 heap_free(ret); 824 825 return hres; 826 } 827 828 static HRESULT WINAPI ResProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, 829 PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, 830 DWORD* pcchResult, DWORD dwReserved) 831 { 832 TRACE("%p)->(%s %d %x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), ParseAction, 833 dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved); 834 835 if(ParseAction == PARSE_SECURITY_URL) { 836 WCHAR file_part[MAX_PATH], full_path[MAX_PATH]; 837 WCHAR *ptr; 838 DWORD size, len; 839 840 static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'}; 841 static const WCHAR wszRes[] = {'r','e','s',':','/','/'}; 842 843 if(strlenW(pwzUrl) <= sizeof(wszRes)/sizeof(WCHAR) || memcmp(pwzUrl, wszRes, sizeof(wszRes))) 844 return E_INVALIDARG; 845 846 ptr = strchrW(pwzUrl + sizeof(wszRes)/sizeof(WCHAR), '/'); 847 if(!ptr) 848 return E_INVALIDARG; 849 850 len = ptr - (pwzUrl + sizeof(wszRes)/sizeof(WCHAR)); 851 if(len >= sizeof(file_part)/sizeof(WCHAR)) { 852 FIXME("Too long URL\n"); 853 return MK_E_SYNTAX; 854 } 855 856 memcpy(file_part, pwzUrl + sizeof(wszRes)/sizeof(WCHAR), len*sizeof(WCHAR)); 857 file_part[len] = 0; 858 859 len = SearchPathW(NULL, file_part, NULL, sizeof(full_path)/sizeof(WCHAR), full_path, NULL); 860 if(!len) { 861 HMODULE module; 862 863 /* SearchPath does not work well with winelib files (like our test executable), 864 * so we also try to load the library here */ 865 module = LoadLibraryExW(file_part, NULL, LOAD_LIBRARY_AS_DATAFILE); 866 if(!module) { 867 WARN("Could not find file %s\n", debugstr_w(file_part)); 868 return MK_E_SYNTAX; 869 } 870 871 len = GetModuleFileNameW(module, full_path, sizeof(full_path)/sizeof(WCHAR)); 872 FreeLibrary(module); 873 if(!len) 874 return E_FAIL; 875 } 876 877 size = sizeof(wszFile)/sizeof(WCHAR) + len + 1; 878 if(pcchResult) 879 *pcchResult = size; 880 if(size > cchResult) 881 return S_FALSE; 882 883 memcpy(pwzResult, wszFile, sizeof(wszFile)); 884 memcpy(pwzResult + sizeof(wszFile)/sizeof(WCHAR), full_path, (len+1)*sizeof(WCHAR)); 885 return S_OK; 886 } 887 888 if(ParseAction == PARSE_DOMAIN) { 889 if(!pcchResult) 890 return E_POINTER; 891 892 if(pwzUrl) 893 *pcchResult = strlenW(pwzUrl)+1; 894 else 895 *pcchResult = 1; 896 return E_FAIL; 897 } 898 899 return INET_E_DEFAULT_ACTION; 900 } 901 902 static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, 903 QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf, 904 DWORD dwReserved) 905 { 906 TRACE("%p)->(%s %08x %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer, 907 cbBuffer, pcbBuf, dwReserved); 908 909 switch(QueryOption) { 910 case QUERY_USES_NETWORK: 911 if(!pBuffer || cbBuffer < sizeof(DWORD)) 912 return E_FAIL; 913 914 *(DWORD*)pBuffer = 0; 915 if(pcbBuf) 916 *pcbBuf = sizeof(DWORD); 917 break; 918 919 case QUERY_IS_SECURE: 920 FIXME("QUERY_IS_SECURE not supported\n"); 921 return E_NOTIMPL; 922 case QUERY_IS_SAFE: 923 FIXME("QUERY_IS_SAFE not supported\n"); 924 return E_NOTIMPL; 925 default: 926 return INET_E_USE_DEFAULT_PROTOCOLHANDLER; 927 } 928 929 return S_OK; 930 } 931 932 static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = { 933 InternetProtocolInfo_QueryInterface, 934 InternetProtocolInfo_AddRef, 935 InternetProtocolInfo_Release, 936 ResProtocolInfo_ParseUrl, 937 InternetProtocolInfo_CombineUrl, 938 InternetProtocolInfo_CompareUrl, 939 ResProtocolInfo_QueryInfo 940 }; 941 942 static const IClassFactoryVtbl ResProtocolFactoryVtbl = { 943 ClassFactory_QueryInterface, 944 ClassFactory_AddRef, 945 ClassFactory_Release, 946 ResProtocolFactory_CreateInstance, 947 ClassFactory_LockServer 948 }; 949 950 static ProtocolFactory ResProtocolFactory = { 951 { &ResProtocolInfoVtbl }, 952 { &ResProtocolFactoryVtbl } 953 }; 954 955 /******************************************************************** 956 * JSProtocol implementation 957 */ 958 959 static HRESULT WINAPI JSProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, 960 REFIID riid, void **ppv) 961 { 962 FIXME("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv); 963 return E_NOTIMPL; 964 } 965 966 static HRESULT WINAPI JSProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, 967 PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, 968 DWORD* pcchResult, DWORD dwReserved) 969 { 970 TRACE("%p)->(%s %d %x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), ParseAction, 971 dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved); 972 973 switch(ParseAction) { 974 case PARSE_SECURITY_URL: 975 FIXME("PARSE_SECURITY_URL\n"); 976 return E_NOTIMPL; 977 case PARSE_DOMAIN: 978 FIXME("PARSE_DOMAIN\n"); 979 return E_NOTIMPL; 980 default: 981 return INET_E_DEFAULT_ACTION; 982 } 983 984 return S_OK; 985 } 986 987 static HRESULT WINAPI JSProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, 988 QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf, 989 DWORD dwReserved) 990 { 991 TRACE("%p)->(%s %08x %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer, 992 cbBuffer, pcbBuf, dwReserved); 993 994 switch(QueryOption) { 995 case QUERY_USES_NETWORK: 996 if(!pBuffer || cbBuffer < sizeof(DWORD)) 997 return E_FAIL; 998 999 *(DWORD*)pBuffer = 0; 1000 if(pcbBuf) 1001 *pcbBuf = sizeof(DWORD); 1002 break; 1003 1004 case QUERY_IS_SECURE: 1005 FIXME("QUERY_IS_SECURE not supported\n"); 1006 return E_NOTIMPL; 1007 1008 default: 1009 return INET_E_USE_DEFAULT_PROTOCOLHANDLER; 1010 } 1011 1012 return S_OK; 1013 } 1014 1015 static const IInternetProtocolInfoVtbl JSProtocolInfoVtbl = { 1016 InternetProtocolInfo_QueryInterface, 1017 InternetProtocolInfo_AddRef, 1018 InternetProtocolInfo_Release, 1019 JSProtocolInfo_ParseUrl, 1020 InternetProtocolInfo_CombineUrl, 1021 InternetProtocolInfo_CompareUrl, 1022 JSProtocolInfo_QueryInfo 1023 }; 1024 1025 static const IClassFactoryVtbl JSProtocolFactoryVtbl = { 1026 ClassFactory_QueryInterface, 1027 ClassFactory_AddRef, 1028 ClassFactory_Release, 1029 JSProtocolFactory_CreateInstance, 1030 ClassFactory_LockServer 1031 }; 1032 1033 static ProtocolFactory JSProtocolFactory = { 1034 { &JSProtocolInfoVtbl }, 1035 { &JSProtocolFactoryVtbl } 1036 }; 1037 1038 HRESULT ProtocolFactory_Create(REFCLSID rclsid, REFIID riid, void **ppv) 1039 { 1040 ProtocolFactory *cf = NULL; 1041 1042 if(IsEqualGUID(&CLSID_AboutProtocol, rclsid)) 1043 cf = &AboutProtocolFactory; 1044 else if(IsEqualGUID(&CLSID_ResProtocol, rclsid)) 1045 cf = &ResProtocolFactory; 1046 else if(IsEqualGUID(&CLSID_JSProtocol, rclsid)) 1047 cf = &JSProtocolFactory; 1048 1049 if(!cf) { 1050 FIXME("not implemented protocol %s\n", debugstr_guid(rclsid)); 1051 return CLASS_E_CLASSNOTAVAILABLE; 1052 } 1053 1054 return IInternetProtocolInfo_QueryInterface(&cf->IInternetProtocolInfo_iface, riid, ppv); 1055 } 1056