2020-02-22 17:41:24 +00:00
# ifndef __SERIALIZER_H
# define __SERIALIZER_H
# include <stdint.h>
# include <type_traits>
# include "tarray.h"
2020-04-11 21:54:33 +00:00
# include "file_zip.h"
2020-02-22 17:41:24 +00:00
# include "tflags.h"
# include "vectors.h"
# include "palentry.h"
2020-04-11 21:54:33 +00:00
# include "name.h"
2020-04-07 16:04:35 +00:00
# include "dictionary.h"
2020-02-22 17:41:24 +00:00
extern bool save_full ;
struct FWriter ;
struct FReader ;
2020-04-06 19:10:07 +00:00
class PClass ;
2020-02-22 17:41:24 +00:00
class FFont ;
class FSoundID ;
2020-04-12 06:21:50 +00:00
union FRenderStyle ;
2020-04-06 19:10:07 +00:00
class DObject ;
class FTextureID ;
2020-02-22 17:41:24 +00:00
inline bool nullcmp ( const void * buffer , size_t length )
{
const char * p = ( const char * ) buffer ;
for ( ; length > 0 ; length - - )
{
if ( * p + + ! = 0 ) return false ;
}
return true ;
}
struct NumericValue
{
enum EType
{
NM_invalid ,
NM_signed ,
NM_unsigned ,
NM_float
} type ;
union
{
int64_t signedval ;
uint64_t unsignedval ;
double floatval ;
} ;
bool operator ! = ( const NumericValue & other )
{
return type ! = other . type | | signedval ! = other . signedval ;
}
} ;
class FSerializer
{
public :
FWriter * w = nullptr ;
FReader * r = nullptr ;
2020-04-07 16:04:35 +00:00
bool soundNamesAreUnique = false ; // While in GZDoom, sound names are unique, that isn't universally true - let the serializer handle both cases with a flag.
2020-02-22 17:41:24 +00:00
unsigned ArraySize ( ) ;
void WriteKey ( const char * key ) ;
void WriteObjects ( ) ;
2020-04-07 16:04:35 +00:00
private :
virtual void CloseReaderCustom ( ) { }
2020-02-22 17:41:24 +00:00
public :
~ FSerializer ( )
{
mErrors = 0 ; // The destructor may not throw an exception so silence the error checker.
Close ( ) ;
}
2020-04-07 16:04:35 +00:00
void SetUniqueSoundNames ( ) { soundNamesAreUnique = true ; }
2020-02-22 17:41:24 +00:00
bool OpenWriter ( bool pretty = true ) ;
bool OpenReader ( const char * buffer , size_t length ) ;
bool OpenReader ( FCompressedBuffer * input ) ;
void Close ( ) ;
void ReadObjects ( bool hubtravel ) ;
bool BeginObject ( const char * name ) ;
void EndObject ( ) ;
2021-11-20 16:01:59 +00:00
bool HasObject ( const char * name ) ;
2020-02-22 17:41:24 +00:00
bool BeginArray ( const char * name ) ;
void EndArray ( ) ;
unsigned GetSize ( const char * group ) ;
const char * GetKey ( ) ;
const char * GetOutput ( unsigned * len = nullptr ) ;
FCompressedBuffer GetCompressedOutput ( ) ;
2020-04-07 16:04:35 +00:00
// The sprite serializer is a special case because it is needed by the VM to handle its 'spriteid' type.
virtual FSerializer & Sprite ( const char * key , int32_t & spritenum , int32_t * def ) ;
// This is only needed by the type system.
virtual FSerializer & StatePointer ( const char * key , void * ptraddr , bool * res ) ;
2020-09-06 11:39:57 +00:00
FSerializer & SerializeMemory ( const char * key , void * mem , size_t length ) ;
2020-04-07 16:04:35 +00:00
2020-02-22 17:41:24 +00:00
FSerializer & StringPtr ( const char * key , const char * & charptr ) ; // This only retrieves the address but creates no permanent copy of the string unlike the regular char* serializer.
FSerializer & AddString ( const char * key , const char * charptr ) ;
const char * GetString ( const char * key ) ;
FSerializer & ScriptNum ( const char * key , int & num ) ;
bool isReading ( ) const
{
return r ! = nullptr ;
}
bool isWriting ( ) const
{
return w ! = nullptr ;
}
2021-12-30 09:30:21 +00:00
2020-02-22 17:41:24 +00:00
bool canSkip ( ) const ;
template < class T >
FSerializer & operator ( ) ( const char * key , T & obj )
{
return Serialize ( * this , key , obj , ( T * ) nullptr ) ;
}
template < class T >
FSerializer & operator ( ) ( const char * key , T & obj , T & def )
{
return Serialize ( * this , key , obj , save_full ? nullptr : & def ) ;
}
2020-10-13 17:43:45 +00:00
template < class T >
FSerializer & operator ( ) ( const char * key , T & obj , T * def )
{
return Serialize ( * this , key , obj , ! def | | save_full ? nullptr : def ) ;
}
2020-02-22 17:41:24 +00:00
template < class T >
FSerializer & Array ( const char * key , T * obj , int count , bool fullcompare = false )
{
if ( ! save_full & & fullcompare & & isWriting ( ) & & nullcmp ( obj , count * sizeof ( T ) ) )
{
return * this ;
}
if ( BeginArray ( key ) )
{
if ( isReading ( ) )
{
int max = ArraySize ( ) ;
if ( max < count ) count = max ;
}
for ( int i = 0 ; i < count ; i + + )
{
Serialize ( * this , nullptr , obj [ i ] , ( T * ) nullptr ) ;
}
EndArray ( ) ;
}
return * this ;
}
template < class T >
FSerializer & Array ( const char * key , T * obj , T * def , int count , bool fullcompare = false )
{
if ( ! save_full & & fullcompare & & isWriting ( ) & & def ! = nullptr & & ! memcmp ( obj , def , count * sizeof ( T ) ) )
{
return * this ;
}
if ( BeginArray ( key ) )
{
if ( isReading ( ) )
{
int max = ArraySize ( ) ;
if ( max < count ) count = max ;
}
for ( int i = 0 ; i < count ; i + + )
{
Serialize ( * this , nullptr , obj [ i ] , def ? & def [ i ] : nullptr ) ;
}
EndArray ( ) ;
2020-10-13 17:43:45 +00:00
}
return * this ;
}
template < class T , class Map >
FSerializer & SparseArray ( const char * key , T * obj , int count , const Map & map , bool fullcompare = false )
{
if ( BeginArray ( key ) )
{
int max = count ;
if ( isReading ( ) )
{
max = ArraySize ( ) ;
}
for ( int i = 0 ; i < count ; i + + )
{
if ( map [ i ] )
{
Serialize ( * this , nullptr , obj [ i ] , ( T * ) nullptr ) ;
if ( - - max < 0 ) break ;
}
}
EndArray ( ) ;
2020-02-22 17:41:24 +00:00
}
return * this ;
}
template < class T >
FSerializer & Enum ( const char * key , T & obj )
{
auto val = ( typename std : : underlying_type < T > : : type ) obj ;
Serialize ( * this , key , val , nullptr ) ;
obj = ( T ) val ;
return * this ;
}
int mErrors = 0 ;
2020-09-27 08:03:53 +00:00
int mObjectErrors = 0 ;
2020-02-22 17:41:24 +00:00
} ;
2020-04-07 16:04:35 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , char & value , char * defval ) ;
2020-02-22 17:41:24 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , bool & value , bool * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , int64_t & value , int64_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , uint64_t & value , uint64_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , int32_t & value , int32_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , uint32_t & value , uint32_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , int8_t & value , int8_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , uint8_t & value , uint8_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , int16_t & value , int16_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , uint16_t & value , uint16_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , double & value , double * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , float & value , float * defval ) ;
2020-04-06 19:10:07 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , FTextureID & value , FTextureID * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , DObject * & value , DObject * * /*defval*/ , bool * retcode = nullptr ) ;
2020-02-22 17:41:24 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , FName & value , FName * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , FSoundID & sid , FSoundID * def ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , FString & sid , FString * def ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , NumericValue & sid , NumericValue * def ) ;
2021-11-26 12:00:33 +00:00
template < typename T /*, typename = std::enable_if_t<std::is_base_of_v<DObject, T>>*/ >
2020-02-22 17:41:24 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , T * & value , T * * )
{
DObject * v = static_cast < DObject * > ( value ) ;
Serialize ( arc , key , v , nullptr ) ;
value = static_cast < T * > ( v ) ;
return arc ;
}
template < class T , class TT >
FSerializer & Serialize ( FSerializer & arc , const char * key , TArray < T , TT > & value , TArray < T , TT > * def )
{
if ( arc . isWriting ( ) )
{
2020-06-29 21:36:06 +00:00
if ( value . Size ( ) = = 0 & & key ) return arc ; // do not save empty arrays
2020-02-22 17:41:24 +00:00
}
bool res = arc . BeginArray ( key ) ;
if ( arc . isReading ( ) )
{
if ( ! res )
{
value . Clear ( ) ;
return arc ;
}
value . Resize ( arc . ArraySize ( ) ) ;
}
for ( unsigned i = 0 ; i < value . Size ( ) ; i + + )
{
Serialize ( arc , nullptr , value [ i ] , def ? & ( * def ) [ i ] : nullptr ) ;
}
arc . EndArray ( ) ;
return arc ;
}
2021-04-02 09:55:23 +00:00
template < class T >
2021-04-02 08:28:18 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , TPointer < T > & value , TPointer < T > * def )
{
if ( arc . isWriting ( ) )
{
if ( value . Data ( ) = = nullptr & & key ) return arc ;
}
bool res = arc . BeginArray ( key ) ;
if ( arc . isReading ( ) )
{
if ( ! res | | arc . ArraySize ( ) = = 0 )
{
value . Clear ( ) ;
return arc ;
}
value . Alloc ( ) ;
}
if ( value . Data ( ) )
{
Serialize ( arc , nullptr , * value , def ? def - > Data ( ) : nullptr ) ;
}
arc . EndArray ( ) ;
return arc ;
}
2020-07-20 22:07:02 +00:00
template < int size >
FSerializer & Serialize ( FSerializer & arc , const char * key , FixedBitArray < size > & value , FixedBitArray < size > * def )
{
2020-09-27 08:03:53 +00:00
return arc . SerializeMemory ( key , value . Storage ( ) , value . StorageSize ( ) ) ;
2020-07-20 22:07:02 +00:00
}
2021-11-20 23:24:47 +00:00
inline FSerializer & Serialize ( FSerializer & arc , const char * key , BitArray & value , BitArray * def )
{
return arc . SerializeMemory ( key , value . Storage ( ) . Data ( ) , value . Storage ( ) . Size ( ) ) ;
}
2020-04-06 19:10:07 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , PClass * & clst , PClass * * def ) ;
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , FFont * & font , FFont * * def ) ;
2020-04-07 16:04:35 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , Dictionary * & dict , Dictionary * * def ) ;
2020-02-22 17:41:24 +00:00
inline FSerializer & Serialize ( FSerializer & arc , const char * key , DVector3 & p , DVector3 * def )
{
return arc . Array < double > ( key , & p [ 0 ] , def ? & ( * def ) [ 0 ] : nullptr , 3 , true ) ;
}
inline FSerializer & Serialize ( FSerializer & arc , const char * key , DRotator & p , DRotator * def )
{
return arc . Array < DAngle > ( key , & p [ 0 ] , def ? & ( * def ) [ 0 ] : nullptr , 3 , true ) ;
}
inline FSerializer & Serialize ( FSerializer & arc , const char * key , DVector2 & p , DVector2 * def )
{
return arc . Array < double > ( key , & p [ 0 ] , def ? & ( * def ) [ 0 ] : nullptr , 2 , true ) ;
}
2020-10-03 15:04:45 +00:00
template < class T >
inline FSerializer & Serialize ( FSerializer & arc , const char * key , TAngle < T > & p , TAngle < T > * def )
2020-02-22 17:41:24 +00:00
{
return Serialize ( arc , key , p . Degrees , def ? & def - > Degrees : nullptr ) ;
}
inline FSerializer & Serialize ( FSerializer & arc , const char * key , PalEntry & pe , PalEntry * def )
{
return Serialize ( arc , key , pe . d , def ? & def - > d : nullptr ) ;
}
FSerializer & Serialize ( FSerializer & arc , const char * key , FRenderStyle & style , FRenderStyle * def ) ;
template < class T , class TT >
FSerializer & Serialize ( FSerializer & arc , const char * key , TFlags < T , TT > & flags , TFlags < T , TT > * def )
{
return Serialize ( arc , key , flags . Value , def ? & def - > Value : nullptr ) ;
}
2020-02-23 16:11:54 +00:00
// Automatic save record registration
struct SaveRecord
{
const char * GameModule ;
void ( * Handler ) ( FSerializer & arc ) ;
SaveRecord ( const char * nm , void ( * handler ) ( FSerializer & arc ) ) ;
} ;
struct SaveRecords
{
TArray < SaveRecord * > records ;
void RunHandlers ( const char * gameModule , FSerializer & arc )
{
for ( auto record : records )
{
if ( ! strcmp ( gameModule , record - > GameModule ) )
{
record - > Handler ( arc ) ;
}
}
}
} ;
extern SaveRecords saveRecords ;
inline SaveRecord : : SaveRecord ( const char * nm , void ( * handler ) ( FSerializer & arc ) )
{
GameModule = nm ;
Handler = handler ;
saveRecords . records . Push ( this ) ;
}
2020-04-07 16:04:35 +00:00
FString DictionaryToString ( const Dictionary & dict ) ;
Dictionary * DictionaryFromString ( const FString & string ) ;
2020-02-22 17:41:24 +00:00
# endif