mirror of https://github.com/tongzx/nt5src
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
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;
|
|
}
|
|
|