www.pudn.com > pueblo.zip > ChMData.cpp
/*----------------------------------------------------------------------------
_ _ _
/\ | | | (_)
/ \ _ __ __| |_ __ ___ _ __ ___ ___ __| |_ __ _
/ /\ \ | '_ \ / _` | '__/ _ \| '_ ` _ \ / _ \/ _` | |/ _` |
/ ____ \| | | | (_| | | | (_) | | | | | | __/ (_| | | (_| |
/_/ \_\_| |_|\__,_|_| \___/|_| |_| |_|\___|\__,_|_|\__,_|
The contents of this file are subject to the Andromedia Public
License Version 1.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.andromedia.com/APL/
Software distributed under the License is distributed on an
"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is Pueblo client code, released November 4, 1998.
The Initial Developer of the Original Code is Andromedia Incorporated.
Portions created by Andromedia are Copyright (C) 1998 Andromedia
Incorporated. All Rights Reserved.
Andromedia Incorporated 415.365.6700
818 Mission Street - 2nd Floor 415.365.6701 fax
San Francisco, CA 94103
Contributor(s):
--------------------------------------------------------------------------
Chaco team: Dan Greening, Glenn Crocker, Jim Doubek,
Coyote Lussier, Pritham Shetty.
Wrote and designed original codebase.
------------------------------------------------------------------------------
This file consists of the interface for the ChMemData class.
----------------------------------------------------------------------------*/
// $Header: /home/cvs/chaco/api/ChMData.cpp,v 2.0 1995/05/11 00:09:13 coyote Exp $
#include "headers.h"
#include
#include
#if defined( CH_UNIX )
#include
#include
#define ASSERT_VALID( object )
#endif // defined( CH_UNIX )
/*----------------------------------------------------------------------------
ChMemData Constructor and Destructor
----------------------------------------------------------------------------*/
ChMemData::ChMemData() : ChData( modeReadWrite )
{
m_suGrowAmount = 1024;
m_luPosition = 0;
m_luBufferSize = 0;
m_luDataSize = 0;
m_pBuffer = 0;
m_luBufferSize = 0;
}
ChMemData::~ChMemData()
{
if (m_pBuffer)
{ /* Ensure that the memory data has
been closed */
Close();
}
ASSERT( 0 == m_pBuffer );
m_suGrowAmount = 0;
m_luPosition = 0;
m_luBufferSize = 0;
m_luDataSize = 0;
}
/*----------------------------------------------------------------------------
ChMemData public methods
----------------------------------------------------------------------------*/
void ChMemData::Flush()
{
ASSERT_VALID( this );
}
void ChMemData::Close()
{
ASSERT_VALID( this );
m_suGrowAmount = 0;
m_luPosition = 0;
m_luBufferSize = 0;
m_luDataSize = 0;
if (m_pBuffer)
{ // Free any data allocated
Free( m_pBuffer );
}
m_pBuffer = 0;
}
void ChMemData::Abort()
{
ASSERT_VALID( this );
Close();
}
/*----------------------------------------------------------------------------
ChMemData public methods (should not be used by module authors)
----------------------------------------------------------------------------*/
chuint32 ChMemData::GetSize() const
{
return m_luDataSize;
}
chuint32 ChMemData::GetPosition() const
{
return m_luPosition;
}
chuint32 ChMemData::Read( void* pBuffer, chuint32 luCount )
{
chuint32 luBytesRead;
ASSERT_VALID( this );
if (0 == luCount)
{ // We're not reading anything
return 0;
}
ASSERT( 0 != pBuffer );
if (m_luPosition > m_luDataSize)
{ // We're positioned past the end
return 0;
}
if (m_luPosition + luCount > m_luDataSize)
{ /* We can only read the number of
bytes remaining, which is less
than they asked for */
luBytesRead = m_luDataSize - m_luPosition;
}
else
{
luBytesRead = luCount;
}
Memcpy( (chuint8 *)pBuffer, m_pBuffer + m_luPosition, luBytesRead );
m_luPosition += luBytesRead; // Move the current position
ASSERT_VALID( this );
return luBytesRead;
}
void ChMemData::Write( const void *pBuffer, chuint32 luCount )
{
ASSERT_VALID( this );
if (0 == luCount)
{ // Nothing to write!
return;
}
ASSERT( 0 != pBuffer );
if (m_luPosition + luCount > m_luBufferSize)
{ // The storage isn't large enough
GrowData( m_luPosition + luCount );
}
ASSERT( m_luPosition + luCount <= m_luBufferSize );
Memcpy( m_pBuffer + m_luPosition, (chuint8 *)pBuffer, luCount );
m_luPosition += luCount; // Move the current position
if (m_luPosition > m_luDataSize)
{ /* If the position is past the end
of the data block (?) correct
things */
m_luDataSize = m_luPosition;
}
ASSERT_VALID( this );
}
chint32 ChMemData::Seek( chint32 lOff, chuint16 suFrom )
{
chint32 lNewPos = m_luPosition;
ASSERT_VALID( this );
ASSERT( suFrom == begin || suFrom == end || suFrom == current);
if (suFrom == begin)
{
lNewPos = lOff;
}
else if (suFrom == current)
{
lNewPos += lOff;
}
else if (suFrom == end)
{
lNewPos = m_luDataSize + lOff;
}
else
{ // Error!
return -1;
}
if (lNewPos < 0)
{ // Seek failed badly...
#if defined( CH_EXCEPTIONS )
{
#if defined( CH_MSW) && defined( CH_ARCH_16 )
{
THROW( new ChDataEx( ChEx::badSeek ) );
}
#else
throw ChDataEx( ChEx::badSeek );
#endif
}
#else // defined( CH_EXCEPTIONS )
{
return -1 ;
}
#endif // defined( CH_EXCEPTIONS )
}
m_luPosition = lNewPos;
ASSERT_VALID( this );
return m_luPosition;
}
chuint32 ChMemData::GetBufferPtr( chuint16 suCommand, chuint32 luCount,
void **ppBufStart, void **ppBufMax )
{
/* ChMemData supports "direct
buffering" interaction with
ChArchive */
ASSERT( suCommand == bufferCheck || suCommand == bufferCommit ||
suCommand == bufferRead || suCommand == bufferWrite );
if (suCommand == bufferCheck)
{
return 1; /* Just a check for direct buffer
support */
}
if (suCommand == bufferCommit)
{ // Commit buffer
ASSERT( 0 == ppBufStart );
ASSERT( 0 == ppBufMax );
m_luPosition += luCount;
if (m_luPosition > m_luDataSize)
{
m_luDataSize = m_luPosition;
}
return 0;
}
/* When storing, grow file as
necessary to satisfy buffer
request */
if ((suCommand == bufferWrite) && (m_luPosition + luCount > m_luBufferSize))
{
GrowData( m_luPosition + luCount );
}
ASSERT( suCommand == bufferWrite || suCommand == bufferRead );
// Store buffer max and min
ASSERT( 0 != ppBufStart );
ASSERT( 0 != ppBufMax );
*ppBufStart = m_pBuffer + m_luPosition;
*ppBufMax = m_pBuffer + min( m_luBufferSize, m_luPosition + luCount );
/* Advance current file position
only on read */
if (bufferRead == suCommand)
{
m_luPosition += (chuint8 *)*ppBufMax - (chuint8 *)*ppBufStart;
}
/* Return number of bytes in
returned buffer space (may be
<= luCount) */
return (chuint8 *)*ppBufMax - (chuint8 *)*ppBufStart;
}
void ChMemData::SetLength( chuint32 luNewLen )
{
ASSERT_VALID( this );
if (luNewLen > m_luBufferSize)
{
GrowData( luNewLen );
}
if (luNewLen < m_luPosition)
{
m_luPosition = luNewLen;
}
m_luDataSize = luNewLen;
ASSERT_VALID( this );
}
/*----------------------------------------------------------------------------
ChMemData low-level functionality (protected)
----------------------------------------------------------------------------*/
void* ChMemData::Alloc( chuint32 luSize )
{
return (void *)malloc( (size_t)luSize );
}
void* ChMemData::Realloc( void *pBlock, chuint32 luNewSize )
{
return (void *)realloc( pBlock, (size_t)luNewSize );
}
#pragma intrinsic( memcpy )
void* ChMemData::Memcpy( void *pTarget, const void *pSource, chuint32 luCount )
{
ASSERT( 0 != pTarget );
ASSERT( 0 != pSource );
return (void *)ChMemCopy( pTarget, pSource, luCount );
}
#pragma function( memcpy )
void ChMemData::Free( void *pBlock )
{
ASSERT( 0 != pBlock );
free( pBlock );
}
void ChMemData::GrowData( chuint32 luNewLen )
{
ASSERT_VALID( this );
if (luNewLen > m_luBufferSize)
{ // Grow the buffer
chuint8 *pNew;
chuint32 luNewBufSize = m_luBufferSize;
while (luNewBufSize < luNewLen)
{
luNewBufSize += m_suGrowAmount;
}
if (0 == m_pBuffer)
{
pNew = (chuint8 *)Alloc( luNewBufSize );
}
else
{
pNew = (chuint8 *)Realloc( m_pBuffer, luNewBufSize );
}
if (0 == pNew)
{ // Out of memory
#if defined( CH_EXCEPTIONS )
{
#if defined( CH_MSW) && defined( CH_ARCH_16 )
{
THROW( new ChMemEx() );
}
#else
throw ChMemEx();
#endif
}
#endif // defined( CH_EXCEPTIONS )
}
m_pBuffer = pNew;
m_luBufferSize = luNewBufSize;
}
ASSERT_VALID( this );
}