2016-09-10 02:28:11 +02:00
/*
* BinaryDeserializer . h , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
# pragma once
2023-11-08 22:05:36 +02:00
# include "CSerializer.h"
2024-08-24 00:32:02 +02:00
# include "SerializerReflection.h"
2024-01-20 23:26:04 +02:00
# include "ESerializationVersion.h"
2016-09-10 02:28:11 +02:00
# include "../mapObjects/CGHeroInstance.h"
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_BEGIN
2016-09-10 02:28:11 +02:00
class DLL_LINKAGE CLoaderBase
{
protected :
IBinaryReader * reader ;
public :
CLoaderBase ( IBinaryReader * r ) : reader ( r ) { } ;
2024-03-28 04:03:44 +02:00
inline void read ( void * data , unsigned size , bool reverseEndianness )
2016-09-10 02:28:11 +02:00
{
2024-02-02 02:36:57 +02:00
auto bytePtr = reinterpret_cast < std : : byte * > ( data ) ;
reader - > read ( bytePtr , size ) ;
2024-03-28 04:03:44 +02:00
if ( reverseEndianness )
2024-02-02 02:36:57 +02:00
std : : reverse ( bytePtr , bytePtr + size ) ;
2016-09-10 02:28:11 +02:00
} ;
} ;
/// Main class for deserialization of classes from binary form
/// Effectively revesed version of BinarySerializer
2024-05-17 15:09:45 +02:00
class BinaryDeserializer : public CLoaderBase
2016-09-10 02:28:11 +02:00
{
2024-07-20 20:29:41 +02:00
template < typename Fake , typename T >
static bool loadIfStackInstance ( T & data )
2016-09-10 02:28:11 +02:00
{
2024-07-20 20:29:41 +02:00
return false ;
}
template < typename Fake >
bool loadIfStackInstance ( const CStackInstance * & data )
{
CArmedInstance * armyPtr = nullptr ;
ObjectInstanceID armyID ;
SlotID slot ;
load ( armyID ) ;
load ( slot ) ;
if ( armyID = = ObjectInstanceID : : NONE )
2016-09-10 02:28:11 +02:00
return false ;
2024-07-20 20:29:41 +02:00
if ( reader - > smartVectorMembersSerialization )
{
if ( const auto * info = reader - > getVectorizedTypeInfo < CArmedInstance , ObjectInstanceID > ( ) )
2024-08-12 20:26:30 +02:00
armyPtr = reader - > getVectorItemFromId < CArmedInstance , ObjectInstanceID > ( * info , armyID ) ;
2016-09-10 02:28:11 +02:00
}
2024-07-20 20:29:41 +02:00
if ( slot ! = SlotID : : COMMANDER_SLOT_PLACEHOLDER )
2016-09-10 02:28:11 +02:00
{
2024-07-20 20:29:41 +02:00
assert ( armyPtr - > hasStackAtSlot ( slot ) ) ;
data = armyPtr - > stacks [ slot ] ;
2016-09-10 02:28:11 +02:00
}
2024-07-20 20:29:41 +02:00
else
{
auto * hero = dynamic_cast < CGHeroInstance * > ( armyPtr ) ;
assert ( hero ) ;
assert ( hero - > commander ) ;
data = hero - > commander ;
}
return true ;
}
2016-09-10 02:28:11 +02:00
2024-05-17 18:36:07 +02:00
STRONG_INLINE uint32_t readAndCheckLength ( )
2018-01-29 17:54:41 +02:00
{
2024-05-17 18:36:07 +02:00
uint32_t length ;
2018-01-29 17:54:41 +02:00
load ( length ) ;
2023-04-11 16:46:08 +02:00
//NOTE: also used for h3m's embedded in campaigns, so it may be quite large in some cases (e.g. XXL maps with multiple objects)
if ( length > 1000000 )
2018-01-29 17:54:41 +02:00
{
logGlobal - > warn ( " Warning: very big length: %d " , length ) ;
reader - > reportState ( logGlobal ) ;
} ;
return length ;
}
2016-09-10 02:28:11 +02:00
int write ( const void * data , unsigned size ) ;
public :
2024-01-20 20:34:51 +02:00
using Version = ESerializationVersion ;
2024-03-28 04:03:44 +02:00
bool reverseEndianness ; //if source has different endianness than us, we reverse bytes
2024-01-20 20:34:51 +02:00
Version version ;
2016-09-10 02:28:11 +02:00
2024-05-07 16:50:21 +02:00
std : : vector < std : : string > loadedStrings ;
2024-05-17 18:36:07 +02:00
std : : map < uint32_t , Serializeable * > loadedPointers ;
2024-05-07 21:17:05 +02:00
std : : map < const Serializeable * , std : : shared_ptr < Serializeable > > loadedSharedPointers ;
2024-01-10 19:43:34 +02:00
IGameCallback * cb = nullptr ;
2024-07-27 18:51:23 +02:00
static constexpr bool trackSerializedPointers = true ;
static constexpr bool saving = false ;
bool loadingGamestate = false ;
2016-09-10 02:28:11 +02:00
2024-05-17 18:36:07 +02:00
bool hasFeature ( Version what ) const
2024-05-07 16:48:40 +02:00
{
return version > = what ;
} ;
2024-05-17 15:09:45 +02:00
DLL_LINKAGE BinaryDeserializer ( IBinaryReader * r ) ;
2016-09-10 02:28:11 +02:00
template < class T >
BinaryDeserializer & operator & ( T & t )
{
this - > load ( t ) ;
return * this ;
}
2024-05-16 20:53:49 +02:00
int64_t loadEncodedInteger ( )
2024-05-07 17:39:43 +02:00
{
2024-05-16 20:53:49 +02:00
uint64_t valueUnsigned = 0 ;
2024-05-07 17:39:43 +02:00
uint_fast8_t offset = 0 ;
for ( ; ; )
{
uint8_t byteValue ;
load ( byteValue ) ;
if ( ( byteValue & 0x80 ) ! = 0 )
{
2024-11-29 18:55:30 +02:00
valueUnsigned | = static_cast < uint64_t > ( byteValue & 0x7f ) < < offset ;
2024-05-07 17:39:43 +02:00
offset + = 7 ;
}
else
{
2024-11-29 18:55:30 +02:00
valueUnsigned | = static_cast < uint64_t > ( byteValue & 0x3f ) < < offset ;
2024-05-16 20:53:49 +02:00
bool isNegative = ( byteValue & 0x40 ) ! = 0 ;
if ( isNegative )
return - static_cast < int64_t > ( valueUnsigned ) ;
2024-05-07 17:39:43 +02:00
else
2024-05-16 20:53:49 +02:00
return valueUnsigned ;
2024-05-07 17:39:43 +02:00
}
}
}
template < class T , typename std : : enable_if_t < std : : is_floating_point_v < T > , int > = 0 >
2016-09-10 02:28:11 +02:00
void load ( T & data )
{
2024-03-28 04:03:44 +02:00
this - > read ( static_cast < void * > ( & data ) , sizeof ( data ) , reverseEndianness ) ;
2016-09-10 02:28:11 +02:00
}
2024-05-07 17:39:43 +02:00
template < class T , typename std : : enable_if_t < std : : is_integral_v < T > & & ! std : : is_same_v < T , bool > , int > = 0 >
void load ( T & data )
{
if constexpr ( sizeof ( T ) = = 1 )
{
this - > read ( static_cast < void * > ( & data ) , sizeof ( data ) , reverseEndianness ) ;
}
else
{
2024-05-16 20:53:49 +02:00
static_assert ( ! std : : is_same_v < uint64_t , T > , " Serialization of unsigned 64-bit value may not work in some cases " ) ;
2024-05-07 17:39:43 +02:00
if ( hasFeature ( Version : : COMPACT_INTEGER_SERIALIZATION ) )
2024-05-16 20:53:49 +02:00
data = loadEncodedInteger ( ) ;
2024-05-07 17:39:43 +02:00
else
this - > read ( static_cast < void * > ( & data ) , sizeof ( data ) , reverseEndianness ) ;
}
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < is_serializeable < BinaryDeserializer , T > : : value , int > = 0 >
2016-09-10 02:28:11 +02:00
void load ( T & data )
{
////that const cast is evil because it allows to implicitly overwrite const objects when deserializing
2024-03-02 13:48:17 +02:00
typedef typename std : : remove_const_t < T > nonConstT ;
2023-04-17 23:11:16 +02:00
auto & hlp = const_cast < nonConstT & > ( data ) ;
2024-01-20 20:34:51 +02:00
hlp . serialize ( * this ) ;
2016-09-10 02:28:11 +02:00
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < std : : is_array_v < T > , int > = 0 >
2016-09-10 02:28:11 +02:00
void load ( T & data )
{
2024-05-17 18:36:07 +02:00
uint32_t size = std : : size ( data ) ;
for ( uint32_t i = 0 ; i < size ; i + + )
2016-09-10 02:28:11 +02:00
load ( data [ i ] ) ;
}
2024-05-07 17:39:43 +02:00
void load ( Version & data )
{
this - > read ( static_cast < void * > ( & data ) , sizeof ( data ) , reverseEndianness ) ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < std : : is_enum_v < T > , int > = 0 >
2016-09-10 02:28:11 +02:00
void load ( T & data )
{
2024-05-17 18:36:07 +02:00
int32_t read ;
2016-09-10 02:28:11 +02:00
load ( read ) ;
data = static_cast < T > ( read ) ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < std : : is_same_v < T , bool > , int > = 0 >
2016-09-10 02:28:11 +02:00
void load ( T & data )
{
2024-05-17 18:36:07 +02:00
uint8_t read ;
2016-09-10 02:28:11 +02:00
load ( read ) ;
data = static_cast < bool > ( read ) ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < ! std : : is_same_v < T , bool > , int > = 0 >
2016-10-30 11:42:53 +02:00
void load ( std : : vector < T > & data )
2016-09-10 02:28:11 +02:00
{
2024-05-17 18:36:07 +02:00
uint32_t length = readAndCheckLength ( ) ;
2016-09-10 02:28:11 +02:00
data . resize ( length ) ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2016-09-10 02:28:11 +02:00
load ( data [ i ] ) ;
}
2024-03-05 17:59:56 +02:00
template < typename T , typename std : : enable_if_t < ! std : : is_same_v < T , bool > , int > = 0 >
void load ( std : : deque < T > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = readAndCheckLength ( ) ;
2024-03-05 17:59:56 +02:00
data . resize ( length ) ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2024-03-05 17:59:56 +02:00
load ( data [ i ] ) ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < std : : is_pointer_v < T > , int > = 0 >
2016-09-10 02:28:11 +02:00
void load ( T & data )
{
2023-11-07 17:29:57 +02:00
bool isNull ;
load ( isNull ) ;
if ( isNull )
2016-09-10 02:28:11 +02:00
{
data = nullptr ;
return ;
}
if ( reader - > smartVectorMembersSerialization )
{
2024-03-02 13:48:17 +02:00
typedef typename std : : remove_const_t < typename std : : remove_pointer_t < T > > TObjectType ; //eg: const CGHeroInstance * => CGHeroInstance
2016-09-10 02:28:11 +02:00
typedef typename VectorizedTypeFor < TObjectType > : : type VType ; //eg: CGHeroInstance -> CGobjectInstance
typedef typename VectorizedIDType < TObjectType > : : type IDType ;
if ( const auto * info = reader - > getVectorizedTypeInfo < VType , IDType > ( ) )
{
IDType id ;
load ( id ) ;
if ( id ! = IDType ( - 1 ) )
{
data = static_cast < T > ( reader - > getVectorItemFromId < VType , IDType > ( * info , id ) ) ;
return ;
}
}
}
if ( reader - > sendStackInstanceByIds )
{
2024-07-20 20:29:41 +02:00
bool gotLoaded = loadIfStackInstance < void > ( data ) ;
2016-09-10 02:28:11 +02:00
if ( gotLoaded )
return ;
}
2024-05-17 18:36:07 +02:00
uint32_t pid = 0xffffffff ; //pointer id (or maybe rather pointee id)
2024-07-27 18:51:23 +02:00
if ( trackSerializedPointers )
2016-09-10 02:28:11 +02:00
{
load ( pid ) ; //get the id
2023-04-17 23:11:16 +02:00
auto i = loadedPointers . find ( pid ) ; //lookup
2016-09-10 02:28:11 +02:00
if ( i ! = loadedPointers . end ( ) )
{
// We already got this pointer
// Cast it in case we are loading it to a non-first base pointer
2024-05-07 21:17:05 +02:00
data = dynamic_cast < T > ( i - > second ) ;
2016-09-10 02:28:11 +02:00
return ;
}
}
//get type id
2024-05-17 18:36:07 +02:00
uint16_t tid ;
2016-09-10 02:28:11 +02:00
load ( tid ) ;
2024-08-24 00:32:02 +02:00
typedef typename std : : remove_pointer_t < T > npT ;
typedef typename std : : remove_const_t < npT > ncpT ;
2016-09-10 02:28:11 +02:00
if ( ! tid )
{
2024-01-10 19:43:34 +02:00
data = ClassObjectCreator < ncpT > : : invoke ( cb ) ;
2016-09-10 02:28:11 +02:00
ptrAllocated ( data , pid ) ;
load ( * data ) ;
}
else
{
2024-08-24 00:32:02 +02:00
auto * app = CSerializationApplier : : getInstance ( ) . getApplier ( tid ) ;
2016-10-27 17:39:17 +02:00
if ( app = = nullptr )
{
logGlobal - > error ( " load %d %d - no loader exists " , tid , pid ) ;
data = nullptr ;
return ;
}
2024-08-24 00:32:02 +02:00
auto dataNonConst = dynamic_cast < ncpT * > ( app - > createPtr ( * this , cb ) ) ;
data = dataNonConst ;
ptrAllocated ( data , pid ) ;
app - > loadPtr ( * this , cb , dataNonConst ) ;
2016-09-10 02:28:11 +02:00
}
}
template < typename T >
2024-05-17 18:36:07 +02:00
void ptrAllocated ( T * ptr , uint32_t pid )
2016-09-10 02:28:11 +02:00
{
2024-07-27 18:51:23 +02:00
if ( trackSerializedPointers & & pid ! = 0xffffffff )
2024-05-07 21:17:05 +02:00
loadedPointers [ pid ] = const_cast < Serializeable * > ( dynamic_cast < const Serializeable * > ( ptr ) ) ; //add loaded pointer to our lookup map; cast is to avoid errors with const T* pt
2016-09-10 02:28:11 +02:00
}
template < typename T >
void load ( std : : shared_ptr < T > & data )
{
2024-03-02 13:48:17 +02:00
typedef typename std : : remove_const_t < T > NonConstT ;
2016-09-10 02:28:11 +02:00
NonConstT * internalPtr ;
load ( internalPtr ) ;
2024-05-17 18:36:07 +02:00
const auto * internalPtrDerived = static_cast < Serializeable * > ( internalPtr ) ;
2016-09-10 02:28:11 +02:00
if ( internalPtr )
{
auto itr = loadedSharedPointers . find ( internalPtrDerived ) ;
if ( itr ! = loadedSharedPointers . end ( ) )
{
// This pointers is already loaded. The "data" needs to be pointed to it,
// so their shared state is actually shared.
2023-11-08 22:05:36 +02:00
data = std : : static_pointer_cast < T > ( itr - > second ) ;
2016-09-10 02:28:11 +02:00
}
else
{
auto hlp = std : : shared_ptr < NonConstT > ( internalPtr ) ;
2022-09-11 15:12:35 +02:00
data = hlp ;
2024-05-07 21:17:05 +02:00
loadedSharedPointers [ internalPtrDerived ] = std : : static_pointer_cast < Serializeable > ( hlp ) ;
2022-09-11 15:12:35 +02:00
}
}
else
data . reset ( ) ;
}
2022-09-29 19:07:56 +02:00
2023-10-21 18:48:07 +02:00
void load ( std : : monostate & data )
{
// no-op
}
2022-09-11 15:12:35 +02:00
template < typename T >
2022-09-29 19:07:56 +02:00
void load ( std : : shared_ptr < const T > & data )
2022-09-11 15:12:35 +02:00
{
2022-09-29 19:07:56 +02:00
std : : shared_ptr < T > nonConstData ;
2022-09-11 15:12:35 +02:00
2022-09-29 19:07:56 +02:00
load ( nonConstData ) ;
2022-09-11 15:12:35 +02:00
2022-09-29 19:07:56 +02:00
data = nonConstData ;
2016-09-10 02:28:11 +02:00
}
2022-09-29 19:07:56 +02:00
2016-09-10 02:28:11 +02:00
template < typename T >
void load ( std : : unique_ptr < T > & data )
{
T * internalPtr ;
load ( internalPtr ) ;
data . reset ( internalPtr ) ;
}
template < typename T , size_t N >
void load ( std : : array < T , N > & data )
{
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < N ; i + + )
2016-09-10 02:28:11 +02:00
load ( data [ i ] ) ;
}
template < typename T >
void load ( std : : set < T > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = readAndCheckLength ( ) ;
2016-09-10 02:28:11 +02:00
data . clear ( ) ;
T ins ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2016-09-10 02:28:11 +02:00
{
load ( ins ) ;
data . insert ( ins ) ;
}
}
template < typename T , typename U >
void load ( std : : unordered_set < T , U > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = readAndCheckLength ( ) ;
2016-09-10 02:28:11 +02:00
data . clear ( ) ;
T ins ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2016-09-10 02:28:11 +02:00
{
load ( ins ) ;
data . insert ( ins ) ;
}
}
template < typename T >
void load ( std : : list < T > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = readAndCheckLength ( ) ;
2016-09-10 02:28:11 +02:00
data . clear ( ) ;
T ins ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2016-09-10 02:28:11 +02:00
{
load ( ins ) ;
data . push_back ( ins ) ;
}
}
template < typename T1 , typename T2 >
void load ( std : : pair < T1 , T2 > & data )
{
load ( data . first ) ;
load ( data . second ) ;
}
2024-05-16 21:03:04 +02:00
template < typename T1 , typename T2 >
void load ( std : : unordered_map < T1 , T2 > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = readAndCheckLength ( ) ;
2024-05-16 21:03:04 +02:00
data . clear ( ) ;
T1 key ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2024-05-16 21:03:04 +02:00
{
load ( key ) ;
load ( data [ key ] ) ;
}
}
2016-09-10 02:28:11 +02:00
template < typename T1 , typename T2 >
void load ( std : : map < T1 , T2 > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = readAndCheckLength ( ) ;
2016-09-10 02:28:11 +02:00
data . clear ( ) ;
T1 key ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2016-09-10 02:28:11 +02:00
{
load ( key ) ;
2024-01-01 00:44:09 +02:00
load ( data [ key ] ) ;
2016-09-10 02:28:11 +02:00
}
}
void load ( std : : string & data )
{
2024-05-07 16:50:21 +02:00
if ( hasFeature ( Version : : COMPACT_STRING_SERIALIZATION ) )
{
int32_t length ;
load ( length ) ;
if ( length < 0 )
{
int32_t stringID = - length - 1 ; // -1, -2 ... -> 0, 1 ...
data = loadedStrings [ stringID ] ;
}
if ( length = = 0 )
{
data = { } ;
}
if ( length > 0 )
{
data . resize ( length ) ;
this - > read ( static_cast < void * > ( data . data ( ) ) , length , false ) ;
loadedStrings . push_back ( data ) ;
}
}
else
{
2024-05-17 18:36:07 +02:00
uint32_t length = readAndCheckLength ( ) ;
2024-05-07 16:50:21 +02:00
data . resize ( length ) ;
this - > read ( static_cast < void * > ( data . data ( ) ) , length , false ) ;
}
2016-09-10 02:28:11 +02:00
}
2023-11-04 16:21:54 +02:00
template < typename . . . TN >
void load ( std : : variant < TN . . . > & data )
2016-09-10 02:28:11 +02:00
{
2024-05-17 18:36:07 +02:00
int32_t which ;
2016-09-10 02:28:11 +02:00
load ( which ) ;
2023-11-04 16:21:54 +02:00
assert ( which < sizeof . . . ( TN ) ) ;
// Create array of variants that contains all default-constructed alternatives
const std : : variant < TN . . . > table [ ] = { TN { } . . . } ;
// use appropriate alternative for result
data = table [ which ] ;
// perform actual load via std::visit dispatch
2023-11-04 19:25:50 +02:00
std : : visit ( [ & ] ( auto & o ) { load ( o ) ; } , data ) ;
2016-09-10 02:28:11 +02:00
}
2023-04-16 19:42:56 +02:00
template < typename T >
void load ( std : : optional < T > & data )
2016-09-10 02:28:11 +02:00
{
2024-05-17 18:36:07 +02:00
uint8_t present ;
2016-09-10 02:28:11 +02:00
load ( present ) ;
if ( present )
{
2017-08-05 15:09:29 +02:00
//TODO: replace with emplace once we start request Boost 1.56+, see PR360
2016-09-10 02:28:11 +02:00
T t ;
load ( t ) ;
2023-04-16 19:42:56 +02:00
data = std : : make_optional ( std : : move ( t ) ) ;
2016-09-10 02:28:11 +02:00
}
else
{
2023-04-16 19:42:56 +02:00
data = std : : optional < T > ( ) ;
2016-09-10 02:28:11 +02:00
}
}
2022-09-18 16:39:10 +02:00
template < typename T >
void load ( boost : : multi_array < T , 3 > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = readAndCheckLength ( ) ;
uint32_t x ;
uint32_t y ;
uint32_t z ;
2022-09-18 16:39:10 +02:00
load ( x ) ;
load ( y ) ;
load ( z ) ;
data . resize ( boost : : extents [ x ] [ y ] [ z ] ) ;
assert ( length = = data . num_elements ( ) ) ; //x*y*z should be equal to number of elements
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2022-09-18 16:39:10 +02:00
load ( data . data ( ) [ i ] ) ;
}
2023-05-05 11:56:11 +02:00
template < std : : size_t T >
void load ( std : : bitset < T > & data )
{
static_assert ( T < = 64 ) ;
if constexpr ( T < = 16 )
{
uint16_t read ;
load ( read ) ;
data = read ;
}
else if constexpr ( T < = 32 )
{
uint32_t read ;
load ( read ) ;
data = read ;
}
else if constexpr ( T < = 64 )
{
uint64_t read ;
load ( read ) ;
data = read ;
}
}
2016-09-10 02:28:11 +02:00
} ;
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_END