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