381 lines
10 KiB
C
381 lines
10 KiB
C
![]() |
/*
|
||
|
* Based on ../shell32/memorystream.c
|
||
|
*
|
||
|
* Copyright 1999 Juergen Schmied
|
||
|
* Copyright 2003 Mike McCormack for CodeWeavers
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2.1 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*/
|
||
|
|
||
|
#include <stdarg.h>
|
||
|
|
||
|
#define COBJMACROS
|
||
|
|
||
|
#include "windef.h"
|
||
|
#include "winbase.h"
|
||
|
#include "winreg.h"
|
||
|
#include "winternl.h"
|
||
|
#include "winuser.h"
|
||
|
#include "objbase.h"
|
||
|
#include "wine/debug.h"
|
||
|
#include "wine/unicode.h"
|
||
|
#include "ole2.h"
|
||
|
#include "urlmon.h"
|
||
|
#include "wininet.h"
|
||
|
#include "shlwapi.h"
|
||
|
#include "urlmon_main.h"
|
||
|
|
||
|
WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
|
||
|
|
||
|
static const IStreamVtbl stvt;
|
||
|
|
||
|
HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL,
|
||
|
DWORD dwSize,
|
||
|
LPWSTR pszFileName,
|
||
|
HANDLE *phfile,
|
||
|
IUMCacheStream **ppstr)
|
||
|
{
|
||
|
IUMCacheStream* ucstr;
|
||
|
HANDLE handle;
|
||
|
LPWSTR ext;
|
||
|
LPCWSTR c;
|
||
|
LPCWSTR eloc = 0;
|
||
|
HRESULT hr;
|
||
|
|
||
|
for (c = pszURL; *c && *c != '#' && *c != '?'; ++c)
|
||
|
{
|
||
|
if (*c == '.')
|
||
|
eloc = c + 1;
|
||
|
else if (*c == '/' || *c == '\\')
|
||
|
eloc = 0;
|
||
|
}
|
||
|
|
||
|
if (!eloc)
|
||
|
eloc = c;
|
||
|
|
||
|
ext = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (c - eloc + 1));
|
||
|
memcpy(ext, eloc, sizeof(WCHAR) * (c - eloc));
|
||
|
ext[c - eloc] = 0;
|
||
|
|
||
|
if(!CreateUrlCacheEntryW(pszURL, dwSize, ext, pszFileName, 0))
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
else
|
||
|
hr = 0;
|
||
|
|
||
|
HeapFree(GetProcessHeap(), 0, ext);
|
||
|
|
||
|
if (hr)
|
||
|
return hr;
|
||
|
|
||
|
TRACE("Opening %s\n", debugstr_w(pszFileName) );
|
||
|
|
||
|
handle = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL );
|
||
|
if( handle == INVALID_HANDLE_VALUE )
|
||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||
|
|
||
|
if (phfile)
|
||
|
{
|
||
|
/* Call CreateFileW again because we need a handle with its own file pointer, and DuplicateHandle will return
|
||
|
* a handle that shares its file pointer with the original.
|
||
|
*/
|
||
|
*phfile = CreateFileW( pszFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
|
||
|
|
||
|
if (*phfile == (HANDLE) HFILE_ERROR)
|
||
|
{
|
||
|
DWORD dwError = GetLastError();
|
||
|
|
||
|
CloseHandle(handle);
|
||
|
return HRESULT_FROM_WIN32(dwError);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ucstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(IUMCacheStream));
|
||
|
if(ucstr )
|
||
|
{
|
||
|
ucstr->pszURL = HeapAlloc(GetProcessHeap(),
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
sizeof(WCHAR) * (lstrlenW(pszURL) + 1));
|
||
|
if (ucstr->pszURL)
|
||
|
{
|
||
|
ucstr->pszFileName = HeapAlloc(GetProcessHeap(),
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
sizeof(WCHAR) * (lstrlenW(pszFileName) + 1));
|
||
|
if (ucstr->pszFileName)
|
||
|
{
|
||
|
ucstr->lpVtbl=&stvt;
|
||
|
ucstr->ref = 1;
|
||
|
ucstr->handle = handle;
|
||
|
ucstr->closed = 0;
|
||
|
lstrcpyW(ucstr->pszURL, pszURL);
|
||
|
lstrcpyW(ucstr->pszFileName, pszFileName);
|
||
|
|
||
|
*ppstr = ucstr;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
HeapFree(GetProcessHeap(), 0, ucstr->pszURL);
|
||
|
}
|
||
|
HeapFree(GetProcessHeap(), 0, ucstr);
|
||
|
}
|
||
|
CloseHandle(handle);
|
||
|
if (phfile)
|
||
|
CloseHandle(*phfile);
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
void UMCloseCacheFileStream(IUMCacheStream *This)
|
||
|
{
|
||
|
if (!This->closed)
|
||
|
{
|
||
|
FILETIME ftZero;
|
||
|
|
||
|
ftZero.dwLowDateTime = ftZero.dwHighDateTime = 0;
|
||
|
|
||
|
This->closed = 1;
|
||
|
CommitUrlCacheEntryW(This->pszURL,
|
||
|
This->pszFileName,
|
||
|
ftZero,
|
||
|
ftZero,
|
||
|
NORMAL_CACHE_ENTRY,
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**************************************************************************
|
||
|
* IStream_fnQueryInterface
|
||
|
*/
|
||
|
static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface,
|
||
|
REFIID riid,
|
||
|
LPVOID *ppvObj)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
|
||
|
|
||
|
*ppvObj = NULL;
|
||
|
|
||
|
if(IsEqualIID(riid, &IID_IUnknown) ||
|
||
|
IsEqualIID(riid, &IID_IStream))
|
||
|
{
|
||
|
*ppvObj = This;
|
||
|
}
|
||
|
|
||
|
if(*ppvObj)
|
||
|
{
|
||
|
IStream_AddRef((IStream*)*ppvObj);
|
||
|
TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
|
||
|
return S_OK;
|
||
|
}
|
||
|
TRACE("-- Interface: E_NOINTERFACE\n");
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
/**************************************************************************
|
||
|
* IStream_fnAddRef
|
||
|
*/
|
||
|
static ULONG WINAPI IStream_fnAddRef(IStream *iface)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
ULONG refCount = InterlockedIncrement(&This->ref);
|
||
|
|
||
|
TRACE("(%p)->(count=%lu)\n", This, refCount - 1);
|
||
|
|
||
|
return refCount;
|
||
|
}
|
||
|
|
||
|
/**************************************************************************
|
||
|
* IStream_fnRelease
|
||
|
*/
|
||
|
static ULONG WINAPI IStream_fnRelease(IStream *iface)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
ULONG refCount = InterlockedDecrement(&This->ref);
|
||
|
|
||
|
TRACE("(%p)->(count=%lu)\n", This, refCount + 1);
|
||
|
|
||
|
if (!refCount)
|
||
|
{
|
||
|
TRACE(" destroying UMCacheStream (%p)\n",This);
|
||
|
UMCloseCacheFileStream(This);
|
||
|
CloseHandle(This->handle);
|
||
|
HeapFree(GetProcessHeap(), 0, This->pszFileName);
|
||
|
HeapFree(GetProcessHeap(), 0, This->pszURL);
|
||
|
HeapFree(GetProcessHeap(),0,This);
|
||
|
}
|
||
|
return refCount;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI IStream_fnRead (IStream * iface,
|
||
|
void* pv,
|
||
|
ULONG cb,
|
||
|
ULONG* pcbRead)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)->(%p,0x%08lx,%p)\n",This, pv, cb, pcbRead);
|
||
|
|
||
|
if ( !pv )
|
||
|
return STG_E_INVALIDPOINTER;
|
||
|
|
||
|
if ( ! ReadFile( This->handle, pv, cb, pcbRead, NULL ) )
|
||
|
return S_FALSE;
|
||
|
|
||
|
if (!*pcbRead)
|
||
|
return This->closed ? S_FALSE : E_PENDING;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI IStream_fnWrite (IStream * iface,
|
||
|
const void* pv,
|
||
|
ULONG cb,
|
||
|
ULONG* pcbWritten)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI IStream_fnSeek ( IStream * iface,
|
||
|
LARGE_INTEGER dlibMove,
|
||
|
DWORD dwOrigin,
|
||
|
ULARGE_INTEGER* plibNewPosition)
|
||
|
{
|
||
|
DWORD pos, newposlo, newposhi;
|
||
|
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)\n",This);
|
||
|
|
||
|
pos = dlibMove.QuadPart; /* FIXME: truncates */
|
||
|
newposhi = 0;
|
||
|
newposlo = SetFilePointer( This->handle, pos, &newposhi, dwOrigin );
|
||
|
if( newposlo == INVALID_SET_FILE_POINTER )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (plibNewPosition)
|
||
|
plibNewPosition->QuadPart = newposlo | ( (LONGLONG)newposhi<<32);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI IStream_fnSetSize (IStream * iface,
|
||
|
ULARGE_INTEGER libNewSize)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)\n",This);
|
||
|
|
||
|
if( ! SetFilePointer( This->handle, libNewSize.QuadPart, NULL, FILE_BEGIN ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( ! SetEndOfFile( This->handle ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI IStream_fnCopyTo (IStream * iface,
|
||
|
IStream* pstm,
|
||
|
ULARGE_INTEGER cb,
|
||
|
ULARGE_INTEGER* pcbRead,
|
||
|
ULARGE_INTEGER* pcbWritten)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)\n",This);
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI IStream_fnCommit (IStream * iface,
|
||
|
DWORD grfCommitFlags)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)\n",This);
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI IStream_fnRevert (IStream * iface)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)\n",This);
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
static HRESULT WINAPI IStream_fnLockRegion (IStream * iface,
|
||
|
ULARGE_INTEGER libOffset,
|
||
|
ULARGE_INTEGER cb,
|
||
|
DWORD dwLockType)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)\n",This);
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
static HRESULT WINAPI IStream_fnUnlockRegion (IStream * iface,
|
||
|
ULARGE_INTEGER libOffset,
|
||
|
ULARGE_INTEGER cb,
|
||
|
DWORD dwLockType)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)\n",This);
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
static HRESULT WINAPI IStream_fnStat (IStream * iface,
|
||
|
STATSTG* pstatstg,
|
||
|
DWORD grfStatFlag)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)\n",This);
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
static HRESULT WINAPI IStream_fnClone (IStream * iface,
|
||
|
IStream** ppstm)
|
||
|
{
|
||
|
IUMCacheStream *This = (IUMCacheStream *)iface;
|
||
|
|
||
|
TRACE("(%p)\n",This);
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
static const IStreamVtbl stvt =
|
||
|
{
|
||
|
IStream_fnQueryInterface,
|
||
|
IStream_fnAddRef,
|
||
|
IStream_fnRelease,
|
||
|
IStream_fnRead,
|
||
|
IStream_fnWrite,
|
||
|
IStream_fnSeek,
|
||
|
IStream_fnSetSize,
|
||
|
IStream_fnCopyTo,
|
||
|
IStream_fnCommit,
|
||
|
IStream_fnRevert,
|
||
|
IStream_fnLockRegion,
|
||
|
IStream_fnUnlockRegion,
|
||
|
IStream_fnStat,
|
||
|
IStream_fnClone
|
||
|
|
||
|
};
|