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