241 lines
5.8 KiB
C++
241 lines
5.8 KiB
C++
|
// 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"
|
||
|
|
||
|
#ifdef DEBUG_NEW
|
||
|
#define new DEBUG_NEW
|
||
|
#endif
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|