push bc3e5bf5ba806943a97979264a1f2e4a4dde5c94
[wine/hacks.git] / dlls / urlmon / umstream.c
blob213608fb59bf870694b1b3d10605e534bb9486ee
1 /*
2 * Based on ../shell32/memorystream.c
4 * Copyright 1999 Juergen Schmied
5 * Copyright 2003 Mike McCormack for CodeWeavers
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.
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.
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
22 #include <stdarg.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winternl.h"
30 #include "winuser.h"
31 #include "objbase.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34 #include "ole2.h"
35 #include "urlmon.h"
36 #include "wininet.h"
37 #include "shlwapi.h"
38 #include "urlmon_main.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
42 static const IStreamVtbl stvt;
44 HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL,
45 DWORD dwSize,
46 LPWSTR pszFileName,
47 HANDLE *phfile,
48 IUMCacheStream **ppstr)
50 IUMCacheStream* ucstr;
51 HANDLE handle;
52 DWORD size;
53 LPWSTR url, c, ext = NULL;
54 HRESULT hr;
56 size = (strlenW(pszURL)+1)*sizeof(WCHAR);
57 url = HeapAlloc(GetProcessHeap(), 0, size);
58 memcpy(url, pszURL, size);
60 for (c = url; *c && *c != '#' && *c != '?'; ++c)
62 if (*c == '.')
63 ext = c+1;
64 else if(*c == '/')
65 ext = NULL;
68 *c = 0;
70 if(!CreateUrlCacheEntryW(url, dwSize, ext, pszFileName, 0))
71 hr = HRESULT_FROM_WIN32(GetLastError());
72 else
73 hr = 0;
75 HeapFree(GetProcessHeap(), 0, url);
77 if (hr)
78 return hr;
80 TRACE("Opening %s\n", debugstr_w(pszFileName) );
82 handle = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL );
83 if( handle == INVALID_HANDLE_VALUE )
84 return HRESULT_FROM_WIN32(GetLastError());
86 if (phfile)
88 /* Call CreateFileW again because we need a handle with its own file pointer, and DuplicateHandle will return
89 * a handle that shares its file pointer with the original.
91 *phfile = CreateFileW( pszFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
93 if (*phfile == (HANDLE) HFILE_ERROR)
95 DWORD dwError = GetLastError();
97 CloseHandle(handle);
98 return HRESULT_FROM_WIN32(dwError);
102 ucstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(IUMCacheStream));
103 if(ucstr )
105 ucstr->pszURL = HeapAlloc(GetProcessHeap(),
106 HEAP_ZERO_MEMORY,
107 sizeof(WCHAR) * (lstrlenW(pszURL) + 1));
108 if (ucstr->pszURL)
110 ucstr->pszFileName = HeapAlloc(GetProcessHeap(),
111 HEAP_ZERO_MEMORY,
112 sizeof(WCHAR) * (lstrlenW(pszFileName) + 1));
113 if (ucstr->pszFileName)
115 ucstr->lpVtbl=&stvt;
116 ucstr->ref = 1;
117 ucstr->handle = handle;
118 ucstr->closed = 0;
119 lstrcpyW(ucstr->pszURL, pszURL);
120 lstrcpyW(ucstr->pszFileName, pszFileName);
122 *ppstr = ucstr;
124 return S_OK;
126 HeapFree(GetProcessHeap(), 0, ucstr->pszURL);
128 HeapFree(GetProcessHeap(), 0, ucstr);
130 CloseHandle(handle);
131 if (phfile)
132 CloseHandle(*phfile);
133 return E_OUTOFMEMORY;
136 void UMCloseCacheFileStream(IUMCacheStream *This)
138 if (!This->closed)
140 FILETIME ftZero;
142 ftZero.dwLowDateTime = ftZero.dwHighDateTime = 0;
144 This->closed = 1;
145 CommitUrlCacheEntryW(This->pszURL,
146 This->pszFileName,
147 ftZero,
148 ftZero,
149 NORMAL_CACHE_ENTRY,
157 /**************************************************************************
158 * IStream_fnQueryInterface
160 static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface,
161 REFIID riid,
162 LPVOID *ppvObj)
164 IUMCacheStream *This = (IUMCacheStream *)iface;
166 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
168 *ppvObj = NULL;
170 if(IsEqualIID(riid, &IID_IUnknown) ||
171 IsEqualIID(riid, &IID_IStream))
173 *ppvObj = This;
176 if(*ppvObj)
178 IStream_AddRef((IStream*)*ppvObj);
179 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
180 return S_OK;
182 TRACE("-- Interface: E_NOINTERFACE\n");
183 return E_NOINTERFACE;
186 /**************************************************************************
187 * IStream_fnAddRef
189 static ULONG WINAPI IStream_fnAddRef(IStream *iface)
191 IUMCacheStream *This = (IUMCacheStream *)iface;
192 ULONG refCount = InterlockedIncrement(&This->ref);
194 TRACE("(%p)->(count=%u)\n", This, refCount - 1);
196 return refCount;
199 /**************************************************************************
200 * IStream_fnRelease
202 static ULONG WINAPI IStream_fnRelease(IStream *iface)
204 IUMCacheStream *This = (IUMCacheStream *)iface;
205 ULONG refCount = InterlockedDecrement(&This->ref);
207 TRACE("(%p)->(count=%u)\n", This, refCount + 1);
209 if (!refCount)
211 TRACE(" destroying UMCacheStream (%p)\n",This);
212 UMCloseCacheFileStream(This);
213 CloseHandle(This->handle);
214 HeapFree(GetProcessHeap(), 0, This->pszFileName);
215 HeapFree(GetProcessHeap(), 0, This->pszURL);
216 HeapFree(GetProcessHeap(),0,This);
218 return refCount;
221 static HRESULT WINAPI IStream_fnRead (IStream * iface,
222 void* pv,
223 ULONG cb,
224 ULONG* pcbRead)
226 ULONG dwBytesRead;
227 IUMCacheStream *This = (IUMCacheStream *)iface;
229 TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead);
231 if ( !pv )
232 return STG_E_INVALIDPOINTER;
234 if ( !pcbRead)
235 pcbRead = &dwBytesRead;
237 if ( ! ReadFile( This->handle, pv, cb, (LPDWORD)pcbRead, NULL ) )
238 return S_FALSE;
240 if (!*pcbRead)
241 return This->closed ? S_FALSE : E_PENDING;
242 return S_OK;
245 static HRESULT WINAPI IStream_fnWrite (IStream * iface,
246 const void* pv,
247 ULONG cb,
248 ULONG* pcbWritten)
250 return E_NOTIMPL;
253 static HRESULT WINAPI IStream_fnSeek (IStream * iface,
254 LARGE_INTEGER dlibMove,
255 DWORD dwOrigin,
256 ULARGE_INTEGER* plibNewPosition)
258 LARGE_INTEGER newpos;
259 IUMCacheStream *This = (IUMCacheStream *)iface;
261 TRACE("(%p)\n",This);
263 if (!SetFilePointerEx( This->handle, dlibMove, &newpos, dwOrigin ))
264 return E_FAIL;
266 if (plibNewPosition)
267 plibNewPosition->QuadPart = newpos.QuadPart;
269 return S_OK;
272 static HRESULT WINAPI IStream_fnSetSize (IStream * iface,
273 ULARGE_INTEGER libNewSize)
275 LARGE_INTEGER newpos;
276 IUMCacheStream *This = (IUMCacheStream *)iface;
278 TRACE("(%p)\n",This);
280 newpos.QuadPart = libNewSize.QuadPart;
281 if( ! SetFilePointerEx( This->handle, newpos, NULL, FILE_BEGIN ) )
282 return E_FAIL;
284 if( ! SetEndOfFile( This->handle ) )
285 return E_FAIL;
287 return S_OK;
290 static HRESULT WINAPI IStream_fnCopyTo (IStream * iface,
291 IStream* pstm,
292 ULARGE_INTEGER cb,
293 ULARGE_INTEGER* pcbRead,
294 ULARGE_INTEGER* pcbWritten)
296 IUMCacheStream *This = (IUMCacheStream *)iface;
298 TRACE("(%p)\n",This);
300 return E_NOTIMPL;
303 static HRESULT WINAPI IStream_fnCommit (IStream * iface,
304 DWORD grfCommitFlags)
306 IUMCacheStream *This = (IUMCacheStream *)iface;
308 TRACE("(%p)\n",This);
310 return E_NOTIMPL;
313 static HRESULT WINAPI IStream_fnRevert (IStream * iface)
315 IUMCacheStream *This = (IUMCacheStream *)iface;
317 TRACE("(%p)\n",This);
319 return E_NOTIMPL;
321 static HRESULT WINAPI IStream_fnLockRegion (IStream * iface,
322 ULARGE_INTEGER libOffset,
323 ULARGE_INTEGER cb,
324 DWORD dwLockType)
326 IUMCacheStream *This = (IUMCacheStream *)iface;
328 TRACE("(%p)\n",This);
330 return E_NOTIMPL;
332 static HRESULT WINAPI IStream_fnUnlockRegion (IStream * iface,
333 ULARGE_INTEGER libOffset,
334 ULARGE_INTEGER cb,
335 DWORD dwLockType)
337 IUMCacheStream *This = (IUMCacheStream *)iface;
339 TRACE("(%p)\n",This);
341 return E_NOTIMPL;
343 static HRESULT WINAPI IStream_fnStat (IStream * iface,
344 STATSTG* pstatstg,
345 DWORD grfStatFlag)
347 IUMCacheStream *This = (IUMCacheStream *)iface;
349 TRACE("(%p)\n",This);
351 return E_NOTIMPL;
353 static HRESULT WINAPI IStream_fnClone (IStream * iface,
354 IStream** ppstm)
356 IUMCacheStream *This = (IUMCacheStream *)iface;
358 TRACE("(%p)\n",This);
360 return E_NOTIMPL;
363 static const IStreamVtbl stvt =
365 IStream_fnQueryInterface,
366 IStream_fnAddRef,
367 IStream_fnRelease,
368 IStream_fnRead,
369 IStream_fnWrite,
370 IStream_fnSeek,
371 IStream_fnSetSize,
372 IStream_fnCopyTo,
373 IStream_fnCommit,
374 IStream_fnRevert,
375 IStream_fnLockRegion,
376 IStream_fnUnlockRegion,
377 IStream_fnStat,
378 IStream_fnClone
382 typedef struct ProxyBindStatusCallback
384 const IBindStatusCallbackVtbl *lpVtbl;
386 IBindStatusCallback *pBSC;
387 } ProxyBindStatusCallback;
389 static HRESULT WINAPI ProxyBindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
391 if (IsEqualGUID(&IID_IBindStatusCallback, riid) ||
392 IsEqualGUID(&IID_IUnknown, riid))
394 *ppv = iface;
395 IUnknown_AddRef(iface);
396 return S_OK;
399 *ppv = NULL;
400 return E_NOINTERFACE;
403 static ULONG WINAPI ProxyBindStatusCallback_AddRef(IBindStatusCallback *iface)
405 return 2;
408 static ULONG WINAPI ProxyBindStatusCallback_Release(IBindStatusCallback *iface)
410 return 1;
413 static HRESULT WINAPI ProxyBindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
414 IBinding *pib)
416 ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
417 return IBindStatusCallback_OnStartBinding(This->pBSC, dwReserved, pib);
420 static HRESULT WINAPI ProxyBindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
422 ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
423 return IBindStatusCallback_GetPriority(This->pBSC, pnPriority);
426 static HRESULT WINAPI ProxyBindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
428 ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
429 return IBindStatusCallback_OnLowResource(This->pBSC, reserved);
432 static HRESULT WINAPI ProxyBindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
433 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
435 ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
436 return IBindStatusCallback_OnProgress(This->pBSC, ulProgress,
437 ulProgressMax, ulStatusCode,
438 szStatusText);
441 static HRESULT WINAPI ProxyBindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
443 ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
444 return IBindStatusCallback_OnStopBinding(This->pBSC, hresult, szError);
447 static HRESULT WINAPI ProxyBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
449 ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
450 return IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
453 static HRESULT WINAPI ProxyBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
454 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
456 ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
457 return IBindStatusCallback_OnDataAvailable(This->pBSC, grfBSCF, dwSize,
458 pformatetc, pstgmed);
461 static HRESULT WINAPI ProxyBindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
463 ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
464 return IBindStatusCallback_OnObjectAvailable(This->pBSC, riid, punk);
467 static HRESULT WINAPI BlockingBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
468 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
470 return S_OK;
473 static const IBindStatusCallbackVtbl BlockingBindStatusCallbackVtbl =
475 ProxyBindStatusCallback_QueryInterface,
476 ProxyBindStatusCallback_AddRef,
477 ProxyBindStatusCallback_Release,
478 ProxyBindStatusCallback_OnStartBinding,
479 ProxyBindStatusCallback_GetPriority,
480 ProxyBindStatusCallback_OnLowResource,
481 ProxyBindStatusCallback_OnProgress,
482 ProxyBindStatusCallback_OnStopBinding,
483 ProxyBindStatusCallback_GetBindInfo,
484 BlockingBindStatusCallback_OnDataAvailable,
485 ProxyBindStatusCallback_OnObjectAvailable
488 static HRESULT WINAPI AsyncBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
490 ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
491 HRESULT hr = IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
492 *grfBINDF |= BINDF_PULLDATA | BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
493 return hr;
496 static const IBindStatusCallbackVtbl AsyncBindStatusCallbackVtbl =
498 ProxyBindStatusCallback_QueryInterface,
499 ProxyBindStatusCallback_AddRef,
500 ProxyBindStatusCallback_Release,
501 ProxyBindStatusCallback_OnStartBinding,
502 ProxyBindStatusCallback_GetPriority,
503 ProxyBindStatusCallback_OnLowResource,
504 ProxyBindStatusCallback_OnProgress,
505 ProxyBindStatusCallback_OnStopBinding,
506 AsyncBindStatusCallback_GetBindInfo,
507 ProxyBindStatusCallback_OnDataAvailable,
508 ProxyBindStatusCallback_OnObjectAvailable
511 static HRESULT URLStartDownload(LPCWSTR szURL, LPSTREAM *ppStream, IBindStatusCallback *pBSC)
513 HRESULT hr;
514 IMoniker *pMoniker;
515 IBindCtx *pbc;
517 *ppStream = NULL;
519 hr = CreateURLMoniker(NULL, szURL, &pMoniker);
520 if (FAILED(hr))
521 return hr;
523 hr = CreateBindCtx(0, &pbc);
524 if (FAILED(hr))
526 IMoniker_Release(pMoniker);
527 return hr;
530 hr = RegisterBindStatusCallback(pbc, pBSC, NULL, 0);
531 if (FAILED(hr))
533 IBindCtx_Release(pbc);
534 IMoniker_Release(pMoniker);
535 return hr;
538 hr = IMoniker_BindToStorage(pMoniker, pbc, NULL, &IID_IStream, (void **)ppStream);
540 /* BindToStorage returning E_PENDING because it's asynchronous is not an error */
541 if (hr == E_PENDING) hr = S_OK;
543 IBindCtx_Release(pbc);
544 IMoniker_Release(pMoniker);
546 return hr;
549 /***********************************************************************
550 * URLOpenBlockingStreamA (URLMON.@)
552 HRESULT WINAPI URLOpenBlockingStreamA(LPUNKNOWN pCaller, LPCSTR szURL,
553 LPSTREAM *ppStream, DWORD dwReserved,
554 LPBINDSTATUSCALLBACK lpfnCB)
556 LPWSTR szURLW;
557 int len;
558 HRESULT hr;
560 TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, szURL, ppStream, dwReserved, lpfnCB);
562 if (!szURL || !ppStream)
563 return E_INVALIDARG;
565 len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
566 szURLW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
567 if (!szURLW)
569 *ppStream = NULL;
570 return E_OUTOFMEMORY;
572 MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
574 hr = URLOpenBlockingStreamW(pCaller, szURLW, ppStream, dwReserved, lpfnCB);
576 HeapFree(GetProcessHeap(), 0, szURLW);
578 return hr;
581 /***********************************************************************
582 * URLOpenBlockingStreamW (URLMON.@)
584 HRESULT WINAPI URLOpenBlockingStreamW(LPUNKNOWN pCaller, LPCWSTR szURL,
585 LPSTREAM *ppStream, DWORD dwReserved,
586 LPBINDSTATUSCALLBACK lpfnCB)
588 ProxyBindStatusCallback blocking_bsc;
590 TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, debugstr_w(szURL), ppStream,
591 dwReserved, lpfnCB);
593 if (!szURL || !ppStream)
594 return E_INVALIDARG;
596 blocking_bsc.lpVtbl = &BlockingBindStatusCallbackVtbl;
597 blocking_bsc.pBSC = lpfnCB;
599 return URLStartDownload(szURL, ppStream, (IBindStatusCallback *)&blocking_bsc);
602 /***********************************************************************
603 * URLOpenStreamA (URLMON.@)
605 HRESULT WINAPI URLOpenStreamA(LPUNKNOWN pCaller, LPCSTR szURL, DWORD dwReserved,
606 LPBINDSTATUSCALLBACK lpfnCB)
608 LPWSTR szURLW;
609 int len;
610 HRESULT hr;
612 TRACE("(%p, %s, 0x%x, %p)\n", pCaller, szURL, dwReserved, lpfnCB);
614 if (!szURL)
615 return E_INVALIDARG;
617 len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
618 szURLW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
619 if (!szURLW)
620 return E_OUTOFMEMORY;
621 MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
623 hr = URLOpenStreamW(pCaller, szURLW, dwReserved, lpfnCB);
625 HeapFree(GetProcessHeap(), 0, szURLW);
627 return hr;
630 /***********************************************************************
631 * URLOpenStreamW (URLMON.@)
633 HRESULT WINAPI URLOpenStreamW(LPUNKNOWN pCaller, LPCWSTR szURL, DWORD dwReserved,
634 LPBINDSTATUSCALLBACK lpfnCB)
636 HRESULT hr;
637 ProxyBindStatusCallback async_bsc;
638 IStream *pStream;
640 TRACE("(%p, %s, 0x%x, %p)\n", pCaller, debugstr_w(szURL), dwReserved,
641 lpfnCB);
643 if (!szURL)
644 return E_INVALIDARG;
646 async_bsc.lpVtbl = &AsyncBindStatusCallbackVtbl;
647 async_bsc.pBSC = lpfnCB;
649 hr = URLStartDownload(szURL, &pStream, (IBindStatusCallback *)&async_bsc);
650 if (SUCCEEDED(hr) && pStream)
651 IStream_Release(pStream);
653 return hr;