/* $Id: serialize.hpp,v 1.19.4.1 2006/01/20 11:33:53 chfreund Exp $ */ #ifndef _SERIALIZE_HPP_ #define _SERIALIZE_HPP_ #include "global.hpp" #include #include /**********************************************************/ #if DBG_LEVEL >= 2 #define USE_DE_SERIALIZATION_TAGS #include #endif #ifdef USE_DE_SERIALIZATION_TAGS #ifndef DE_SERIALIZE_TAG //! string, that is used to set a tag in the serialization #define DE_SERIALIZE_TAG "wop_tag" #endif //! size of the serialization tag (must add it in the serialized size) #define TAG_SIZE \ sizeof(DE_SERIALIZE_TAG) //! macro to add the size of the (de)serialization tag #define PLUS_TAG_SIZE( FACTOR ) \ + (FACTOR * TAG_SIZE) #define ADD_TAG_SIZE( VARIABLE ) \ VARIABLE += TAG_SIZE; #define ADD_MULTI_TAG_SIZE( VARIABLE, FACTOR ) \ VARIABLE += (FACTOR * TAG_SIZE); //! sets a tag in the serialization buffer (don't forget to adapt the buffer size!) #define SERIALIZE_TAG(buffer) { \ Serialize::serialize( sizeof( DE_SERIALIZE_TAG ), \ DE_SERIALIZE_TAG, buffer ); \ } //! reads a tag from the serialization buffer and aborts, if tag is not valid #define DESERIALIZE_TAG(buffer) { \ char testTag[sizeof( DE_SERIALIZE_TAG )]; \ Serialize::deserialize( TAG_SIZE, buffer, testTag ); \ testTag[sizeof( DE_SERIALIZE_TAG )-1] = 0; \ ASSERT( ! strncmp( DE_SERIALIZE_TAG, testTag, TAG_SIZE ), \ "bad tag deserialized in %s, " \ "line %d\n read \"%s\", should be \"%s\"\n", \ __FILE__, __LINE__, (const char*)testTag, DE_SERIALIZE_TAG );\ } //! macros for checking the match of getSerializeBufferSize #define START_SERIALIZED_SIZE_CHECK( BUFFER ) \ const Uint8*serializedSizeCheckStartBuffer = BUFFER; #define END_SERIALIZED_SIZE_CHECK( BUFFER, CLASS ) \ ASSERT( (Uint32)(BUFFER - serializedSizeCheckStartBuffer) \ == CLASS::getSerializeBufferSize(), \ "getSerializeBufferSize() == %d, but the pointer " \ " moved %d bytes\n %s, line %d\n", \ CLASS::getSerializeBufferSize(), \ BUFFER - serializedSizeCheckStartBuffer, \ __FILE__, __LINE__ ); #else // USE_DE_SERIALIZATION_TAGS // define empty macros, if we do not need them #define DE_SERIALIZE_TAG #define TAG_SIZE #define SERIALIZE_TAG( buffer ) #define DESERIALIZE_TAG( buffer ) #define PLUS_TAG_SIZE( FACTOR ) #define ADD_TAG_SIZE( VARIABLE ) #define ADD_MULTI_TAG_SIZE #define START_SERIALIZED_SIZE_CHECK( BUFFER ) #define END_SERIALIZED_SIZE_CHECK( BUFFER, CLASS ) #endif // USE_DE_SERIALIZATION_TAGS /**********************************************************/ /*! A class with generic serialization / deserialization functions * for simple types which takes the endianess of the system into account. * Note that the buffer pointers passed to the functions points to the * next buffer element to be written out / read in after the completion * of the function. */ template class Serialize { public: /*! This method returns the size in bytes of a data item * Per default this is just the size of the data in the system. * This function has to be overloaded for types where the size * of a serialized item differs from the size of the data in * memory */ static Uint32 sizeOf( T item ) { return sizeof( T ); } static Uint32 sizeOf() { return sizeof( T ); } /*! This method serializes one data value stored in item into the * memory starting at buffer */ static void serialize( const T& item, Uint8*& buffer ) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN const Uint8 *dataPointer = reinterpret_cast( &item ); for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *buffer++ = *dataPointer++; } #else const Uint8 *dataPointer = reinterpret_cast( &item ) + sizeof( T ) - 1; for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *buffer++ = *dataPointer--; } #endif } /* *! This method serializes one data value stored in item into the * memory starting at buffer * static void serialize( const volatile T& item, Uint8*& buffer ) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN const volatile Uint8 *dataPointer = reinterpret_cast( &item ); for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *buffer++ = *dataPointer++; } #else const volatile Uint8 *dataPointer = reinterpret_cast( &item ) + sizeof( T ) - 1; for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *buffer++ = *dataPointer--; } #endif } */ /*! This method serializes numberItems data values stored consecutively * in the array item into the memory starting at buffer */ static void serialize( int numberItems, const T* item, Uint8*& buffer ) { for (int n = 0; n < numberItems; n++) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN const Uint8 *dataPointer = reinterpret_cast( item + n ); for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *buffer++ = *dataPointer++; } #else const Uint8 *dataPointer = reinterpret_cast( item + n ) + sizeof( T ) - 1; for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *buffer++ = *dataPointer--; } #endif } } /*! This method deserializes one data value to be stored in item from the * memory starting at buffer */ static void deserialize( Uint8*& buffer, T& item ) { LOG( 5 ) INFO( "Serialize::deserialize: deserializing item with size %3i\n", sizeof( T )); #if SDL_BYTEORDER == SDL_BIG_ENDIAN Uint8 *dataPointer = reinterpret_cast( &item ); for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *dataPointer++ = *buffer++; } #else Uint8 *dataPointer = reinterpret_cast( &item ) + sizeof( T ) - 1; for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *dataPointer-- = *buffer++; } #endif } /* *! This method deserializes one data value to be stored in item from the * memory starting at buffer * static void deserialize( Uint8*& buffer, volatile T& item ) { LOG( 5 ) INFO( "Serialize::deserialize: deserializing item with size %3i\n", sizeof( T )); #if SDL_BYTEORDER == SDL_BIG_ENDIAN volatile Uint8 *dataPointer = reinterpret_cast( &item ); for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *dataPointer++ = *buffer++; } #else volatile Uint8 *dataPointer = reinterpret_cast( &item ) + sizeof( T ) - 1; for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *dataPointer-- = *buffer++; } #endif } */ /* This method deserializes numberItems data values to be stored consecutively * in the array item from the memory starting at buffer */ static void deserialize( int numberItems, Uint8*& buffer, T* item ) { LOG( 5 ) INFO( "Serialize::deserialize: deserializing %2i items with size %3i\n", numberItems, sizeof( T )); for ( int n = 0; n < numberItems; n++) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN Uint8 *dataPointer = reinterpret_cast( item + n ); for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *dataPointer++ = *buffer++; } #else Uint8 *dataPointer = reinterpret_cast( item + n ) + sizeof( T ) - 1; for ( Uint32 i = 0; i < sizeof( T ); i++ ) { *dataPointer-- = *buffer++; } #endif } } }; /*! Specialization of the class for bools, as sizeof( bool ) equals to 1 on * x86-architectures but equals to 4 on PowerPCs. * We choose to represent a serialized bool as an Uint8. */ template <> class Serialize { public: static Uint32 sizeOf( bool item ) { return sizeof( Uint8 ); } static Uint32 sizeOf() { return sizeof( Uint8 ); } /*! This method serializes one data value stored in item into the * memory starting at buffer */ static void serialize( bool item, Uint8*& buffer ) { Uint8 value; value = (item ? 1 : 0); Serialize::serialize( value, buffer ); } /*! This method serializes numberItems data values stored consecutively * in the array item into the memory starting at buffer */ static void serialize( int numberItems, bool* item, Uint8*& buffer ) { Uint8 value; for (int i = 0; i < numberItems; i++) { value = (item[i] ? 1 : 0); Serialize::serialize( value, buffer ); } } /*! This method deserializes one data value to be stored in item from the * memory starting at buffer */ static void deserialize( Uint8*& buffer, bool& item ) { Uint8 value; LOG( 5 ) INFO( "Serialize::deserialize: deserializing bool\n" ); Serialize::deserialize( buffer, value ); item = (value == 1); } /* This method deserializes numberItems data values to be stored consecutively * in the array item from the memory starting at buffer */ static void deserialize( int numberItems, Uint8*& buffer, bool* item ) { Uint8 value; LOG( 5 ) INFO( "Serialize::deserialize: deserializing %2i bools\n", numberItems ); for ( int i = 0; i < numberItems; i++) { Serialize::deserialize( buffer, value ); item[i] = (value == 1); } } }; #endif // _SERIALIZE_HPP_