Reactos
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
25typedef struct {
26 IInternetProtocolInfo IInternetProtocolInfo_iface;
27 IClassFactory IClassFactory_iface;
28} ProtocolFactory;
29
30static inline ProtocolFactory *impl_from_IInternetProtocolInfo(IInternetProtocolInfo *iface)
31{
32 return CONTAINING_RECORD(iface, ProtocolFactory, IInternetProtocolInfo_iface);
33}
34
35static 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
60static ULONG WINAPI InternetProtocolInfo_AddRef(IInternetProtocolInfo *iface)
61{
62 TRACE("(%p)\n", iface);
63 return 2;
64}
65
66static ULONG WINAPI InternetProtocolInfo_Release(IInternetProtocolInfo *iface)
67{
68 TRACE("(%p)\n", iface);
69 return 1;
70}
71
72static 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
83static 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
90static inline ProtocolFactory *impl_from_IClassFactory(IClassFactory *iface)
91{
92 return CONTAINING_RECORD(iface, ProtocolFactory, IClassFactory_iface);
93}
94
95static 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
101static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
102{
103 ProtocolFactory *This = impl_from_IClassFactory(iface);
104 return IInternetProtocolInfo_AddRef(&This->IInternetProtocolInfo_iface);
105}
106
107static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
108{
109 ProtocolFactory *This = impl_from_IClassFactory(iface);
110 return IInternetProtocolInfo_Release(&This->IInternetProtocolInfo_iface);
111}
112
113static 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
123typedef 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
135static inline AboutProtocol *AboutProtocol_from_IInternetProtocol(IInternetProtocol *iface)
136{
137 return CONTAINING_RECORD(iface, AboutProtocol, IInternetProtocol_iface);
138}
139
140static 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
171static 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
179static 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
195static 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
266static 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
273static 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
281static 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
288static 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
295static 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
302static 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
322static 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
330static 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
339static 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
348static 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
364static 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
397static 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
429static 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
478static 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
488static const IClassFactoryVtbl AboutProtocolFactoryVtbl = {
489 ClassFactory_QueryInterface,
490 ClassFactory_AddRef,
491 ClassFactory_Release,
492 AboutProtocolFactory_CreateInstance,
493 ClassFactory_LockServer
494};
495
496static ProtocolFactory AboutProtocolFactory = {
497 { &AboutProtocolInfoVtbl },
498 { &AboutProtocolFactoryVtbl }
499};
500
501/********************************************************************
502 * ResProtocol implementation
503 */
504
505typedef 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
516static inline ResProtocol *ResProtocol_from_IInternetProtocol(IInternetProtocol *iface)
517{
518 return CONTAINING_RECORD(iface, ResProtocol, IInternetProtocol_iface);
519}
520
521static 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
552static 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
560static 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
576static 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
693static 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
700static 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
708static 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
718static 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
725static 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
732static 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
752static 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
760static 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
770static 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
780static 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
796static 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
828static 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
902static 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
932static 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
942static const IClassFactoryVtbl ResProtocolFactoryVtbl = {
943 ClassFactory_QueryInterface,
944 ClassFactory_AddRef,
945 ClassFactory_Release,
946 ResProtocolFactory_CreateInstance,
947 ClassFactory_LockServer
948};
949
950static ProtocolFactory ResProtocolFactory = {
951 { &ResProtocolInfoVtbl },
952 { &ResProtocolFactoryVtbl }
953};
954
955/********************************************************************
956 * JSProtocol implementation
957 */
958
959static 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
966static 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
987static 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
1015static 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
1025static const IClassFactoryVtbl JSProtocolFactoryVtbl = {
1026 ClassFactory_QueryInterface,
1027 ClassFactory_AddRef,
1028 ClassFactory_Release,
1029 JSProtocolFactory_CreateInstance,
1030 ClassFactory_LockServer
1031};
1032
1033static ProtocolFactory JSProtocolFactory = {
1034 { &JSProtocolInfoVtbl },
1035 { &JSProtocolFactoryVtbl }
1036};
1037
1038HRESULT 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}