#ifndef XNA_CONTENT_READER_HPP #define XNA_CONTENT_READER_HPP #include "../common/color.hpp" #include "../common/numerics.hpp" #include "../csharp/binary.hpp" #include "../csharp/type.hpp" #include "../default.hpp" #include "typereadermanager.hpp" #include namespace xna { class ContentReader : public BinaryReader, public std::enable_shared_from_this { public: static sptr Create(ContentManager* contentManager, sptr& input, String const& assetName); template T ReadAsset(); template T ReadObject(); template T ReadObject(T existingInstance); template T ReadObject(ContentTypeReader& typeReader); template T ReadObject(ContentTypeReader& typeReader, T existingInstance); Vector2 ReadVector2(); Vector3 ReadVector3(); Vector4 ReadVector4(); Matrix ReadMatrix(); Quaternion ReadQuaternion(); Color ReadColor(); float ReadSingle(); double ReadDouble(); std::vector ReadByteBuffer(size_t size, xna_error_nullarg); private: ContentReader(ContentManager* contentManager, sptr& input, String const& assetName, Int graphicsProfile) : BinaryReader(input), _contentManager(contentManager), _assetName(assetName) {} static sptr PrepareStream(sptr& input, String const& assetName, Int& graphicsProfile); Int ReadHeader(); template T ReadObjectInternal(std::any& existingInstance, xna_error_nullarg); template T ReadObjectInternal(ContentTypeReader& typeReader, std::any& existingInstance, xna_error_nullarg); template T InvokeReader(ContentTypeReader& reader, std::any& existingInstance, xna_error_nullarg); private: ContentManager* _contentManager = nullptr; String _assetName; std::vector> typeReaders; Int graphicsProfile{ 0 }; static constexpr Ushort XnbVersionProfileMask = 32512; static constexpr Ushort XnbCompressedVersion = 32773; static constexpr Ushort XnbVersion = 5; static constexpr Int XnbVersionProfileShift = 8; }; template inline T ContentReader::ReadObjectInternal(std::any& existingInstance, xna_error_ptr_arg) { const auto num = Read7BitEncodedInt(); if (num == 0) { return T(); } const auto index = num - 1; if (index >= typeReaders.size()) { xna_error_apply(err, XnaErrorCode::ARGUMENT_OUT_OF_RANGE); return T(); } auto reader = typeReaders[index]; //Verificação necessária pois a depender da situação é encontrado um reader errado auto typeT = typeof(); auto typeThash = typeT->GetHashCode(); auto readerType = reader->TargetType(); if (readerType->GetHashCode() != typeThash) { for (auto const& item : typeReaders) { if (item->TargetType()->GetHashCode() == typeThash) { reader = item; break; } } if(reader->TargetType()->GetHashCode() != typeThash) throw std::runtime_error("ContentReader::ReadObjectInternal: wrong reader!"); } return InvokeReader(*reader, existingInstance, err); } template inline T ContentReader::InvokeReader(ContentTypeReader& reader, std::any& existingInstance, xna_error_ptr_arg) { auto contentTypeReader = reinterpret_cast*>(&reader); T objB; if (contentTypeReader) { auto existingInstance1 = existingInstance.has_value() ? std::any_cast(existingInstance) : T(); objB = contentTypeReader->Read(*this, existingInstance1); return objB; } return T(); } template inline T ContentReader::ReadAsset() { const auto sharedResourceCount = ReadHeader(); auto obj = ReadObject(); return obj; } template inline T ContentReader::ReadObject() { auto a = std::any(); return ReadObjectInternal(a); } template inline T ContentReader::ReadObject(T existingInstance) { return ReadObjectInternal(std::any(existingInstance)); } template inline T ContentReader::ReadObject(ContentTypeReader& typeReader) { auto obj = std::any(); return ReadObjectInternal(typeReader, obj); } template inline T ContentReader::ReadObject(ContentTypeReader& typeReader, T existingInstance) { return ReadObjectInternal(typeReader, std::any(existingInstance)); } template inline T ContentReader::ReadObjectInternal(ContentTypeReader& typeReader, std::any& existingInstance, xna_error_ptr_arg) { return typeReader.TargetIsValueType ? InvokeReader(typeReader, existingInstance, err) : ReadObjectInternal(existingInstance, err); } } #endif