msvcp90: Added char_traits<wchar_t> implementation.
[wine] / dlls / urlmon / umstream.c
1 /*
2  * Based on ../shell32/memorystream.c
3  *
4  * Copyright 1999 Juergen Schmied
5  * Copyright 2003 Mike McCormack for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "urlmon_main.h"
23
24 #include "winreg.h"
25 #include "winternl.h"
26 #include "wininet.h"
27 #include "shlwapi.h"
28
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
32
33 typedef struct ProxyBindStatusCallback
34 {
35     const IBindStatusCallbackVtbl *lpVtbl;
36
37     IBindStatusCallback *pBSC;
38 } ProxyBindStatusCallback;
39
40 static HRESULT WINAPI ProxyBindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
41 {
42     if (IsEqualGUID(&IID_IBindStatusCallback, riid) ||
43         IsEqualGUID(&IID_IUnknown, riid))
44     {
45         *ppv = iface;
46         IUnknown_AddRef(iface);
47         return S_OK;
48     }
49
50     *ppv = NULL;
51     return E_NOINTERFACE;
52 }
53
54 static ULONG WINAPI ProxyBindStatusCallback_AddRef(IBindStatusCallback *iface)
55 {
56     return 2;
57 }
58
59 static ULONG WINAPI ProxyBindStatusCallback_Release(IBindStatusCallback *iface)
60 {
61     return 1;
62 }
63
64 static HRESULT WINAPI ProxyBindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
65                                                IBinding *pib)
66 {
67     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
68
69     if(This->pBSC)
70         return IBindStatusCallback_OnStartBinding(This->pBSC, dwReserved, pib);
71
72     return S_OK;
73 }
74
75 static HRESULT WINAPI ProxyBindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
76 {
77     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
78
79     if(This->pBSC)
80         return IBindStatusCallback_GetPriority(This->pBSC, pnPriority);
81
82     return S_OK;
83 }
84
85 static HRESULT WINAPI ProxyBindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
86 {
87     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
88
89     if(This->pBSC)
90         return IBindStatusCallback_OnLowResource(This->pBSC, reserved);
91
92     return S_OK;
93 }
94
95 static HRESULT WINAPI ProxyBindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
96                                            ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
97 {
98     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
99
100     if(This->pBSC)
101         return IBindStatusCallback_OnProgress(This->pBSC, ulProgress,
102                                           ulProgressMax, ulStatusCode,
103                                           szStatusText);
104
105     return S_OK;
106 }
107
108 static HRESULT WINAPI ProxyBindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
109 {
110     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
111
112     if(This->pBSC)
113         return IBindStatusCallback_OnStopBinding(This->pBSC, hresult, szError);
114
115     return S_OK;
116 }
117
118 static HRESULT WINAPI ProxyBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
119 {
120     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
121
122     if(This->pBSC)
123         return IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
124
125     return E_INVALIDARG;
126 }
127
128 static HRESULT WINAPI ProxyBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
129                                                               DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
130 {
131     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
132
133     if(This->pBSC)
134         return IBindStatusCallback_OnDataAvailable(This->pBSC, grfBSCF, dwSize,
135                                                pformatetc, pstgmed);
136
137     return S_OK;
138 }
139
140 static HRESULT WINAPI ProxyBindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
141 {
142     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
143
144     if(This->pBSC)
145         return IBindStatusCallback_OnObjectAvailable(This->pBSC, riid, punk);
146
147     return S_OK;
148 }
149
150 static HRESULT WINAPI BlockingBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
151                                                                  DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
152 {
153     return S_OK;
154 }
155
156 static const IBindStatusCallbackVtbl BlockingBindStatusCallbackVtbl =
157 {
158     ProxyBindStatusCallback_QueryInterface,
159     ProxyBindStatusCallback_AddRef,
160     ProxyBindStatusCallback_Release,
161     ProxyBindStatusCallback_OnStartBinding,
162     ProxyBindStatusCallback_GetPriority,
163     ProxyBindStatusCallback_OnLowResource,
164     ProxyBindStatusCallback_OnProgress,
165     ProxyBindStatusCallback_OnStopBinding,
166     ProxyBindStatusCallback_GetBindInfo,
167     BlockingBindStatusCallback_OnDataAvailable,
168     ProxyBindStatusCallback_OnObjectAvailable
169 };
170
171 static HRESULT WINAPI AsyncBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
172 {
173     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
174     HRESULT hr = IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
175     *grfBINDF |= BINDF_PULLDATA | BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
176     return hr;
177 }
178
179 static const IBindStatusCallbackVtbl AsyncBindStatusCallbackVtbl =
180 {
181     ProxyBindStatusCallback_QueryInterface,
182     ProxyBindStatusCallback_AddRef,
183     ProxyBindStatusCallback_Release,
184     ProxyBindStatusCallback_OnStartBinding,
185     ProxyBindStatusCallback_GetPriority,
186     ProxyBindStatusCallback_OnLowResource,
187     ProxyBindStatusCallback_OnProgress,
188     ProxyBindStatusCallback_OnStopBinding,
189     AsyncBindStatusCallback_GetBindInfo,
190     ProxyBindStatusCallback_OnDataAvailable,
191     ProxyBindStatusCallback_OnObjectAvailable
192 };
193
194 static HRESULT URLStartDownload(LPCWSTR szURL, LPSTREAM *ppStream, IBindStatusCallback *pBSC)
195 {
196     HRESULT hr;
197     IMoniker *pMoniker;
198     IBindCtx *pbc;
199
200     *ppStream = NULL;
201
202     hr = CreateURLMoniker(NULL, szURL, &pMoniker);
203     if (FAILED(hr))
204         return hr;
205
206     hr = CreateBindCtx(0, &pbc);
207     if (FAILED(hr))
208     {
209         IMoniker_Release(pMoniker);
210         return hr;
211     }
212
213     hr = RegisterBindStatusCallback(pbc, pBSC, NULL, 0);
214     if (FAILED(hr))
215     {
216         IBindCtx_Release(pbc);
217         IMoniker_Release(pMoniker);
218         return hr;
219     }
220
221     hr = IMoniker_BindToStorage(pMoniker, pbc, NULL, &IID_IStream, (void **)ppStream);
222
223     /* BindToStorage returning E_PENDING because it's asynchronous is not an error */
224     if (hr == E_PENDING) hr = S_OK;
225
226     IBindCtx_Release(pbc);
227     IMoniker_Release(pMoniker);
228
229     return hr;
230 }
231
232 /***********************************************************************
233  *              URLOpenBlockingStreamA (URLMON.@)
234  */
235 HRESULT WINAPI URLOpenBlockingStreamA(LPUNKNOWN pCaller, LPCSTR szURL,
236                                       LPSTREAM *ppStream, DWORD dwReserved,
237                                       LPBINDSTATUSCALLBACK lpfnCB)
238 {
239     LPWSTR szURLW;
240     int len;
241     HRESULT hr;
242
243     TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, szURL, ppStream, dwReserved, lpfnCB);
244
245     if (!szURL || !ppStream)
246         return E_INVALIDARG;
247
248     len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
249     szURLW = heap_alloc(len * sizeof(WCHAR));
250     if (!szURLW)
251     {
252         *ppStream = NULL;
253         return E_OUTOFMEMORY;
254     }
255     MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
256
257     hr = URLOpenBlockingStreamW(pCaller, szURLW, ppStream, dwReserved, lpfnCB);
258
259     heap_free(szURLW);
260
261     return hr;
262 }
263
264 /***********************************************************************
265  *              URLOpenBlockingStreamW (URLMON.@)
266  */
267 HRESULT WINAPI URLOpenBlockingStreamW(LPUNKNOWN pCaller, LPCWSTR szURL,
268                                       LPSTREAM *ppStream, DWORD dwReserved,
269                                       LPBINDSTATUSCALLBACK lpfnCB)
270 {
271     ProxyBindStatusCallback blocking_bsc;
272
273     TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, debugstr_w(szURL), ppStream,
274           dwReserved, lpfnCB);
275
276     if (!szURL || !ppStream)
277         return E_INVALIDARG;
278
279     blocking_bsc.lpVtbl = &BlockingBindStatusCallbackVtbl;
280     blocking_bsc.pBSC = lpfnCB;
281
282     return URLStartDownload(szURL, ppStream, (IBindStatusCallback *)&blocking_bsc);
283 }
284
285 /***********************************************************************
286  *              URLOpenStreamA (URLMON.@)
287  */
288 HRESULT WINAPI URLOpenStreamA(LPUNKNOWN pCaller, LPCSTR szURL, DWORD dwReserved,
289                               LPBINDSTATUSCALLBACK lpfnCB)
290 {
291     LPWSTR szURLW;
292     int len;
293     HRESULT hr;
294
295     TRACE("(%p, %s, 0x%x, %p)\n", pCaller, szURL, dwReserved, lpfnCB);
296
297     if (!szURL)
298         return E_INVALIDARG;
299
300     len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
301     szURLW = heap_alloc(len * sizeof(WCHAR));
302     if (!szURLW)
303         return E_OUTOFMEMORY;
304     MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
305
306     hr = URLOpenStreamW(pCaller, szURLW, dwReserved, lpfnCB);
307
308     heap_free(szURLW);
309
310     return hr;
311 }
312
313 /***********************************************************************
314  *              URLOpenStreamW (URLMON.@)
315  */
316 HRESULT WINAPI URLOpenStreamW(LPUNKNOWN pCaller, LPCWSTR szURL, DWORD dwReserved,
317                               LPBINDSTATUSCALLBACK lpfnCB)
318 {
319     HRESULT hr;
320     ProxyBindStatusCallback async_bsc;
321     IStream *pStream;
322
323     TRACE("(%p, %s, 0x%x, %p)\n", pCaller, debugstr_w(szURL), dwReserved,
324           lpfnCB);
325
326     if (!szURL)
327         return E_INVALIDARG;
328
329     async_bsc.lpVtbl = &AsyncBindStatusCallbackVtbl;
330     async_bsc.pBSC = lpfnCB;
331
332     hr = URLStartDownload(szURL, &pStream, (IBindStatusCallback *)&async_bsc);
333     if (SUCCEEDED(hr) && pStream)
334         IStream_Release(pStream);
335
336     return hr;
337 }