710 lines
15 KiB
C++
710 lines
15 KiB
C++
/*++
|
||
|
||
Microsoft Windows
|
||
Copyright (c) 1994 Microsoft Corporation. All rights reserved.
|
||
|
||
Module Name:
|
||
stream.cxx
|
||
|
||
Abstract:
|
||
Implements the IStream interface on a memory buffer.
|
||
|
||
Author:
|
||
ShannonC 09-Mar-1994
|
||
|
||
Environment:
|
||
Windows NT and Windows 95. We do not support DOS and Win16.
|
||
|
||
Revision History:
|
||
12-Oct-94 ShannonC Reformat for code review.
|
||
|
||
--*/
|
||
|
||
#include <ndrp.h>
|
||
#include <ndrole.h>
|
||
|
||
class CNdrStream : public IStream
|
||
{
|
||
public:
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
QueryInterface(
|
||
IN REFIID riid,
|
||
OUT void **ppvObj);
|
||
|
||
virtual ULONG STDMETHODCALLTYPE
|
||
AddRef();
|
||
|
||
virtual ULONG STDMETHODCALLTYPE
|
||
Release();
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
Read(
|
||
IN void * pv,
|
||
IN ULONG cb,
|
||
OUT ULONG * pcbRead);
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
Write(
|
||
IN void const *pv,
|
||
IN ULONG cb,
|
||
OUT ULONG * pcbWritten);
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
Seek(
|
||
IN LARGE_INTEGER dlibMove,
|
||
IN DWORD dwOrigin,
|
||
OUT ULARGE_INTEGER *plibNewPosition);
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
SetSize(
|
||
IN ULARGE_INTEGER libNewSize);
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
CopyTo(
|
||
IN IStream * pstm,
|
||
IN ULARGE_INTEGER cb,
|
||
OUT ULARGE_INTEGER *pcbRead,
|
||
OUT ULARGE_INTEGER *pcbWritten);
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
Commit(
|
||
IN DWORD grfCommitFlags);
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
Revert();
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
LockRegion(
|
||
IN ULARGE_INTEGER libOffset,
|
||
IN ULARGE_INTEGER cb,
|
||
IN DWORD dwLockType);
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
UnlockRegion(
|
||
IN ULARGE_INTEGER libOffset,
|
||
IN ULARGE_INTEGER cb,
|
||
IN DWORD dwLockType);
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
Stat(
|
||
OUT STATSTG * pstatstg,
|
||
IN DWORD grfStatFlag);
|
||
|
||
virtual HRESULT STDMETHODCALLTYPE
|
||
Clone(
|
||
OUT IStream **ppstm);
|
||
|
||
CNdrStream(
|
||
IN unsigned char * pData,
|
||
IN unsigned long cbMax);
|
||
|
||
private:
|
||
long RefCount;
|
||
unsigned char * pBuffer;
|
||
unsigned long cbBufferLength;
|
||
unsigned long position;
|
||
};
|
||
|
||
EXTERN_C IStream *STDAPICALLTYPE
|
||
NdrpCreateStreamOnMemory(
|
||
IN unsigned char * pData,
|
||
IN unsigned long cbSize)
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function creates a stream on the specified memory buffer.
|
||
|
||
Arguments:
|
||
pData - Supplies pointer to memory buffer.
|
||
cbSize - Supplies size of memory buffer.
|
||
|
||
Return Value:
|
||
This function returns a pointer to the newly created stream.
|
||
|
||
--*/
|
||
{
|
||
CNdrStream *pStream = new CNdrStream(pData, cbSize);
|
||
return (IStream *)pStream;
|
||
}
|
||
|
||
CNdrStream::CNdrStream(
|
||
IN unsigned char * pData,
|
||
IN unsigned long cbMax)
|
||
: pBuffer(pData), cbBufferLength(cbMax)
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function creates a stream on the specified memory buffer.
|
||
|
||
Arguments:
|
||
pData - Supplies pointer to memory buffer.
|
||
cbMax - Supplies size of memory buffer.
|
||
|
||
Return Value:
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
RefCount = 1;
|
||
position = 0;
|
||
}
|
||
|
||
|
||
ULONG STDMETHODCALLTYPE
|
||
CNdrStream::AddRef()
|
||
/*++
|
||
|
||
Routine Description:
|
||
Increment the reference count.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
Reference count.
|
||
|
||
--*/
|
||
{
|
||
InterlockedIncrement(&RefCount);
|
||
return (ULONG) RefCount;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::Clone(
|
||
OUT IStream **ppstm)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Create a new IStream object. The new IStream gets an
|
||
independent seek pointer but it shares the underlying
|
||
data buffer with the original IStream object.
|
||
|
||
Arguments:
|
||
ppstm - Pointer to the new stream.
|
||
|
||
Return Value:
|
||
S_OK - The stream was successfully copied.
|
||
E_OUTOFMEMORY - The stream could not be copied due to lack of memory.
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
CNdrStream *pStream = new CNdrStream(pBuffer, cbBufferLength);
|
||
|
||
if(pStream != 0)
|
||
{
|
||
pStream->position = position;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
|
||
*ppstm = (IStream *) pStream;
|
||
|
||
return hr;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::Commit(
|
||
IN DWORD grfCommitFlags)
|
||
/*++
|
||
|
||
Routine Description:
|
||
This stream does not support transacted mode. This function does nothing.
|
||
|
||
Arguments:
|
||
grfCommitFlags
|
||
|
||
Return Value:
|
||
S_OK
|
||
|
||
--*/
|
||
{
|
||
return S_OK;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::CopyTo(
|
||
IN IStream * pstm,
|
||
IN ULARGE_INTEGER cb,
|
||
OUT ULARGE_INTEGER *pcbRead,
|
||
OUT ULARGE_INTEGER *pcbWritten)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Copies data from one stream to another stream.
|
||
|
||
Arguments:
|
||
pstm - Specifies the destination stream.
|
||
cb - Specifies the number of bytes to be copied to the destination stream.
|
||
pcbRead - Returns the number of bytes read from the source stream.
|
||
pcbWritten - Returns the number of bytes written to the destination stream.
|
||
|
||
Return Value:
|
||
S_OK - The data was successfully copied.
|
||
Other errors from IStream::Write.
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
unsigned char * pSource;
|
||
unsigned long cbRead;
|
||
unsigned long cbWritten;
|
||
unsigned long cbRemaining;
|
||
|
||
//Check if we are going off the end of the buffer.
|
||
if(position < cbBufferLength)
|
||
cbRemaining = cbBufferLength - position;
|
||
else
|
||
cbRemaining = 0;
|
||
|
||
if((cb.HighPart == 0) && (cb.LowPart <= cbRemaining))
|
||
cbRead = cb.LowPart;
|
||
else
|
||
cbRead = cbRemaining;
|
||
|
||
pSource = pBuffer + position;
|
||
|
||
//copy the data
|
||
hr = pstm->Write(pSource, cbRead, &cbWritten);
|
||
|
||
//advance the current position
|
||
position += cbRead;
|
||
|
||
if (pcbRead != 0)
|
||
{
|
||
pcbRead->LowPart = cbRead;
|
||
pcbRead->HighPart = 0;
|
||
}
|
||
if (pcbWritten != 0)
|
||
{
|
||
pcbWritten->LowPart = cbWritten;
|
||
pcbWritten->HighPart = 0;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::LockRegion(
|
||
IN ULARGE_INTEGER libOffset,
|
||
IN ULARGE_INTEGER cb,
|
||
IN DWORD dwLockType)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Range locking is not supported by this stream.
|
||
|
||
Return Value:
|
||
STG_E_INVALIDFUNCTION.
|
||
|
||
--*/
|
||
{
|
||
return STG_E_INVALIDFUNCTION;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::QueryInterface(
|
||
REFIID riid,
|
||
void **ppvObj)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Query for an interface on the stream. The stream supports
|
||
the IUnknown and IStream interfaces.
|
||
|
||
Arguments:
|
||
riid - Supplies the IID of the interface being requested.
|
||
ppvObject - Returns a pointer to the requested interface.
|
||
|
||
Return Value:
|
||
S_OK
|
||
E_NOINTERFACE
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
|
||
if ((memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) ||
|
||
(memcmp(&riid, &IID_IStream, sizeof(IID)) == 0))
|
||
{
|
||
this->AddRef();
|
||
*ppvObj = (IStream *) this;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
*ppvObj = 0;
|
||
hr = E_NOINTERFACE;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::Read(
|
||
OUT void * pv,
|
||
IN ULONG cb,
|
||
OUT ULONG *pcbRead)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Reads data from the stream starting at the current seek pointer.
|
||
|
||
Arguments:
|
||
pv - Returns the data read from the stream.
|
||
cb - Supplies the number of bytes to read from the stream.
|
||
pcbRead - Returns the number of bytes actually read from the stream.
|
||
|
||
Return Value:
|
||
S_OK - The data was successfully read from the stream.
|
||
S_FALSE - The number of bytes read was smaller than the number requested.
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
unsigned long cbRead;
|
||
unsigned long cbRemaining;
|
||
|
||
//Check if we are reading past the end of the buffer.
|
||
if(position < cbBufferLength)
|
||
cbRemaining = cbBufferLength - position;
|
||
else
|
||
cbRemaining = 0;
|
||
|
||
if(cb <= cbRemaining)
|
||
{
|
||
cbRead = cb;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
cbRead = cbRemaining;
|
||
hr = S_FALSE;
|
||
}
|
||
|
||
//copy the data
|
||
RpcpMemoryCopy(pv, pBuffer + position, cbRead);
|
||
|
||
//advance the current position
|
||
position += cbRead;
|
||
|
||
if(pcbRead != 0)
|
||
*pcbRead = cbRead;
|
||
|
||
return hr;
|
||
}
|
||
|
||
ULONG STDMETHODCALLTYPE
|
||
CNdrStream::Release()
|
||
/*++
|
||
|
||
Routine Description:
|
||
Decrement the reference count. When the reference count
|
||
reaches zero, the stream is deleted.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
Reference count.
|
||
|
||
--*/
|
||
{
|
||
unsigned long count;
|
||
|
||
count = RefCount - 1;
|
||
if(InterlockedDecrement(&RefCount) == 0)
|
||
{
|
||
count = 0;
|
||
delete this;
|
||
}
|
||
|
||
return count;
|
||
}
|
||
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::Revert()
|
||
/*++
|
||
|
||
Routine Description:
|
||
This stream does not support transacted mode. This function does nothing.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
S_OK.
|
||
|
||
--*/
|
||
{
|
||
return S_OK;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::Seek(
|
||
IN LARGE_INTEGER dlibMove,
|
||
IN DWORD dwOrigin,
|
||
OUT ULARGE_INTEGER *plibNewPosition)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Sets the position of the seek pointer. It is an error to seek
|
||
before the beginning of the stream or past the end of the stream.
|
||
|
||
Arguments:
|
||
dlibMove - Supplies the offset from the position specified in dwOrigin.
|
||
dwOrigin - Supplies the seek mode.
|
||
plibNewPosition - Returns the new position of the seek pointer.
|
||
|
||
Return Value:
|
||
S_OK - The seek pointer was successfully adjusted.
|
||
STG_E_INVALIDFUNCTION - dwOrigin contains invalid value.
|
||
STG_E_SEEKERROR - The seek pointer cannot be positioned before the
|
||
beginning of the stream or past the
|
||
end of the stream.
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
long high;
|
||
long low;
|
||
unsigned long offset;
|
||
unsigned long cbRemaining;
|
||
|
||
switch (dwOrigin)
|
||
{
|
||
case STREAM_SEEK_SET:
|
||
//Set the seek position relative to the beginning of the stream.
|
||
if((dlibMove.HighPart == 0) && (dlibMove.LowPart <= cbBufferLength))
|
||
{
|
||
position = dlibMove.LowPart;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
//It is an error to seek past the end of the stream.
|
||
hr = STG_E_SEEKERROR;
|
||
}
|
||
break;
|
||
|
||
case STREAM_SEEK_CUR:
|
||
//Set the seek position relative to the current position of the stream.
|
||
high = (long) dlibMove.HighPart;
|
||
if(high < 0)
|
||
{
|
||
//Negative offset
|
||
low = (long) dlibMove.LowPart;
|
||
offset = -low;
|
||
|
||
if((high == -1) && (offset <= position))
|
||
{
|
||
position -= offset;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
//It is an error to seek before the beginning of the stream.
|
||
hr = STG_E_SEEKERROR;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//Positive offset
|
||
if(position < cbBufferLength)
|
||
cbRemaining = cbBufferLength - position;
|
||
else
|
||
cbRemaining = 0;
|
||
|
||
if((dlibMove.HighPart == 0) && (dlibMove.LowPart <= cbRemaining))
|
||
{
|
||
position += dlibMove.LowPart;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
//It is an error to seek past the end of the stream.
|
||
hr = STG_E_SEEKERROR;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case STREAM_SEEK_END:
|
||
//Set the seek position relative to the end of the stream.
|
||
high = (long) dlibMove.HighPart;
|
||
if(high < 0)
|
||
{
|
||
//Negative offset
|
||
low = (long) dlibMove.LowPart;
|
||
offset = -low;
|
||
|
||
if((high == -1) && (offset <= cbBufferLength))
|
||
{
|
||
position = cbBufferLength - offset;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
//It is an error to seek before the beginning of the stream.
|
||
hr = STG_E_SEEKERROR;
|
||
}
|
||
}
|
||
else if(dlibMove.QuadPart == 0)
|
||
{
|
||
position = cbBufferLength;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
//Positive offset
|
||
//It is an error to seek past the end of the stream.
|
||
hr = STG_E_SEEKERROR;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
//dwOrigin contains an invalid value.
|
||
hr = STG_E_INVALIDFUNCTION;
|
||
}
|
||
|
||
if (plibNewPosition != 0)
|
||
{
|
||
plibNewPosition->LowPart = position;
|
||
plibNewPosition->HighPart = 0;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::SetSize(
|
||
IN ULARGE_INTEGER libNewSize)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Changes the size of the stream.
|
||
|
||
Arguments:
|
||
libNewSize - Supplies the new size of the stream.
|
||
|
||
Return Value:
|
||
S_OK - The stream size was successfully changed.
|
||
STG_E_MEDIUMFULL - The stream size could not be changed.
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
|
||
if((libNewSize.HighPart == 0) && (libNewSize.LowPart <= cbBufferLength))
|
||
{
|
||
cbBufferLength = libNewSize.LowPart;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
hr = STG_E_MEDIUMFULL;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::Stat(
|
||
OUT STATSTG * pstatstg,
|
||
IN DWORD grfStatFlag)
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function gets information about this stream.
|
||
|
||
Arguments:
|
||
pstatstg - Returns information about this stream.
|
||
grfStatFlg - Specifies the information to be returned in pstatstg.
|
||
|
||
Return Value:
|
||
S_OK.
|
||
|
||
--*/
|
||
{
|
||
memset(pstatstg, 0, sizeof(STATSTG));
|
||
pstatstg->type = STGTY_STREAM;
|
||
pstatstg->cbSize.LowPart = cbBufferLength;
|
||
pstatstg->cbSize.HighPart = 0;
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::UnlockRegion(
|
||
IN ULARGE_INTEGER libOffset,
|
||
IN ULARGE_INTEGER cb,
|
||
IN DWORD dwLockType)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Range locking is not supported by this stream.
|
||
|
||
Return Value:
|
||
STG_E_INVALIDFUNCTION.
|
||
|
||
--*/
|
||
{
|
||
return STG_E_INVALIDFUNCTION;
|
||
}
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CNdrStream::Write(
|
||
IN void const *pv,
|
||
IN ULONG cb,
|
||
OUT ULONG * pcbWritten)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Write data to the stream starting at the current seek pointer.
|
||
|
||
Arguments:
|
||
pv - Supplies the data to be written to the stream.
|
||
cb - Specifies the number of bytes to be written to the stream.
|
||
pcbWritten - Returns the number of bytes actually written to the stream.
|
||
|
||
Return Value:
|
||
S_OK - The data was successfully written to the stream.
|
||
STG_E_MEDIUMFULL - Data cannot be written past the end of the stream.
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
unsigned long cbRemaining;
|
||
unsigned long cbWritten;
|
||
|
||
//Check if we are writing past the end of the buffer.
|
||
if(position < cbBufferLength)
|
||
cbRemaining = cbBufferLength - position;
|
||
else
|
||
cbRemaining = 0;
|
||
|
||
if(cb <= cbRemaining)
|
||
{
|
||
cbWritten = cb;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
cbWritten = cbRemaining;
|
||
hr = STG_E_MEDIUMFULL;
|
||
}
|
||
|
||
// Write the data.
|
||
RpcpMemoryCopy(pBuffer + position, pv, cbWritten);
|
||
|
||
//Advance the current position
|
||
position += cbWritten;
|
||
|
||
//update pcbWritten
|
||
if (pcbWritten != 0)
|
||
*pcbWritten = cbWritten;
|
||
|
||
return hr;
|
||
}
|
||
|