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"
34 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(itss
);
39 const IInternetProtocolVtbl
*lpInternetProtocolVtbl
;
40 const IInternetProtocolInfoVtbl
*lpInternetProtocolInfoVtbl
;
45 struct chmFile
*chm_file
;
46 struct chmUnitInfo chm_object
;
49 #define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
50 #define PROTINFO(x) ((IInternetProtocolInfo*) &(x)->lpInternetProtocolInfoVtbl)
52 static void release_chm(ITSProtocol
*This
)
55 chm_close(This
->chm_file
);
56 This
->chm_file
= NULL
;
61 #define PROTOCOL_THIS(iface) DEFINE_THIS(ITSProtocol, InternetProtocol, iface)
63 static HRESULT WINAPI
ITSProtocol_QueryInterface(IInternetProtocol
*iface
, REFIID riid
, void **ppv
)
65 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
68 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
69 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
70 *ppv
= PROTOCOL(This
);
71 }else if(IsEqualGUID(&IID_IInternetProtocolRoot
, riid
)) {
72 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This
, ppv
);
73 *ppv
= PROTOCOL(This
);
74 }else if(IsEqualGUID(&IID_IInternetProtocol
, riid
)) {
75 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This
, ppv
);
76 *ppv
= PROTOCOL(This
);
77 }else if(IsEqualGUID(&IID_IInternetProtocolInfo
, riid
)) {
78 TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This
, ppv
);
79 *ppv
= PROTINFO(This
);
83 IInternetProtocol_AddRef(iface
);
87 WARN("not supported interface %s\n", debugstr_guid(riid
));
91 static ULONG WINAPI
ITSProtocol_AddRef(IInternetProtocol
*iface
)
93 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
94 LONG ref
= InterlockedIncrement(&This
->ref
);
95 TRACE("(%p) ref=%d\n", This
, ref
);
99 static ULONG WINAPI
ITSProtocol_Release(IInternetProtocol
*iface
)
101 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
102 LONG ref
= InterlockedDecrement(&This
->ref
);
104 TRACE("(%p) ref=%d\n", This
, ref
);
108 HeapFree(GetProcessHeap(), 0, This
);
116 static LPCWSTR
skip_schema(LPCWSTR url
)
118 static const WCHAR its_schema
[] = {'i','t','s',':'};
119 static const WCHAR msits_schema
[] = {'m','s','-','i','t','s',':'};
120 static const WCHAR mk_schema
[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':'};
122 if(!strncmpiW(its_schema
, url
, sizeof(its_schema
)/sizeof(WCHAR
)))
123 return url
+sizeof(its_schema
)/sizeof(WCHAR
);
124 if(!strncmpiW(msits_schema
, url
, sizeof(msits_schema
)/sizeof(WCHAR
)))
125 return url
+sizeof(msits_schema
)/sizeof(WCHAR
);
126 if(!strncmpiW(mk_schema
, url
, sizeof(mk_schema
)/sizeof(WCHAR
)))
127 return url
+sizeof(mk_schema
)/sizeof(WCHAR
);
132 static HRESULT
report_result(IInternetProtocolSink
*sink
, HRESULT hres
)
134 IInternetProtocolSink_ReportResult(sink
, hres
, 0, NULL
);
138 static HRESULT WINAPI
ITSProtocol_Start(IInternetProtocol
*iface
, LPCWSTR szUrl
,
139 IInternetProtocolSink
*pOIProtSink
, IInternetBindInfo
*pOIBindInfo
,
140 DWORD grfPI
, DWORD dwReserved
)
142 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
144 DWORD bindf
= 0, len
;
145 LPWSTR file_name
, mime
, object_name
, p
;
147 struct chmFile
*chm_file
;
148 struct chmUnitInfo chm_object
;
152 static const WCHAR separator
[] = {':',':',0};
154 TRACE("(%p)->(%s %p %p %08x %d)\n", This
, debugstr_w(szUrl
), pOIProtSink
,
155 pOIBindInfo
, grfPI
, dwReserved
);
157 ptr
= skip_schema(szUrl
);
159 return INET_E_USE_DEFAULT_PROTOCOLHANDLER
;
161 memset(&bindinfo
, 0, sizeof(bindinfo
));
162 bindinfo
.cbSize
= sizeof(BINDINFO
);
163 hres
= IInternetBindInfo_GetBindInfo(pOIBindInfo
, &bindf
, &bindinfo
);
165 WARN("GetBindInfo failed: %08x\n", hres
);
169 ReleaseBindInfo(&bindinfo
);
171 len
= strlenW(ptr
)+3;
172 file_name
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
173 memcpy(file_name
, ptr
, len
*sizeof(WCHAR
));
174 hres
= UrlUnescapeW(file_name
, NULL
, &len
, URL_UNESCAPE_INPLACE
);
176 WARN("UrlUnescape failed: %08x\n", hres
);
177 HeapFree(GetProcessHeap(), 0, file_name
);
181 p
= strstrW(file_name
, separator
);
183 WARN("invalid url\n");
184 HeapFree(GetProcessHeap(), 0, file_name
);
185 return report_result(pOIProtSink
, STG_E_FILENOTFOUND
);
189 chm_file
= chm_openW(file_name
);
191 WARN("Could not open chm file\n");
192 HeapFree(GetProcessHeap(), 0, file_name
);
193 return report_result(pOIProtSink
, STG_E_FILENOTFOUND
);
197 len
= strlenW(object_name
);
199 if(*object_name
!= '/' && *object_name
!= '\\') {
200 memmove(object_name
+1, object_name
, (len
+1)*sizeof(WCHAR
));
205 if(object_name
[len
-1] == '/')
206 object_name
[--len
] = 0;
208 for(p
=object_name
; *p
; p
++) {
213 TRACE("Resolving %s\n", debugstr_w(object_name
));
215 memset(&chm_object
, 0, sizeof(chm_object
));
216 res
= chm_resolve_object(chm_file
, object_name
, &chm_object
);
217 if(res
!= CHM_RESOLVE_SUCCESS
) {
218 WARN("Could not resolve chm object\n");
219 HeapFree(GetProcessHeap(), 0, file_name
);
221 return report_result(pOIProtSink
, STG_E_FILENOTFOUND
);
224 IInternetProtocolSink_ReportProgress(pOIProtSink
, BINDSTATUS_SENDINGREQUEST
,
225 strrchrW(object_name
, '/')+1);
227 /* FIXME: Native doesn't use FindMimeFromData */
228 hres
= FindMimeFromData(NULL
, object_name
, NULL
, 0, NULL
, 0, &mime
, 0);
229 HeapFree(GetProcessHeap(), 0, file_name
);
230 if(SUCCEEDED(hres
)) {
231 IInternetProtocolSink_ReportProgress(pOIProtSink
, BINDSTATUS_MIMETYPEAVAILABLE
, mime
);
235 release_chm(This
); /* Native leaks handle here */
236 This
->chm_file
= chm_file
;
237 This
->chm_object
= chm_object
;
239 hres
= IInternetProtocolSink_ReportData(pOIProtSink
,
240 BSCF_FIRSTDATANOTIFICATION
|BSCF_DATAFULLYAVAILABLE
,
241 chm_object
.length
, chm_object
.length
);
243 WARN("ReportData failed: %08x\n", hres
);
245 return report_result(pOIProtSink
, hres
);
248 hres
= IInternetProtocolSink_ReportProgress(pOIProtSink
, BINDSTATUS_BEGINDOWNLOADDATA
, NULL
);
250 return report_result(pOIProtSink
, hres
);
253 static HRESULT WINAPI
ITSProtocol_Continue(IInternetProtocol
*iface
, PROTOCOLDATA
*pProtocolData
)
255 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
256 FIXME("(%p)->(%p)\n", This
, pProtocolData
);
260 static HRESULT WINAPI
ITSProtocol_Abort(IInternetProtocol
*iface
, HRESULT hrReason
,
263 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
264 FIXME("(%p)->(%08x %08x)\n", This
, hrReason
, dwOptions
);
268 static HRESULT WINAPI
ITSProtocol_Terminate(IInternetProtocol
*iface
, DWORD dwOptions
)
270 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
272 TRACE("(%p)->(%08x)\n", This
, dwOptions
);
277 static HRESULT WINAPI
ITSProtocol_Suspend(IInternetProtocol
*iface
)
279 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
280 FIXME("(%p)\n", This
);
284 static HRESULT WINAPI
ITSProtocol_Resume(IInternetProtocol
*iface
)
286 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
287 FIXME("(%p)\n", This
);
291 static HRESULT WINAPI
ITSProtocol_Read(IInternetProtocol
*iface
, void *pv
,
292 ULONG cb
, ULONG
*pcbRead
)
294 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
296 TRACE("(%p)->(%p %u %p)\n", This
, pv
, cb
, pcbRead
);
299 return INET_E_DATA_NOT_AVAILABLE
;
301 *pcbRead
= chm_retrieve_object(This
->chm_file
, &This
->chm_object
, pv
, This
->offset
, cb
);
302 This
->offset
+= *pcbRead
;
304 return *pcbRead
? S_OK
: S_FALSE
;
307 static HRESULT WINAPI
ITSProtocol_Seek(IInternetProtocol
*iface
, LARGE_INTEGER dlibMove
,
308 DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
310 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
311 FIXME("(%p)->(%d %d %p)\n", This
, dlibMove
.u
.LowPart
, dwOrigin
, plibNewPosition
);
315 static HRESULT WINAPI
ITSProtocol_LockRequest(IInternetProtocol
*iface
, DWORD dwOptions
)
317 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
319 TRACE("(%p)->(%08x)\n", This
, dwOptions
);
324 static HRESULT WINAPI
ITSProtocol_UnlockRequest(IInternetProtocol
*iface
)
326 ITSProtocol
*This
= PROTOCOL_THIS(iface
);
328 TRACE("(%p)\n", This
);
335 static const IInternetProtocolVtbl ITSProtocolVtbl
= {
336 ITSProtocol_QueryInterface
,
340 ITSProtocol_Continue
,
342 ITSProtocol_Terminate
,
347 ITSProtocol_LockRequest
,
348 ITSProtocol_UnlockRequest
351 #define PROTINFO_THIS(iface) DEFINE_THIS(ITSProtocol, InternetProtocolInfo, iface)
353 static HRESULT WINAPI
ITSProtocolInfo_QueryInterface(IInternetProtocolInfo
*iface
,
354 REFIID riid
, void **ppv
)
356 ITSProtocol
*This
= PROTINFO_THIS(iface
);
357 return IInternetProtocol_QueryInterface(PROTOCOL(This
), riid
, ppv
);
360 static ULONG WINAPI
ITSProtocolInfo_AddRef(IInternetProtocolInfo
*iface
)
362 ITSProtocol
*This
= PROTINFO_THIS(iface
);
363 return IInternetProtocol_AddRef(PROTOCOL(This
));
366 static ULONG WINAPI
ITSProtocolInfo_Release(IInternetProtocolInfo
*iface
)
368 ITSProtocol
*This
= PROTINFO_THIS(iface
);
369 return IInternetProtocol_Release(PROTOCOL(This
));
372 static HRESULT WINAPI
ITSProtocolInfo_ParseUrl(IInternetProtocolInfo
*iface
, LPCWSTR pwzUrl
,
373 PARSEACTION ParseAction
, DWORD dwParseFlags
, LPWSTR pwzResult
, DWORD cchResult
,
374 DWORD
*pcchResult
, DWORD dwReserved
)
376 ITSProtocol
*This
= PROTINFO_THIS(iface
);
378 TRACE("(%p)->(%s %x %08x %p %d %p %d)\n", This
, debugstr_w(pwzUrl
), ParseAction
,
379 dwParseFlags
, pwzResult
, cchResult
, pcchResult
, dwReserved
);
381 switch(ParseAction
) {
382 case PARSE_CANONICALIZE
:
383 FIXME("PARSE_CANONICALIZE\n");
385 case PARSE_SECURITY_URL
:
386 FIXME("PARSE_SECURITY_URL\n");
389 return INET_E_DEFAULT_ACTION
;
395 static HRESULT WINAPI
ITSProtocolInfo_CombineUrl(IInternetProtocolInfo
*iface
,
396 LPCWSTR pwzBaseUrl
, LPCWSTR pwzRelativeUrl
, DWORD dwCombineFlags
, LPWSTR pwzResult
,
397 DWORD cchResult
, DWORD
* pcchResult
, DWORD dwReserved
)
399 ITSProtocol
*This
= PROTINFO_THIS(iface
);
400 LPCWSTR base_end
, ptr
;
403 static const WCHAR separator
[] = {':',':',0};
405 TRACE("(%p)->(%s %s %08x %p %d %p %d)\n", This
, debugstr_w(pwzBaseUrl
),
406 debugstr_w(pwzRelativeUrl
), dwCombineFlags
, pwzResult
, cchResult
,
407 pcchResult
, dwReserved
);
409 base_end
= strstrW(pwzBaseUrl
, separator
);
414 if(!skip_schema(pwzBaseUrl
))
415 return INET_E_USE_DEFAULT_PROTOCOLHANDLER
;
417 if(strchrW(pwzRelativeUrl
, ':'))
418 return STG_E_INVALIDNAME
;
420 if(pwzRelativeUrl
[0] != '/') {
421 ptr
= strrchrW(base_end
, '/');
425 base_end
+= strlenW(base_end
);
428 rel_len
= strlenW(pwzRelativeUrl
)+1;
430 *pcchResult
= rel_len
+ (base_end
-pwzBaseUrl
);
432 if(*pcchResult
> cchResult
)
433 return E_OUTOFMEMORY
;
435 memcpy(pwzResult
, pwzBaseUrl
, (base_end
-pwzBaseUrl
)*sizeof(WCHAR
));
436 strcpyW(pwzResult
+ (base_end
-pwzBaseUrl
), pwzRelativeUrl
);
441 static HRESULT WINAPI
ITSProtocolInfo_CompareUrl(IInternetProtocolInfo
*iface
, LPCWSTR pwzUrl1
,
442 LPCWSTR pwzUrl2
, DWORD dwCompareFlags
)
444 ITSProtocol
*This
= PROTINFO_THIS(iface
);
445 FIXME("%p)->(%s %s %08x)\n", This
, debugstr_w(pwzUrl1
), debugstr_w(pwzUrl2
), dwCompareFlags
);
449 static HRESULT WINAPI
ITSProtocolInfo_QueryInfo(IInternetProtocolInfo
*iface
, LPCWSTR pwzUrl
,
450 QUERYOPTION QueryOption
, DWORD dwQueryFlags
, LPVOID pBuffer
, DWORD cbBuffer
, DWORD
* pcbBuf
,
453 ITSProtocol
*This
= PROTINFO_THIS(iface
);
454 FIXME("(%p)->(%s %08x %08x %p %d %p %d)\n", This
, debugstr_w(pwzUrl
), QueryOption
,
455 dwQueryFlags
, pBuffer
, cbBuffer
, pcbBuf
, dwReserved
);
461 static const IInternetProtocolInfoVtbl ITSProtocolInfoVtbl
= {
462 ITSProtocolInfo_QueryInterface
,
463 ITSProtocolInfo_AddRef
,
464 ITSProtocolInfo_Release
,
465 ITSProtocolInfo_ParseUrl
,
466 ITSProtocolInfo_CombineUrl
,
467 ITSProtocolInfo_CompareUrl
,
468 ITSProtocolInfo_QueryInfo
471 HRESULT
ITSProtocol_create(IUnknown
*pUnkOuter
, LPVOID
*ppobj
)
475 TRACE("(%p %p)\n", pUnkOuter
, ppobj
);
479 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ITSProtocol
));
481 ret
->lpInternetProtocolVtbl
= &ITSProtocolVtbl
;
482 ret
->lpInternetProtocolInfoVtbl
= &ITSProtocolInfoVtbl
;
485 *ppobj
= PROTOCOL(ret
);