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