wined3d: Implement more GLSL instructions and a little cleanup.
[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 #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         if(!pcchResult)
418             return E_POINTER;
419
420         if(pwzUrl)
421             *pcchResult = strlenW(pwzUrl)+1;
422         else
423             *pcchResult = 1;
424         return E_FAIL;
425     }
426
427     return INET_E_DEFAULT_ACTION;
428 }
429
430 static HRESULT WINAPI AboutProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
431         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
432         DWORD* pcchResult, DWORD dwReserved)
433 {
434     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
435             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
436     return E_NOTIMPL;
437 }
438
439 static HRESULT WINAPI AboutProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
440         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
441 {
442     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
443     return E_NOTIMPL;
444 }
445
446 static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
447         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
448         DWORD dwReserved)
449 {
450     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
451             cbBuffer, pcbBuf, dwReserved);
452     return E_NOTIMPL;
453 }
454
455 static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = {
456     InternetProtocolInfo_QueryInterface,
457     InternetProtocolInfo_AddRef,
458     InternetProtocolInfo_Release,
459     AboutProtocolInfo_ParseUrl,
460     AboutProtocolInfo_CombineUrl,
461     AboutProtocolInfo_CompareUrl,
462     AboutProtocolInfo_QueryInfo
463 };
464
465 static const IClassFactoryVtbl AboutProtocolFactoryVtbl = {
466     ClassFactory_QueryInterface,
467     ClassFactory_AddRef,
468     ClassFactory_Release,
469     AboutProtocolFactory_CreateInstance,
470     ClassFactory_LockServer
471 };
472
473 static ProtocolFactory AboutProtocolFactory = {
474     &AboutProtocolInfoVtbl,
475     &AboutProtocolFactoryVtbl
476 };
477
478 /********************************************************************
479  * ResProtocol implementation
480  */
481
482 typedef struct {
483     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
484     LONG ref;
485
486     BYTE *data;
487     ULONG data_len;
488     ULONG cur;
489
490     IUnknown *pUnkOuter;
491 } ResProtocol;
492
493 #define PROTOCOL_THIS(iface) DEFINE_THIS(ResProtocol, InternetProtocol, iface)
494
495 static HRESULT WINAPI ResProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
496 {
497     ResProtocol *This = PROTOCOL_THIS(iface);
498
499     *ppv = NULL;
500
501     if(IsEqualGUID(&IID_IUnknown, riid)) {
502         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
503         if(This->pUnkOuter)
504             return IUnknown_QueryInterface(This->pUnkOuter, &IID_IUnknown, ppv);
505         *ppv = PROTOCOL(This);
506     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
507         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
508         *ppv = PROTOCOL(This);
509     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
510         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
511         *ppv = PROTOCOL(This);
512     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
513         FIXME("IServiceProvider is not implemented\n");
514         return E_NOINTERFACE;
515     }
516
517     if(!*ppv) {
518         TRACE("unknown interface %s\n", debugstr_guid(riid));
519         return E_NOINTERFACE;
520     }
521
522     IInternetProtocol_AddRef(iface);
523     return S_OK;
524 }
525
526 static ULONG WINAPI ResProtocol_AddRef(IInternetProtocol *iface)
527 {
528     ResProtocol *This = PROTOCOL_THIS(iface);
529     ULONG ref = InterlockedIncrement(&This->ref);
530     TRACE("(%p) ref=%ld\n", iface, ref);
531     return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
532 }
533
534 static ULONG WINAPI ResProtocol_Release(IInternetProtocol *iface)
535 {
536     ResProtocol *This = (ResProtocol*)iface;
537     IUnknown *pUnkOuter = This->pUnkOuter;
538     ULONG ref = InterlockedDecrement(&This->ref);
539
540     TRACE("(%p) ref=%lx\n", iface, ref);
541
542     if(!ref) {
543         HeapFree(GetProcessHeap(), 0, This->data);
544         HeapFree(GetProcessHeap(), 0, This);
545         UNLOCK_MODULE();
546     }
547
548     return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
549 }
550
551 static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
552         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
553         DWORD grfPI, DWORD dwReserved)
554 {
555     ResProtocol *This = PROTOCOL_THIS(iface);
556     DWORD grfBINDF = 0, len;
557     BINDINFO bindinfo;
558     LPWSTR url_dll, url_file, url, mime;
559     HMODULE hdll;
560     HRSRC src;
561     HRESULT hres;
562
563     static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
564
565     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
566             pOIBindInfo, grfPI, dwReserved);
567
568     memset(&bindinfo, 0, sizeof(bindinfo));
569     bindinfo.cbSize = sizeof(BINDINFO);
570     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
571     ReleaseBindInfo(&bindinfo);
572
573     len = strlenW(szUrl)+16;
574     url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
575     hres = CoInternetParseUrl(szUrl, PARSE_ENCODE, 0, url, len, &len, 0);
576     if(FAILED(hres)) {
577         WARN("CoInternetParseUrl failed: %08lx\n", hres);
578         HeapFree(GetProcessHeap(), 0, url);
579         IInternetProtocolSink_ReportResult(pOIProtSink, hres, 0, NULL);
580         return hres;
581     }
582
583     if(len < sizeof(wszRes)/sizeof(wszRes[0]) || memcmp(url, wszRes, sizeof(wszRes))) {
584         WARN("Wrong protocol of url: %s\n", debugstr_w(url));
585         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
586         HeapFree(GetProcessHeap(), 0, url);
587         return MK_E_SYNTAX;
588     }
589
590     url_dll = url + sizeof(wszRes)/sizeof(wszRes[0]);
591     if(!(url_file = strchrW(url_dll, '/'))) {
592         WARN("wrong url: %s\n", debugstr_w(url));
593         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
594         HeapFree(GetProcessHeap(), 0, url);
595         return MK_E_SYNTAX;
596     }
597
598     *url_file++ = 0;
599     hdll = LoadLibraryExW(url_dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
600     if(!hdll) {
601         WARN("Could not open dll: %s\n", debugstr_w(url_dll));
602         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
603         return HRESULT_FROM_WIN32(GetLastError());
604     }
605
606     src = FindResourceW(hdll, url_file, (LPCWSTR)RT_HTML);
607     if(!src) {
608         WARN("Could not find resource\n");
609         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
610         HeapFree(GetProcessHeap(), 0, url);
611         return HRESULT_FROM_WIN32(GetLastError());
612     }
613
614     if(This->data) {
615         WARN("data already loaded\n");
616         HeapFree(GetProcessHeap(), 0, This->data);
617     }
618
619     This->data_len = SizeofResource(hdll, src);
620     This->data = HeapAlloc(GetProcessHeap(), 0, This->data_len);
621     memcpy(This->data, LoadResource(hdll, src), This->data_len);
622     This->cur = 0;
623
624     FreeLibrary(hdll);
625
626     hres = FindMimeFromData(NULL, url_file, NULL, 0, NULL, 0, &mime, 0);
627     HeapFree(GetProcessHeap(), 0, url);
628     if(SUCCEEDED(hres)) {
629         IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
630         CoTaskMemFree(mime);
631     }
632
633     IInternetProtocolSink_ReportData(pOIProtSink,
634             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
635             This->data_len, This->data_len);
636
637     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
638     
639     return S_OK;
640 }
641
642 static HRESULT WINAPI ResProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
643 {
644     ResProtocol *This = PROTOCOL_THIS(iface);
645     FIXME("(%p)->(%p)\n", This, pProtocolData);
646     return E_NOTIMPL;
647 }
648
649 static HRESULT WINAPI ResProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
650         DWORD dwOptions)
651 {
652     ResProtocol *This = PROTOCOL_THIS(iface);
653     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
654     return E_NOTIMPL;
655 }
656
657 static HRESULT WINAPI ResProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
658 {
659     ResProtocol *This = PROTOCOL_THIS(iface);
660
661     TRACE("(%p)->(%08lx)\n", This, dwOptions);
662
663     /* test show that we don't have to do anything here */
664     return S_OK;
665 }
666
667 static HRESULT WINAPI ResProtocol_Suspend(IInternetProtocol *iface)
668 {
669     ResProtocol *This = PROTOCOL_THIS(iface);
670     FIXME("(%p)\n", This);
671     return E_NOTIMPL;
672 }
673
674 static HRESULT WINAPI ResProtocol_Resume(IInternetProtocol *iface)
675 {
676     ResProtocol *This = PROTOCOL_THIS(iface);
677     FIXME("(%p)\n", This);
678     return E_NOTIMPL;
679 }
680
681 static HRESULT WINAPI ResProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
682 {
683     ResProtocol *This = PROTOCOL_THIS(iface);
684
685     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
686
687     if(!This->data)
688         return E_FAIL;
689
690     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
691
692     if(!*pcbRead)
693         return S_FALSE;
694
695     memcpy(pv, This->data, *pcbRead);
696     This->cur += *pcbRead;
697
698     return S_OK;
699 }
700
701 static HRESULT WINAPI ResProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
702         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
703 {
704     ResProtocol *This = PROTOCOL_THIS(iface);
705     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
706     return E_NOTIMPL;
707 }
708
709 static HRESULT WINAPI ResProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
710 {
711     ResProtocol *This = PROTOCOL_THIS(iface);
712
713     TRACE("(%p)->(%ld)\n", This, dwOptions);
714
715     /* test show that we don't have to do anything here */
716     return S_OK;
717 }
718
719 static HRESULT WINAPI ResProtocol_UnlockRequest(IInternetProtocol *iface)
720 {
721     ResProtocol *This = PROTOCOL_THIS(iface);
722
723     TRACE("(%p)\n", This);
724
725     /* test show that we don't have to do anything here */
726     return S_OK;
727 }
728
729 #undef PROTOCOL_THIS
730
731 static const IInternetProtocolVtbl ResProtocolVtbl = {
732     ResProtocol_QueryInterface,
733     ResProtocol_AddRef,
734     ResProtocol_Release,
735     ResProtocol_Start,
736     ResProtocol_Continue,
737     ResProtocol_Abort,
738     ResProtocol_Terminate,
739     ResProtocol_Suspend,
740     ResProtocol_Resume,
741     ResProtocol_Read,
742     ResProtocol_Seek,
743     ResProtocol_LockRequest,
744     ResProtocol_UnlockRequest
745 };
746
747 static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
748         REFIID riid, void **ppv)
749 {
750     ResProtocol *ret;
751     HRESULT hres = S_OK;
752
753     TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
754
755     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ResProtocol));
756     ret->lpInternetProtocolVtbl = &ResProtocolVtbl;
757     ret->ref = 0;
758     ret->data = NULL;
759     ret->data_len = 0;
760     ret->cur = 0;
761     ret->pUnkOuter = pUnkOuter;
762
763     if(pUnkOuter) {
764         ret->ref = 1;
765         if(IsEqualGUID(&IID_IUnknown, riid))
766             *ppv = PROTOCOL(ret);
767         else
768             hres = E_FAIL;
769     }else {
770         hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
771     }
772
773     if(SUCCEEDED(hres))
774         LOCK_MODULE();
775     else
776         HeapFree(GetProcessHeap(), 0, ret);
777
778     return hres;
779 }
780
781 static HRESULT WINAPI ResProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
782         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
783         DWORD* pcchResult, DWORD dwReserved)
784 {
785     TRACE("%p)->(%s %d %lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
786             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
787
788     if(ParseAction == PARSE_SECURITY_URL) {
789         WCHAR *ptr;
790         DWORD size;
791
792         static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'};
793         static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
794
795         if(strlenW(pwzUrl) <= sizeof(wszRes)/sizeof(WCHAR) || memcmp(pwzUrl, wszRes, sizeof(wszRes)))
796             return MK_E_SYNTAX;
797
798         ptr = strchrW(pwzUrl + sizeof(wszRes)/sizeof(WCHAR), '/');
799         if(!ptr)
800             return MK_E_SYNTAX;
801
802         size = ptr-pwzUrl + sizeof(wszFile)/sizeof(WCHAR) - sizeof(wszRes)/sizeof(WCHAR);
803         if(size >= cchResult)
804             return S_FALSE;
805
806         /* FIXME: return full path */
807         memcpy(pwzResult, wszFile, sizeof(wszFile));
808         memcpy(pwzResult + sizeof(wszFile)/sizeof(WCHAR),
809                 pwzUrl + sizeof(wszRes)/sizeof(WCHAR),
810                 size*sizeof(WCHAR) - sizeof(wszFile));
811         pwzResult[size] = 0;
812
813         if(pcchResult)
814             *pcchResult = size;
815         return S_OK;
816     }
817
818     if(ParseAction == PARSE_DOMAIN) {
819         if(!pcchResult)
820             return E_POINTER;
821
822         if(pwzUrl)
823             *pcchResult = strlenW(pwzUrl)+1;
824         else
825             *pcchResult = 1;
826         return E_FAIL;
827     }
828
829     return INET_E_DEFAULT_ACTION;
830 }
831
832 static HRESULT WINAPI ResProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
833         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
834         DWORD* pcchResult, DWORD dwReserved)
835 {
836     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
837             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
838     return E_NOTIMPL;
839 }
840
841 static HRESULT WINAPI ResProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
842         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
843 {
844     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
845     return E_NOTIMPL;
846 }
847
848 static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
849         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
850         DWORD dwReserved)
851 {
852     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
853             cbBuffer, pcbBuf, dwReserved);
854     return E_NOTIMPL;
855 }
856
857 static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = {
858     InternetProtocolInfo_QueryInterface,
859     InternetProtocolInfo_AddRef,
860     InternetProtocolInfo_Release,
861     ResProtocolInfo_ParseUrl,
862     ResProtocolInfo_CombineUrl,
863     ResProtocolInfo_CompareUrl,
864     ResProtocolInfo_QueryInfo
865 };
866
867 static const IClassFactoryVtbl ResProtocolFactoryVtbl = {
868     ClassFactory_QueryInterface,
869     ClassFactory_AddRef,
870     ClassFactory_Release,
871     ResProtocolFactory_CreateInstance,
872     ClassFactory_LockServer
873 };
874
875 static ProtocolFactory ResProtocolFactory = {
876     &ResProtocolInfoVtbl,
877     &ResProtocolFactoryVtbl
878 };
879
880 HRESULT ProtocolFactory_Create(REFCLSID rclsid, REFIID riid, void **ppv)
881 {
882     ProtocolFactory *cf = NULL;
883
884     if(IsEqualGUID(&CLSID_AboutProtocol, rclsid))
885         cf = &AboutProtocolFactory;
886     else if(IsEqualGUID(&CLSID_ResProtocol, rclsid))
887         cf = &ResProtocolFactory;
888
889     if(!cf) {
890         FIXME("not implemented protocol %s\n", debugstr_guid(rclsid));
891         return CLASS_E_CLASSNOTAVAILABLE;
892     }
893  
894     return IUnknown_QueryInterface((IUnknown*)cf, riid, ppv);
895 }