355 lines
6 KiB
C++
355 lines
6 KiB
C++
|
/*++
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|