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