[MSHTA] Implement MSHTA.exe (#577) CORE-12813
[reactos.git] / dll / win32 / mshtml / protocol.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 "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 }