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