msxml3: Use url monikers to load xml.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 #include "wine/unicode.h"
33
34 #include "mshtml_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 /********************************************************************
39  * common ProtocolFactory implementation
40  */
41
42 #define PROTOCOLINFO(x) ((IInternetProtocolInfo*) &(x)->lpInternetProtocolInfoVtbl)
43 #define CLASSFACTORY(x) ((IClassFactory*)         &(x)->lpClassFactoryVtbl)
44 #define PROTOCOL(x)     ((IInternetProtocol*)     &(x)->lpInternetProtocolVtbl)
45
46 typedef struct {
47     const IInternetProtocolInfoVtbl *lpInternetProtocolInfoVtbl;
48     const IClassFactoryVtbl         *lpClassFactoryVtbl;
49 } ProtocolFactory;
50
51 #define PROTOCOLINFO_THIS(iface) DEFINE_THIS(ProtocolFactory, InternetProtocolInfo, iface)
52
53 static HRESULT WINAPI InternetProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv)
54 {
55     ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
56
57     *ppv = NULL;
58     if(IsEqualGUID(&IID_IUnknown, riid)) {
59         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
60         *ppv = PROTOCOLINFO(This);
61     }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) {
62         TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv);
63         *ppv = PROTOCOLINFO(This);
64     }else if(IsEqualGUID(&IID_IClassFactory, riid)) {
65         TRACE("(%p)->(IID_IClassFactory %p)\n", This, ppv);
66         *ppv = CLASSFACTORY(This);
67     }
68
69     if(!*ppv) {
70         WARN("unknown interface %s\n", debugstr_guid(riid));
71         return E_NOINTERFACE;
72     }
73
74     IInternetProtocolInfo_AddRef(iface);
75     return S_OK;
76 }
77
78 static ULONG WINAPI InternetProtocolInfo_AddRef(IInternetProtocolInfo *iface)
79 {
80     ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
81     TRACE("(%p)\n", This);
82     LOCK_MODULE();
83     return 2;
84 }
85
86 static ULONG WINAPI InternetProtocolInfo_Release(IInternetProtocolInfo *iface)
87 {
88     ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
89     TRACE("(%p)\n", This);
90     UNLOCK_MODULE();
91     return 1;
92 }
93
94 #undef PROTOCOLINFO_THIS
95
96 #define CLASSFACTORY_THIS(iface) DEFINE_THIS(ProtocolFactory, ClassFactory, iface)
97
98 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
99 {
100     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
101     return IInternetProtocolInfo_QueryInterface(PROTOCOLINFO(This), riid, ppv);
102 }
103
104 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
105 {
106     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
107     return IInternetProtocolInfo_AddRef(PROTOCOLINFO(This));
108 }
109
110 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
111 {
112     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
113     return IInternetProtocolInfo_Release(PROTOCOLINFO(This));
114 }
115
116 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
117 {
118     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
119
120     TRACE("(%p)->(%x)\n", This, dolock);
121
122     if(dolock)
123         LOCK_MODULE();
124     else
125         UNLOCK_MODULE();
126
127     return S_OK;
128 }
129
130 #undef CLASSFACTORY_THIS
131
132 /********************************************************************
133  * AboutProtocol implementation
134  */
135
136 typedef struct {
137     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
138
139     LONG ref;
140
141     BYTE *data;
142     ULONG data_len;
143     ULONG cur;
144
145     IUnknown *pUnkOuter;
146 } AboutProtocol;
147
148 #define PROTOCOL_THIS(iface) DEFINE_THIS(AboutProtocol, InternetProtocol, iface)
149
150 static HRESULT WINAPI AboutProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
151 {
152     AboutProtocol *This = PROTOCOL_THIS(iface);
153
154     *ppv = NULL;
155
156     if(IsEqualGUID(&IID_IUnknown, riid)) {
157         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
158         if(This->pUnkOuter)
159             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
160         *ppv = PROTOCOL(This);
161     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
162         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
163         *ppv = PROTOCOL(This);
164     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
165         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
166         *ppv = PROTOCOL(This);
167     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
168         FIXME("IServiceProvider is not implemented\n");
169         return E_NOINTERFACE;
170     }
171
172     if(!*ppv) {
173         TRACE("unknown interface %s\n", debugstr_guid(riid));
174         return E_NOINTERFACE;
175     }
176
177     IInternetProtocol_AddRef(iface);
178     return S_OK;
179 }
180
181 static ULONG WINAPI AboutProtocol_AddRef(IInternetProtocol *iface)
182 {
183     AboutProtocol *This = PROTOCOL_THIS(iface);
184     ULONG ref = InterlockedIncrement(&This->ref);
185     TRACE("(%p) ref=%ld\n", iface, ref);
186     return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
187 }
188
189 static ULONG WINAPI AboutProtocol_Release(IInternetProtocol *iface)
190 {
191     AboutProtocol *This = PROTOCOL_THIS(iface);
192     IUnknown *pUnkOuter = This->pUnkOuter;
193     ULONG ref = InterlockedDecrement(&This->ref);
194
195     TRACE("(%p) ref=%lx\n", iface, ref);
196
197     if(!ref) {
198         HeapFree(GetProcessHeap(), 0, This->data);
199         HeapFree(GetProcessHeap(), 0, This);
200         UNLOCK_MODULE();
201     }
202
203     return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
204 }
205
206 static HRESULT WINAPI AboutProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
207         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
208         DWORD grfPI, DWORD dwReserved)
209 {
210     AboutProtocol *This = PROTOCOL_THIS(iface);
211     BINDINFO bindinfo;
212     DWORD grfBINDF = 0;
213     LPCWSTR text = NULL;
214
215     static const WCHAR html_begin[] = {0xfeff,'<','H','T','M','L','>',0};
216     static const WCHAR html_end[] = {'<','/','H','T','M','L','>',0};
217     static const WCHAR wszBlank[] = {'b','l','a','n','k',0};
218     static const WCHAR wszAbout[] = {'a','b','o','u','t',':'};
219     static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
220
221     /* NOTE:
222      * the about protocol seems not to work as I would expect. It creates html document
223      * for a given url, eg. about:some_text -> <HTML>some_text</HTML> except for the case when
224      * some_text = "blank", when document is blank (<HTML></HMTL>). The same happens
225      * when the url does not have "about:" in the beginning.
226      */
227
228     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
229             pOIBindInfo, grfPI, dwReserved);
230
231     memset(&bindinfo, 0, sizeof(bindinfo));
232     bindinfo.cbSize = sizeof(BINDINFO);
233     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
234     ReleaseBindInfo(&bindinfo);
235
236     if(strlenW(szUrl)>=sizeof(wszAbout)/sizeof(WCHAR) && !memcmp(wszAbout, szUrl, sizeof(wszAbout))) {
237         text = szUrl + sizeof(wszAbout)/sizeof(WCHAR);
238         if(!strcmpW(wszBlank, text))
239             text = NULL;
240     }
241
242     This->data_len = sizeof(html_begin)+sizeof(html_end)-sizeof(WCHAR) 
243         + (text ? strlenW(text)*sizeof(WCHAR) : 0);
244     This->data = HeapAlloc(GetProcessHeap(), 0, This->data_len);
245
246     memcpy(This->data, html_begin, sizeof(html_begin));
247     if(text)
248         strcatW((LPWSTR)This->data, text);
249     strcatW((LPWSTR)This->data, html_end);
250     
251     This->cur = 0;
252
253     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml);
254
255     IInternetProtocolSink_ReportData(pOIProtSink,
256             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
257             This->data_len, This->data_len);
258
259     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
260
261     return S_OK;
262 }
263
264 static HRESULT WINAPI AboutProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
265 {
266     AboutProtocol *This = PROTOCOL_THIS(iface);
267     FIXME("(%p)->(%p)\n", This, pProtocolData);
268     return E_NOTIMPL;
269 }
270
271 static HRESULT WINAPI AboutProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
272         DWORD dwOptions)
273 {
274     AboutProtocol *This = PROTOCOL_THIS(iface);
275     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
276     return E_NOTIMPL;
277 }
278
279 static HRESULT WINAPI AboutProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
280 {
281     AboutProtocol *This = PROTOCOL_THIS(iface);
282     TRACE("(%p)->(%08lx)\n", This, dwOptions);
283     return S_OK;
284 }
285
286 static HRESULT WINAPI AboutProtocol_Suspend(IInternetProtocol *iface)
287 {
288     AboutProtocol *This = PROTOCOL_THIS(iface);
289     FIXME("(%p)\n", This);
290     return E_NOTIMPL;
291 }
292
293 static HRESULT WINAPI AboutProtocol_Resume(IInternetProtocol *iface)
294 {
295     AboutProtocol *This = PROTOCOL_THIS(iface);
296     FIXME("(%p)\n", This);
297     return E_NOTIMPL;
298 }
299
300 static HRESULT WINAPI AboutProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
301 {
302     AboutProtocol *This = PROTOCOL_THIS(iface);
303
304     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
305
306     if(!This->data)
307         return E_FAIL;
308
309     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
310
311     if(!*pcbRead)
312         return S_FALSE;
313
314     memcpy(pv, This->data, *pcbRead);
315     This->cur += *pcbRead;
316
317     return S_OK;
318 }
319
320 static HRESULT WINAPI AboutProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
321         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
322 {
323     AboutProtocol *This = PROTOCOL_THIS(iface);
324     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
325     return E_NOTIMPL;
326 }
327
328 static HRESULT WINAPI AboutProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
329 {
330     AboutProtocol *This = PROTOCOL_THIS(iface);
331
332     TRACE("(%p)->(%ld)\n", This, dwOptions);
333
334     return S_OK;
335 }
336
337 static HRESULT WINAPI AboutProtocol_UnlockRequest(IInternetProtocol *iface)
338 {
339     AboutProtocol *This = PROTOCOL_THIS(iface);
340
341     TRACE("(%p)\n", This);
342
343     return S_OK;
344 }
345
346 #undef PROTOCOL_THIS
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 = HeapAlloc(GetProcessHeap(), 0, sizeof(AboutProtocol));
373     ret->lpInternetProtocolVtbl = &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 = PROTOCOL(ret);
385         else
386             hres = E_INVALIDARG;
387     }else {
388         hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
389     }
390
391     if(SUCCEEDED(hres))
392         LOCK_MODULE();
393     else
394         HeapFree(GetProcessHeap(), 0, ret);
395
396     return hres;
397 }
398
399 static HRESULT WINAPI AboutProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
400         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
401         DWORD* pcchResult, DWORD dwReserved)
402 {
403     TRACE("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
404             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
405
406     if(ParseAction == PARSE_SECURITY_URL) {
407         int len = lstrlenW(pwzUrl);
408
409         if(len >= cchResult)
410             return S_FALSE;
411
412         memcpy(pwzResult, pwzUrl, (len+1)*sizeof(WCHAR));
413         return S_OK;
414     }
415
416     if(ParseAction == PARSE_DOMAIN) {
417         /* Tests show that we don't have to do anything here */
418         return S_OK;
419     }
420
421     return INET_E_DEFAULT_ACTION;
422 }
423
424 static HRESULT WINAPI AboutProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
425         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
426         DWORD* pcchResult, DWORD dwReserved)
427 {
428     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
429             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
430     return E_NOTIMPL;
431 }
432
433 static HRESULT WINAPI AboutProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
434         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
435 {
436     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
437     return E_NOTIMPL;
438 }
439
440 static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
441         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
442         DWORD dwReserved)
443 {
444     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
445             cbBuffer, pcbBuf, dwReserved);
446     return E_NOTIMPL;
447 }
448
449 static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = {
450     InternetProtocolInfo_QueryInterface,
451     InternetProtocolInfo_AddRef,
452     InternetProtocolInfo_Release,
453     AboutProtocolInfo_ParseUrl,
454     AboutProtocolInfo_CombineUrl,
455     AboutProtocolInfo_CompareUrl,
456     AboutProtocolInfo_QueryInfo
457 };
458
459 static const IClassFactoryVtbl AboutProtocolFactoryVtbl = {
460     ClassFactory_QueryInterface,
461     ClassFactory_AddRef,
462     ClassFactory_Release,
463     AboutProtocolFactory_CreateInstance,
464     ClassFactory_LockServer
465 };
466
467 static ProtocolFactory AboutProtocolFactory = {
468     &AboutProtocolInfoVtbl,
469     &AboutProtocolFactoryVtbl
470 };
471
472 /********************************************************************
473  * ResProtocol implementation
474  */
475
476 typedef struct {
477     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
478     LONG ref;
479
480     BYTE *data;
481     ULONG data_len;
482     ULONG cur;
483
484     IUnknown *pUnkOuter;
485 } ResProtocol;
486
487 #define PROTOCOL_THIS(iface) DEFINE_THIS(ResProtocol, InternetProtocol, iface)
488
489 static HRESULT WINAPI ResProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
490 {
491     ResProtocol *This = PROTOCOL_THIS(iface);
492
493     *ppv = NULL;
494
495     if(IsEqualGUID(&IID_IUnknown, riid)) {
496         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
497         if(This->pUnkOuter)
498             return IUnknown_QueryInterface(This->pUnkOuter, &IID_IUnknown, ppv);
499         *ppv = PROTOCOL(This);
500     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
501         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
502         *ppv = PROTOCOL(This);
503     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
504         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
505         *ppv = PROTOCOL(This);
506     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
507         FIXME("IServiceProvider is not implemented\n");
508         return E_NOINTERFACE;
509     }
510
511     if(!*ppv) {
512         TRACE("unknown interface %s\n", debugstr_guid(riid));
513         return E_NOINTERFACE;
514     }
515
516     IInternetProtocol_AddRef(iface);
517     return S_OK;
518 }
519
520 static ULONG WINAPI ResProtocol_AddRef(IInternetProtocol *iface)
521 {
522     ResProtocol *This = PROTOCOL_THIS(iface);
523     ULONG ref = InterlockedIncrement(&This->ref);
524     TRACE("(%p) ref=%ld\n", iface, ref);
525     return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
526 }
527
528 static ULONG WINAPI ResProtocol_Release(IInternetProtocol *iface)
529 {
530     ResProtocol *This = (ResProtocol*)iface;
531     IUnknown *pUnkOuter = This->pUnkOuter;
532     ULONG ref = InterlockedDecrement(&This->ref);
533
534     TRACE("(%p) ref=%lx\n", iface, ref);
535
536     if(!ref) {
537         HeapFree(GetProcessHeap(), 0, This->data);
538         HeapFree(GetProcessHeap(), 0, This);
539         UNLOCK_MODULE();
540     }
541
542     return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
543 }
544
545 static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
546         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
547         DWORD grfPI, DWORD dwReserved)
548 {
549     ResProtocol *This = PROTOCOL_THIS(iface);
550     DWORD grfBINDF = 0, len;
551     BINDINFO bindinfo;
552     LPWSTR url_dll, url_file, url, mime;
553     HMODULE hdll;
554     HRSRC src;
555     HRESULT hres;
556
557     static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
558
559     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
560             pOIBindInfo, grfPI, dwReserved);
561
562     memset(&bindinfo, 0, sizeof(bindinfo));
563     bindinfo.cbSize = sizeof(BINDINFO);
564     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
565     ReleaseBindInfo(&bindinfo);
566
567     len = strlenW(szUrl)+16;
568     url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
569     hres = CoInternetParseUrl(szUrl, PARSE_ENCODE, 0, url, len, &len, 0);
570     if(FAILED(hres)) {
571         WARN("CoInternetParseUrl failed: %08lx\n", hres);
572         HeapFree(GetProcessHeap(), 0, url);
573         IInternetProtocolSink_ReportResult(pOIProtSink, hres, 0, NULL);
574         return hres;
575     }
576
577     if(len < sizeof(wszRes)/sizeof(wszRes[0]) || memcmp(url, wszRes, sizeof(wszRes))) {
578         WARN("Wrong protocol of url: %s\n", debugstr_w(url));
579         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
580         HeapFree(GetProcessHeap(), 0, url);
581         return MK_E_SYNTAX;
582     }
583
584     url_dll = url + sizeof(wszRes)/sizeof(wszRes[0]);
585     if(!(url_file = strchrW(url_dll, '/'))) {
586         WARN("wrong url: %s\n", debugstr_w(url));
587         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
588         HeapFree(GetProcessHeap(), 0, url);
589         return MK_E_SYNTAX;
590     }
591
592     *url_file++ = 0;
593     hdll = LoadLibraryExW(url_dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
594     if(!hdll) {
595         WARN("Could not open dll: %s\n", debugstr_w(url_dll));
596         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
597         return HRESULT_FROM_WIN32(GetLastError());
598     }
599
600     src = FindResourceW(hdll, url_file, (LPCWSTR)RT_HTML);
601     if(!src) {
602         WARN("Could not find resource\n");
603         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
604         HeapFree(GetProcessHeap(), 0, url);
605         return HRESULT_FROM_WIN32(GetLastError());
606     }
607
608     if(This->data) {
609         WARN("data already loaded\n");
610         HeapFree(GetProcessHeap(), 0, This->data);
611     }
612
613     This->data_len = SizeofResource(hdll, src);
614     This->data = HeapAlloc(GetProcessHeap(), 0, This->data_len);
615     memcpy(This->data, LoadResource(hdll, src), This->data_len);
616     This->cur = 0;
617
618     FreeLibrary(hdll);
619
620     hres = FindMimeFromData(NULL, url_file, NULL, 0, NULL, 0, &mime, 0);
621     HeapFree(GetProcessHeap(), 0, url);
622     if(SUCCEEDED(hres)) {
623         IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
624         CoTaskMemFree(mime);
625     }
626
627     IInternetProtocolSink_ReportData(pOIProtSink,
628             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
629             This->data_len, This->data_len);
630
631     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
632     
633     return S_OK;
634 }
635
636 static HRESULT WINAPI ResProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
637 {
638     ResProtocol *This = PROTOCOL_THIS(iface);
639     FIXME("(%p)->(%p)\n", This, pProtocolData);
640     return E_NOTIMPL;
641 }
642
643 static HRESULT WINAPI ResProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
644         DWORD dwOptions)
645 {
646     ResProtocol *This = PROTOCOL_THIS(iface);
647     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
648     return E_NOTIMPL;
649 }
650
651 static HRESULT WINAPI ResProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
652 {
653     ResProtocol *This = PROTOCOL_THIS(iface);
654
655     TRACE("(%p)->(%08lx)\n", This, dwOptions);
656
657     /* test show that we don't have to do anything here */
658     return S_OK;
659 }
660
661 static HRESULT WINAPI ResProtocol_Suspend(IInternetProtocol *iface)
662 {
663     ResProtocol *This = PROTOCOL_THIS(iface);
664     FIXME("(%p)\n", This);
665     return E_NOTIMPL;
666 }
667
668 static HRESULT WINAPI ResProtocol_Resume(IInternetProtocol *iface)
669 {
670     ResProtocol *This = PROTOCOL_THIS(iface);
671     FIXME("(%p)\n", This);
672     return E_NOTIMPL;
673 }
674
675 static HRESULT WINAPI ResProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
676 {
677     ResProtocol *This = PROTOCOL_THIS(iface);
678
679     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
680
681     if(!This->data)
682         return E_FAIL;
683
684     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
685
686     if(!*pcbRead)
687         return S_FALSE;
688
689     memcpy(pv, This->data, *pcbRead);
690     This->cur += *pcbRead;
691
692     return S_OK;
693 }
694
695 static HRESULT WINAPI ResProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
696         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
697 {
698     ResProtocol *This = PROTOCOL_THIS(iface);
699     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
700     return E_NOTIMPL;
701 }
702
703 static HRESULT WINAPI ResProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
704 {
705     ResProtocol *This = PROTOCOL_THIS(iface);
706
707     TRACE("(%p)->(%ld)\n", This, dwOptions);
708
709     /* test show that we don't have to do anything here */
710     return S_OK;
711 }
712
713 static HRESULT WINAPI ResProtocol_UnlockRequest(IInternetProtocol *iface)
714 {
715     ResProtocol *This = PROTOCOL_THIS(iface);
716
717     TRACE("(%p)\n", This);
718
719     /* test show that we don't have to do anything here */
720     return S_OK;
721 }
722
723 #undef PROTOCOL_THIS
724
725 static const IInternetProtocolVtbl ResProtocolVtbl = {
726     ResProtocol_QueryInterface,
727     ResProtocol_AddRef,
728     ResProtocol_Release,
729     ResProtocol_Start,
730     ResProtocol_Continue,
731     ResProtocol_Abort,
732     ResProtocol_Terminate,
733     ResProtocol_Suspend,
734     ResProtocol_Resume,
735     ResProtocol_Read,
736     ResProtocol_Seek,
737     ResProtocol_LockRequest,
738     ResProtocol_UnlockRequest
739 };
740
741 static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
742         REFIID riid, void **ppv)
743 {
744     ResProtocol *ret;
745     HRESULT hres = S_OK;
746
747     TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
748
749     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ResProtocol));
750     ret->lpInternetProtocolVtbl = &ResProtocolVtbl;
751     ret->ref = 0;
752     ret->data = NULL;
753     ret->data_len = 0;
754     ret->cur = 0;
755     ret->pUnkOuter = pUnkOuter;
756
757     if(pUnkOuter) {
758         ret->ref = 1;
759         if(IsEqualGUID(&IID_IUnknown, riid))
760             *ppv = PROTOCOL(ret);
761         else
762             hres = E_FAIL;
763     }else {
764         hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
765     }
766
767     if(SUCCEEDED(hres))
768         LOCK_MODULE();
769     else
770         HeapFree(GetProcessHeap(), 0, ret);
771
772     return hres;
773 }
774
775 static HRESULT WINAPI ResProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
776         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
777         DWORD* pcchResult, DWORD dwReserved)
778 {
779     TRACE("%p)->(%s %d %lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
780             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
781
782     if(ParseAction == PARSE_SECURITY_URL) {
783         WCHAR *ptr;
784         DWORD size;
785
786         static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'};
787         static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
788
789         if(strlenW(pwzUrl) <= sizeof(wszRes)/sizeof(WCHAR) || memcmp(pwzUrl, wszRes, sizeof(wszRes)))
790             return MK_E_SYNTAX;
791
792         ptr = strchrW(pwzUrl + sizeof(wszRes)/sizeof(WCHAR), '/');
793         if(!ptr)
794             return MK_E_SYNTAX;
795
796         size = ptr-pwzUrl + sizeof(wszFile)/sizeof(WCHAR) - sizeof(wszRes)/sizeof(WCHAR);
797         if(size >= cchResult)
798             return S_FALSE;
799
800         /* FIXME: return full path */
801         memcpy(pwzResult, wszFile, sizeof(wszFile));
802         memcpy(pwzResult + sizeof(wszFile)/sizeof(WCHAR),
803                 pwzUrl + sizeof(wszRes)/sizeof(WCHAR),
804                 size*sizeof(WCHAR) - sizeof(wszFile));
805         pwzResult[size] = 0;
806
807         if(pcchResult)
808             *pcchResult = size;
809         return S_OK;
810     }
811
812     if(ParseAction == PARSE_DOMAIN) {
813         /* Tests show that we don't have to do anything here */
814         return S_OK;
815     }
816
817     return INET_E_DEFAULT_ACTION;
818 }
819
820 static HRESULT WINAPI ResProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
821         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
822         DWORD* pcchResult, DWORD dwReserved)
823 {
824     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
825             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
826     return E_NOTIMPL;
827 }
828
829 static HRESULT WINAPI ResProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
830         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
831 {
832     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
833     return E_NOTIMPL;
834 }
835
836 static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
837         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
838         DWORD dwReserved)
839 {
840     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
841             cbBuffer, pcbBuf, dwReserved);
842     return E_NOTIMPL;
843 }
844
845 static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = {
846     InternetProtocolInfo_QueryInterface,
847     InternetProtocolInfo_AddRef,
848     InternetProtocolInfo_Release,
849     ResProtocolInfo_ParseUrl,
850     ResProtocolInfo_CombineUrl,
851     ResProtocolInfo_CompareUrl,
852     ResProtocolInfo_QueryInfo
853 };
854
855 static const IClassFactoryVtbl ResProtocolFactoryVtbl = {
856     ClassFactory_QueryInterface,
857     ClassFactory_AddRef,
858     ClassFactory_Release,
859     ResProtocolFactory_CreateInstance,
860     ClassFactory_LockServer
861 };
862
863 static ProtocolFactory ResProtocolFactory = {
864     &ResProtocolInfoVtbl,
865     &ResProtocolFactoryVtbl
866 };
867
868 HRESULT ProtocolFactory_Create(REFCLSID rclsid, REFIID riid, void **ppv)
869 {
870     ProtocolFactory *cf = NULL;
871
872     if(IsEqualGUID(&CLSID_AboutProtocol, rclsid))
873         cf = &AboutProtocolFactory;
874     else if(IsEqualGUID(&CLSID_ResProtocol, rclsid))
875         cf = &ResProtocolFactory;
876
877     if(!cf) {
878         FIXME("not implemented protocol %s\n", debugstr_guid(rclsid));
879         return CLASS_E_CLASSNOTAVAILABLE;
880     }
881  
882     return IUnknown_QueryInterface((IUnknown*)cf, riid, ppv);
883 }