- moved serializer to 'common'.
This commit is contained in:
parent
7b292cca57
commit
f6bd2e4f76
5 changed files with 13 additions and 13 deletions
17
src/common/engine/serialize_obj.h
Normal file
17
src/common/engine/serialize_obj.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
// These are in a separate header because they require some rather 'dirty' headers to work which should not be part of serializer.h
|
||||
|
||||
template<class T>
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr<T> &value, TObjPtr<T> *)
|
||||
{
|
||||
Serialize(arc, key, value.o, nullptr);
|
||||
return arc;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr<T> &value, T *)
|
||||
{
|
||||
Serialize(arc, key, value.o, nullptr);
|
||||
return arc;
|
||||
}
|
||||
1569
src/common/engine/serializer.cpp
Normal file
1569
src/common/engine/serializer.cpp
Normal file
File diff suppressed because it is too large
Load diff
313
src/common/engine/serializer.h
Normal file
313
src/common/engine/serializer.h
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
#ifndef __SERIALIZER_H
|
||||
#define __SERIALIZER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <type_traits>
|
||||
#include "tarray.h"
|
||||
#include "file_zip.h"
|
||||
#include "tflags.h"
|
||||
#include "vectors.h"
|
||||
#include "palentry.h"
|
||||
#include "name.h"
|
||||
#include "dictionary.h"
|
||||
|
||||
extern bool save_full;
|
||||
|
||||
struct FWriter;
|
||||
struct FReader;
|
||||
class PClass;
|
||||
class FFont;
|
||||
class FSoundID;
|
||||
union FRenderStyle;
|
||||
class DObject;
|
||||
class FTextureID;
|
||||
|
||||
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;
|
||||
bool soundNamesAreUnique = false; // While in GZDoom, sound names are unique, that isn't universally true - let the serializer handle both cases with a flag.
|
||||
|
||||
unsigned ArraySize();
|
||||
void WriteKey(const char *key);
|
||||
void WriteObjects();
|
||||
|
||||
private:
|
||||
virtual void CloseReaderCustom() {}
|
||||
public:
|
||||
|
||||
~FSerializer()
|
||||
{
|
||||
mErrors = 0; // The destructor may not throw an exception so silence the error checker.
|
||||
Close();
|
||||
}
|
||||
void SetUniqueSoundNames() { soundNamesAreUnique = true; }
|
||||
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();
|
||||
bool BeginArray(const char *name);
|
||||
void EndArray();
|
||||
unsigned GetSize(const char *group);
|
||||
const char *GetKey();
|
||||
const char *GetOutput(unsigned *len = nullptr);
|
||||
FCompressedBuffer GetCompressedOutput();
|
||||
// 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);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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;
|
||||
};
|
||||
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval);
|
||||
|
||||
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);
|
||||
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);
|
||||
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<class T>
|
||||
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())
|
||||
{
|
||||
if (value.Size() == 0) return arc; // do not save empty arrays
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
template<> FSerializer& Serialize(FSerializer& arc, const char* key, PClass*& clst, PClass** def);
|
||||
template<> FSerializer& Serialize(FSerializer& arc, const char* key, FFont*& font, FFont** def);
|
||||
template<> FSerializer &Serialize(FSerializer &arc, const char *key, Dictionary *&dict, Dictionary **def);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline FSerializer &Serialize(FSerializer &arc, const char *key, DAngle &p, DAngle *def)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
FString DictionaryToString(const Dictionary &dict);
|
||||
Dictionary *DictionaryFromString(const FString &string);
|
||||
|
||||
#endif
|
||||
240
src/common/engine/serializer_internal.h
Normal file
240
src/common/engine/serializer_internal.h
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
const char* UnicodeToString(const char* cc);
|
||||
const char* StringToUnicode(const char* cc, int size = -1);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FJSONObject
|
||||
{
|
||||
rapidjson::Value* mObject;
|
||||
rapidjson::Value::MemberIterator mIterator;
|
||||
int mIndex;
|
||||
|
||||
FJSONObject(rapidjson::Value* v)
|
||||
{
|
||||
mObject = v;
|
||||
if (v->IsObject()) mIterator = v->MemberBegin();
|
||||
else if (v->IsArray())
|
||||
{
|
||||
mIndex = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// some wrapper stuff to keep the RapidJSON dependencies out of the global headers.
|
||||
// FSerializer should not expose any of this, although it is needed by special serializers.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FWriter
|
||||
{
|
||||
typedef rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<> > Writer;
|
||||
typedef rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<> > PrettyWriter;
|
||||
|
||||
Writer *mWriter1;
|
||||
PrettyWriter *mWriter2;
|
||||
TArray<bool> mInObject;
|
||||
rapidjson::StringBuffer mOutString;
|
||||
TArray<DObject *> mDObjects;
|
||||
TMap<DObject *, int> mObjectMap;
|
||||
|
||||
FWriter(bool pretty)
|
||||
{
|
||||
if (!pretty)
|
||||
{
|
||||
mWriter1 = new Writer(mOutString);
|
||||
mWriter2 = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
mWriter1 = nullptr;
|
||||
mWriter2 = new PrettyWriter(mOutString);
|
||||
}
|
||||
}
|
||||
|
||||
~FWriter()
|
||||
{
|
||||
if (mWriter1) delete mWriter1;
|
||||
if (mWriter2) delete mWriter2;
|
||||
}
|
||||
|
||||
|
||||
bool inObject() const
|
||||
{
|
||||
return mInObject.Size() > 0 && mInObject.Last();
|
||||
}
|
||||
|
||||
void StartObject()
|
||||
{
|
||||
if (mWriter1) mWriter1->StartObject();
|
||||
else if (mWriter2) mWriter2->StartObject();
|
||||
}
|
||||
|
||||
void EndObject()
|
||||
{
|
||||
if (mWriter1) mWriter1->EndObject();
|
||||
else if (mWriter2) mWriter2->EndObject();
|
||||
}
|
||||
|
||||
void StartArray()
|
||||
{
|
||||
if (mWriter1) mWriter1->StartArray();
|
||||
else if (mWriter2) mWriter2->StartArray();
|
||||
}
|
||||
|
||||
void EndArray()
|
||||
{
|
||||
if (mWriter1) mWriter1->EndArray();
|
||||
else if (mWriter2) mWriter2->EndArray();
|
||||
}
|
||||
|
||||
void Key(const char *k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Key(k);
|
||||
else if (mWriter2) mWriter2->Key(k);
|
||||
}
|
||||
|
||||
void Null()
|
||||
{
|
||||
if (mWriter1) mWriter1->Null();
|
||||
else if (mWriter2) mWriter2->Null();
|
||||
}
|
||||
|
||||
void StringU(const char *k, bool encode)
|
||||
{
|
||||
if (encode) k = StringToUnicode(k);
|
||||
if (mWriter1) mWriter1->String(k);
|
||||
else if (mWriter2) mWriter2->String(k);
|
||||
}
|
||||
|
||||
void String(const char *k)
|
||||
{
|
||||
k = StringToUnicode(k);
|
||||
if (mWriter1) mWriter1->String(k);
|
||||
else if (mWriter2) mWriter2->String(k);
|
||||
}
|
||||
|
||||
void String(const char *k, int size)
|
||||
{
|
||||
k = StringToUnicode(k, size);
|
||||
if (mWriter1) mWriter1->String(k);
|
||||
else if (mWriter2) mWriter2->String(k);
|
||||
}
|
||||
|
||||
void Bool(bool k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Bool(k);
|
||||
else if (mWriter2) mWriter2->Bool(k);
|
||||
}
|
||||
|
||||
void Int(int32_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Int(k);
|
||||
else if (mWriter2) mWriter2->Int(k);
|
||||
}
|
||||
|
||||
void Int64(int64_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Int64(k);
|
||||
else if (mWriter2) mWriter2->Int64(k);
|
||||
}
|
||||
|
||||
void Uint(uint32_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Uint(k);
|
||||
else if (mWriter2) mWriter2->Uint(k);
|
||||
}
|
||||
|
||||
void Uint64(int64_t k)
|
||||
{
|
||||
if (mWriter1) mWriter1->Uint64(k);
|
||||
else if (mWriter2) mWriter2->Uint64(k);
|
||||
}
|
||||
|
||||
void Double(double k)
|
||||
{
|
||||
if (mWriter1)
|
||||
{
|
||||
mWriter1->Double(k);
|
||||
}
|
||||
else if (mWriter2)
|
||||
{
|
||||
mWriter2->Double(k);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FReader
|
||||
{
|
||||
TArray<FJSONObject> mObjects;
|
||||
rapidjson::Document mDoc;
|
||||
TArray<DObject *> mDObjects;
|
||||
rapidjson::Value *mKeyValue = nullptr;
|
||||
bool mObjectsRead = false;
|
||||
|
||||
FReader(const char *buffer, size_t length)
|
||||
{
|
||||
mDoc.Parse(buffer, length);
|
||||
mObjects.Push(FJSONObject(&mDoc));
|
||||
}
|
||||
|
||||
rapidjson::Value *FindKey(const char *key)
|
||||
{
|
||||
FJSONObject &obj = mObjects.Last();
|
||||
|
||||
if (obj.mObject->IsObject())
|
||||
{
|
||||
if (key == nullptr)
|
||||
{
|
||||
// we are performing an iteration of the object through GetKey.
|
||||
auto p = mKeyValue;
|
||||
mKeyValue = nullptr;
|
||||
return p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the given key by name;
|
||||
auto it = obj.mObject->FindMember(key);
|
||||
if (it == obj.mObject->MemberEnd()) return nullptr;
|
||||
return &it->value;
|
||||
}
|
||||
}
|
||||
else if (obj.mObject->IsArray() && (unsigned)obj.mIndex < obj.mObject->Size())
|
||||
{
|
||||
return &(*obj.mObject)[obj.mIndex++];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
template<class T>
|
||||
FSerializer &SerializePointer(FSerializer &arc, const char *key, T *&value, T **defval, T *base)
|
||||
{
|
||||
assert(base != nullptr);
|
||||
if (arc.isReading() || !arc.w->inObject() || defval == nullptr || value != *defval)
|
||||
{
|
||||
int64_t vv = value == nullptr ? -1 : value - base;
|
||||
Serialize(arc, key, vv, nullptr);
|
||||
value = vv < 0 ? nullptr : base + vv;
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue