// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #include #include #include #include namespace Nz { /*! * \ingroup core * \brief Computes the hash of a hashable object * \return A bytearray which represents the hash * * \param hash Enumeration of type HashType * \param v Object to hash * * \remark a HashAppend specialization for type T is required * * \see ComputeHash */ template ByteArray ComputeHash(HashType hash, T&& v) { return ComputeHash(*AbstractHash::Get(hash), std::forward(v)); } /*! * \ingroup core * \brief Computes the hash of a hashable object * \return A bytearray which represents the hash * * \param hash Pointer to abstract hash * \param v Object to hash * * \remark Produce a NazaraAssert if pointer to Abstracthash is invalid * \remark a HashAppend specialization for type T is required * * \see ComputeHash */ template ByteArray ComputeHash(AbstractHash& hash, T&& v) { hash.Begin(); HashAppend(hash, std::forward(v)); return hash.End(); } inline bool HashAppend(AbstractHash& hash, const std::string_view& v) { hash.Append(reinterpret_cast(v.data()), v.size()); return true; } template bool Serialize(SerializationContext& context, T&& value) { return Serialize(context, std::forward(value), TypeTag>()); } /*! * \ingroup core * \brief Serializes a boolean * \return true if serialization succeeded * * \param context Context for the serialization * \param value Boolean to serialize * * \see Serialize, Unserialize */ inline bool Serialize(SerializationContext& context, bool value, TypeTag) { if (context.writeBitPos == 8) { context.writeBitPos = 0; context.writeByte = 0; } if (value) context.writeByte |= 1 << context.writeBitPos; if (++context.writeBitPos >= 8) return Serialize(context, context.writeByte, TypeTag()); else return true; } /*! * \ingroup core * \brief Serializes a std::string * \return true if successful * * \param context Context for the serialization * \param value String to serialize */ bool Serialize(SerializationContext& context, const std::string& value, TypeTag) { if (!Serialize(context, UInt32(value.size()), TypeTag())) return false; return context.stream->Write(value.data(), value.size()) == value.size(); } /*! * \ingroup core * \brief Serializes an arithmetic type * \return true if serialization succeeded * * \param context Context for the serialization * \param value Arithmetic type to serialize * * \see Serialize, Unserialize */ template std::enable_if_t::value, bool> Serialize(SerializationContext& context, T value, TypeTag) { // Flush bits in case a writing is in progress context.FlushBits(); if (context.endianness != Endianness::Unknown && context.endianness != GetPlatformEndianness()) SwapBytes(&value, sizeof(T)); return context.stream->Write(&value, sizeof(T)) == sizeof(T); } template bool Unserialize(SerializationContext& context, T* value) { return Unserialize(context, value, TypeTag()); } /*! * \ingroup core * \brief Unserializes a boolean * \return true if unserialization succedeed * * \param context Context for the unserialization * \param value Pointer to boolean to unserialize * * \see Serialize, Unserialize */ inline bool Unserialize(SerializationContext& context, bool* value, TypeTag) { if (context.readBitPos == 8) { if (!Unserialize(context, &context.readByte, TypeTag())) return false; context.readBitPos = 0; } if (value) *value = (context.readByte & (1 << context.readBitPos)) != 0; context.readBitPos++; return true; } /*! * \brief Unserializes a string * \return true if successful * * \param context Context of unserialization * \param string std::string to unserialize */ bool Unserialize(SerializationContext& context, std::string* string, TypeTag) { UInt32 size; if (!Unserialize(context, &size, TypeTag())) return false; string->resize(size); return context.stream->Read(&(*string)[0], size) == size; } /*! * \ingroup core * \brief Unserializes an arithmetic type * \return true if unserialization succedeed * * \param context Context for the unserialization * \param value Pointer to arithmetic type to serialize * * \remark Produce a NazaraAssert if pointer to value is invalid * * \see Serialize, Unserialize */ template std::enable_if_t::value, bool> Unserialize(SerializationContext& context, T* value, TypeTag) { NazaraAssert(value, "Invalid data pointer"); context.ResetReadBitPosition(); if (context.stream->Read(value, sizeof(T)) == sizeof(T)) { if (context.endianness != Endianness::Unknown && context.endianness != GetPlatformEndianness()) SwapBytes(value, sizeof(T)); return true; } else return false; } } #include