- moved serializer to 'common'.

This commit is contained in:
Christoph Oelckers 2020-04-11 19:28:30 +02:00
commit f6bd2e4f76
5 changed files with 13 additions and 13 deletions

View 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;
}

File diff suppressed because it is too large Load diff

View 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

View 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;
}