Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

710 lines
15 KiB

/*++
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;
}