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.
 
 
 
 
 
 

354 lines
6.0 KiB

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
Abstract:
History:
--*/
#include "precomp.h"
#include "buffer.h"
#include "comutl.h"
/************************************************************************
CBuffer
*************************************************************************/
CBuffer::CBuffer( PBYTE pData, ULONG cData, BOOL bDelete )
: m_pData(pData), m_cData(cData), m_bDelete(bDelete), m_iData(0), m_cRefs(0)
{
}
CBuffer::~CBuffer()
{
if ( m_bDelete )
{
delete [] m_pData;
}
}
CBuffer::CBuffer( const CBuffer& rOther )
: m_pData(NULL), m_cData(0), m_bDelete(FALSE), m_iData(0), m_cRefs(0)
{
*this = rOther;
}
CBuffer& CBuffer::operator= ( const CBuffer& rOther )
{
EnsureSize( rOther.m_iData );
memcpy( m_pData, rOther.m_pData, m_iData );
return *this;
}
void CBuffer::EnsureSize( ULONG ulSize )
{
if ( ulSize <= m_cData )
{
return;
}
ULONG cData = m_cData*2 > ulSize ? m_cData*2 : ulSize + 256;
BYTE* pData = new BYTE[cData];
if ( pData == NULL )
{
throw CX_MemoryException();
}
memcpy( pData, m_pData, m_iData );
if ( m_bDelete )
{
delete [] m_pData;
}
m_bDelete = TRUE;
m_cData = cData;
m_pData = pData;
}
HRESULT CBuffer::ReadLPWSTR( LPCWSTR& rwszStr )
{
HRESULT hr;
ULONG cStr;
hr = Read( &cStr, sizeof(DWORD), NULL );
if ( hr != S_OK )
{
return hr;
}
if ( m_cData-m_iData < cStr )
{
return S_FALSE;
}
rwszStr = LPCWSTR(m_pData+m_iData);
m_iData += cStr;
return S_OK;
}
HRESULT CBuffer::WriteLPWSTR( LPCWSTR wszStr )
{
HRESULT hr;
//
// ensure that the packed string's length is divisible by sizeof WCHAR.
// this makes it easier to ensure that all strings in the message are
// at least aligned appropriately.
//
DWORD cStr = (wcslen(wszStr) + 1)*2; // in bytes
DWORD cPad = cStr%2;
DWORD cPackedStr = cStr + cPad;
hr = Write( &cPackedStr, sizeof(DWORD), NULL );
if ( FAILED(hr) )
{
return hr;
}
hr = Write( wszStr, cStr, NULL );
if ( SUCCEEDED(hr) )
{
hr = Advance( cPad );
}
return hr;
}
ULONG CBuffer::AddRef()
{
return InterlockedIncrement( &m_cRefs );
}
ULONG CBuffer::Release()
{
ULONG cRefs = InterlockedDecrement( &m_cRefs );
if ( cRefs == 0 )
{
delete this;
}
return cRefs;
}
STDMETHODIMP CBuffer::QueryInterface( REFIID riid, void** ppv )
{
*ppv = NULL;
if ( riid==IID_IStream ||
riid==IID_ISequentialStream ||
riid==IID_IUnknown )
{
*ppv = (IStream*)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP CBuffer::Read( void *pv, ULONG cb, ULONG *pcbRead )
{
ULONG cRead = cb > m_cData-m_iData ? m_cData-m_iData : cb;
memcpy( pv, m_pData + m_iData, cRead );
if ( pcbRead != NULL )
{
*pcbRead = cRead;
}
m_iData += cRead;
return cRead == cb ? S_OK : S_FALSE;
}
STDMETHODIMP CBuffer::Write( const void *pv, ULONG cb, ULONG *pcbWritten )
{
ENTER_API_CALL
HRESULT hr;
if ( pcbWritten != NULL )
{
*pcbWritten = 0;
}
EnsureSize( m_iData + cb );
memcpy( m_pData + m_iData, pv, cb );
m_iData += cb;
if ( pcbWritten != NULL )
{
*pcbWritten = cb;
}
return S_OK;
EXIT_API_CALL
}
STDMETHODIMP CBuffer::Seek( LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition )
{
ENTER_API_CALL
HRESULT hr;
__int64 i64Data;
__int64 i64Move = dlibMove.QuadPart;
if ( plibNewPosition != NULL )
{
plibNewPosition->QuadPart = m_iData;
}
if ( dwOrigin == STREAM_SEEK_SET )
{
i64Data = 0;
}
else if ( dwOrigin == STREAM_SEEK_CUR )
{
i64Data = m_iData;
}
else if ( dwOrigin == STREAM_SEEK_END )
{
i64Data = m_cData;
}
else
{
return STG_E_INVALIDFUNCTION;
}
i64Data += i64Move;
EnsureSize( ULONG(i64Data) );
m_iData = ULONG(i64Data);
if ( plibNewPosition != NULL )
{
plibNewPosition->QuadPart = i64Data;
}
return S_OK;
EXIT_API_CALL
}
STDMETHODIMP CBuffer::SetSize( ULARGE_INTEGER libNewSize )
{
ENTER_API_CALL
EnsureSize( libNewSize.LowPart );
return S_OK;
EXIT_API_CALL
}
STDMETHODIMP CBuffer::CopyTo( IStream *pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead,
ULARGE_INTEGER *pcbWritten )
{
ENTER_API_CALL
HRESULT hr;
ULONG cRead, cWritten;
if ( pcbRead != NULL )
{
pcbRead->QuadPart = 0;
}
cRead = cb.LowPart > m_cData-m_iData ? m_cData-m_iData : cb.LowPart;
hr = pstm->Write( m_pData + m_iData, cRead, &cWritten );
if ( pcbWritten != NULL )
{
pcbWritten->QuadPart = cWritten;
}
if ( FAILED(hr) )
{
return hr;
}
m_iData += cRead;
if ( pcbRead != NULL )
{
pcbRead->QuadPart = cRead;
}
return hr;
EXIT_API_CALL
}
STDMETHODIMP CBuffer::Stat( STATSTG* pstatstg, DWORD grfStatFlag )
{
if ( pstatstg == NULL )
{
return STG_E_INVALIDPOINTER;
}
ZeroMemory( pstatstg, sizeof(STATSTG) );
pstatstg->cbSize.LowPart = m_cData;
return S_OK;
}
STDMETHODIMP CBuffer::Clone( IStream **ppstm )
{
ENTER_API_CALL
BYTE* pData = new BYTE[m_cData];
if ( pData == NULL )
{
return E_OUTOFMEMORY;
}
CBuffer* pNew;
try
{
pNew = new CBuffer( pData, m_cData );
}
catch( CX_MemoryException )
{
delete pData;
throw;
}
if ( pNew == NULL ) // just in case we don't have a new which throws on OOM
{
delete pData;
return E_OUTOFMEMORY;
}
pNew->m_iData = m_iData;
return pNew->QueryInterface( IID_IStream, (void**)ppstm );
EXIT_API_CALL
}