webservices/tests: Add a test to show that the reader converts text to UTF-8.
[wine.git] / dlls / inetcomm / protocol.c
blobb7b01d4aaf2b6d0dcd9d9655ccac6d786ff4b8cf
1 /*
2 * Copyright 2017 Jacek Caban for CodeWeavers
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.
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.
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
19 #define COBJMACROS
20 #define NONAMELESSUNION
22 #include <assert.h>
24 #include "mimeole.h"
25 #include "inetcomm_private.h"
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
32 typedef struct {
33 IUnknown IUnknown_inner;
34 IInternetProtocol IInternetProtocol_iface;
35 IInternetProtocolInfo IInternetProtocolInfo_iface;
37 LONG ref;
38 IUnknown *outer_unk;
40 WCHAR *location;
41 IStream *stream;
42 IInternetProtocolSink *sink;
43 } MimeHtmlProtocol;
45 typedef struct {
46 const WCHAR *mhtml;
47 size_t mhtml_len;
48 const WCHAR *location;
49 } mhtml_url_t;
51 typedef struct {
52 IBindStatusCallback IBindStatusCallback_iface;
54 LONG ref;
56 MimeHtmlProtocol *protocol;
57 HRESULT status;
58 IStream *stream;
59 WCHAR url[1];
60 } MimeHtmlBinding;
62 static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'};
63 static const WCHAR mhtml_separatorW[] = {'!','x','-','u','s','c',':'};
65 static inline LPWSTR heap_strdupW(LPCWSTR str)
67 LPWSTR ret = NULL;
69 if(str) {
70 DWORD size;
72 size = (strlenW(str)+1)*sizeof(WCHAR);
73 ret = heap_alloc(size);
74 if(ret)
75 memcpy(ret, str, size);
78 return ret;
81 static HRESULT parse_mhtml_url(const WCHAR *url, mhtml_url_t *r)
83 const WCHAR *p;
85 if(strncmpiW(url, mhtml_prefixW, sizeof(mhtml_prefixW)/sizeof(WCHAR)))
86 return E_FAIL;
88 r->mhtml = url + sizeof(mhtml_prefixW)/sizeof(WCHAR);
89 p = strchrW(r->mhtml, '!');
90 if(p) {
91 r->mhtml_len = p - r->mhtml;
92 /* FIXME: We handle '!' and '!x-usc:' in URLs as the same thing. Those should not be the same. */
93 if(!strncmpW(p, mhtml_separatorW, sizeof(mhtml_separatorW)/sizeof(WCHAR)))
94 p += sizeof(mhtml_separatorW)/sizeof(WCHAR);
95 else
96 p++;
97 }else {
98 r->mhtml_len = strlenW(r->mhtml);
101 r->location = p;
102 return S_OK;
105 static HRESULT report_result(MimeHtmlProtocol *protocol, HRESULT result)
107 if(protocol->sink) {
108 IInternetProtocolSink_ReportResult(protocol->sink, result, ERROR_SUCCESS, NULL);
109 IInternetProtocolSink_Release(protocol->sink);
110 protocol->sink = NULL;
113 return result;
116 static HRESULT on_mime_message_available(MimeHtmlProtocol *protocol, IMimeMessage *mime_message)
118 FINDBODY find = {NULL};
119 IMimeBody *mime_body;
120 PROPVARIANT value;
121 HBODY body;
122 HRESULT hres;
124 hres = IMimeMessage_FindFirst(mime_message, &find, &body);
125 if(FAILED(hres))
126 return report_result(protocol, hres);
128 if(protocol->location) {
129 BOOL found = FALSE;
130 do {
131 hres = IMimeMessage_FindNext(mime_message, &find, &body);
132 if(FAILED(hres)) {
133 WARN("location %s not found\n", debugstr_w(protocol->location));
134 return report_result(protocol, hres);
137 value.vt = VT_LPWSTR;
138 hres = IMimeMessage_GetBodyProp(mime_message, body, "content-location", 0, &value);
139 if(hres == MIME_E_NOT_FOUND)
140 continue;
141 if(FAILED(hres))
142 return report_result(protocol, hres);
144 found = !strcmpW(protocol->location, value.u.pwszVal);
145 PropVariantClear(&value);
146 }while(!found);
147 }else {
148 hres = IMimeMessage_FindNext(mime_message, &find, &body);
149 if(FAILED(hres)) {
150 WARN("location %s not found\n", debugstr_w(protocol->location));
151 return report_result(protocol, hres);
155 hres = IMimeMessage_BindToObject(mime_message, body, &IID_IMimeBody, (void**)&mime_body);
156 if(FAILED(hres))
157 return report_result(protocol, hres);
159 value.vt = VT_LPWSTR;
160 hres = IMimeBody_GetProp(mime_body, "content-type", 0, &value);
161 if(SUCCEEDED(hres)) {
162 hres = IInternetProtocolSink_ReportProgress(protocol->sink, BINDSTATUS_MIMETYPEAVAILABLE, value.u.pwszVal);
163 PropVariantClear(&value);
166 /* FIXME: Create and report cache file. */
168 hres = IMimeBody_GetData(mime_body, IET_DECODED, &protocol->stream);
169 if(FAILED(hres))
170 return report_result(protocol, hres);
172 IInternetProtocolSink_ReportData(protocol->sink, BSCF_FIRSTDATANOTIFICATION
173 | BSCF_INTERMEDIATEDATANOTIFICATION
174 | BSCF_LASTDATANOTIFICATION
175 | BSCF_DATAFULLYAVAILABLE
176 | BSCF_AVAILABLEDATASIZEUNKNOWN, 0, 0);
178 return report_result(protocol, S_OK);
181 static HRESULT load_mime_message(IStream *stream, IMimeMessage **ret)
183 IMimeMessage *mime_message;
184 HRESULT hres;
186 hres = MimeMessage_create(NULL, (void**)&mime_message);
187 if(FAILED(hres))
188 return hres;
190 IMimeMessage_InitNew(mime_message);
192 hres = IMimeMessage_Load(mime_message, stream);
193 if(FAILED(hres)) {
194 IMimeMessage_Release(mime_message);
195 return hres;
198 *ret = mime_message;
199 return S_OK;
202 static inline MimeHtmlBinding *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
204 return CONTAINING_RECORD(iface, MimeHtmlBinding, IBindStatusCallback_iface);
207 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
208 REFIID riid, void **ppv)
210 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
212 if(IsEqualGUID(&IID_IUnknown, riid)) {
213 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
214 *ppv = &This->IBindStatusCallback_iface;
215 }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
216 TRACE("(%p)->(IID_IBindStatusCallback %p)\n", This, ppv);
217 *ppv = &This->IBindStatusCallback_iface;
218 }else {
219 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
220 *ppv = NULL;
221 return E_NOINTERFACE;
224 IUnknown_AddRef((IUnknown*)*ppv);
225 return S_OK;
228 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
230 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
231 LONG ref = InterlockedIncrement(&This->ref);
233 TRACE("(%p) ref=%d\n", This, ref);
235 return ref;
238 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
240 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
241 LONG ref = InterlockedDecrement(&This->ref);
243 TRACE("(%p) ref=%d\n", This, ref);
245 if(!ref) {
246 if(This->protocol)
247 IInternetProtocol_Release(&This->protocol->IInternetProtocol_iface);
248 if(This->stream)
249 IStream_Release(This->stream);
250 heap_free(This);
253 return ref;
256 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
257 DWORD dwReserved, IBinding *pib)
259 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
261 TRACE("(%p)->(%x %p)\n", This, dwReserved, pib);
263 assert(!This->stream);
264 return CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
267 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
269 return E_NOTIMPL;
272 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD dwReserved)
274 return E_NOTIMPL;
277 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
278 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
280 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
281 TRACE("(%p)->(%u/%u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode, debugstr_w(szStatusText));
282 return S_OK;
285 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
287 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
288 IMimeMessage *mime_message = NULL;
290 TRACE("(%p)->(%x %s)\n", This, hresult, debugstr_w(szError));
292 if(SUCCEEDED(hresult)) {
293 hresult = load_mime_message(This->stream, &mime_message);
294 IStream_Release(This->stream);
295 This->stream = NULL;
298 This->status = hresult;
300 if(mime_message)
301 on_mime_message_available(This->protocol, mime_message);
302 else
303 report_result(This->protocol, hresult);
305 if(mime_message)
306 IMimeMessage_Release(mime_message);
307 IInternetProtocol_Release(&This->protocol->IInternetProtocol_iface);
308 This->protocol = NULL;
309 return S_OK;
312 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
313 DWORD* grfBINDF, BINDINFO* pbindinfo)
315 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
317 TRACE("(%p)\n", This);
319 *grfBINDF = BINDF_ASYNCHRONOUS;
320 return S_OK;
323 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
324 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
326 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
327 BYTE buf[4*1024];
328 DWORD read;
329 HRESULT hres;
331 TRACE("(%p)\n", This);
333 assert(pstgmed->tymed == TYMED_ISTREAM);
335 while(1) {
336 hres = IStream_Read(pstgmed->u.pstm, buf, sizeof(buf), &read);
337 if(FAILED(hres))
338 return hres;
339 if(!read)
340 break;
341 hres = IStream_Write(This->stream, buf, read, NULL);
342 if(FAILED(hres))
343 return hres;
345 return S_OK;
348 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
349 REFIID riid, IUnknown* punk)
351 ERR("\n");
352 return E_NOTIMPL;
355 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
356 BindStatusCallback_QueryInterface,
357 BindStatusCallback_AddRef,
358 BindStatusCallback_Release,
359 BindStatusCallback_OnStartBinding,
360 BindStatusCallback_GetPriority,
361 BindStatusCallback_OnLowResource,
362 BindStatusCallback_OnProgress,
363 BindStatusCallback_OnStopBinding,
364 BindStatusCallback_GetBindInfo,
365 BindStatusCallback_OnDataAvailable,
366 BindStatusCallback_OnObjectAvailable
369 static inline MimeHtmlProtocol *impl_from_IUnknown(IUnknown *iface)
371 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IUnknown_inner);
374 static HRESULT WINAPI MimeHtmlProtocol_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
376 MimeHtmlProtocol *This = impl_from_IUnknown(iface);
378 if(IsEqualGUID(&IID_IUnknown, riid)) {
379 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
380 *ppv = &This->IInternetProtocol_iface;
381 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
382 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
383 *ppv = &This->IInternetProtocol_iface;
384 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
385 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
386 *ppv = &This->IInternetProtocol_iface;
387 }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) {
388 TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv);
389 *ppv = &This->IInternetProtocolInfo_iface;
390 }else {
391 FIXME("unknown interface %s\n", debugstr_guid(riid));
392 *ppv = NULL;
393 return E_NOINTERFACE;
396 IUnknown_AddRef((IUnknown*)*ppv);
397 return S_OK;
400 static ULONG WINAPI MimeHtmlProtocol_AddRef(IUnknown *iface)
402 MimeHtmlProtocol *This = impl_from_IUnknown(iface);
403 ULONG ref = InterlockedIncrement(&This->ref);
405 TRACE("(%p) ref=%d\n", This, ref);
407 return ref;
410 static ULONG WINAPI MimeHtmlProtocol_Release(IUnknown *iface)
412 MimeHtmlProtocol *This = impl_from_IUnknown(iface);
413 ULONG ref = InterlockedDecrement(&This->ref);
415 TRACE("(%p) ref=%x\n", This, ref);
417 if(!ref) {
418 if(This->sink)
419 IInternetProtocolSink_Release(This->sink);
420 if(This->stream)
421 IStream_Release(This->stream);
422 heap_free(This->location);
423 heap_free(This);
426 return ref;
429 static const IUnknownVtbl MimeHtmlProtocolInnerVtbl = {
430 MimeHtmlProtocol_QueryInterface,
431 MimeHtmlProtocol_AddRef,
432 MimeHtmlProtocol_Release
435 static inline MimeHtmlProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
437 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IInternetProtocol_iface);
440 static HRESULT WINAPI InternetProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
442 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
443 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
446 static ULONG WINAPI InternetProtocol_AddRef(IInternetProtocol *iface)
448 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
449 return IUnknown_AddRef(This->outer_unk);
452 static ULONG WINAPI InternetProtocol_Release(IInternetProtocol *iface)
454 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
455 return IUnknown_Release(This->outer_unk);
458 static HRESULT WINAPI MimeHtmlProtocol_Start(IInternetProtocol *iface, const WCHAR *szUrl,
459 IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
460 DWORD grfPI, HANDLE_PTR dwReserved)
462 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
463 BINDINFO bindinfo = { sizeof(bindinfo) };
464 MimeHtmlBinding *binding;
465 IBindCtx *bind_ctx;
466 IStream *stream;
467 mhtml_url_t url;
468 DWORD bindf = 0;
469 IMoniker *mon;
470 HRESULT hres;
472 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved);
474 hres = parse_mhtml_url(szUrl, &url);
475 if(FAILED(hres))
476 return hres;
478 if(url.location && !(This->location = heap_strdupW(url.location)))
479 return E_OUTOFMEMORY;
481 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo);
482 if(FAILED(hres)) {
483 WARN("GetBindInfo failed: %08x\n", hres);
484 return hres;
486 if((bindf & (BINDF_ASYNCHRONOUS|BINDF_FROMURLMON|BINDF_NEEDFILE)) != (BINDF_ASYNCHRONOUS|BINDF_FROMURLMON|BINDF_NEEDFILE))
487 FIXME("unsupported bindf %x\n", bindf);
489 IInternetProtocolSink_AddRef(This->sink = pOIProtSink);
491 binding = heap_alloc(FIELD_OFFSET(MimeHtmlBinding, url[url.mhtml_len+1]));
492 if(!binding)
493 return E_OUTOFMEMORY;
494 memcpy(binding->url, url.mhtml, url.mhtml_len*sizeof(WCHAR));
495 binding->url[url.mhtml_len] = 0;
497 hres = CreateURLMoniker(NULL, binding->url, &mon);
498 if(FAILED(hres)) {
499 heap_free(binding);
500 return hres;
503 binding->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
504 binding->ref = 1;
505 binding->status = E_PENDING;
506 binding->stream = NULL;
507 binding->protocol = NULL;
509 hres = CreateAsyncBindCtx(0, &binding->IBindStatusCallback_iface, NULL, &bind_ctx);
510 if(FAILED(hres)) {
511 IMoniker_Release(mon);
512 IBindStatusCallback_Release(&binding->IBindStatusCallback_iface);
513 return hres;
516 IInternetProtocol_AddRef(&This->IInternetProtocol_iface);
517 binding->protocol = This;
519 hres = IMoniker_BindToStorage(mon, bind_ctx, NULL, &IID_IStream, (void**)&stream);
520 IBindCtx_Release(bind_ctx);
521 IMoniker_Release(mon);
522 if(stream)
523 IStream_Release(stream);
524 hres = binding->status;
525 IBindStatusCallback_Release(&binding->IBindStatusCallback_iface);
526 if(FAILED(hres) && hres != E_PENDING)
527 report_result(This, hres);
528 return hres;
531 static HRESULT WINAPI MimeHtmlProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
533 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
534 FIXME("(%p)->(%p)\n", This, pProtocolData);
535 return E_NOTIMPL;
538 static HRESULT WINAPI MimeHtmlProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, DWORD dwOptions)
540 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
541 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
542 return E_NOTIMPL;
545 static HRESULT WINAPI MimeHtmlProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
547 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
548 TRACE("(%p)->(%08x)\n", This, dwOptions);
549 return S_OK;
552 static HRESULT WINAPI MimeHtmlProtocol_Suspend(IInternetProtocol *iface)
554 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
555 FIXME("(%p)\n", This);
556 return E_NOTIMPL;
559 static HRESULT WINAPI MimeHtmlProtocol_Resume(IInternetProtocol *iface)
561 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
562 FIXME("(%p)\n", This);
563 return E_NOTIMPL;
566 static HRESULT WINAPI MimeHtmlProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
568 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
569 ULONG read = 0;
570 HRESULT hres;
572 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
574 hres = IStream_Read(This->stream, pv, cb, &read);
575 if(pcbRead)
576 *pcbRead = read;
577 if(hres != S_OK)
578 return hres;
580 return read ? S_OK : S_FALSE;
583 static HRESULT WINAPI MimeHtmlProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
584 DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
586 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
587 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
588 return E_NOTIMPL;
591 static HRESULT WINAPI MimeHtmlProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
593 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
594 FIXME("(%p)->(%d)\n", This, dwOptions);
595 return S_OK;
598 static HRESULT WINAPI MimeHtmlProtocol_UnlockRequest(IInternetProtocol *iface)
600 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
601 FIXME("(%p)\n", This);
602 return S_OK;
605 static const IInternetProtocolVtbl MimeHtmlProtocolVtbl = {
606 InternetProtocol_QueryInterface,
607 InternetProtocol_AddRef,
608 InternetProtocol_Release,
609 MimeHtmlProtocol_Start,
610 MimeHtmlProtocol_Continue,
611 MimeHtmlProtocol_Abort,
612 MimeHtmlProtocol_Terminate,
613 MimeHtmlProtocol_Suspend,
614 MimeHtmlProtocol_Resume,
615 MimeHtmlProtocol_Read,
616 MimeHtmlProtocol_Seek,
617 MimeHtmlProtocol_LockRequest,
618 MimeHtmlProtocol_UnlockRequest
621 static inline MimeHtmlProtocol *impl_from_IInternetProtocolInfo(IInternetProtocolInfo *iface)
623 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IInternetProtocolInfo_iface);
626 static HRESULT WINAPI MimeHtmlProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv)
628 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
629 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
632 static ULONG WINAPI MimeHtmlProtocolInfo_AddRef(IInternetProtocolInfo *iface)
634 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
635 return IUnknown_AddRef(This->outer_unk);
638 static ULONG WINAPI MimeHtmlProtocolInfo_Release(IInternetProtocolInfo *iface)
640 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
641 return IUnknown_Release(This->outer_unk);
644 static HRESULT WINAPI MimeHtmlProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
645 PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
646 DWORD* pcchResult, DWORD dwReserved)
648 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
649 FIXME("(%p)->(%s %d %x %p %d %p %d)\n", This, debugstr_w(pwzUrl), ParseAction,
650 dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
651 return INET_E_DEFAULT_ACTION;
654 static HRESULT WINAPI MimeHtmlProtocolInfo_CombineUrl(IInternetProtocolInfo *iface,
655 LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult,
656 DWORD cchResult, DWORD* pcchResult, DWORD dwReserved)
658 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
659 size_t len = sizeof(mhtml_prefixW)/sizeof(WCHAR);
660 mhtml_url_t url;
661 WCHAR *p;
662 HRESULT hres;
664 TRACE("(%p)->(%s %s %08x %p %d %p %d)\n", This, debugstr_w(pwzBaseUrl),
665 debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult,
666 pcchResult, dwReserved);
668 hres = parse_mhtml_url(pwzBaseUrl, &url);
669 if(FAILED(hres))
670 return hres;
672 if(!strncmpiW(pwzRelativeUrl, mhtml_prefixW, sizeof(mhtml_prefixW)/sizeof(WCHAR))) {
673 FIXME("Relative URL is mhtml protocol\n");
674 return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
677 len += url.mhtml_len;
678 if(*pwzRelativeUrl)
679 len += strlenW(pwzRelativeUrl) + sizeof(mhtml_separatorW)/sizeof(WCHAR);
680 if(len >= cchResult) {
681 *pcchResult = 0;
682 return E_FAIL;
685 memcpy(pwzResult, mhtml_prefixW, sizeof(mhtml_prefixW));
686 p = pwzResult + sizeof(mhtml_prefixW)/sizeof(WCHAR);
687 memcpy(p, url.mhtml, url.mhtml_len*sizeof(WCHAR));
688 p += url.mhtml_len;
689 if(*pwzRelativeUrl) {
690 memcpy(p, mhtml_separatorW, sizeof(mhtml_separatorW));
691 p += sizeof(mhtml_separatorW)/sizeof(WCHAR);
692 strcpyW(p, pwzRelativeUrl);
693 }else {
694 *p = 0;
697 *pcchResult = len;
698 return S_OK;
701 static HRESULT WINAPI MimeHtmlProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
702 LPCWSTR pwzUrl2, DWORD dwCompareFlags)
704 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
705 FIXME("(%p)->(%s %s %08x)\n", This, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
706 return E_NOTIMPL;
709 static HRESULT WINAPI MimeHtmlProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
710 QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
711 DWORD dwReserved)
713 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
714 FIXME("(%p)->(%s %08x %08x %p %d %p %d)\n", This, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
715 cbBuffer, pcbBuf, dwReserved);
716 return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
719 static const IInternetProtocolInfoVtbl MimeHtmlProtocolInfoVtbl = {
720 MimeHtmlProtocolInfo_QueryInterface,
721 MimeHtmlProtocolInfo_AddRef,
722 MimeHtmlProtocolInfo_Release,
723 MimeHtmlProtocolInfo_ParseUrl,
724 MimeHtmlProtocolInfo_CombineUrl,
725 MimeHtmlProtocolInfo_CompareUrl,
726 MimeHtmlProtocolInfo_QueryInfo
729 HRESULT MimeHtmlProtocol_create(IUnknown *outer, void **obj)
731 MimeHtmlProtocol *protocol;
733 protocol = heap_alloc(sizeof(*protocol));
734 if(!protocol)
735 return E_OUTOFMEMORY;
737 protocol->IUnknown_inner.lpVtbl = &MimeHtmlProtocolInnerVtbl;
738 protocol->IInternetProtocol_iface.lpVtbl = &MimeHtmlProtocolVtbl;
739 protocol->IInternetProtocolInfo_iface.lpVtbl = &MimeHtmlProtocolInfoVtbl;
740 protocol->ref = 1;
741 protocol->outer_unk = outer ? outer : &protocol->IUnknown_inner;
742 protocol->location = NULL;
743 protocol->stream = NULL;
744 protocol->sink = NULL;
746 *obj = &protocol->IUnknown_inner;
747 return S_OK;