usp10: Handle multi-glyph clusters in ScriptStringOut.
[wine/multimedia.git] / dlls / itss / protocol.c
blobfa2ad8bd5af70d64c4b5a92f73197e2c776ca71f
1 /*
2 * Copyright 2006-2007 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 #include <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "winreg.h"
27 #include "ole2.h"
28 #include "urlmon.h"
29 #include "shlwapi.h"
30 #include "itsstor.h"
31 #include "chm_lib.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(itss);
38 typedef struct {
39 IInternetProtocol IInternetProtocol_iface;
40 IInternetProtocolInfo IInternetProtocolInfo_iface;
42 LONG ref;
44 ULONG offset;
45 struct chmFile *chm_file;
46 struct chmUnitInfo chm_object;
47 } ITSProtocol;
49 static inline ITSProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
51 return CONTAINING_RECORD(iface, ITSProtocol, IInternetProtocol_iface);
54 static inline ITSProtocol *impl_from_IInternetProtocolInfo(IInternetProtocolInfo *iface)
56 return CONTAINING_RECORD(iface, ITSProtocol, IInternetProtocolInfo_iface);
59 static void release_chm(ITSProtocol *This)
61 if(This->chm_file) {
62 chm_close(This->chm_file);
63 This->chm_file = NULL;
65 This->offset = 0;
68 static HRESULT WINAPI ITSProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
70 ITSProtocol *This = impl_from_IInternetProtocol(iface);
72 *ppv = NULL;
73 if(IsEqualGUID(&IID_IUnknown, riid)) {
74 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
75 *ppv = &This->IInternetProtocol_iface;
76 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
77 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
78 *ppv = &This->IInternetProtocol_iface;
79 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
80 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
81 *ppv = &This->IInternetProtocol_iface;
82 }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) {
83 TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv);
84 *ppv = &This->IInternetProtocolInfo_iface;
87 if(*ppv) {
88 IInternetProtocol_AddRef(iface);
89 return S_OK;
92 WARN("not supported interface %s\n", debugstr_guid(riid));
93 return E_NOINTERFACE;
96 static ULONG WINAPI ITSProtocol_AddRef(IInternetProtocol *iface)
98 ITSProtocol *This = impl_from_IInternetProtocol(iface);
99 LONG ref = InterlockedIncrement(&This->ref);
100 TRACE("(%p) ref=%d\n", This, ref);
101 return ref;
104 static ULONG WINAPI ITSProtocol_Release(IInternetProtocol *iface)
106 ITSProtocol *This = impl_from_IInternetProtocol(iface);
107 LONG ref = InterlockedDecrement(&This->ref);
109 TRACE("(%p) ref=%d\n", This, ref);
111 if(!ref) {
112 release_chm(This);
113 HeapFree(GetProcessHeap(), 0, This);
115 ITSS_UnlockModule();
118 return ref;
121 static LPCWSTR skip_schema(LPCWSTR url)
123 static const WCHAR its_schema[] = {'i','t','s',':'};
124 static const WCHAR msits_schema[] = {'m','s','-','i','t','s',':'};
125 static const WCHAR mk_schema[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':'};
127 if(!strncmpiW(its_schema, url, sizeof(its_schema)/sizeof(WCHAR)))
128 return url+sizeof(its_schema)/sizeof(WCHAR);
129 if(!strncmpiW(msits_schema, url, sizeof(msits_schema)/sizeof(WCHAR)))
130 return url+sizeof(msits_schema)/sizeof(WCHAR);
131 if(!strncmpiW(mk_schema, url, sizeof(mk_schema)/sizeof(WCHAR)))
132 return url+sizeof(mk_schema)/sizeof(WCHAR);
134 return NULL;
137 static HRESULT report_result(IInternetProtocolSink *sink, HRESULT hres)
139 IInternetProtocolSink_ReportResult(sink, hres, 0, NULL);
140 return hres;
143 static HRESULT WINAPI ITSProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
144 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
145 DWORD grfPI, HANDLE_PTR dwReserved)
147 ITSProtocol *This = impl_from_IInternetProtocol(iface);
148 BINDINFO bindinfo;
149 DWORD bindf = 0, len;
150 LPWSTR file_name, mime, object_name, p;
151 LPCWSTR ptr;
152 struct chmFile *chm_file;
153 struct chmUnitInfo chm_object;
154 int res;
155 HRESULT hres;
157 static const WCHAR separator[] = {':',':',0};
159 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
160 pOIBindInfo, grfPI, dwReserved);
162 ptr = skip_schema(szUrl);
163 if(!ptr)
164 return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
166 memset(&bindinfo, 0, sizeof(bindinfo));
167 bindinfo.cbSize = sizeof(BINDINFO);
168 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo);
169 if(FAILED(hres)) {
170 WARN("GetBindInfo failed: %08x\n", hres);
171 return hres;
174 ReleaseBindInfo(&bindinfo);
176 len = strlenW(ptr)+3;
177 file_name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
178 memcpy(file_name, ptr, len*sizeof(WCHAR));
179 hres = UrlUnescapeW(file_name, NULL, &len, URL_UNESCAPE_INPLACE);
180 if(FAILED(hres)) {
181 WARN("UrlUnescape failed: %08x\n", hres);
182 HeapFree(GetProcessHeap(), 0, file_name);
183 return hres;
186 p = strstrW(file_name, separator);
187 if(!p) {
188 WARN("invalid url\n");
189 HeapFree(GetProcessHeap(), 0, file_name);
190 return report_result(pOIProtSink, STG_E_FILENOTFOUND);
193 *p = 0;
194 chm_file = chm_openW(file_name);
195 if(!chm_file) {
196 WARN("Could not open chm file\n");
197 HeapFree(GetProcessHeap(), 0, file_name);
198 return report_result(pOIProtSink, STG_E_FILENOTFOUND);
201 object_name = p+2;
202 len = strlenW(object_name);
204 if(*object_name != '/' && *object_name != '\\') {
205 memmove(object_name+1, object_name, (len+1)*sizeof(WCHAR));
206 *object_name = '/';
207 len++;
210 if(object_name[len-1] == '/')
211 object_name[--len] = 0;
213 for(p=object_name; *p; p++) {
214 if(*p == '\\')
215 *p = '/';
218 TRACE("Resolving %s\n", debugstr_w(object_name));
220 memset(&chm_object, 0, sizeof(chm_object));
221 res = chm_resolve_object(chm_file, object_name, &chm_object);
222 if(res != CHM_RESOLVE_SUCCESS) {
223 WARN("Could not resolve chm object\n");
224 HeapFree(GetProcessHeap(), 0, file_name);
225 chm_close(chm_file);
226 return report_result(pOIProtSink, STG_E_FILENOTFOUND);
229 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST,
230 strrchrW(object_name, '/')+1);
232 /* FIXME: Native doesn't use FindMimeFromData */
233 hres = FindMimeFromData(NULL, object_name, NULL, 0, NULL, 0, &mime, 0);
234 HeapFree(GetProcessHeap(), 0, file_name);
235 if(SUCCEEDED(hres)) {
236 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
237 CoTaskMemFree(mime);
240 release_chm(This); /* Native leaks handle here */
241 This->chm_file = chm_file;
242 This->chm_object = chm_object;
244 hres = IInternetProtocolSink_ReportData(pOIProtSink,
245 BSCF_FIRSTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE,
246 chm_object.length, chm_object.length);
247 if(FAILED(hres)) {
248 WARN("ReportData failed: %08x\n", hres);
249 release_chm(This);
250 return report_result(pOIProtSink, hres);
253 hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_BEGINDOWNLOADDATA, NULL);
255 return report_result(pOIProtSink, hres);
258 static HRESULT WINAPI ITSProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
260 ITSProtocol *This = impl_from_IInternetProtocol(iface);
261 FIXME("(%p)->(%p)\n", This, pProtocolData);
262 return E_NOTIMPL;
265 static HRESULT WINAPI ITSProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
266 DWORD dwOptions)
268 ITSProtocol *This = impl_from_IInternetProtocol(iface);
269 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
270 return E_NOTIMPL;
273 static HRESULT WINAPI ITSProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
275 ITSProtocol *This = impl_from_IInternetProtocol(iface);
277 TRACE("(%p)->(%08x)\n", This, dwOptions);
279 return S_OK;
282 static HRESULT WINAPI ITSProtocol_Suspend(IInternetProtocol *iface)
284 ITSProtocol *This = impl_from_IInternetProtocol(iface);
285 FIXME("(%p)\n", This);
286 return E_NOTIMPL;
289 static HRESULT WINAPI ITSProtocol_Resume(IInternetProtocol *iface)
291 ITSProtocol *This = impl_from_IInternetProtocol(iface);
292 FIXME("(%p)\n", This);
293 return E_NOTIMPL;
296 static HRESULT WINAPI ITSProtocol_Read(IInternetProtocol *iface, void *pv,
297 ULONG cb, ULONG *pcbRead)
299 ITSProtocol *This = impl_from_IInternetProtocol(iface);
301 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
303 if(!This->chm_file)
304 return INET_E_DATA_NOT_AVAILABLE;
306 *pcbRead = chm_retrieve_object(This->chm_file, &This->chm_object, pv, This->offset, cb);
307 This->offset += *pcbRead;
309 return *pcbRead ? S_OK : S_FALSE;
312 static HRESULT WINAPI ITSProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
313 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
315 ITSProtocol *This = impl_from_IInternetProtocol(iface);
316 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
317 return E_NOTIMPL;
320 static HRESULT WINAPI ITSProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
322 ITSProtocol *This = impl_from_IInternetProtocol(iface);
324 TRACE("(%p)->(%08x)\n", This, dwOptions);
326 return S_OK;
329 static HRESULT WINAPI ITSProtocol_UnlockRequest(IInternetProtocol *iface)
331 ITSProtocol *This = impl_from_IInternetProtocol(iface);
333 TRACE("(%p)\n", This);
335 return S_OK;
338 static const IInternetProtocolVtbl ITSProtocolVtbl = {
339 ITSProtocol_QueryInterface,
340 ITSProtocol_AddRef,
341 ITSProtocol_Release,
342 ITSProtocol_Start,
343 ITSProtocol_Continue,
344 ITSProtocol_Abort,
345 ITSProtocol_Terminate,
346 ITSProtocol_Suspend,
347 ITSProtocol_Resume,
348 ITSProtocol_Read,
349 ITSProtocol_Seek,
350 ITSProtocol_LockRequest,
351 ITSProtocol_UnlockRequest
354 static HRESULT WINAPI ITSProtocolInfo_QueryInterface(IInternetProtocolInfo *iface,
355 REFIID riid, void **ppv)
357 ITSProtocol *This = impl_from_IInternetProtocolInfo(iface);
358 return IInternetProtocol_QueryInterface(&This->IInternetProtocol_iface, riid, ppv);
361 static ULONG WINAPI ITSProtocolInfo_AddRef(IInternetProtocolInfo *iface)
363 ITSProtocol *This = impl_from_IInternetProtocolInfo(iface);
364 return IInternetProtocol_AddRef(&This->IInternetProtocol_iface);
367 static ULONG WINAPI ITSProtocolInfo_Release(IInternetProtocolInfo *iface)
369 ITSProtocol *This = impl_from_IInternetProtocolInfo(iface);
370 return IInternetProtocol_Release(&This->IInternetProtocol_iface);
373 static HRESULT WINAPI ITSProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
374 PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
375 DWORD *pcchResult, DWORD dwReserved)
377 ITSProtocol *This = impl_from_IInternetProtocolInfo(iface);
379 TRACE("(%p)->(%s %x %08x %p %d %p %d)\n", This, debugstr_w(pwzUrl), ParseAction,
380 dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
382 switch(ParseAction) {
383 case PARSE_CANONICALIZE:
384 FIXME("PARSE_CANONICALIZE\n");
385 return E_NOTIMPL;
386 case PARSE_SECURITY_URL:
387 FIXME("PARSE_SECURITY_URL\n");
388 return E_NOTIMPL;
389 default:
390 return INET_E_DEFAULT_ACTION;
393 return S_OK;
396 static HRESULT WINAPI ITSProtocolInfo_CombineUrl(IInternetProtocolInfo *iface,
397 LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult,
398 DWORD cchResult, DWORD* pcchResult, DWORD dwReserved)
400 ITSProtocol *This = impl_from_IInternetProtocolInfo(iface);
401 LPCWSTR base_end, ptr;
402 DWORD rel_len;
404 static const WCHAR separator[] = {':',':',0};
406 TRACE("(%p)->(%s %s %08x %p %d %p %d)\n", This, debugstr_w(pwzBaseUrl),
407 debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult,
408 pcchResult, dwReserved);
410 base_end = strstrW(pwzBaseUrl, separator);
411 if(!base_end)
412 return 0x80041001;
413 base_end += 2;
415 if(!skip_schema(pwzBaseUrl))
416 return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
418 if(strchrW(pwzRelativeUrl, ':'))
419 return STG_E_INVALIDNAME;
421 if(pwzRelativeUrl[0] != '/') {
422 ptr = strrchrW(base_end, '/');
423 if(ptr)
424 base_end = ptr+1;
425 else
426 base_end += strlenW(base_end);
429 rel_len = strlenW(pwzRelativeUrl)+1;
431 *pcchResult = rel_len + (base_end-pwzBaseUrl);
433 if(*pcchResult > cchResult)
434 return E_OUTOFMEMORY;
436 memcpy(pwzResult, pwzBaseUrl, (base_end-pwzBaseUrl)*sizeof(WCHAR));
437 strcpyW(pwzResult + (base_end-pwzBaseUrl), pwzRelativeUrl);
439 return S_OK;
442 static HRESULT WINAPI ITSProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
443 LPCWSTR pwzUrl2, DWORD dwCompareFlags)
445 ITSProtocol *This = impl_from_IInternetProtocolInfo(iface);
446 FIXME("%p)->(%s %s %08x)\n", This, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
447 return E_NOTIMPL;
450 static HRESULT WINAPI ITSProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
451 QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
452 DWORD dwReserved)
454 ITSProtocol *This = impl_from_IInternetProtocolInfo(iface);
455 FIXME("(%p)->(%s %08x %08x %p %d %p %d)\n", This, debugstr_w(pwzUrl), QueryOption,
456 dwQueryFlags, pBuffer, cbBuffer, pcbBuf, dwReserved);
457 return E_NOTIMPL;
460 static const IInternetProtocolInfoVtbl ITSProtocolInfoVtbl = {
461 ITSProtocolInfo_QueryInterface,
462 ITSProtocolInfo_AddRef,
463 ITSProtocolInfo_Release,
464 ITSProtocolInfo_ParseUrl,
465 ITSProtocolInfo_CombineUrl,
466 ITSProtocolInfo_CompareUrl,
467 ITSProtocolInfo_QueryInfo
470 HRESULT ITSProtocol_create(IUnknown *pUnkOuter, LPVOID *ppobj)
472 ITSProtocol *ret;
474 TRACE("(%p %p)\n", pUnkOuter, ppobj);
476 ITSS_LockModule();
478 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ITSProtocol));
480 ret->IInternetProtocol_iface.lpVtbl = &ITSProtocolVtbl;
481 ret->IInternetProtocolInfo_iface.lpVtbl = &ITSProtocolInfoVtbl;
482 ret->ref = 1;
484 *ppobj = &ret->IInternetProtocol_iface;
486 return S_OK;