From e1010144324975426d1201b8e937d0fbb5934531 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 20 Sep 2016 18:27:47 +0200 Subject: [PATCH] - converted the user variable serializer. --- src/b_bot.h | 2 - src/dobject.cpp | 60 +---- src/dobject.h | 2 - src/dobjtype.cpp | 651 ++++++++++++++------------------------------- src/dobjtype.h | 54 ++-- src/json.cpp | 20 -- src/serializer.cpp | 160 ++++++++++- src/serializer.h | 39 ++- 8 files changed, 419 insertions(+), 569 deletions(-) diff --git a/src/b_bot.h b/src/b_bot.h index 5ad77707e..5dfbb7e63 100644 --- a/src/b_bot.h +++ b/src/b_bot.h @@ -58,8 +58,6 @@ struct botskill_t int isp; //Instincts of Self Preservation. Personality }; -FArchive &operator<< (FArchive &arc, botskill_t &skill); - enum { BOTINUSE_No, diff --git a/src/dobject.cpp b/src/dobject.cpp index ab4f25bf6..aa874d747 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -478,68 +478,20 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld) // //========================================================================== -void DObject::SerializeUserVars(FArchive &arc) +void DObject::SerializeUserVars(FSerializer &arc) { - PSymbolTable *symt; - FName varname; - DWORD count, j; - int *varloc = NULL; - - symt = &GetClass()->Symbols; - - if (arc.IsStoring()) + if (arc.isWriting()) { // Write all fields that aren't serialized by native code. - GetClass()->WriteValue(arc, this); - } - else if (SaveVersion >= 4535) - { - GetClass()->ReadValue(arc, this); + GetClass()->WriteAllFields(arc, this); } else - { // Old version that only deals with ints - // Read user variables until 'None' is encountered. - arc << varname; - while (varname != NAME_None) - { - PField *var = dyn_cast(symt->FindSymbol(varname, true)); - DWORD wanted = 0; - - if (var != NULL && !(var->Flags & VARF_Native)) - { - PType *type = var->Type; - PArray *arraytype = dyn_cast(type); - if (arraytype != NULL) - { - wanted = arraytype->ElementCount; - type = arraytype->ElementType; - } - else - { - wanted = 1; - } - assert(type == TypeSInt32); - varloc = (int *)(reinterpret_cast(this) + var->Offset); - } - count = arc.ReadCount(); - for (j = 0; j < MIN(wanted, count); ++j) - { - arc << varloc[j]; - } - if (wanted < count) - { - // Ignore remaining values from archive. - for (; j < count; ++j) - { - int foo; - arc << foo; - } - } - arc << varname; - } + { + GetClass()->ReadAllFields(arc, this); } } + //========================================================================== // // diff --git a/src/dobject.h b/src/dobject.h index 0f81ae873..b47915659 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -460,8 +460,6 @@ public: inline bool IsKindOf (const PClass *base) const; inline bool IsA (const PClass *type) const; - void SerializeUserVars(FArchive &arc); - void SerializeUserVars(FSerializer &arc); virtual void Serialize(FSerializer &arc); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index e7a31d8cf..a82d26a54 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -39,7 +39,7 @@ #include "dobject.h" #include "i_system.h" -#include "farchive.h" +#include "serializer.h" #include "actor.h" #include "templates.h" #include "autosegs.h" @@ -47,6 +47,7 @@ #include "a_pickups.h" #include "a_weaponpiece.h" #include "d_player.h" +#include "doomerrors.h" #include "fragglescript/t_fs.h" // MACROS ------------------------------------------------------------------ @@ -390,7 +391,7 @@ bool PType::VisitedNodeSet::Check(const PType *node) // //========================================================================== -void PType::WriteValue(FArchive &ar, const void *addr) const +void PType::WriteValue(FSerializer &ar, const char *key,const void *addr) const { assert(0 && "Cannot write value for this type"); } @@ -401,108 +402,12 @@ void PType::WriteValue(FArchive &ar, const void *addr) const // //========================================================================== -bool PType::ReadValue(FArchive &ar, void *addr) const +bool PType::ReadValue(FSerializer &ar, const char *key, void *addr) const { assert(0 && "Cannot read value for this type"); - SkipValue(ar); return false; } -//========================================================================== -// -// PType :: SkipValue STATIC -// -//========================================================================== - -void PType::SkipValue(FArchive &ar) -{ - BYTE tag; - ar << tag; - SkipValue(ar, tag); -} - -void PType::SkipValue(FArchive &ar, int tag) -{ - assert(ar.IsLoading() && "SkipValue passed an archive that is writing"); - BYTE buff[8]; - - switch (tag) - { - case VAL_Zero: case VAL_One: - break; - - case VAL_Int8: case VAL_UInt8: - ar.Read(buff, 1); - break; - - case VAL_Int16: case VAL_UInt16: - ar.Read(buff, 2); - break; - - case VAL_Int32: case VAL_UInt32: case VAL_Float32: - ar.Read(buff, 4); - break; - - case VAL_Int64: case VAL_UInt64: case VAL_Float64: - ar.Read(buff, 8); - break; - - case VAL_Name: - ar.ReadName(); - break; - - case VAL_Object: - { -#if 0 - DObject *skipper; - ar << skipper; -#endif - break; - } - case VAL_State: - { -#if 0 - FState *skipper; - ar << skipper; -#endif - break; - } - case VAL_String: - { - FString skipper; - ar << skipper; - break; - } - case VAL_Array: - { - DWORD count = ar.ReadCount(); - while (count-- > 0) - { - SkipValue(ar); - } - break; - } - case VAL_Struct: - { - const char *label; - for (label = ar.ReadName(); label != NULL; label = ar.ReadName()) - { - SkipValue(ar); - } - break; - } - case VAL_Class: - { - PClass *type; - for (ar.UserReadClass(type); type != NULL; ar.UserReadClass(type)) - { - SkipValue(ar, VAL_Struct); - } - break; - } - } -} - //========================================================================== // // PType :: SetDefaultValue @@ -809,116 +714,41 @@ PInt::PInt(unsigned int size, bool unsign) // // PInt :: WriteValue // -// Write the value using the minimum byte size needed to represent it. This -// means that the value as written is not necessarily of the same type as -// stored, but the signedness information is preserved. -// //========================================================================== -void PInt::WriteValue(FArchive &ar, const void *addr) const +void PInt::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - BYTE bval; - - // The process for bytes is the same whether signed or unsigned, since - // they can't be compacted into a representation with fewer bytes. - if (Size == 1) + if (Size == 8 && Unsigned) { - bval = *(BYTE *)addr; - } - else if (Unsigned) - { - unsigned val; - if (Size == 8) - { - QWORD qval = *(QWORD *)addr; - if (qval & 0xFFFFFFFF00000000llu) - { // Value needs 64 bits - ar.WriteByte(VAL_UInt64); - ar.WriteInt64(qval); - return; - } - // Value can fit in 32 bits or less - val = (unsigned)qval; - goto check_u32; - } - else if (Size == 4) - { - val = *(DWORD *)addr; -check_u32: if (val & 0xFFFF0000u) - { // Value needs 32 bits - ar.WriteByte(VAL_UInt32); - ar.WriteInt32(val); - return; - } - // Value can fit in 16 bits or less - goto check_u16; - } - else// if (Size == 2) - { - val = *(WORD *)addr; -check_u16: if (val & 0xFFFFFF00u) - { // Value needs 16 bits - ar.WriteByte(VAL_UInt16); - ar.WriteInt16(val); - return; - } - // Value can fit in 8 bits - bval = (BYTE)val; - } - } - else // Signed - { - int val; - if (Size == 8) - { - SQWORD qval = *(SQWORD *)addr; - INT_MIN; - if (qval < (-0x7FFFFFFF - 1) || qval > 0x7FFFFFFF) - { // Value needs 64 bits - ar.WriteByte(VAL_Int64); - ar.WriteInt64(qval); - return; - } - // Value can fit in 32 bits or less - val = (int)qval; - goto check_s32; - } - else if (Size == 4) - { - val = *(SDWORD *)addr; -check_s32: if (val < -0x8000 || val > 0x7FFF) - { // Value needs 32 bits - ar.WriteByte(VAL_Int32); - ar.WriteInt32(val); - return; - } - // Value can fit in 16 bits or less - goto check_s16; - } - else// if (Size == 2) - { - val = *(SWORD *)addr; -check_s16: if (val < -0x80 || val > 0x7F) - { // Value needs 16 bits - ar.WriteByte(VAL_Int16); - ar.WriteInt16(val); - return; - } - // Value can fit in 8 bits - bval = (BYTE)val; - } - } - // If we get here, the value fits in a byte. Values of 0 and 1 are - // optimized away into the tag so they don't require any extra space - // to store. - if (bval & 0xFE) - { - BYTE out[2] = { Unsigned ? VAL_UInt8 : VAL_Int8, bval }; - ar.Write(out, 2); + // this is a special case that cannot be represented by an int64_t. + uint64_t val = *(uint64_t*)addr; + ar(key, val); } else { - ar.WriteByte(VAL_Zero + bval); + int64_t val; + switch (Size) + { + case 1: + val = Unsigned ? *(uint8_t*)addr : *(int8_t*)addr; + break; + + case 2: + val = Unsigned ? *(uint16_t*)addr : *(int16_t*)addr; + break; + + case 4: + val = Unsigned ? *(uint32_t*)addr : *(int32_t*)addr; + break; + + case 8: + val = *(int64_t*)addr; + break; + + default: + return; // something invalid + } + ar(key, val); } } @@ -928,47 +758,37 @@ check_s16: if (val < -0x80 || val > 0x7F) // //========================================================================== -bool PInt::ReadValue(FArchive &ar, void *addr) const +bool PInt::ReadValue(FSerializer &ar, const char *key, void *addr) const { - union - { - QWORD uval; - SQWORD sval; - }; - BYTE tag; - union - { - BYTE val8; - WORD val16; - DWORD val32; - float single; - double dbl; - }; + NumericValue val; - ar << tag; - switch (tag) - { - case VAL_Zero: uval = 0; break; - case VAL_One: uval = 1; break; - case VAL_Int8: ar << val8; sval = (SBYTE)val8; break; - case VAL_UInt8: ar << val8; uval = val8; break; - case VAL_Int16: ar << val16; sval = (SWORD)val16; break; - case VAL_UInt16: ar << val16; uval = val16; break; - case VAL_Int32: ar << val32; sval = (SDWORD)val32; break; - case VAL_UInt32: ar << val32; uval = val32; break; - case VAL_Int64: ar << sval; break; - case VAL_UInt64: ar << uval; break; - case VAL_Float32: ar << single; sval = (SQWORD)single; break; - case VAL_Float64: ar << dbl; sval = (SQWORD)dbl; break; - default: SkipValue(ar, tag); return false; // Incompatible type - } + ar(key, val); + if (val.type == NumericValue::NM_invalid) return false; // not found or usable + if (val.type == NumericValue::NM_float) val.signedval = (int64_t)val.floatval; + + // No need to check the unsigned state here. Downcasting to smaller types will yield the same result for both. switch (Size) { - case 1: *(BYTE *)addr = (BYTE)uval; break; - case 2: *(WORD *)addr = (WORD)uval; break; - case 4: *(DWORD *)addr = (DWORD)uval; break; - case 8: *(QWORD *)addr = uval; break; + case 1: + *(uint8_t*)addr = (uint8_t)val.signedval; + break; + + case 2: + *(uint16_t*)addr = (uint16_t)val.signedval; + break; + + case 4: + *(uint32_t*)addr = (uint32_t)val.signedval; + break; + + case 8: + *(uint64_t*)addr = (uint64_t)val.signedval; + break; + + default: + return false; // something invalid } + return true; } @@ -1263,28 +1083,16 @@ void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count) // //========================================================================== -void PFloat::WriteValue(FArchive &ar, const void *addr) const +void PFloat::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - float singleprecision; if (Size == 8) { - // If it can be written as single precision without information - // loss, then prefer that over writing a full-sized double. - double doubleprecision = *(double *)addr; - singleprecision = (float)doubleprecision; - if (singleprecision != doubleprecision) - { - ar.WriteByte(VAL_Float64); - ar << doubleprecision; - return; - } + ar(key, *(double*)addr); } else { - singleprecision = *(float *)addr; + ar(key, *(float*)addr); } - ar.WriteByte(VAL_Float32); - ar << singleprecision; } //========================================================================== @@ -1293,60 +1101,26 @@ void PFloat::WriteValue(FArchive &ar, const void *addr) const // //========================================================================== -static bool ReadValueDbl(FArchive &ar, double *addr, unsigned tag) +bool PFloat::ReadValue(FSerializer &ar, const char *key, void *addr) const { - double val; - union - { - BYTE val8; - WORD val16; - DWORD val32; - QWORD val64; - fixed_t fix; - float single; - angle_t ang; - }; + NumericValue val; - switch (tag) + ar(key, val); + if (val.type == NumericValue::NM_invalid) return false; // not found or usable + else if (val.type == NumericValue::NM_signed) val.floatval = (double)val.signedval; + else if (val.type == NumericValue::NM_unsigned) val.floatval = (double)val.unsignedval; + + if (Size == 8) { - case VAL_Zero: val = 0; break; - case VAL_One: val = 1; break; - case VAL_Int8: ar << val8; val = (SBYTE)val8; break; - case VAL_UInt8: ar << val8; val = val8; break; - case VAL_Int16: ar << val16; val = (SWORD)val16; break; - case VAL_UInt16: ar << val16; val = val16; break; - case VAL_Int32: ar << val32; val = (SDWORD)val32; break; - case VAL_UInt32: ar << val32; val = val32; break; - case VAL_Int64: ar << val64; val = (double)(SQWORD)val64; break; - case VAL_UInt64: ar << val64; val = (double)val64; break; - case VAL_Float32: ar << single; val = single; break; - case VAL_Float64: ar << val; break; - default: PType::SkipValue(ar, tag); return false; // Incompatible type + *(double*)addr = val.floatval; + } + else + { + *(float*)addr = (float)val.floatval; } - *(double *)addr = val; return true; } -bool PFloat::ReadValue(FArchive &ar, void *addr) const -{ - BYTE tag; - ar << tag; - double val; - if (ReadValueDbl(ar, &val, tag)) - { - if (Size == 4) - { - *(float *)addr = (float)val; - } - else - { - *(double *)addr = val; - } - return true; - } - return false; -} - //========================================================================== // // PFloat :: SetValue @@ -1486,10 +1260,9 @@ int PString::GetRegType() const // //========================================================================== -void PString::WriteValue(FArchive &ar, const void *addr) const +void PString::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - ar.WriteByte(VAL_String); - ar.WriteString(*(const FString *)addr); + ar(key, *(FString*)addr); } //========================================================================== @@ -1498,25 +1271,19 @@ void PString::WriteValue(FArchive &ar, const void *addr) const // //========================================================================== -bool PString::ReadValue(FArchive &ar, void *addr) const +bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const { - BYTE tag; - ar << tag; - if (tag == VAL_String) + const char *cptr; + ar.StringPtr(key, cptr); + if (cptr == nullptr) { - ar << *(FString *)addr; - } - else if (tag == VAL_Name) - { - const char *str = ar.ReadName(); - *(FString *)addr = str; + return false; } else { - SkipValue(ar, tag); - return false; + *(FString*)addr = cptr; + return true; } - return true; } //========================================================================== @@ -1578,10 +1345,10 @@ PName::PName() // //========================================================================== -void PName::WriteValue(FArchive &ar, const void *addr) const +void PName::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - ar.WriteByte(VAL_Name); - ar.WriteName(((const FName *)addr)->GetChars()); + const char *cptr = ((const FName*)addr)->GetChars(); + ar.StringPtr(key, cptr); } //========================================================================== @@ -1590,26 +1357,19 @@ void PName::WriteValue(FArchive &ar, const void *addr) const // //========================================================================== -bool PName::ReadValue(FArchive &ar, void *addr) const +bool PName::ReadValue(FSerializer &ar, const char *key, void *addr) const { - BYTE tag; - ar << tag; - if (tag == VAL_Name) + const char *cptr; + ar.StringPtr(key, cptr); + if (cptr == nullptr) { - *(FName *)addr = FName(ar.ReadName()); - } - else if (tag == VAL_String) - { - FString str; - ar << str; - *(FName *)addr = FName(str); + return false; } else { - SkipValue(ar, tag); - return false; + *(FName*)addr = FName(cptr); + return true; } - return true; } /* PSound *****************************************************************/ @@ -1634,10 +1394,10 @@ PSound::PSound() // //========================================================================== -void PSound::WriteValue(FArchive &ar, const void *addr) const +void PSound::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - ar.WriteByte(VAL_Name); - ar.WriteName(*(const FSoundID *)addr); + const char *cptr = *(const FSoundID *)addr; + ar.StringPtr(key, cptr); } //========================================================================== @@ -1646,28 +1406,19 @@ void PSound::WriteValue(FArchive &ar, const void *addr) const // //========================================================================== -bool PSound::ReadValue(FArchive &ar, void *addr) const +bool PSound::ReadValue(FSerializer &ar, const char *key, void *addr) const { - BYTE tag; - - ar << tag; - if (tag == VAL_Name) + const char *cptr; + ar.StringPtr(key, cptr); + if (cptr == nullptr) { - const char *str = ar.ReadName(); - *(FSoundID *)addr = FSoundID(str); - } - else if (tag == VAL_String) - { - FString str; - ar << str; - *(FSoundID *)addr = FSoundID(str); + return false; } else { - SkipValue(ar, tag); - return false; + *(FSoundID *)addr = FSoundID(cptr); + return true; } - return true; } /* PColor *****************************************************************/ @@ -1740,10 +1491,9 @@ int PStatePointer::GetRegType() const // //========================================================================== -void PStatePointer::WriteValue(FArchive &ar, const void *addr) const +void PStatePointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - ar.WriteByte(VAL_State); - //ar << *(FState **)addr; + ar(key, *(FState **)addr); } //========================================================================== @@ -1752,17 +1502,11 @@ void PStatePointer::WriteValue(FArchive &ar, const void *addr) const // //========================================================================== -bool PStatePointer::ReadValue(FArchive &ar, void *addr) const +bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) const { - BYTE tag; - ar << tag; - if (tag == VAL_State) - { - //ar << *(FState **)addr; - return true; - } - SkipValue(ar, tag); - return false; + bool res = false; + ::Serialize(ar, key, *(FState **)addr, nullptr, &res); + return res; } /* PPointer ***************************************************************/ @@ -1858,20 +1602,17 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const // //========================================================================== -void PPointer::WriteValue(FArchive &ar, const void *addr) const +void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const { -#if 0 if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - ar.WriteByte(VAL_Object); - ar << *(DObject **)addr; + ar(key, *(DObject **)addr); } else { assert(0 && "Pointer points to a type we don't handle"); I_Error("Attempt to save pointer to unhandled type"); } -#endif } //========================================================================== @@ -1880,18 +1621,14 @@ void PPointer::WriteValue(FArchive &ar, const void *addr) const // //========================================================================== -bool PPointer::ReadValue(FArchive &ar, void *addr) const +bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const { -#if 0 - BYTE tag; - ar << tag; - if (tag == VAL_Object && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - ar << *(DObject **)addr; - return true; + bool res = false; + ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + return res; } - SkipValue(ar, tag); -#endif return false; } @@ -2106,15 +1843,17 @@ void PArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const // //========================================================================== -void PArray::WriteValue(FArchive &ar, const void *addr) const +void PArray::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - ar.WriteByte(VAL_Array); - ar.WriteCount(ElementCount); - const BYTE *addrb = (const BYTE *)addr; - for (unsigned i = 0; i < ElementCount; ++i) + if (ar.BeginArray(key)) { - ElementType->WriteValue(ar, addrb); - addrb += ElementSize; + const BYTE *addrb = (const BYTE *)addr; + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->WriteValue(ar, nullptr, addrb); + addrb += ElementSize; + } + ar.EndArray(); } } @@ -2124,34 +1863,27 @@ void PArray::WriteValue(FArchive &ar, const void *addr) const // //========================================================================== -bool PArray::ReadValue(FArchive &ar, void *addr) const +bool PArray::ReadValue(FSerializer &ar, const char *key, void *addr) const { - bool readsomething = false; - BYTE tag; - - ar << tag; - if (tag == VAL_Array) + if (ar.BeginArray(key)) { - unsigned count = ar.ReadCount(); - unsigned i; + bool readsomething = false; + unsigned count = ar.ArraySize(); + unsigned loop = MIN(count, ElementCount); BYTE *addrb = (BYTE *)addr; - for (i = 0; i < MIN(count, ElementCount); ++i) + for(unsigned i=0;iReadValue(ar, addrb); + readsomething |= ElementType->ReadValue(ar, key, addrb); addrb += ElementSize; } - if (i < ElementCount) + if (loop < ElementCount) { DPrintf(DMSG_WARNING, "Array on disk (%u) is bigger than in memory (%u)\n", count, ElementCount); - for (; i < ElementCount; ++i) - { - SkipValue(ar); - } } + ar.EndArray(); return readsomething; } - SkipValue(ar, tag); return false; } @@ -2445,10 +2177,13 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArray &fields) +void PStruct::WriteFields(FSerializer &ar, const void *addr, const TArray &fields) { for (unsigned i = 0; i < fields.Size(); ++i) { @@ -2483,11 +2217,9 @@ void PStruct::WriteFields(FArchive &ar, const void *addr, const TArray // Skip fields with native serialization if (!(field->Flags & VARF_Native)) { - ar.WriteName(field->SymbolName); - field->Type->WriteValue(ar, (const BYTE *)addr + field->Offset); + field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const BYTE *)addr + field->Offset); } } - ar.WriteName(NULL); } //========================================================================== @@ -2496,36 +2228,33 @@ void PStruct::WriteFields(FArchive &ar, const void *addr, const TArray // //========================================================================== -bool PStruct::ReadFields(FArchive &ar, void *addr) const +bool PStruct::ReadFields(FSerializer &ar, void *addr) const { bool readsomething = false; - const char *label = ar.ReadName(); - if (label == NULL) - { // If there is nothing to restore, we count it as success. - return true; - } - for (; label != NULL; label = ar.ReadName()) + bool foundsomething = false; + const char *label; + while ((label = ar.GetKey())) { + foundsomething = true; + const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true); if (sym == NULL) { DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", label, TypeName.GetChars()); - SkipValue(ar); } else if (!sym->IsKindOf(RUNTIME_CLASS(PField))) { DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n", label, TypeName.GetChars()); - SkipValue(ar); } else { - readsomething |= static_cast(sym)->Type->ReadValue(ar, + readsomething |= static_cast(sym)->Type->ReadValue(ar, label, (BYTE *)addr + static_cast(sym)->Offset); } } - return readsomething; + return readsomething || !foundsomething; } //========================================================================== @@ -2749,7 +2478,7 @@ END_POINTERS // //========================================================================== -static void RecurseWriteFields(const PClass *type, FArchive &ar, const void *addr) +static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void *addr) { if (type != NULL) { @@ -2763,19 +2492,33 @@ static void RecurseWriteFields(const PClass *type, FArchive &ar, const void *add // a more-derived class has variables that shadow a less- // derived class. Whether or not that is a language feature // that will actually be allowed remains to be seen. - ar.UserWriteClass(const_cast(type)); - PStruct::WriteFields(ar, addr, type->Fields); + FString key; + key.Format("class:%s", type->TypeName.GetChars()); + if (ar.BeginObject(key.GetChars())) + { + PStruct::WriteFields(ar, addr, type->Fields); + ar.EndObject(); + } break; } } } } -void PClass::WriteValue(FArchive &ar, const void *addr) const +void PClass::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (ar.BeginObject(key)) + { + RecurseWriteFields(this, ar, addr); + ar.EndObject(); + } +} + +// Same as WriteValue, but does not create a new object in the serializer +// This is so that user variables do not contain unnecessary subblocks. +void PClass::WriteAllFields(FSerializer &ar, const void *addr) const { - ar.WriteByte(VAL_Class); RecurseWriteFields(this, ar, addr); - ar.UserWriteClass(NULL); } //========================================================================== @@ -2784,20 +2527,32 @@ void PClass::WriteValue(FArchive &ar, const void *addr) const // //========================================================================== -bool PClass::ReadValue(FArchive &ar, void *addr) const +bool PClass::ReadValue(FSerializer &ar, const char *key, void *addr) const { - BYTE tag; - ar << tag; - if (tag != VAL_Class) + if (ar.BeginObject(key)) { - SkipValue(ar, tag); - return false; + bool ret = ReadAllFields(ar, addr); + ar.EndObject(); + return ret; } - else + return true; +} + +bool PClass::ReadAllFields(FSerializer &ar, void *addr) const +{ + bool readsomething = false; + bool foundsomething = false; + const char *key; + while ((key = ar.GetKey())) { - bool readsomething = false; - PClass *type; - for (ar.UserReadClass(type); type != NULL; ar.UserReadClass(type)) + if (strncmp(key, "class:", 6)) + { + // This key does not represent any class fields anymore + break; + } + foundsomething = true; + PClass *type = PClass::FindClass(key + 6); + if (type != nullptr) { // Only read it if the type is related to this one. const PClass *parent; @@ -2808,7 +2563,7 @@ bool PClass::ReadValue(FArchive &ar, void *addr) const break; } } - if (parent != NULL) + if (parent != nullptr) { readsomething |= type->ReadFields(ar, addr); } @@ -2816,11 +2571,15 @@ bool PClass::ReadValue(FArchive &ar, void *addr) const { DPrintf(DMSG_ERROR, "Unknown superclass %s of class %s\n", type->TypeName.GetChars(), TypeName.GetChars()); - SkipValue(ar, VAL_Struct); } } - return readsomething; + else + { + DPrintf(DMSG_ERROR, "Unknown superclass %s of class %s\n", + key+6, TypeName.GetChars()); + } } + return readsomething || !foundsomething; } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index d0ccee746..62cfa6753 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -193,15 +193,11 @@ public: // a tag indicating its type. The tag is there so that variable types can be changed // without completely breaking savegames, provided that the change isn't between // totally unrelated types. - virtual void WriteValue(FArchive &ar, const void *addr) const; + virtual void WriteValue(FSerializer &ar, const char *key,const void *addr) const; // Returns true if the stored value was compatible. False otherwise. // If the value was incompatible, then the memory at *addr is unchanged. - virtual bool ReadValue(FArchive &ar, void *addr) const; - - // Skips over a value written with WriteValue - static void SkipValue(FArchive &ar); - static void SkipValue(FArchive &ar, int tag); + virtual bool ReadValue(FSerializer &ar, const char *key,void *addr) const; // Sets the default value for this type at (base + offset) // If the default value is binary 0, then this function doesn't need @@ -354,8 +350,8 @@ class PInt : public PBasicType public: PInt(unsigned int size, bool unsign); - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, double val); @@ -383,8 +379,8 @@ class PFloat : public PBasicType public: PFloat(unsigned int size); - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, double val); @@ -421,8 +417,8 @@ public: virtual int GetRegType() const; - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const override; void InitializeValue(void *addr, const void *def) const override; void DestroyValue(void *addr) const override; @@ -436,8 +432,8 @@ class PName : public PInt public: PName(); - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; }; class PSound : public PInt @@ -446,8 +442,8 @@ class PSound : public PInt public: PSound(); - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; }; class PColor : public PInt @@ -465,8 +461,8 @@ class PStatePointer : public PBasicType public: PStatePointer(); - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; virtual int GetStoreOp() const; virtual int GetLoadOp() const; @@ -489,8 +485,8 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; protected: PPointer(); @@ -559,8 +555,8 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *special) const override; @@ -622,12 +618,12 @@ public: size_t PropagateMark(); - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *specials) const override; - static void WriteFields(FArchive &ar, const void *addr, const TArray &fields); - bool ReadFields(FArchive &ar, void *addr) const; + static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields); + bool ReadFields(FSerializer &ar, void *addr) const; protected: PStruct(); }; @@ -692,8 +688,10 @@ public: typedef PClassClass MetaClass; MetaClass *GetClass() const; - void WriteValue(FArchive &ar, const void *addr) const override; - bool ReadValue(FArchive &ar, void *addr) const override; + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + void WriteAllFields(FSerializer &ar, const void *addr) const; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; + bool ReadAllFields(FSerializer &ar, void *addr) const; virtual void DeriveData(PClass *newclass) {} static void StaticInit(); diff --git a/src/json.cpp b/src/json.cpp index 43f185301..1d8d506f8 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -7,26 +7,6 @@ -void DObject::SerializeUserVars(FSerializer &arc) -{ - PSymbolTable *symt; - FName varname; - //DWORD count, j; - int *varloc = NULL; - - symt = &GetClass()->Symbols; - - if (arc.isWriting()) - { - // Write all fields that aren't serialized by native code. - //GetClass()->WriteValue(arc, this); - } - else - { - //GetClass()->ReadValue(arc, this); - } -} - //========================================================================== // // diff --git a/src/serializer.cpp b/src/serializer.cpp index 1386319fb..8e249e9d8 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -44,12 +44,18 @@ struct FJSONObject rapidjson::Value *mObject; rapidjson::Value::MemberIterator mIterator; int mIndex; + bool mRandomAccess; - FJSONObject(rapidjson::Value *v) + FJSONObject(rapidjson::Value *v, bool randomaccess = false) { mObject = v; + mRandomAccess = randomaccess; if (v->IsObject()) mIterator = v->MemberBegin(); - else if (v->IsArray()) mIndex = 0; + else if (v->IsArray()) + { + mIndex = 0; + mIterator = v->MemberEnd(); + } } }; @@ -100,7 +106,7 @@ struct FReader rapidjson::Document doc; doc.Parse(buffer, length); mDocObj = doc.GetObject(); - mObjects.Push(FJSONObject(&mDocObj)); + mObjects.Push(FJSONObject(&mDocObj)); // Todo: Decide if this should be made random access... } rapidjson::Value *FindKey(const char *key) @@ -109,13 +115,23 @@ struct FReader if (obj.mObject->IsObject()) { - if (obj.mIterator != obj.mObject->MemberEnd()) + if (!obj.mRandomAccess) { - if (!strcmp(key, obj.mIterator->name.GetString())) + if (obj.mIterator != obj.mObject->MemberEnd()) { - return &(obj.mIterator++)->value; + if (!strcmp(key, obj.mIterator->name.GetString())) + { + return &(obj.mIterator++)->value; + } } } + else + { + // for unordered searches. This is slower but will not rely on sequential order of items. + auto it = obj.mObject->FindMember(key); + if (it == obj.mObject->MemberEnd()) return nullptr; + return &it->value; + } } else if (obj.mObject->IsArray()) { @@ -227,7 +243,7 @@ void FSerializer::WriteKey(const char *key) // //========================================================================== -bool FSerializer::BeginObject(const char *name) +bool FSerializer::BeginObject(const char *name, bool randomaccess) { if (isWriting()) { @@ -242,7 +258,7 @@ bool FSerializer::BeginObject(const char *name) { if (val->IsObject()) { - r->mObjects.Push(FJSONObject(val)); + r->mObjects.Push(FJSONObject(val, randomaccess)); } else { @@ -530,6 +546,10 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr) { charptr = val->GetString(); } + else + { + charptr = nullptr; + } } } return *this; @@ -550,6 +570,20 @@ unsigned FSerializer::GetSize(const char *group) return val.Size(); } +//========================================================================== +// +// +// +//========================================================================== + +const char *FSerializer::GetKey() +{ + if (isWriting()) return nullptr; // we do not know this when writing. + auto &it = r->mObjects.Last().mIterator; + if (it == r->mObjects.Last().mObject->MemberEnd()) return nullptr; + return it->name.GetString(); +} + //========================================================================== // // Writes out all collected objects @@ -994,8 +1028,9 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe // //========================================================================== -FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/) +FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/, bool *retcode) { + if (retcode) *retcode = true; if (arc.isWriting()) { if (value != nullptr) @@ -1017,10 +1052,14 @@ FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObje if (val != nullptr) { } - else + else if (!retcode) { value = nullptr; } + else + { + *retcode = false; + } } return arc; } @@ -1185,18 +1224,55 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor } +//========================================================================== +// +// almost, but not quite the same as the above. +// +//========================================================================== + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&clst, PClass **def) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || def == nullptr || clst != *def) + { + arc.WriteKey(key); + arc.w->mWriter.String(clst->TypeName.GetChars()); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + clst = PClass::FindClass(val->GetString()); + } + else + { + I_Error("string type expected for '%s'", key); + } + } + } + return arc; + +} + //========================================================================== // // // //========================================================================== -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) +FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode) { + if (retcode) *retcode = false; if (arc.isWriting()) { if (!arc.w->inObject() || def == nullptr || state != *def) { + if (retcode) *retcode = true; arc.WriteKey(key); if (state == nullptr) { @@ -1227,10 +1303,12 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FState *&st { if (val->IsNull()) { + if (retcode) *retcode = true; state = nullptr; } else if (val->IsArray()) { + if (retcode) *retcode = true; const rapidjson::Value &cls = (*val)[0]; const rapidjson::Value &ndx = (*val)[1]; @@ -1244,7 +1322,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FState *&st } } } - else + else if (!retcode) { I_Error("array type expected for '%s'", key); } @@ -1455,7 +1533,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon const char *n; arc.StringPtr(key, n); font = V_GetFont(n); - if (font == NULL) + if (font == nullptr) { Printf("Could not load font %s\n", n); font = SmallFont; @@ -1465,3 +1543,59 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon } +//========================================================================== +// +// Handler to retrieve a numeric value of any kind. +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &value, NumericValue *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + switch (value.type) + { + case NumericValue::NM_signed: + arc.w->mWriter.Int64(value.signedval); + break; + case NumericValue::NM_unsigned: + arc.w->mWriter.Uint64(value.unsignedval); + break; + case NumericValue::NM_float: + arc.w->mWriter.Double(value.floatval); + break; + default: + arc.w->mWriter.Null(); + break; + } + } + } + else + { + auto val = arc.r->FindKey(key); + value.signedval = 0; + value.type = NumericValue::NM_invalid; + if (val != nullptr) + { + if (val->IsUint64()) + { + value.unsignedval = val->GetUint64(); + value.type = NumericValue::NM_unsigned; + } + else if (val->IsInt64()) + { + value.signedval = val->GetInt64(); + value.type = NumericValue::NM_signed; + } + else if (val->IsDouble()) + { + value.floatval = val->GetDouble(); + value.type = NumericValue::NM_float; + } + } + } + return arc; +} diff --git a/src/serializer.h b/src/serializer.h index abc62755a..cec13ae1c 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -14,6 +14,29 @@ extern TArray loadlines; extern TArray loadsides; extern char nulspace[]; +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 @@ -24,6 +47,7 @@ public: FReader *r = nullptr; int ArraySize(); + void WriteKey(const char *key); public: @@ -34,13 +58,13 @@ public: bool OpenWriter(); bool OpenReader(const char *buffer, size_t length); void Close(); - void WriteKey(const char *key); - bool BeginObject(const char *name); + bool BeginObject(const char *name, bool randomaccess = false); void EndObject(); bool BeginArray(const char *name); void EndArray(); void WriteObjects(); unsigned GetSize(const char *group); + const char *GetKey(); const char *GetOutput(unsigned *len = nullptr); FSerializer &Args(const char *key, int *args, int *defargs, int special); FSerializer &Terrain(const char *key, int &terrain, int *def = nullptr); @@ -130,10 +154,11 @@ FSerializer &Serialize(FSerializer &arc, const char *key, uint16_t &value, uint1 FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double *defval); FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *defval); FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/); +FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/, bool *retcode = nullptr); 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); template FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) @@ -184,13 +209,19 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&va template<> FSerializer &Serialize(FSerializer &arc, const char *key, vertex_t *&value, vertex_t **defval); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDynamicColormap *&cm, FDynamicColormap **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor *&clst, PClassActor **def); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&clst, PClass **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDialogueNode *&node, FStrifeDialogueNode **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&pstr, FString **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimation *&pstr, FDoorAnimation **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def); +FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode); +template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) +{ + return Serialize(arc, key, state, def, nullptr); +} + inline FSerializer &Serialize(FSerializer &arc, const char *key, DVector3 &p, DVector3 *def) {