shlwapi: Implement URL_APPLY_GUESSFILE in UrlApplyScheme.
[wine] / dlls / msxml3 / bsc.c
1 /*
2  * Copyright 2008 Piotr 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 #define COBJMACROS
20 #define NONAMELESSUNION
21
22 #include "config.h"
23
24 #include <stdarg.h>
25 #ifdef HAVE_LIBXML2
26 # include <libxml/parser.h>
27 # include <libxml/xmlerror.h>
28 #endif
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "ole2.h"
34 #include "msxml6.h"
35 #include "wininet.h"
36 #include "urlmon.h"
37 #include "winreg.h"
38 #include "shlwapi.h"
39
40 #include "wine/debug.h"
41
42 #include "msxml_private.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
45
46 struct bsc_t {
47     IBindStatusCallback IBindStatusCallback_iface;
48
49     LONG ref;
50
51     void *obj;
52     HRESULT (*onDataAvailable)(void*,char*,DWORD);
53
54     IBinding *binding;
55     IStream *memstream;
56 };
57
58 static inline bsc_t *impl_from_IBindStatusCallback( IBindStatusCallback *iface )
59 {
60     return CONTAINING_RECORD(iface, bsc_t, IBindStatusCallback_iface);
61 }
62
63 static HRESULT WINAPI bsc_QueryInterface(
64     IBindStatusCallback *iface,
65     REFIID riid,
66     LPVOID *ppobj )
67 {
68     if (IsEqualGUID(riid, &IID_IUnknown) ||
69         IsEqualGUID(riid, &IID_IBindStatusCallback))
70     {
71         IBindStatusCallback_AddRef( iface );
72         *ppobj = iface;
73         return S_OK;
74     }
75
76     TRACE("interface %s not implemented\n", debugstr_guid(riid));
77     *ppobj = NULL;
78     return E_NOINTERFACE;
79 }
80
81 static ULONG WINAPI bsc_AddRef(
82     IBindStatusCallback *iface )
83 {
84     bsc_t *This = impl_from_IBindStatusCallback(iface);
85     LONG ref = InterlockedIncrement(&This->ref);
86
87     TRACE("(%p) ref=%d\n", This, ref);
88
89     return ref;
90 }
91
92 static ULONG WINAPI bsc_Release(
93     IBindStatusCallback *iface )
94 {
95     bsc_t *This = impl_from_IBindStatusCallback(iface);
96     LONG ref = InterlockedDecrement(&This->ref);
97
98     TRACE("(%p) ref=%d\n", This, ref);
99
100     if(!ref) {
101         if (This->binding)   IBinding_Release(This->binding);
102         if (This->memstream) IStream_Release(This->memstream);
103         heap_free(This);
104     }
105
106     return ref;
107 }
108
109 static HRESULT WINAPI bsc_OnStartBinding(
110         IBindStatusCallback* iface,
111         DWORD dwReserved,
112         IBinding* pib)
113 {
114     bsc_t *This = impl_from_IBindStatusCallback(iface);
115     HRESULT hr;
116
117     TRACE("(%p)->(%x %p)\n", This, dwReserved, pib);
118
119     This->binding = pib;
120     IBinding_AddRef(pib);
121
122     hr = CreateStreamOnHGlobal(NULL, TRUE, &This->memstream);
123     if(FAILED(hr))
124         return hr;
125
126     return S_OK;
127 }
128
129 static HRESULT WINAPI bsc_GetPriority(
130         IBindStatusCallback* iface,
131         LONG* pnPriority)
132 {
133     return S_OK;
134 }
135
136 static HRESULT WINAPI bsc_OnLowResource(
137         IBindStatusCallback* iface,
138         DWORD reserved)
139 {
140     return S_OK;
141 }
142
143 static HRESULT WINAPI bsc_OnProgress(
144         IBindStatusCallback* iface,
145         ULONG ulProgress,
146         ULONG ulProgressMax,
147         ULONG ulStatusCode,
148         LPCWSTR szStatusText)
149 {
150     return S_OK;
151 }
152
153 static HRESULT WINAPI bsc_OnStopBinding(
154         IBindStatusCallback* iface,
155         HRESULT hresult,
156         LPCWSTR szError)
157 {
158     bsc_t *This = impl_from_IBindStatusCallback(iface);
159     HRESULT hr = S_OK;
160
161     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
162
163     if(This->binding) {
164         IBinding_Release(This->binding);
165         This->binding = NULL;
166     }
167
168     if(This->obj && SUCCEEDED(hresult)) {
169         HGLOBAL hglobal;
170         hr = GetHGlobalFromStream(This->memstream, &hglobal);
171         if(SUCCEEDED(hr))
172         {
173             DWORD len = GlobalSize(hglobal);
174             char *ptr = GlobalLock(hglobal);
175
176             hr = This->onDataAvailable(This->obj, ptr, len);
177
178             GlobalUnlock(hglobal);
179         }
180     }
181
182     return hr;
183 }
184
185 static HRESULT WINAPI bsc_GetBindInfo(
186         IBindStatusCallback* iface,
187         DWORD* grfBINDF,
188         BINDINFO* pbindinfo)
189 {
190     *grfBINDF = BINDF_GETNEWESTVERSION|BINDF_PULLDATA|BINDF_RESYNCHRONIZE|BINDF_PRAGMA_NO_CACHE;
191
192     return S_OK;
193 }
194
195 static HRESULT WINAPI bsc_OnDataAvailable(
196         IBindStatusCallback* iface,
197         DWORD grfBSCF,
198         DWORD dwSize,
199         FORMATETC* pformatetc,
200         STGMEDIUM* pstgmed)
201 {
202     bsc_t *This = impl_from_IBindStatusCallback(iface);
203     BYTE buf[4096];
204     DWORD read, written;
205     HRESULT hr;
206
207     TRACE("(%p)->(%x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
208
209     do
210     {
211         hr = IStream_Read(pstgmed->u.pstm, buf, sizeof(buf), &read);
212         if(FAILED(hr))
213             break;
214
215         hr = IStream_Write(This->memstream, buf, read, &written);
216     } while(SUCCEEDED(hr) && written != 0 && read != 0);
217
218     return S_OK;
219 }
220
221 static HRESULT WINAPI bsc_OnObjectAvailable(
222         IBindStatusCallback* iface,
223         REFIID riid,
224         IUnknown* punk)
225 {
226     return S_OK;
227 }
228
229 static const struct IBindStatusCallbackVtbl bsc_vtbl =
230 {
231     bsc_QueryInterface,
232     bsc_AddRef,
233     bsc_Release,
234     bsc_OnStartBinding,
235     bsc_GetPriority,
236     bsc_OnLowResource,
237     bsc_OnProgress,
238     bsc_OnStopBinding,
239     bsc_GetBindInfo,
240     bsc_OnDataAvailable,
241     bsc_OnObjectAvailable
242 };
243
244 HRESULT bind_url(LPCWSTR url, HRESULT (*onDataAvailable)(void*,char*,DWORD), void *obj, bsc_t **ret)
245 {
246     WCHAR fileUrl[INTERNET_MAX_URL_LENGTH];
247     bsc_t *bsc;
248     IBindCtx *pbc;
249     HRESULT hr;
250
251     TRACE("%s\n", debugstr_w(url));
252
253     if(!PathIsURLW(url))
254     {
255         WCHAR fullpath[MAX_PATH];
256         DWORD needed = sizeof(fileUrl)/sizeof(WCHAR);
257
258         if(!PathSearchAndQualifyW(url, fullpath, sizeof(fullpath)/sizeof(WCHAR)))
259         {
260             WARN("can't find path\n");
261             return E_FAIL;
262         }
263
264         if(FAILED(UrlCreateFromPathW(url, fileUrl, &needed, 0)))
265         {
266             ERR("can't create url from path\n");
267             return E_FAIL;
268         }
269         url = fileUrl;
270     }
271
272     hr = CreateBindCtx(0, &pbc);
273     if(FAILED(hr))
274         return hr;
275
276     bsc = heap_alloc(sizeof(bsc_t));
277
278     bsc->IBindStatusCallback_iface.lpVtbl = &bsc_vtbl;
279     bsc->ref = 1;
280     bsc->obj = obj;
281     bsc->onDataAvailable = onDataAvailable;
282     bsc->binding = NULL;
283     bsc->memstream = NULL;
284
285     hr = RegisterBindStatusCallback(pbc, &bsc->IBindStatusCallback_iface, NULL, 0);
286     if(SUCCEEDED(hr))
287     {
288         IMoniker *moniker;
289
290         hr = CreateURLMoniker(NULL, url, &moniker);
291         if(SUCCEEDED(hr))
292         {
293             IStream *stream;
294             hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
295             IMoniker_Release(moniker);
296             if(stream)
297                 IStream_Release(stream);
298         }
299         IBindCtx_Release(pbc);
300     }
301
302     if(FAILED(hr))
303     {
304         IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
305         bsc = NULL;
306     }
307
308     *ret = bsc;
309     return hr;
310 }
311
312 void detach_bsc(bsc_t *bsc)
313 {
314     if(bsc->binding)
315         IBinding_Abort(bsc->binding);
316
317     bsc->obj = NULL;
318     IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
319 }