2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* Compound Storage (32 bit version)
|
|
|
|
* Stream implementation
|
|
|
|
*
|
|
|
|
* This file contains the implementation of the stream interface
|
|
|
|
* for streams contained in a compound storage.
|
|
|
|
*
|
|
|
|
* Copyright 1999 Francis Beaudet
|
|
|
|
* Copyright 1999 Thuy Nguyen
|
|
|
|
*
|
|
|
|
* 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
|
2007-04-20 12:23:52 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
|
2013-12-26 16:07:35 +00:00
|
|
|
#include "precomp.h"
|
2005-07-31 12:11:56 +00:00
|
|
|
#include "storage32.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(storage);
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This implements the IUnknown method QueryInterface for this
|
|
|
|
* class
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_QueryInterface(
|
|
|
|
IStream* iface,
|
|
|
|
REFIID riid, /* [in] */
|
|
|
|
void** ppvObject) /* [iid_is][out] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (ppvObject==0)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
*ppvObject = 0;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
if (IsEqualIID(&IID_IUnknown, riid) ||
|
|
|
|
IsEqualIID(&IID_ISequentialStream, riid) ||
|
|
|
|
IsEqualIID(&IID_IStream, riid))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
*ppvObject = &This->IStream_iface;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
2012-12-12 21:01:41 +00:00
|
|
|
else
|
2005-07-31 12:11:56 +00:00
|
|
|
return E_NOINTERFACE;
|
|
|
|
|
|
|
|
IStream_AddRef(iface);
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This implements the IUnknown method AddRef for this
|
|
|
|
* class
|
|
|
|
*/
|
|
|
|
static ULONG WINAPI StgStreamImpl_AddRef(
|
|
|
|
IStream* iface)
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2005-07-31 12:11:56 +00:00
|
|
|
return InterlockedIncrement(&This->ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This implements the IUnknown method Release for this
|
|
|
|
* class
|
|
|
|
*/
|
|
|
|
static ULONG WINAPI StgStreamImpl_Release(
|
|
|
|
IStream* iface)
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2013-09-26 13:58:03 +00:00
|
|
|
ULONG ref = InterlockedDecrement(&This->ref);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2013-09-26 13:58:03 +00:00
|
|
|
if (!ref)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2013-09-26 13:58:03 +00:00
|
|
|
TRACE("(%p)\n", This);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Release the reference we are holding on the parent storage.
|
|
|
|
* IStorage_Release(&This->parentStorage->IStorage_iface);
|
|
|
|
*
|
|
|
|
* No, don't do this. Some apps call IStorage_Release without
|
|
|
|
* calling IStream_Release first. If we grab a reference the
|
|
|
|
* file is not closed, and the app fails when it tries to
|
|
|
|
* reopen the file (Easy-PC, for example). Just inform the
|
|
|
|
* storage that we have closed the stream
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (This->parentStorage)
|
|
|
|
StorageBaseImpl_RemoveStream(This->parentStorage, This);
|
|
|
|
This->parentStorage = 0;
|
|
|
|
HeapFree(GetProcessHeap(), 0, This);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This method is part of the ISequentialStream interface.
|
|
|
|
*
|
|
|
|
* It reads a block of information from the stream at the current
|
|
|
|
* position. It then moves the current position at the end of the
|
|
|
|
* read block
|
|
|
|
*
|
|
|
|
* See the documentation of ISequentialStream for more info.
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_Read(
|
|
|
|
IStream* iface,
|
|
|
|
void* pv, /* [length_is][size_is][out] */
|
|
|
|
ULONG cb, /* [in] */
|
|
|
|
ULONG* pcbRead) /* [out] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
ULONG bytesReadBuffer;
|
2006-01-06 20:19:21 +00:00
|
|
|
HRESULT res;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%p, %p, %d, %p)\n",
|
2005-07-31 12:11:56 +00:00
|
|
|
iface, pv, cb, pcbRead);
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
if (!This->parentStorage)
|
|
|
|
{
|
|
|
|
WARN("storage reverted\n");
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* If the caller is not interested in the number of bytes read,
|
|
|
|
* we use another buffer to avoid "if" statements in the code.
|
|
|
|
*/
|
|
|
|
if (pcbRead==0)
|
|
|
|
pcbRead = &bytesReadBuffer;
|
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
res = StorageBaseImpl_StreamReadAt(This->parentStorage,
|
|
|
|
This->dirEntry,
|
|
|
|
This->currentPosition,
|
|
|
|
cb,
|
|
|
|
pv,
|
|
|
|
pcbRead);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
if (SUCCEEDED(res))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
/*
|
2010-03-10 14:28:56 +00:00
|
|
|
* Advance the pointer for the number of positions read.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
2014-10-03 11:44:27 +00:00
|
|
|
This->currentPosition.QuadPart += *pcbRead;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("<-- %08x\n", res);
|
2005-07-31 12:11:56 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This method is part of the ISequentialStream interface.
|
|
|
|
*
|
|
|
|
* It writes a block of information to the stream at the current
|
|
|
|
* position. It then moves the current position at the end of the
|
|
|
|
* written block. If the stream is too small to fit the block,
|
|
|
|
* the stream is grown to fit.
|
|
|
|
*
|
|
|
|
* See the documentation of ISequentialStream for more info.
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_Write(
|
|
|
|
IStream* iface,
|
|
|
|
const void* pv, /* [size_is][in] */
|
|
|
|
ULONG cb, /* [in] */
|
|
|
|
ULONG* pcbWritten) /* [out] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
ULONG bytesWritten = 0;
|
2007-04-20 12:23:52 +00:00
|
|
|
HRESULT res;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%p, %p, %d, %p)\n",
|
2005-07-31 12:11:56 +00:00
|
|
|
iface, pv, cb, pcbWritten);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do we have permission to write to this stream?
|
|
|
|
*/
|
|
|
|
switch(STGM_ACCESS_MODE(This->grfMode))
|
|
|
|
{
|
|
|
|
case STGM_WRITE:
|
|
|
|
case STGM_READWRITE:
|
|
|
|
break;
|
|
|
|
default:
|
2007-04-20 12:23:52 +00:00
|
|
|
WARN("access denied by flags: 0x%x\n", STGM_ACCESS_MODE(This->grfMode));
|
2005-07-31 12:11:56 +00:00
|
|
|
return STG_E_ACCESSDENIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pv)
|
|
|
|
return STG_E_INVALIDPOINTER;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
if (!This->parentStorage)
|
|
|
|
{
|
|
|
|
WARN("storage reverted\n");
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
}
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* If the caller is not interested in the number of bytes written,
|
|
|
|
* we use another buffer to avoid "if" statements in the code.
|
|
|
|
*/
|
|
|
|
if (pcbWritten == 0)
|
|
|
|
pcbWritten = &bytesWritten;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the out parameter
|
|
|
|
*/
|
|
|
|
*pcbWritten = 0;
|
|
|
|
|
|
|
|
if (cb == 0)
|
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("<-- S_OK, written 0\n");
|
2005-07-31 12:11:56 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
res = StorageBaseImpl_StreamWriteAt(This->parentStorage,
|
|
|
|
This->dirEntry,
|
|
|
|
This->currentPosition,
|
|
|
|
cb,
|
|
|
|
pv,
|
|
|
|
pcbWritten);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Advance the position pointer for the number of positions written.
|
|
|
|
*/
|
2014-10-03 11:44:27 +00:00
|
|
|
This->currentPosition.QuadPart += *pcbWritten;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-09-17 20:13:28 +00:00
|
|
|
if (SUCCEEDED(res))
|
|
|
|
res = StorageBaseImpl_Flush(This->parentStorage);
|
|
|
|
|
2014-10-03 11:44:27 +00:00
|
|
|
TRACE("<-- %08x, written %u\n", res, *pcbWritten);
|
2007-04-20 12:23:52 +00:00
|
|
|
return res;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This method is part of the IStream interface.
|
|
|
|
*
|
|
|
|
* It will move the current stream pointer according to the parameters
|
|
|
|
* given.
|
|
|
|
*
|
|
|
|
* See the documentation of IStream for more info.
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_Seek(
|
|
|
|
IStream* iface,
|
|
|
|
LARGE_INTEGER dlibMove, /* [in] */
|
|
|
|
DWORD dwOrigin, /* [in] */
|
|
|
|
ULARGE_INTEGER* plibNewPosition) /* [out] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
ULARGE_INTEGER newPosition;
|
2010-03-10 14:28:56 +00:00
|
|
|
DirEntry currentEntry;
|
|
|
|
HRESULT hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%p, %d, %d, %p)\n",
|
2005-07-31 12:11:56 +00:00
|
|
|
iface, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
/*
|
|
|
|
* fail if the stream has no parent (as does windows)
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!This->parentStorage)
|
|
|
|
{
|
|
|
|
WARN("storage reverted\n");
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* The caller is allowed to pass in NULL as the new position return value.
|
|
|
|
* If it happens, we assign it to a dynamic variable to avoid special cases
|
|
|
|
* in the code below.
|
|
|
|
*/
|
|
|
|
if (plibNewPosition == 0)
|
|
|
|
{
|
|
|
|
plibNewPosition = &newPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The file pointer is moved depending on the given "function"
|
|
|
|
* parameter.
|
|
|
|
*/
|
|
|
|
switch (dwOrigin)
|
|
|
|
{
|
|
|
|
case STREAM_SEEK_SET:
|
|
|
|
plibNewPosition->u.HighPart = 0;
|
|
|
|
plibNewPosition->u.LowPart = 0;
|
|
|
|
break;
|
|
|
|
case STREAM_SEEK_CUR:
|
|
|
|
*plibNewPosition = This->currentPosition;
|
|
|
|
break;
|
|
|
|
case STREAM_SEEK_END:
|
2010-03-10 14:28:56 +00:00
|
|
|
hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, This->dirEntry, ¤tEntry);
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
*plibNewPosition = currentEntry.size;
|
2005-07-31 12:11:56 +00:00
|
|
|
break;
|
|
|
|
default:
|
2007-04-20 12:23:52 +00:00
|
|
|
WARN("invalid dwOrigin %d\n", dwOrigin);
|
2005-07-31 12:11:56 +00:00
|
|
|
return STG_E_INVALIDFUNCTION;
|
|
|
|
}
|
|
|
|
|
2009-09-05 15:03:37 +00:00
|
|
|
plibNewPosition->QuadPart += dlibMove.QuadPart;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* tell the caller what we calculated
|
|
|
|
*/
|
|
|
|
This->currentPosition = *plibNewPosition;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This method is part of the IStream interface.
|
|
|
|
*
|
|
|
|
* It will change the size of a stream.
|
|
|
|
*
|
|
|
|
* See the documentation of IStream for more info.
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_SetSize(
|
|
|
|
IStream* iface,
|
|
|
|
ULARGE_INTEGER libNewSize) /* [in] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
HRESULT hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart);
|
|
|
|
|
|
|
|
if(!This->parentStorage)
|
|
|
|
{
|
|
|
|
WARN("storage reverted\n");
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* As documented.
|
|
|
|
*/
|
|
|
|
if (libNewSize.u.HighPart != 0)
|
2007-04-20 12:23:52 +00:00
|
|
|
{
|
|
|
|
WARN("invalid value for libNewSize.u.HighPart %d\n", libNewSize.u.HighPart);
|
2005-07-31 12:11:56 +00:00
|
|
|
return STG_E_INVALIDFUNCTION;
|
2007-04-20 12:23:52 +00:00
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Do we have permission?
|
|
|
|
*/
|
|
|
|
if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
|
2007-04-20 12:23:52 +00:00
|
|
|
{
|
|
|
|
WARN("access denied\n");
|
2005-07-31 12:11:56 +00:00
|
|
|
return STG_E_ACCESSDENIED;
|
2007-04-20 12:23:52 +00:00
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
hr = StorageBaseImpl_StreamSetSize(This->parentStorage, This->dirEntry, libNewSize);
|
2010-09-17 20:13:28 +00:00
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
hr = StorageBaseImpl_Flush(This->parentStorage);
|
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
return hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This method is part of the IStream interface.
|
|
|
|
*
|
|
|
|
* It will copy the 'cb' Bytes to 'pstm' IStream.
|
|
|
|
*
|
|
|
|
* See the documentation of IStream for more info.
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_CopyTo(
|
|
|
|
IStream* iface,
|
|
|
|
IStream* pstm, /* [unique][in] */
|
|
|
|
ULARGE_INTEGER cb, /* [in] */
|
|
|
|
ULARGE_INTEGER* pcbRead, /* [out] */
|
|
|
|
ULARGE_INTEGER* pcbWritten) /* [out] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2005-07-31 12:11:56 +00:00
|
|
|
HRESULT hr = S_OK;
|
|
|
|
BYTE tmpBuffer[128];
|
|
|
|
ULONG bytesRead, bytesWritten, copySize;
|
|
|
|
ULARGE_INTEGER totalBytesRead;
|
|
|
|
ULARGE_INTEGER totalBytesWritten;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%p, %p, %d, %p, %p)\n",
|
2005-07-31 12:11:56 +00:00
|
|
|
iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sanity check
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
|
|
|
|
if (!This->parentStorage)
|
|
|
|
{
|
|
|
|
WARN("storage reverted\n");
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
if ( pstm == 0 )
|
|
|
|
return STG_E_INVALIDPOINTER;
|
|
|
|
|
2008-07-10 09:14:19 +00:00
|
|
|
totalBytesRead.QuadPart = 0;
|
|
|
|
totalBytesWritten.QuadPart = 0;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2008-07-10 09:14:19 +00:00
|
|
|
while ( cb.QuadPart > 0 )
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2008-07-10 09:14:19 +00:00
|
|
|
if ( cb.QuadPart >= sizeof(tmpBuffer) )
|
|
|
|
copySize = sizeof(tmpBuffer);
|
2005-07-31 12:11:56 +00:00
|
|
|
else
|
|
|
|
copySize = cb.u.LowPart;
|
|
|
|
|
|
|
|
IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
|
|
|
|
|
2008-07-10 09:14:19 +00:00
|
|
|
totalBytesRead.QuadPart += bytesRead;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
|
|
|
|
|
2008-07-10 09:14:19 +00:00
|
|
|
totalBytesWritten.QuadPart += bytesWritten;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that read & write operations were successful
|
|
|
|
*/
|
|
|
|
if (bytesRead != bytesWritten)
|
|
|
|
{
|
|
|
|
hr = STG_E_MEDIUMFULL;
|
2007-04-20 12:23:52 +00:00
|
|
|
WARN("medium full\n");
|
2005-07-31 12:11:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bytesRead!=copySize)
|
2008-07-10 09:14:19 +00:00
|
|
|
cb.QuadPart = 0;
|
2005-07-31 12:11:56 +00:00
|
|
|
else
|
2008-07-10 09:14:19 +00:00
|
|
|
cb.QuadPart -= bytesRead;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
2008-07-10 09:14:19 +00:00
|
|
|
if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
|
|
|
|
if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This method is part of the IStream interface.
|
|
|
|
*
|
|
|
|
* For streams contained in structured storages, this method
|
|
|
|
* does nothing. This is what the documentation tells us.
|
|
|
|
*
|
|
|
|
* See the documentation of IStream for more info.
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_Commit(
|
|
|
|
IStream* iface,
|
|
|
|
DWORD grfCommitFlags) /* [in] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2007-04-20 12:23:52 +00:00
|
|
|
|
|
|
|
if (!This->parentStorage)
|
|
|
|
{
|
|
|
|
WARN("storage reverted\n");
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
return StorageBaseImpl_Flush(This->parentStorage);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This method is part of the IStream interface.
|
|
|
|
*
|
|
|
|
* For streams contained in structured storages, this method
|
|
|
|
* does nothing. This is what the documentation tells us.
|
|
|
|
*
|
|
|
|
* See the documentation of IStream for more info.
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_Revert(
|
|
|
|
IStream* iface)
|
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI StgStreamImpl_LockRegion(
|
|
|
|
IStream* iface,
|
|
|
|
ULARGE_INTEGER libOffset, /* [in] */
|
|
|
|
ULARGE_INTEGER cb, /* [in] */
|
|
|
|
DWORD dwLockType) /* [in] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2007-04-20 12:23:52 +00:00
|
|
|
|
|
|
|
if (!This->parentStorage)
|
|
|
|
{
|
|
|
|
WARN("storage reverted\n");
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
FIXME("not implemented!\n");
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI StgStreamImpl_UnlockRegion(
|
|
|
|
IStream* iface,
|
|
|
|
ULARGE_INTEGER libOffset, /* [in] */
|
|
|
|
ULARGE_INTEGER cb, /* [in] */
|
|
|
|
DWORD dwLockType) /* [in] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2007-04-20 12:23:52 +00:00
|
|
|
|
|
|
|
if (!This->parentStorage)
|
|
|
|
{
|
|
|
|
WARN("storage reverted\n");
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
FIXME("not implemented!\n");
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This method is part of the IStream interface.
|
|
|
|
*
|
|
|
|
* This method returns information about the current
|
|
|
|
* stream.
|
|
|
|
*
|
|
|
|
* See the documentation of IStream for more info.
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_Stat(
|
|
|
|
IStream* iface,
|
|
|
|
STATSTG* pstatstg, /* [out] */
|
|
|
|
DWORD grfStatFlag) /* [in] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
DirEntry currentEntry;
|
|
|
|
HRESULT hr;
|
2007-04-20 12:23:52 +00:00
|
|
|
|
|
|
|
TRACE("%p %p %d\n", This, pstatstg, grfStatFlag);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if stream has no parent, return STG_E_REVERTED
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!This->parentStorage)
|
|
|
|
{
|
|
|
|
WARN("storage reverted\n");
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
2010-03-10 14:28:56 +00:00
|
|
|
* Read the information from the directory entry.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
2010-03-10 14:28:56 +00:00
|
|
|
hr = StorageBaseImpl_ReadDirEntry(This->parentStorage,
|
|
|
|
This->dirEntry,
|
|
|
|
¤tEntry);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
if (SUCCEEDED(hr))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-03-10 14:28:56 +00:00
|
|
|
StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage,
|
|
|
|
pstatstg,
|
|
|
|
¤tEntry,
|
2005-07-31 12:11:56 +00:00
|
|
|
grfStatFlag);
|
|
|
|
|
|
|
|
pstatstg->grfMode = This->grfMode;
|
|
|
|
|
2009-08-07 20:15:12 +00:00
|
|
|
/* In simple create mode cbSize is the current pos */
|
2010-03-10 14:28:56 +00:00
|
|
|
if((This->parentStorage->openFlags & STGM_SIMPLE) && This->parentStorage->create)
|
2009-08-07 20:15:12 +00:00
|
|
|
pstatstg->cbSize = This->currentPosition;
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
WARN("failed to read entry\n");
|
|
|
|
return hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This method is part of the IStream interface.
|
|
|
|
*
|
|
|
|
* This method returns a clone of the interface that allows for
|
|
|
|
* another seek pointer
|
|
|
|
*
|
|
|
|
* See the documentation of IStream for more info.
|
|
|
|
*
|
|
|
|
* I am not totally sure what I am doing here but I presume that this
|
|
|
|
* should be basically as simple as creating a new stream with the same
|
|
|
|
* parent etc and positioning its seek cursor.
|
|
|
|
*/
|
|
|
|
static HRESULT WINAPI StgStreamImpl_Clone(
|
|
|
|
IStream* iface,
|
|
|
|
IStream** ppstm) /* [out] */
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
StgStreamImpl* This = impl_from_IStream(iface);
|
2005-07-31 12:11:56 +00:00
|
|
|
HRESULT hres;
|
|
|
|
StgStreamImpl* new_stream;
|
|
|
|
LARGE_INTEGER seek_pos;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("%p %p\n", This, ppstm);
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* Sanity check
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
|
|
|
|
if (!This->parentStorage)
|
|
|
|
return STG_E_REVERTED;
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
if ( ppstm == 0 )
|
|
|
|
return STG_E_INVALIDPOINTER;
|
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->dirEntry);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (!new_stream)
|
|
|
|
return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */
|
|
|
|
|
2012-12-12 21:01:41 +00:00
|
|
|
*ppstm = &new_stream->IStream_iface;
|
2007-04-20 12:23:52 +00:00
|
|
|
IStream_AddRef(*ppstm);
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
seek_pos.QuadPart = This->currentPosition.QuadPart;
|
|
|
|
|
2012-12-12 21:01:41 +00:00
|
|
|
hres = IStream_Seek(*ppstm, seek_pos, STREAM_SEEK_SET, NULL);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
assert (SUCCEEDED(hres));
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Virtual function table for the StgStreamImpl class.
|
|
|
|
*/
|
2012-12-12 21:01:41 +00:00
|
|
|
static const IStreamVtbl StgStreamVtbl =
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
StgStreamImpl_QueryInterface,
|
|
|
|
StgStreamImpl_AddRef,
|
|
|
|
StgStreamImpl_Release,
|
|
|
|
StgStreamImpl_Read,
|
|
|
|
StgStreamImpl_Write,
|
|
|
|
StgStreamImpl_Seek,
|
|
|
|
StgStreamImpl_SetSize,
|
|
|
|
StgStreamImpl_CopyTo,
|
|
|
|
StgStreamImpl_Commit,
|
|
|
|
StgStreamImpl_Revert,
|
|
|
|
StgStreamImpl_LockRegion,
|
|
|
|
StgStreamImpl_UnlockRegion,
|
|
|
|
StgStreamImpl_Stat,
|
|
|
|
StgStreamImpl_Clone
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
** StgStreamImpl implementation
|
|
|
|
*/
|
|
|
|
|
|
|
|
/***
|
|
|
|
* This is the constructor for the StgStreamImpl class.
|
|
|
|
*
|
|
|
|
* Params:
|
|
|
|
* parentStorage - Pointer to the storage that contains the stream to open
|
2010-03-10 14:28:56 +00:00
|
|
|
* dirEntry - Index of the directory entry that points to this stream.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
StgStreamImpl* StgStreamImpl_Construct(
|
|
|
|
StorageBaseImpl* parentStorage,
|
|
|
|
DWORD grfMode,
|
2010-03-10 14:28:56 +00:00
|
|
|
DirRef dirEntry)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
StgStreamImpl* newStream;
|
|
|
|
|
|
|
|
newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl));
|
|
|
|
|
2012-12-12 21:01:41 +00:00
|
|
|
if (newStream)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Set-up the virtual function table and reference count.
|
|
|
|
*/
|
2012-12-12 21:01:41 +00:00
|
|
|
newStream->IStream_iface.lpVtbl = &StgStreamVtbl;
|
2005-07-31 12:11:56 +00:00
|
|
|
newStream->ref = 0;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
newStream->parentStorage = parentStorage;
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* We want to nail-down the reference to the storage in case the
|
|
|
|
* stream out-lives the storage in the client application.
|
2007-04-20 12:23:52 +00:00
|
|
|
*
|
2012-12-12 21:01:41 +00:00
|
|
|
* -- IStorage_AddRef(&newStream->parentStorage->IStorage_iface);
|
2007-04-20 12:23:52 +00:00
|
|
|
*
|
|
|
|
* No, don't do this. Some apps call IStorage_Release without
|
|
|
|
* calling IStream_Release first. If we grab a reference the
|
|
|
|
* file is not closed, and the app fails when it tries to
|
|
|
|
* reopen the file (Easy-PC, for example)
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
newStream->grfMode = grfMode;
|
2010-03-10 14:28:56 +00:00
|
|
|
newStream->dirEntry = dirEntry;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Start the stream at the beginning.
|
|
|
|
*/
|
|
|
|
newStream->currentPosition.u.HighPart = 0;
|
|
|
|
newStream->currentPosition.u.LowPart = 0;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
/* add us to the storage's list of active streams */
|
|
|
|
StorageBaseImpl_AddStream(parentStorage, newStream);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return newStream;
|
|
|
|
}
|