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