// SPDX-FileCopyrightText: 2021 Jorrit Rouwe // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include namespace JPH { /// ObjectStreamIn contains all logic for reading an object from disk. It is the base /// class for the text and binary input streams (ObjectStreamTextIn and ObjectStreamBinaryIn). class ObjectStreamIn : public ObjectStream { private: struct ClassDescription; public: /// Main function to read an object from a stream template static bool sReadObject(istream &inStream, T *&outObject) { // Create the input stream bool result = false; ObjectStreamIn *stream = ObjectStreamIn::Open(inStream); if (stream) { // Read the object outObject = (T *)stream->Read(JPH_RTTI(T)); result = (outObject != nullptr); delete stream; } return result; } /// Main function to read an object from a stream (reference counting pointer version) template static bool sReadObject(istream &inStream, Ref &outObject) { T *object = nullptr; bool result = sReadObject(inStream, object); outObject = object; return result; } /// Main function to read an object from a file template static bool sReadObject(const char *inFileName, T *&outObject) { ifstream stream; stream.open(inFileName, ifstream::in | ifstream::binary); if (!stream.is_open()) return false; return sReadObject(stream, outObject); } /// Main function to read an object from a file (reference counting pointer version) template static bool sReadObject(const char *inFileName, Ref &outObject) { T *object = nullptr; bool result = sReadObject(inFileName, object); outObject = object; return result; } ////////////////////////////////////////////////////// // EVERYTHING BELOW THIS SHOULD NOT DIRECTLY BE CALLED ////////////////////////////////////////////////////// ///@name Serialization operations void * Read(const RTTI *inRTTI); void * ReadObject(const RTTI *& outRTTI); bool ReadRTTI(); bool ReadClassData(const char *inClassName, void *inInstance); bool ReadClassData(const ClassDescription &inClassDesc, void *inInstance); bool ReadPointerData(const RTTI *inRTTI, void **inPointer, int inRefCountOffset = -1); bool SkipAttributeData(int inArrayDepth, EDataType inDataType, const char *inClassName); ///@name Input type specific operations virtual bool ReadDataType(EDataType &outType) = 0; virtual bool ReadName(string &outName) = 0; virtual bool ReadIdentifier(Identifier &outIdentifier) = 0; virtual bool ReadCount(uint32 &outCount) = 0; virtual bool ReadPrimitiveData(uint8 &outPrimitive) = 0; virtual bool ReadPrimitiveData(uint16 &outPrimitive) = 0; virtual bool ReadPrimitiveData(int &outPrimitive) = 0; virtual bool ReadPrimitiveData(uint32 &outPrimitive) = 0; virtual bool ReadPrimitiveData(uint64 &outPrimitive) = 0; virtual bool ReadPrimitiveData(float &outPrimitive) = 0; virtual bool ReadPrimitiveData(bool &outPrimitive) = 0; virtual bool ReadPrimitiveData(string &outPrimitive) = 0; virtual bool ReadPrimitiveData(Float3 &outPrimitive) = 0; virtual bool ReadPrimitiveData(Vec3 &outPrimitive) = 0; virtual bool ReadPrimitiveData(Vec4 &outPrimitive) = 0; virtual bool ReadPrimitiveData(Quat &outPrimitive) = 0; virtual bool ReadPrimitiveData(Mat44 &outPrimitive) = 0; protected: /// Constructor explicit ObjectStreamIn(istream &inStream); /// Determine the type and version of an object stream static bool GetInfo(istream &inStream, EStreamType &outType, int &outVersion, int &outRevision); /// Static constructor static ObjectStreamIn * Open(istream &inStream); istream & mStream; private: /// Class descriptions struct AttributeDescription { AttributeDescription() : mArrayDepth(0), mDataType(EDataType::Invalid), mIndex(-1) { } int mArrayDepth; EDataType mDataType; string mClassName; int mIndex; }; struct ClassDescription { ClassDescription() : mRTTI(nullptr) { } explicit ClassDescription(const RTTI *inRTTI) : mRTTI(inRTTI) { } const RTTI * mRTTI; vector mAttributes; }; struct ObjectInfo { ObjectInfo() : mInstance(nullptr), mRTTI(nullptr) { } ObjectInfo(void *inInstance, const RTTI *inRTTI) : mInstance(inInstance), mRTTI(inRTTI) { } void * mInstance; const RTTI * mRTTI; }; struct Link { void ** mPointer; int mRefCountOffset; Identifier mIdentifier; const RTTI * mRTTI; }; using IdentifierMap = unordered_map; using ClassDescriptionMap = unordered_map; ClassDescriptionMap mClassDescriptionMap; IdentifierMap mIdentifierMap; ///< Links identifier to an object pointer vector mUnresolvedLinks; ///< All pointers (links) are resolved after reading the entire file, e.g. when all object exist }; // Define macro to declare functions for a specific primitive type #define JPH_DECLARE_PRIMITIVE(name) \ bool OSReadData(ObjectStreamIn &ioStream, name &outPrimitive); // This file uses the JPH_DECLARE_PRIMITIVE macro to define all types #include /// Define serialization templates for dynamic arrays template bool OSReadData(ObjectStreamIn &ioStream, vector &inArray) { bool continue_reading = true; // Read array length uint32 array_length; continue_reading = ioStream.ReadCount(array_length); // Read array items if (continue_reading) { inArray.resize(array_length); for (uint32 el = 0; el < array_length && continue_reading; ++el) continue_reading = OSReadData(ioStream, inArray[el]); } return continue_reading; } /// Define serialization templates for static arrays template bool OSReadData(ObjectStreamIn &ioStream, StaticArray &inArray) { bool continue_reading = true; // Read array length uint32 array_length; continue_reading = ioStream.ReadCount(array_length); // Check if we can fit this many elements if (array_length > N) return false; // Read array items if (continue_reading) { inArray.resize(array_length); for (uint32 el = 0; el < array_length && continue_reading; ++el) continue_reading = OSReadData(ioStream, inArray[el]); } return continue_reading; } /// Define serialization templates for C style arrays template bool OSReadData(ObjectStreamIn &ioStream, T (&inArray)[N]) { bool continue_reading = true; // Read array length uint32 array_length; continue_reading = ioStream.ReadCount(array_length); if (array_length != N) return false; // Read array items for (uint32 el = 0; el < N && continue_reading; ++el) continue_reading = OSReadData(ioStream, inArray[el]); return continue_reading; } /// Define serialization templates for references template bool OSReadData(ObjectStreamIn &ioStream, Ref &inRef) { return ioStream.ReadPointerData(JPH_RTTI(T), inRef.InternalGetPointer(), T::sInternalGetRefCountOffset()); } template bool OSReadData(ObjectStreamIn &ioStream, RefConst &inRef) { return ioStream.ReadPointerData(JPH_RTTI(T), inRef.InternalGetPointer(), T::sInternalGetRefCountOffset()); } } // JPH