2012-05-29 13:31:11 +00:00
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "stdmisc.h"
# include "nel/misc/mem_stream.h"
namespace NLMISC
{
void CMemStream : : swap ( CMemStream & other )
{
IStream : : swap ( other ) ;
_Buffer . swap ( other . _Buffer ) ;
std : : swap ( _StringMode , other . _StringMode ) ;
std : : swap ( _DefaultCapacity , other . _DefaultCapacity ) ;
}
/*
* serial ( inherited from IStream )
*/
void CMemStream : : serialBuffer ( uint8 * buf , uint len )
{
// commented for optimum performance
// nlassert (len > 0);
if ( len = = 0 )
return ;
nlassert ( buf ! = NULL ) ;
if ( isReading ( ) )
{
// Check that we don't read more than there is to read
//checkStreamSize(len);
uint32 pos = lengthS ( ) ;
uint32 total = length ( ) ;
if ( pos + len > total ) // calls virtual length (cf. sub messages)
{
throw EStreamOverflow ( " CMemStream serialBuffer overflow: Read past %u bytes " , total ) ;
}
// Serialize in
CFastMem : : memcpy ( buf , _Buffer . getBuffer ( ) . getPtr ( ) + _Buffer . Pos , len ) ;
_Buffer . Pos + = len ;
}
else
{
// Serialize out
increaseBufferIfNecessary ( len ) ;
CFastMem : : memcpy ( _Buffer . getBufferWrite ( ) . getPtr ( ) + _Buffer . Pos , buf , len ) ;
_Buffer . Pos + = len ;
}
}
/*
* serialBit ( inherited from IStream )
*/
void CMemStream : : serialBit ( bool & bit )
{
uint8 u ;
if ( isReading ( ) )
{
serial ( u ) ;
bit = ( u ! = 0 ) ;
}
else
{
u = ( uint8 ) bit ;
serial ( u ) ;
}
}
/*
* seek ( inherited from IStream )
*
* Warning : in output mode , seek ( end ) does not point to the end of the serialized data ,
* but on the end of the whole allocated buffer ( see size ( ) ) .
* If you seek back and want to return to the end of the serialized data , you have to
* store the position ( a better way is to use reserve ( ) / poke ( ) ) .
*
* Possible enhancement :
* In output mode , keep another pointer to track the end of serialized data .
* When serializing , increment the pointer if its value exceeds its previous value
* ( to prevent from an " inside serial " to increment it ) .
* Then a seek ( end ) would get back to the pointer .
*/
bool CMemStream : : seek ( sint32 offset , TSeekOrigin origin ) const throw ( EStream )
{
switch ( origin )
{
case begin :
if ( offset > ( sint ) length ( ) )
return false ;
if ( offset < 0 )
return false ;
_Buffer . Pos = offset ;
break ;
case current :
if ( getPos ( ) + offset > ( sint ) length ( ) )
return false ;
if ( getPos ( ) + offset < 0 )
return false ;
_Buffer . Pos + = offset ;
break ;
case end :
if ( offset < - ( sint ) length ( ) )
return false ;
if ( offset > 0 )
return false ;
_Buffer . Pos = _Buffer . getBuffer ( ) . size ( ) + offset ;
break ;
}
return true ;
}
/*
* Resize the buffer .
* Warning : the position is unchanged , only the size is changed .
*/
void CMemStream : : resize ( uint32 size )
{
if ( size = = length ( ) ) return ;
// need to increase the buffer size
_Buffer . getBufferWrite ( ) . resize ( size ) ;
}
/*
* Input : read from the stream until the next separator , and return the number of bytes read . The separator is then skipped .
*/
uint CMemStream : : serialSeparatedBufferIn ( uint8 * buf , uint len )
{
nlassert ( _StringMode & & isReading ( ) ) ;
// Check that we don't read more than there is to read
if ( ( _Buffer . Pos = = _Buffer . getBuffer ( ) . size ( ) ) | | // we are at the end
( ( lengthS ( ) + len + SEP_SIZE > length ( ) ) & & ( _Buffer . getBuffer ( ) [ _Buffer . getBuffer ( ) . size ( ) - 1 ] ! = SEPARATOR ) ) ) // we are before the end // calls virtual length (cf. sub messages)
{
throw EStreamOverflow ( ) ;
}
// Serialize in
uint32 i = 0 ;
const uint8 * pos = _Buffer . getBuffer ( ) . getPtr ( ) + _Buffer . Pos ;
while ( ( i < len ) & & ( * pos ) ! = SEPARATOR )
{
* ( buf + i ) = * pos ;
i + + ;
+ + pos ;
+ + _Buffer . Pos ;
}
// Exceeds len
if ( ( * pos ) ! = SEPARATOR )
{
throw EStreamOverflow ( ) ;
}
_Buffer . Pos + = SEP_SIZE ;
return i ;
}
/*
* Output : writes len bytes from buf into the stream
*/
void CMemStream : : serialSeparatedBufferOut ( uint8 * buf , uint len )
{
nlassert ( _StringMode & & ( ! isReading ( ) ) ) ;
// Serialize out
uint32 oldBufferSize = _Buffer . getBuffer ( ) . size ( ) ;
if ( _Buffer . Pos + ( len + SEP_SIZE ) > oldBufferSize )
{
// need to increase the buffer size
_Buffer . getBufferWrite ( ) . resize ( oldBufferSize * 2 + len + SEP_SIZE ) ;
}
CFastMem : : memcpy ( _Buffer . getBufferWrite ( ) . getPtr ( ) + _Buffer . Pos , buf , len ) ;
_Buffer . Pos + = len ;
* ( _Buffer . getBufferWrite ( ) . getPtr ( ) + _Buffer . Pos ) = SEPARATOR ;
_Buffer . Pos + = SEP_SIZE ;
}
/* Returns a readable string to display it to the screen. It's only for debugging purpose!
* Don ' t use it for anything else than to debugging , the string format could change in the future .
* \ param hexFormat If true , display all bytes in hexadecimal , else display as chars ( above 31 , otherwise ' . ' )
*/
std : : string CMemStream : : toString ( bool hexFormat ) const
{
std : : string s ;
uint32 len = length ( ) ;
if ( hexFormat )
{
for ( uint i = 0 ; i ! = len ; + + i )
s + = NLMISC : : toString ( " %2X " , buffer ( ) [ i ] ) ;
}
else
{
for ( uint i = 0 ; i ! = len ; + + i )
s + = NLMISC : : toString ( " %c " , ( buffer ( ) [ i ] > 31 ) ? buffer ( ) [ i ] : ' . ' ) ;
}
return s ;
}
// ***************************************************************************
uint CMemStream : : getDbgStreamSize ( ) const
{
if ( isReading ( ) )
return length ( ) ;
else
return 0 ;
}
}