2009-02-04 10:33:18 -06:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2009-02-04 12:04:12 +01:00
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
2008-10-02 16:23:55 -05:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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
2008-10-14 11:57:03 -05:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2008-10-14 11:57:03 -05:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
#ifndef _BYTEBUFFER_H
#define _BYTEBUFFER_H
#include "Common.h"
#include "Errors.h"
#include "Log.h"
#include "Utilities/ByteConverter.h"
2009-08-19 16:26:22 -05:00
class ByteBufferException
{
public :
ByteBufferException ( bool add , size_t pos , size_t esize , size_t size ) : add ( add ), pos ( pos ), esize ( esize ), size ( size )
{
PrintPosError ();
}
void PrintPosError () const
{
sLog . outError ( "ERROR: Attempted to %s in ByteBuffer (pos: %lu size: %lu) value with size: %lu" ,( add ? "put" : "get" ),( unsigned long ) pos , ( unsigned long ) size , ( unsigned long ) esize );
}
private :
bool add ;
size_t pos ;
size_t esize ;
size_t size ;
};
2008-10-02 16:23:55 -05:00
class ByteBuffer
{
public :
const static size_t DEFAULT_SIZE = 0x1000 ;
// constructor
ByteBuffer () : _rpos ( 0 ), _wpos ( 0 )
{
_storage . reserve ( DEFAULT_SIZE );
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
// constructor
ByteBuffer ( size_t res ) : _rpos ( 0 ), _wpos ( 0 )
{
_storage . reserve ( res );
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
// copy constructor
ByteBuffer ( const ByteBuffer & buf ) : _rpos ( buf . _rpos ), _wpos ( buf . _wpos ), _storage ( buf . _storage ) { }
void clear ()
{
_storage . clear ();
_rpos = _wpos = 0 ;
}
template < typename T > void append ( T value )
{
EndianConvert ( value );
append (( uint8 * ) & value , sizeof ( value ));
}
template < typename T > void put ( size_t pos , T value )
{
EndianConvert ( value );
put ( pos ,( uint8 * ) & value , sizeof ( value ));
}
ByteBuffer & operator << ( uint8 value )
{
append < uint8 > ( value );
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator << ( uint16 value )
{
append < uint16 > ( value );
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator << ( uint32 value )
{
append < uint32 > ( value );
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator << ( uint64 value )
{
append < uint64 > ( value );
return * this ;
}
// signed as in 2e complement
ByteBuffer & operator << ( int8 value )
{
append < int8 > ( value );
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator << ( int16 value )
{
append < int16 > ( value );
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator << ( int32 value )
{
append < int32 > ( value );
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator << ( int64 value )
{
append < int64 > ( value );
return * this ;
}
// floating points
ByteBuffer & operator << ( float value )
{
append < float > ( value );
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator << ( double value )
{
append < double > ( value );
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator << ( const std :: string & value )
{
append (( uint8 const * ) value . c_str (), value . length ());
append (( uint8 ) 0 );
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator << ( const char * str )
{
append (( uint8 const * ) str , str ? strlen ( str ) : 0 );
append (( uint8 ) 0 );
return * this ;
}
ByteBuffer & operator >> ( bool & value )
{
value = read < char > () > 0 ? true : false ;
return * this ;
}
ByteBuffer & operator >> ( uint8 & value )
{
value = read < uint8 > ();
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator >> ( uint16 & value )
{
value = read < uint16 > ();
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator >> ( uint32 & value )
{
value = read < uint32 > ();
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator >> ( uint64 & value )
{
value = read < uint64 > ();
return * this ;
}
//signed as in 2e complement
ByteBuffer & operator >> ( int8 & value )
{
value = read < int8 > ();
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator >> ( int16 & value )
{
value = read < int16 > ();
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator >> ( int32 & value )
{
value = read < int32 > ();
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator >> ( int64 & value )
{
value = read < int64 > ();
return * this ;
}
ByteBuffer & operator >> ( float & value )
{
value = read < float > ();
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator >> ( double & value )
{
value = read < double > ();
return * this ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
ByteBuffer & operator >> ( std :: string & value )
{
value . clear ();
while ( rpos () < size ()) // prevent crash at wrong string format in packet
{
2009-06-13 09:44:35 -05:00
char c = read < char > ();
if ( c == 0 )
2008-10-02 16:23:55 -05:00
break ;
2009-06-13 09:44:35 -05:00
value += c ;
2008-10-02 16:23:55 -05:00
}
return * this ;
}
2008-10-20 12:23:56 -05:00
uint8 operator []( size_t pos ) const
2008-10-02 16:23:55 -05:00
{
return read < uint8 > ( pos );
}
size_t rpos () const { return _rpos ; }
size_t rpos ( size_t rpos_ )
{
_rpos = rpos_ ;
return _rpos ;
2009-06-13 09:44:35 -05:00
}
2008-10-02 16:23:55 -05:00
size_t wpos () const { return _wpos ; }
size_t wpos ( size_t wpos_ )
{
_wpos = wpos_ ;
return _wpos ;
}
2009-08-19 16:54:52 -05:00
template < typename T >
void read_skip () { read_skip ( sizeof ( T )); }
template < typename T1 , typename T2 >
void read_skip2 () { read_skip ( sizeof ( T1 ) + sizeof ( T2 )); }
template <>
void read_skip < char *> ()
{
uint8 size = read < uint8 > ();
read_skip ( size );
}
template <>
void read_skip < char const *> () { read_skip < char *> (); }
template <>
void read_skip < std :: string > () { read_skip < char *> (); }
void read_skip ( size_t skip )
{
if ( _rpos + skip > size ())
throw ByteBufferException ( false , _rpos , skip , size ());
_rpos += skip ;
}
2008-10-02 16:23:55 -05:00
template < typename T > T read ()
{
2009-06-13 09:44:35 -05:00
T r = read < T > ( _rpos );
2008-10-02 16:23:55 -05:00
_rpos += sizeof ( T );
return r ;
2009-06-13 09:44:35 -05:00
}
2008-10-02 16:23:55 -05:00
template < typename T > T read ( size_t pos ) const
{
2009-08-19 16:26:22 -05:00
if ( pos + sizeof ( T ) > size ())
throw ByteBufferException ( false , pos , sizeof ( T ), size ());
2008-10-02 16:23:55 -05:00
T val = * (( T const * ) & _storage [ pos ]);
EndianConvert ( val );
return val ;
}
void read ( uint8 * dest , size_t len )
{
2009-08-19 16:26:22 -05:00
if ( _rpos + len > size ())
throw ByteBufferException ( false , _rpos , len , size ());
2008-10-02 16:23:55 -05:00
memcpy ( dest , & _storage [ _rpos ], len );
_rpos += len ;
}
2008-12-27 11:39:40 -06:00
bool readPackGUID ( uint64 & guid )
{
2009-06-13 09:44:35 -05:00
if ( rpos () + 1 > size ())
2008-12-27 11:39:40 -06:00
return false ;
guid = 0 ;
2009-06-13 09:44:35 -05:00
uint8 guidmark = 0 ;
2008-12-27 11:39:40 -06:00
( * this ) >> guidmark ;
2009-06-13 09:44:35 -05:00
for ( int i = 0 ; i < 8 ; ++ i )
2008-12-27 11:39:40 -06:00
{
if ( guidmark & ( uint8 ( 1 ) << i ))
{
2009-06-13 09:44:35 -05:00
if ( rpos () + 1 > size ())
2008-12-27 11:39:40 -06:00
return false ;
uint8 bit ;
( * this ) >> bit ;
2009-06-13 09:44:35 -05:00
guid |= ( uint64 ( bit ) << ( i * 8 ));
2008-12-27 11:39:40 -06:00
}
}
return true ;
}
2008-10-02 16:23:55 -05:00
const uint8 * contents () const { return & _storage [ 0 ]; }
size_t size () const { return _storage . size (); }
bool empty () const { return _storage . empty (); }
void resize ( size_t newsize )
{
_storage . resize ( newsize );
_rpos = 0 ;
_wpos = size ();
2009-06-13 09:44:35 -05:00
}
2008-10-02 16:23:55 -05:00
void reserve ( size_t ressize )
{
2009-06-13 09:44:35 -05:00
if ( ressize > size ())
_storage . reserve ( ressize );
}
2008-10-02 16:23:55 -05:00
void append ( const std :: string & str )
{
2009-06-13 09:44:35 -05:00
append (( uint8 const * ) str . c_str (), str . size () + 1 );
2008-10-02 16:23:55 -05:00
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
void append ( const char * src , size_t cnt )
{
return append (( const uint8 * ) src , cnt );
}
2009-06-13 09:44:35 -05:00
template < class T > void append ( const T * src , size_t cnt )
2008-10-02 16:23:55 -05:00
{
2009-06-13 09:44:35 -05:00
return append (( const uint8 * ) src , cnt * sizeof ( T ));
2008-10-02 16:23:55 -05:00
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
void append ( const uint8 * src , size_t cnt )
{
2009-06-13 09:44:35 -05:00
if ( ! cnt )
return ;
2008-10-02 16:23:55 -05:00
ASSERT ( size () < 10000000 );
if ( _storage . size () < _wpos + cnt )
_storage . resize ( _wpos + cnt );
memcpy ( & _storage [ _wpos ], src , cnt );
_wpos += cnt ;
}
2009-06-13 09:44:35 -05:00
2008-10-02 16:23:55 -05:00
void append ( const ByteBuffer & buffer )
{
2009-06-13 09:44:35 -05:00
if ( buffer . wpos ())
append ( buffer . contents (), buffer . wpos ());
}
// can be used in SMSG_MONSTER_MOVE opcode
void appendPackXYZ ( float x , float y , float z )
{
uint32 packed = 0 ;
packed |= (( int )( x / 0.25f ) & 0x7FF );
packed |= (( int )( y / 0.25f ) & 0x7FF ) << 11 ;
packed |= (( int )( z / 0.25f ) & 0x3FF ) << 22 ;
* this << packed ;
2008-10-02 16:23:55 -05:00
}
void appendPackGUID ( uint64 guid )
{
2009-06-01 12:15:43 -05:00
if ( _storage . size () < _wpos + sizeof ( guid ) + 1 )
_storage . resize ( _wpos + sizeof ( guid ) + 1 );
2008-10-02 16:23:55 -05:00
size_t mask_position = wpos ();
* this << uint8 ( 0 );
2009-06-13 09:44:35 -05:00
for ( uint8 i = 0 ; i < 8 ; ++ i )
2008-10-02 16:23:55 -05:00
{
if ( guid & 0xFF )
{
2009-06-13 09:44:35 -05:00
_storage [ mask_position ] |= uint8 ( 1 << i );
2008-10-02 16:23:55 -05:00
* this << uint8 ( guid & 0xFF );
}
guid >>= 8 ;
}
}
void put ( size_t pos , const uint8 * src , size_t cnt )
{
2009-08-19 16:26:22 -05:00
if ( pos + cnt > size ())
throw ByteBufferException ( true , pos , cnt , size ());
2008-10-02 16:23:55 -05:00
memcpy ( & _storage [ pos ], src , cnt );
}
2009-06-13 09:44:35 -05:00
2008-10-20 12:23:56 -05:00
void print_storage () const
2008-10-02 16:23:55 -05:00
{
if ( ! sLog . IsOutDebug ()) // optimize disabled debug output
return ;
2009-03-24 17:38:14 -06:00
sLog . outDebug ( "STORAGE_SIZE: %lu" , ( unsigned long ) size () );
2009-06-13 09:44:35 -05:00
for ( uint32 i = 0 ; i < size (); ++ i )
2008-10-02 16:23:55 -05:00
sLog . outDebugInLine ( "%u - " , read < uint8 > ( i ) );
sLog . outDebug ( " " );
}
2008-10-20 12:23:56 -05:00
void textlike () const
2008-10-02 16:23:55 -05:00
{
if ( ! sLog . IsOutDebug ()) // optimize disabled debug output
return ;
2009-03-24 17:38:14 -06:00
sLog . outDebug ( "STORAGE_SIZE: %lu" , ( unsigned long ) size () );
2009-06-13 09:44:35 -05:00
for ( uint32 i = 0 ; i < size (); ++ i )
2008-10-02 16:23:55 -05:00
sLog . outDebugInLine ( "%c" , read < uint8 > ( i ) );
sLog . outDebug ( " " );
}
2008-10-20 12:23:56 -05:00
void hexlike () const
2008-10-02 16:23:55 -05:00
{
if ( ! sLog . IsOutDebug ()) // optimize disabled debug output
return ;
uint32 j = 1 , k = 1 ;
2009-03-24 17:38:14 -06:00
sLog . outDebug ( "STORAGE_SIZE: %lu" , ( unsigned long ) size () );
2008-10-02 16:23:55 -05:00
2009-06-13 09:44:35 -05:00
for ( uint32 i = 0 ; i < size (); ++ i )
2008-10-02 16:23:55 -05:00
{
2009-06-13 09:44:35 -05:00
if (( i == ( j * 8 )) && (( i != ( k * 16 ))))
2008-10-02 16:23:55 -05:00
{
2009-05-31 16:26:06 -05:00
if ( read < uint8 > ( i ) < 0x10 )
2008-10-02 16:23:55 -05:00
{
sLog . outDebugInLine ( "| 0%X " , read < uint8 > ( i ) );
}
else
{
sLog . outDebugInLine ( "| %X " , read < uint8 > ( i ) );
}
++ j ;
}
2009-06-13 09:44:35 -05:00
else if ( i == ( k * 16 ))
2008-10-02 16:23:55 -05:00
{
2009-05-31 16:26:06 -05:00
if ( read < uint8 > ( i ) < 0x10 )
2008-10-02 16:23:55 -05:00
{
sLog . outDebugInLine ( " \n " );
sLog . outDebugInLine ( "0%X " , read < uint8 > ( i ) );
}
else
{
sLog . outDebugInLine ( " \n " );
sLog . outDebugInLine ( "%X " , read < uint8 > ( i ) );
}
++ k ;
++ j ;
}
else
{
2009-05-31 16:26:06 -05:00
if ( read < uint8 > ( i ) < 0x10 )
2008-10-02 16:23:55 -05:00
{
sLog . outDebugInLine ( "0%X " , read < uint8 > ( i ) );
}
else
{
sLog . outDebugInLine ( "%X " , read < uint8 > ( i ) );
}
}
}
sLog . outDebugInLine ( " \n " );
}
protected :
size_t _rpos , _wpos ;
std :: vector < uint8 > _storage ;
};
template < typename T > ByteBuffer & operator << ( ByteBuffer & b , std :: vector < T > v )
{
b << ( uint32 ) v . size ();
2009-06-13 09:44:35 -05:00
for ( typename std :: vector < T >:: iterator i = v . begin (); i != v . end (); ++ i )
2008-10-02 16:23:55 -05:00
{
b << * i ;
}
return b ;
}
template < typename T > ByteBuffer & operator >> ( ByteBuffer & b , std :: vector < T > & v )
{
uint32 vsize ;
b >> vsize ;
v . clear ();
while ( vsize -- )
{
T t ;
b >> t ;
v . push_back ( t );
}
return b ;
}
template < typename T > ByteBuffer & operator << ( ByteBuffer & b , std :: list < T > v )
{
b << ( uint32 ) v . size ();
2009-06-13 09:44:35 -05:00
for ( typename std :: list < T >:: iterator i = v . begin (); i != v . end (); ++ i )
2008-10-02 16:23:55 -05:00
{
b << * i ;
}
return b ;
}
template < typename T > ByteBuffer & operator >> ( ByteBuffer & b , std :: list < T > & v )
{
uint32 vsize ;
b >> vsize ;
v . clear ();
while ( vsize -- )
{
T t ;
b >> t ;
v . push_back ( t );
}
return b ;
}
template < typename K , typename V > ByteBuffer & operator << ( ByteBuffer & b , std :: map < K , V > & m )
{
b << ( uint32 ) m . size ();
2009-06-13 09:44:35 -05:00
for ( typename std :: map < K , V >:: iterator i = m . begin (); i != m . end (); ++ i )
2008-10-02 16:23:55 -05:00
{
b << i -> first << i -> second ;
}
return b ;
}
template < typename K , typename V > ByteBuffer & operator >> ( ByteBuffer & b , std :: map < K , V > & m )
{
uint32 msize ;
b >> msize ;
m . clear ();
while ( msize -- )
{
K k ;
V v ;
b >> k >> v ;
m . insert ( make_pair ( k , v ));
}
return b ;
}
2009-03-19 17:13:56 +01:00
// TODO: Make a ByteBuffer.cpp and move all this inlining to it.
template <> inline std :: string ByteBuffer :: read < std :: string > ()
{
std :: string tmp ;
* this >> tmp ;
return tmp ;
}
2008-10-02 16:23:55 -05:00
#endif
2009-02-17 20:07:49 -06:00