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