// NeL - MMORPG Framework // 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 . #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 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; } }