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
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(itss
);
38 IUnknown IUnknown_inner
;
39 IInternetProtocol IInternetProtocol_iface
;
40 IInternetProtocolInfo IInternetProtocolInfo_iface
;
46 struct chmFile
*chm_file
;
47 struct chmUnitInfo chm_object
;
50 static inline ITSProtocol
*impl_from_IUnknown(IUnknown
*iface
)
52 return CONTAINING_RECORD(iface
, ITSProtocol
, IUnknown_inner
);
55 static inline ITSProtocol
*impl_from_IInternetProtocol(IInternetProtocol
*iface
)
57 return CONTAINING_RECORD(iface
, ITSProtocol
, IInternetProtocol_iface
);
60 static inline ITSProtocol
*impl_from_IInternetProtocolInfo(IInternetProtocolInfo
*iface
)
62 return CONTAINING_RECORD(iface
, ITSProtocol
, IInternetProtocolInfo_iface
);
65 static void release_chm(ITSProtocol
*This
)
68 chm_close(This
->chm_file
);
69 This
->chm_file
= NULL
;
74 static HRESULT WINAPI
ITSProtocol_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
76 ITSProtocol
*This
= impl_from_IUnknown(iface
);
78 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
79 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
80 *ppv
= &This
->IUnknown_inner
;
81 }else if(IsEqualGUID(&IID_IInternetProtocolRoot
, riid
)) {
82 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This
, ppv
);
83 *ppv
= &This
->IInternetProtocol_iface
;
84 }else if(IsEqualGUID(&IID_IInternetProtocol
, riid
)) {
85 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This
, ppv
);
86 *ppv
= &This
->IInternetProtocol_iface
;
87 }else if(IsEqualGUID(&IID_IInternetProtocolInfo
, riid
)) {
88 TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This
, ppv
);
89 *ppv
= &This
->IInternetProtocolInfo_iface
;
92 WARN("not supported interface %s\n", debugstr_guid(riid
));
96 IUnknown_AddRef((IUnknown
*)*ppv
);
100 static ULONG WINAPI
ITSProtocol_AddRef(IUnknown
*iface
)
102 ITSProtocol
*This
= impl_from_IUnknown(iface
);
103 LONG ref
= InterlockedIncrement(&This
->ref
);
104 TRACE("(%p) ref=%d\n", This
, ref
);
108 static ULONG WINAPI
ITSProtocol_Release(IUnknown
*iface
)
110 ITSProtocol
*This
= impl_from_IUnknown(iface
);
111 LONG ref
= InterlockedDecrement(&This
->ref
);
113 TRACE("(%p) ref=%d\n", This
, ref
);
117 HeapFree(GetProcessHeap(), 0, This
);
125 static const IUnknownVtbl ITSProtocolUnkVtbl
= {
126 ITSProtocol_QueryInterface
,
131 static HRESULT WINAPI
ITSInternetProtocol_QueryInterface(IInternetProtocol
*iface
, REFIID riid
, void **ppv
)
133 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
134 return IUnknown_QueryInterface(This
->outer
, riid
, ppv
);
137 static ULONG WINAPI
ITSInternetProtocol_AddRef(IInternetProtocol
*iface
)
139 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
140 return IUnknown_AddRef(This
->outer
);
143 static ULONG WINAPI
ITSInternetProtocol_Release(IInternetProtocol
*iface
)
145 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
146 return IUnknown_Release(This
->outer
);
149 static LPCWSTR
skip_schema(LPCWSTR url
)
151 static const WCHAR its_schema
[] = {'i','t','s',':'};
152 static const WCHAR msits_schema
[] = {'m','s','-','i','t','s',':'};
153 static const WCHAR mk_schema
[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':'};
155 if(!wcsnicmp(its_schema
, url
, ARRAY_SIZE(its_schema
)))
156 return url
+ ARRAY_SIZE(its_schema
);
157 if(!wcsnicmp(msits_schema
, url
, ARRAY_SIZE(msits_schema
)))
158 return url
+ ARRAY_SIZE(msits_schema
);
159 if(!wcsnicmp(mk_schema
, url
, ARRAY_SIZE(mk_schema
)))
160 return url
+ ARRAY_SIZE(mk_schema
);
165 /* Adopted from urlmon */
166 static void remove_dot_segments(WCHAR
*path
) {
167 const WCHAR
*in
= path
;
171 /* Move the first path segment in the input buffer to the end of
172 * the output buffer, and any subsequent characters up to, including
173 * the next "/" character (if any) or the end of the input buffer.
176 if(!(*out
++ = *in
++))
186 /* Handle ending "/." */
198 /* If we don't have "/../" or ending "/.." */
199 if(in
[1] != '.' || (in
[2] && in
[2] != '/'))
204 /* Find the slash preceding out pointer and move out pointer to it */
205 if(out
> path
+1 && *--out
== '/')
207 while(out
> path
&& *(--out
) != '/');
214 static HRESULT
report_result(IInternetProtocolSink
*sink
, HRESULT hres
)
216 IInternetProtocolSink_ReportResult(sink
, hres
, 0, NULL
);
220 static HRESULT WINAPI
ITSProtocol_Start(IInternetProtocol
*iface
, LPCWSTR szUrl
,
221 IInternetProtocolSink
*pOIProtSink
, IInternetBindInfo
*pOIBindInfo
,
222 DWORD grfPI
, HANDLE_PTR dwReserved
)
224 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
226 DWORD bindf
= 0, len
;
227 LPWSTR file_name
, mime
, object_name
, p
;
229 struct chmFile
*chm_file
;
230 struct chmUnitInfo chm_object
;
234 static const WCHAR separator
[] = {':',':',0};
236 TRACE("(%p)->(%s %p %p %08x %lx)\n", This
, debugstr_w(szUrl
), pOIProtSink
,
237 pOIBindInfo
, grfPI
, dwReserved
);
239 ptr
= skip_schema(szUrl
);
241 return INET_E_USE_DEFAULT_PROTOCOLHANDLER
;
243 memset(&bindinfo
, 0, sizeof(bindinfo
));
244 bindinfo
.cbSize
= sizeof(BINDINFO
);
245 hres
= IInternetBindInfo_GetBindInfo(pOIBindInfo
, &bindf
, &bindinfo
);
247 WARN("GetBindInfo failed: %08x\n", hres
);
251 ReleaseBindInfo(&bindinfo
);
253 len
= lstrlenW(ptr
)+3;
254 file_name
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
255 memcpy(file_name
, ptr
, len
*sizeof(WCHAR
));
256 hres
= UrlUnescapeW(file_name
, NULL
, &len
, URL_UNESCAPE_INPLACE
);
258 WARN("UrlUnescape failed: %08x\n", hres
);
259 HeapFree(GetProcessHeap(), 0, file_name
);
263 p
= wcsstr(file_name
, separator
);
265 WARN("invalid url\n");
266 HeapFree(GetProcessHeap(), 0, file_name
);
267 return report_result(pOIProtSink
, STG_E_FILENOTFOUND
);
271 chm_file
= chm_openW(file_name
);
273 WARN("Could not open chm file\n");
274 HeapFree(GetProcessHeap(), 0, file_name
);
275 return report_result(pOIProtSink
, STG_E_FILENOTFOUND
);
279 len
= lstrlenW(object_name
);
281 if(*object_name
!= '/' && *object_name
!= '\\') {
282 memmove(object_name
+1, object_name
, (len
+1)*sizeof(WCHAR
));
287 if(object_name
[len
-1] == '/')
288 object_name
[--len
] = 0;
290 for(p
=object_name
; *p
; p
++) {
295 remove_dot_segments(object_name
);
297 TRACE("Resolving %s\n", debugstr_w(object_name
));
299 memset(&chm_object
, 0, sizeof(chm_object
));
300 res
= chm_resolve_object(chm_file
, object_name
, &chm_object
);
301 if(res
!= CHM_RESOLVE_SUCCESS
) {
302 WARN("Could not resolve chm object\n");
303 HeapFree(GetProcessHeap(), 0, file_name
);
305 return report_result(pOIProtSink
, STG_E_FILENOTFOUND
);
308 IInternetProtocolSink_ReportProgress(pOIProtSink
, BINDSTATUS_SENDINGREQUEST
,
309 wcsrchr(object_name
, '/')+1);
311 /* FIXME: Native doesn't use FindMimeFromData */
312 hres
= FindMimeFromData(NULL
, object_name
, NULL
, 0, NULL
, 0, &mime
, 0);
313 HeapFree(GetProcessHeap(), 0, file_name
);
314 if(SUCCEEDED(hres
)) {
315 IInternetProtocolSink_ReportProgress(pOIProtSink
, BINDSTATUS_MIMETYPEAVAILABLE
, mime
);
319 release_chm(This
); /* Native leaks handle here */
320 This
->chm_file
= chm_file
;
321 This
->chm_object
= chm_object
;
323 hres
= IInternetProtocolSink_ReportData(pOIProtSink
,
324 BSCF_FIRSTDATANOTIFICATION
|BSCF_DATAFULLYAVAILABLE
,
325 chm_object
.length
, chm_object
.length
);
327 WARN("ReportData failed: %08x\n", hres
);
329 return report_result(pOIProtSink
, hres
);
332 hres
= IInternetProtocolSink_ReportProgress(pOIProtSink
, BINDSTATUS_BEGINDOWNLOADDATA
, NULL
);
334 return report_result(pOIProtSink
, hres
);
337 static HRESULT WINAPI
ITSProtocol_Continue(IInternetProtocol
*iface
, PROTOCOLDATA
*pProtocolData
)
339 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
340 FIXME("(%p)->(%p)\n", This
, pProtocolData
);
344 static HRESULT WINAPI
ITSProtocol_Abort(IInternetProtocol
*iface
, HRESULT hrReason
,
347 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
348 FIXME("(%p)->(%08x %08x)\n", This
, hrReason
, dwOptions
);
352 static HRESULT WINAPI
ITSProtocol_Terminate(IInternetProtocol
*iface
, DWORD dwOptions
)
354 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
356 TRACE("(%p)->(%08x)\n", This
, dwOptions
);
361 static HRESULT WINAPI
ITSProtocol_Suspend(IInternetProtocol
*iface
)
363 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
364 FIXME("(%p)\n", This
);
368 static HRESULT WINAPI
ITSProtocol_Resume(IInternetProtocol
*iface
)
370 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
371 FIXME("(%p)\n", This
);
375 static HRESULT WINAPI
ITSProtocol_Read(IInternetProtocol
*iface
, void *pv
,
376 ULONG cb
, ULONG
*pcbRead
)
378 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
380 TRACE("(%p)->(%p %u %p)\n", This
, pv
, cb
, pcbRead
);
383 return INET_E_DATA_NOT_AVAILABLE
;
385 *pcbRead
= chm_retrieve_object(This
->chm_file
, &This
->chm_object
, pv
, This
->offset
, cb
);
386 This
->offset
+= *pcbRead
;
388 return *pcbRead
? S_OK
: S_FALSE
;
391 static HRESULT WINAPI
ITSProtocol_Seek(IInternetProtocol
*iface
, LARGE_INTEGER dlibMove
,
392 DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
394 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
395 FIXME("(%p)->(%d %d %p)\n", This
, dlibMove
.u
.LowPart
, dwOrigin
, plibNewPosition
);
399 static HRESULT WINAPI
ITSProtocol_LockRequest(IInternetProtocol
*iface
, DWORD dwOptions
)
401 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
403 TRACE("(%p)->(%08x)\n", This
, dwOptions
);
408 static HRESULT WINAPI
ITSProtocol_UnlockRequest(IInternetProtocol
*iface
)
410 ITSProtocol
*This
= impl_from_IInternetProtocol(iface
);
412 TRACE("(%p)\n", This
);
417 static const IInternetProtocolVtbl ITSProtocolVtbl
= {
418 ITSInternetProtocol_QueryInterface
,
419 ITSInternetProtocol_AddRef
,
420 ITSInternetProtocol_Release
,
422 ITSProtocol_Continue
,
424 ITSProtocol_Terminate
,
429 ITSProtocol_LockRequest
,
430 ITSProtocol_UnlockRequest
433 static HRESULT WINAPI
ITSProtocolInfo_QueryInterface(IInternetProtocolInfo
*iface
,
434 REFIID riid
, void **ppv
)
436 ITSProtocol
*This
= impl_from_IInternetProtocolInfo(iface
);
437 return IInternetProtocol_QueryInterface(&This
->IInternetProtocol_iface
, riid
, ppv
);
440 static ULONG WINAPI
ITSProtocolInfo_AddRef(IInternetProtocolInfo
*iface
)
442 ITSProtocol
*This
= impl_from_IInternetProtocolInfo(iface
);
443 return IInternetProtocol_AddRef(&This
->IInternetProtocol_iface
);
446 static ULONG WINAPI
ITSProtocolInfo_Release(IInternetProtocolInfo
*iface
)
448 ITSProtocol
*This
= impl_from_IInternetProtocolInfo(iface
);
449 return IInternetProtocol_Release(&This
->IInternetProtocol_iface
);
452 static HRESULT WINAPI
ITSProtocolInfo_ParseUrl(IInternetProtocolInfo
*iface
, LPCWSTR pwzUrl
,
453 PARSEACTION ParseAction
, DWORD dwParseFlags
, LPWSTR pwzResult
, DWORD cchResult
,
454 DWORD
*pcchResult
, DWORD dwReserved
)
456 ITSProtocol
*This
= impl_from_IInternetProtocolInfo(iface
);
458 TRACE("(%p)->(%s %x %08x %p %d %p %d)\n", This
, debugstr_w(pwzUrl
), ParseAction
,
459 dwParseFlags
, pwzResult
, cchResult
, pcchResult
, dwReserved
);
461 switch(ParseAction
) {
462 case PARSE_CANONICALIZE
:
463 FIXME("PARSE_CANONICALIZE\n");
465 case PARSE_SECURITY_URL
:
466 FIXME("PARSE_SECURITY_URL\n");
469 return INET_E_DEFAULT_ACTION
;
475 static HRESULT WINAPI
ITSProtocolInfo_CombineUrl(IInternetProtocolInfo
*iface
,
476 LPCWSTR pwzBaseUrl
, LPCWSTR pwzRelativeUrl
, DWORD dwCombineFlags
, LPWSTR pwzResult
,
477 DWORD cchResult
, DWORD
* pcchResult
, DWORD dwReserved
)
479 ITSProtocol
*This
= impl_from_IInternetProtocolInfo(iface
);
480 LPCWSTR base_end
, ptr
;
483 static const WCHAR separator
[] = {':',':',0};
485 TRACE("(%p)->(%s %s %08x %p %d %p %d)\n", This
, debugstr_w(pwzBaseUrl
),
486 debugstr_w(pwzRelativeUrl
), dwCombineFlags
, pwzResult
, cchResult
,
487 pcchResult
, dwReserved
);
489 base_end
= wcsstr(pwzBaseUrl
, separator
);
494 if(!skip_schema(pwzBaseUrl
))
495 return INET_E_USE_DEFAULT_PROTOCOLHANDLER
;
497 if(wcschr(pwzRelativeUrl
, ':'))
498 return STG_E_INVALIDNAME
;
500 if(pwzRelativeUrl
[0] == '#') {
501 base_end
+= lstrlenW(base_end
);
502 }else if(pwzRelativeUrl
[0] != '/') {
503 ptr
= wcsrchr(base_end
, '/');
507 base_end
+= lstrlenW(base_end
);
510 rel_len
= lstrlenW(pwzRelativeUrl
)+1;
512 *pcchResult
= rel_len
+ (base_end
-pwzBaseUrl
);
514 if(*pcchResult
> cchResult
)
515 return E_OUTOFMEMORY
;
517 memcpy(pwzResult
, pwzBaseUrl
, (base_end
-pwzBaseUrl
)*sizeof(WCHAR
));
518 lstrcpyW(pwzResult
+ (base_end
-pwzBaseUrl
), pwzRelativeUrl
);
523 static HRESULT WINAPI
ITSProtocolInfo_CompareUrl(IInternetProtocolInfo
*iface
, LPCWSTR pwzUrl1
,
524 LPCWSTR pwzUrl2
, DWORD dwCompareFlags
)
526 ITSProtocol
*This
= impl_from_IInternetProtocolInfo(iface
);
527 FIXME("%p)->(%s %s %08x)\n", This
, debugstr_w(pwzUrl1
), debugstr_w(pwzUrl2
), dwCompareFlags
);
531 static HRESULT WINAPI
ITSProtocolInfo_QueryInfo(IInternetProtocolInfo
*iface
, LPCWSTR pwzUrl
,
532 QUERYOPTION QueryOption
, DWORD dwQueryFlags
, LPVOID pBuffer
, DWORD cbBuffer
, DWORD
* pcbBuf
,
535 ITSProtocol
*This
= impl_from_IInternetProtocolInfo(iface
);
536 FIXME("(%p)->(%s %08x %08x %p %d %p %d)\n", This
, debugstr_w(pwzUrl
), QueryOption
,
537 dwQueryFlags
, pBuffer
, cbBuffer
, pcbBuf
, dwReserved
);
541 static const IInternetProtocolInfoVtbl ITSProtocolInfoVtbl
= {
542 ITSProtocolInfo_QueryInterface
,
543 ITSProtocolInfo_AddRef
,
544 ITSProtocolInfo_Release
,
545 ITSProtocolInfo_ParseUrl
,
546 ITSProtocolInfo_CombineUrl
,
547 ITSProtocolInfo_CompareUrl
,
548 ITSProtocolInfo_QueryInfo
551 HRESULT
ITSProtocol_create(IUnknown
*outer
, void **ppv
)
555 TRACE("(%p %p)\n", outer
, ppv
);
559 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ITSProtocol
));
561 return E_OUTOFMEMORY
;
563 ret
->IUnknown_inner
.lpVtbl
= &ITSProtocolUnkVtbl
;
564 ret
->IInternetProtocol_iface
.lpVtbl
= &ITSProtocolVtbl
;
565 ret
->IInternetProtocolInfo_iface
.lpVtbl
= &ITSProtocolInfoVtbl
;
567 ret
->outer
= outer
? outer
: &ret
->IUnknown_inner
;
569 *ppv
= &ret
->IUnknown_inner
;