From eeb63b8901a9c049f1bb594abb9ce9b4a9c47620 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 11 Jan 2021 16:39:43 +0000 Subject: zlib -> libdeflate (#5085) + Use libdeflate + Use std::byte * Fix passing temporary to string_view + Emulate make_unique_for_overwrite --- src/WorldStorage/FastNBT.cpp | 78 +++++++------- src/WorldStorage/FastNBT.h | 48 ++++----- src/WorldStorage/FireworksSerializer.cpp | 4 +- src/WorldStorage/MapSerializer.cpp | 53 ++-------- src/WorldStorage/NBTChunkSerializer.cpp | 10 +- src/WorldStorage/NBTChunkSerializer.h | 5 +- src/WorldStorage/SchematicFileSerializer.cpp | 115 +++++---------------- src/WorldStorage/SchematicFileSerializer.h | 33 +++--- src/WorldStorage/ScoreboardSerializer.cpp | 55 +++------- src/WorldStorage/WSSAnvil.cpp | 147 +++++++++++---------------- src/WorldStorage/WSSAnvil.h | 35 +++---- 11 files changed, 201 insertions(+), 382 deletions(-) (limited to 'src/WorldStorage') diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp index ec43d2f12..d5b9fd0f7 100644 --- a/src/WorldStorage/FastNBT.cpp +++ b/src/WorldStorage/FastNBT.cpp @@ -137,7 +137,7 @@ std::error_code make_error_code(eNBTParseError a_Err) noexcept #define NEEDBYTES(N, ERR) \ do { \ - if (m_Length - m_Pos < static_cast(N)) \ + if (m_Data.size() - m_Pos < static_cast(N)) \ { \ return ERR; \ } \ @@ -147,9 +147,8 @@ std::error_code make_error_code(eNBTParseError a_Err) noexcept -cParsedNBT::cParsedNBT(const char * a_Data, size_t a_Length) : +cParsedNBT::cParsedNBT(const ContiguousByteBufferView a_Data) : m_Data(a_Data), - m_Length(a_Length), m_Pos(0) { m_Error = Parse(); @@ -161,12 +160,12 @@ cParsedNBT::cParsedNBT(const char * a_Data, size_t a_Length) : eNBTParseError cParsedNBT::Parse(void) { - if (m_Length < 3) + if (m_Data.size() < 3) { // Data too short return eNBTParseError::npNeedBytes; } - if (m_Data[0] != TAG_Compound) + if (m_Data[0] != std::byte(TAG_Compound)) { // The top-level tag must be a Compound return eNBTParseError::npNoTopLevelCompound; @@ -190,7 +189,7 @@ eNBTParseError cParsedNBT::ReadString(size_t & a_StringStart, size_t & a_StringL { NEEDBYTES(2, eNBTParseError::npStringMissingLength); a_StringStart = m_Pos + 2; - a_StringLen = static_cast(GetBEShort(m_Data + m_Pos)); + a_StringLen = static_cast(GetBEShort(m_Data.data() + m_Pos)); NEEDBYTES(2 + a_StringLen, eNBTParseError::npStringInvalidLength); m_Pos += 2 + a_StringLen; return eNBTParseError::npSuccess; @@ -210,8 +209,8 @@ eNBTParseError cParsedNBT::ReadCompound(void) for (;;) { NEEDBYTES(1, eNBTParseError::npCompoundImbalancedTag); - const char TagTypeNum = m_Data[m_Pos]; - if ((TagTypeNum < TAG_Min) || (TagTypeNum > TAG_Max)) + const auto TagTypeNum = m_Data[m_Pos]; + if ((TagTypeNum < std::byte(TAG_Min)) || (TagTypeNum > std::byte(TAG_Max))) { return eNBTParseError::npUnknownTag; } @@ -248,10 +247,10 @@ eNBTParseError cParsedNBT::ReadList(eTagType a_ChildrenType) // Read the count: NEEDBYTES(4, eNBTParseError::npListMissingLength); - int Count = GetBEInt(m_Data + m_Pos); + int Count = GetBEInt(m_Data.data() + m_Pos); m_Pos += 4; auto MinChildSize = GetMinTagSize(a_ChildrenType); - if ((Count < 0) || (Count > static_cast((m_Length - m_Pos) / MinChildSize))) + if ((Count < 0) || (Count > static_cast((m_Data.size() - m_Pos) / MinChildSize))) { return eNBTParseError::npListInvalidLength; } @@ -312,7 +311,7 @@ eNBTParseError cParsedNBT::ReadTag(void) case TAG_ByteArray: { NEEDBYTES(4, eNBTParseError::npArrayMissingLength); - int len = GetBEInt(m_Data + m_Pos); + int len = GetBEInt(m_Data.data() + m_Pos); m_Pos += 4; if (len < 0) { @@ -344,7 +343,7 @@ eNBTParseError cParsedNBT::ReadTag(void) case TAG_IntArray: { NEEDBYTES(4, eNBTParseError::npArrayMissingLength); - int len = GetBEInt(m_Data + m_Pos); + int len = GetBEInt(m_Data.data() + m_Pos); m_Pos += 4; if (len < 0) { @@ -392,7 +391,7 @@ int cParsedNBT::FindChildByName(int a_Tag, const char * a_Name, size_t a_NameLen { if ( (m_Tags[static_cast(Child)].m_NameLength == a_NameLength) && - (memcmp(m_Data + m_Tags[static_cast(Child)].m_NameStart, a_Name, a_NameLength) == 0) + (memcmp(m_Data.data() + m_Tags[static_cast(Child)].m_NameStart, a_Name, a_NameLength) == 0) ) { return Child; @@ -470,9 +469,9 @@ cFastNBTWriter::cFastNBTWriter(const AString & a_RootTagName) : m_CurrentStack(0) { m_Stack[0].m_Type = TAG_Compound; - m_Result.reserve(100 * 1024); - m_Result.push_back(TAG_Compound); - WriteString(a_RootTagName.data(), static_cast(a_RootTagName.size())); + m_Result.reserve(100 KiB); + m_Result.push_back(std::byte(TAG_Compound)); + WriteString(a_RootTagName); } @@ -502,7 +501,7 @@ void cFastNBTWriter::EndCompound(void) ASSERT(m_CurrentStack > 0); ASSERT(IsStackTopCompound()); - m_Result.push_back(TAG_End); + m_Result.push_back(std::byte(TAG_End)); --m_CurrentStack; } @@ -520,8 +519,8 @@ void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType) TagCommon(a_Name, TAG_List); - m_Result.push_back(static_cast(a_ChildrenType)); - m_Result.append(4, static_cast(0)); + m_Result.push_back(std::byte(a_ChildrenType)); + m_Result.append(4, std::byte(0)); ++m_CurrentStack; m_Stack[m_CurrentStack].m_Type = TAG_List; @@ -540,7 +539,7 @@ void cFastNBTWriter::EndList(void) ASSERT(m_Stack[m_CurrentStack].m_Type == TAG_List); // Update the list count: - SetBEInt(const_cast(m_Result.c_str() + m_Stack[m_CurrentStack].m_Pos), m_Stack[m_CurrentStack].m_Count); + SetBEInt(m_Result.data() + m_Stack[m_CurrentStack].m_Pos, m_Stack[m_CurrentStack].m_Count); --m_CurrentStack; } @@ -552,7 +551,7 @@ void cFastNBTWriter::EndList(void) void cFastNBTWriter::AddByte(const AString & a_Name, unsigned char a_Value) { TagCommon(a_Name, TAG_Byte); - m_Result.push_back(static_cast(a_Value)); + m_Result.push_back(std::byte(a_Value)); } @@ -563,7 +562,7 @@ void cFastNBTWriter::AddShort(const AString & a_Name, Int16 a_Value) { TagCommon(a_Name, TAG_Short); UInt16 Value = htons(static_cast(a_Value)); - m_Result.append(reinterpret_cast(&Value), 2); + m_Result.append(reinterpret_cast(&Value), 2); } @@ -574,7 +573,7 @@ void cFastNBTWriter::AddInt(const AString & a_Name, Int32 a_Value) { TagCommon(a_Name, TAG_Int); UInt32 Value = htonl(static_cast(a_Value)); - m_Result.append(reinterpret_cast(&Value), 4); + m_Result.append(reinterpret_cast(&Value), 4); } @@ -585,7 +584,7 @@ void cFastNBTWriter::AddLong(const AString & a_Name, Int64 a_Value) { TagCommon(a_Name, TAG_Long); UInt64 Value = HostToNetwork8(&a_Value); - m_Result.append(reinterpret_cast(&Value), 8); + m_Result.append(reinterpret_cast(&Value), 8); } @@ -596,7 +595,7 @@ void cFastNBTWriter::AddFloat(const AString & a_Name, float a_Value) { TagCommon(a_Name, TAG_Float); UInt32 Value = HostToNetwork4(&a_Value); - m_Result.append(reinterpret_cast(&Value), 4); + m_Result.append(reinterpret_cast(&Value), 4); } @@ -607,7 +606,7 @@ void cFastNBTWriter::AddDouble(const AString & a_Name, double a_Value) { TagCommon(a_Name, TAG_Double); UInt64 Value = HostToNetwork8(&a_Value); - m_Result.append(reinterpret_cast(&Value), 8); + m_Result.append(reinterpret_cast(&Value), 8); } @@ -618,8 +617,8 @@ void cFastNBTWriter::AddString(const AString & a_Name, const std::string_view a_ { TagCommon(a_Name, TAG_String); const UInt16 Length = htons(static_cast(a_Value.size())); - m_Result.append(reinterpret_cast(&Length), sizeof(Length)); - m_Result.append(a_Value); + m_Result.append(reinterpret_cast(&Length), sizeof(Length)); + m_Result.append({ reinterpret_cast(a_Value.data()), a_Value.size() }); } @@ -630,8 +629,8 @@ void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, { TagCommon(a_Name, TAG_ByteArray); UInt32 len = htonl(static_cast(a_NumElements)); - m_Result.append(reinterpret_cast(&len), 4); - m_Result.append(a_Value, a_NumElements); + m_Result.append(reinterpret_cast(&len), 4); + m_Result.append(reinterpret_cast(a_Value), a_NumElements); } @@ -648,11 +647,11 @@ void cFastNBTWriter::AddIntArray(const AString & a_Name, const Int32 * a_Value, { m_Result.reserve(size + 4 + (a_NumElements * 4)); } - m_Result.append(reinterpret_cast(&len), 4); + m_Result.append(reinterpret_cast(&len), sizeof(len)); for (size_t i = 0; i < a_NumElements; i++) { UInt32 Element = htonl(static_cast(a_Value[i])); - m_Result.append(reinterpret_cast(&Element), 4); + m_Result.append(reinterpret_cast(&Element), sizeof(Element)); } } @@ -663,20 +662,17 @@ void cFastNBTWriter::AddIntArray(const AString & a_Name, const Int32 * a_Value, void cFastNBTWriter::Finish(void) { ASSERT(m_CurrentStack == 0); - m_Result.push_back(TAG_End); + m_Result.push_back(std::byte(TAG_End)); } -void cFastNBTWriter::WriteString(const char * a_Data, UInt16 a_Length) +void cFastNBTWriter::WriteString(const std::string_view a_Data) { - UInt16 Len = htons(a_Length); - m_Result.append(reinterpret_cast(&Len), 2); - m_Result.append(a_Data, a_Length); + // TODO check size <= short max + UInt16 Len = htons(static_cast(a_Data.size())); + m_Result.append(reinterpret_cast(&Len), sizeof(Len)); + m_Result.append(reinterpret_cast(a_Data.data()), a_Data.size()); } - - - - diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h index 257115fe1..0df520e21 100644 --- a/src/WorldStorage/FastNBT.h +++ b/src/WorldStorage/FastNBT.h @@ -152,7 +152,7 @@ Each primitive tag also stores the length of the contained data, in bytes. class cParsedNBT { public: - cParsedNBT(const char * a_Data, size_t a_Length); + cParsedNBT(ContiguousByteBufferView a_Data); bool IsValid(void) const { return (m_Error == eNBTParseError::npSuccess); } @@ -179,7 +179,7 @@ public: /** Returns the length of the tag's data, in bytes. Not valid for Compound or List tags! */ - size_t GetDataLength (int a_Tag) const + size_t GetDataLength(int a_Tag) const { ASSERT(m_Tags[static_cast(a_Tag)].m_Type != TAG_List); ASSERT(m_Tags[static_cast(a_Tag)].m_Type != TAG_Compound); @@ -188,11 +188,11 @@ public: /** Returns the data stored in this tag. Not valid for Compound or List tags! */ - const char * GetData(int a_Tag) const + const std::byte * GetData(int a_Tag) const { ASSERT(m_Tags[static_cast(a_Tag)].m_Type != TAG_List); ASSERT(m_Tags[static_cast(a_Tag)].m_Type != TAG_Compound); - return m_Data + m_Tags[static_cast(a_Tag)].m_DataStart; + return m_Data.data() + m_Tags[static_cast(a_Tag)].m_DataStart; } /** Returns the direct child tag of the specified name, or -1 if no such tag. */ @@ -227,21 +227,21 @@ public: inline Int16 GetShort(int a_Tag) const { ASSERT(m_Tags[static_cast(a_Tag)].m_Type == TAG_Short); - return GetBEShort(m_Data + m_Tags[static_cast(a_Tag)].m_DataStart); + return GetBEShort(GetData(a_Tag)); } /** Returns the value stored in an Int tag. Not valid for any other tag type. */ inline Int32 GetInt(int a_Tag) const { ASSERT(m_Tags[static_cast(a_Tag)].m_Type == TAG_Int); - return GetBEInt(m_Data + m_Tags[static_cast(a_Tag)].m_DataStart); + return GetBEInt(GetData(a_Tag)); } /** Returns the value stored in a Long tag. Not valid for any other tag type. */ inline Int64 GetLong(int a_Tag) const { ASSERT(m_Tags[static_cast(a_Tag)].m_Type == TAG_Long); - return NetworkToHostLong8(m_Data + m_Tags[static_cast(a_Tag)].m_DataStart); + return NetworkToHostLong8(GetData(a_Tag)); } /** Returns the value stored in a Float tag. Not valid for any other tag type. */ @@ -256,7 +256,7 @@ public: UNUSED_VAR(Check1); UNUSED_VAR(Check2); - Int32 i = GetBEInt(m_Data + m_Tags[static_cast(a_Tag)].m_DataStart); + Int32 i = GetBEInt(GetData(a_Tag)); float f; memcpy(&f, &i, sizeof(f)); return f; @@ -273,29 +273,33 @@ public: UNUSED_VAR(Check2); ASSERT(m_Tags[static_cast(a_Tag)].m_Type == TAG_Double); - return NetworkToHostDouble8(m_Data + m_Tags[static_cast(a_Tag)].m_DataStart); + return NetworkToHostDouble8(GetData(a_Tag)); } /** Returns the value stored in a String tag. Not valid for any other tag type. */ inline AString GetString(int a_Tag) const + { + return AString(GetStringView(a_Tag)); + } + + /** Returns the value stored in a String tag. Not valid for any other tag type. */ + inline std::string_view GetStringView(int a_Tag) const { ASSERT(m_Tags[static_cast(a_Tag)].m_Type == TAG_String); - AString res; - res.assign(m_Data + m_Tags[static_cast(a_Tag)].m_DataStart, static_cast(m_Tags[static_cast(a_Tag)].m_DataLength)); - return res; + return { reinterpret_cast(GetData(a_Tag)), GetDataLength(a_Tag) }; } /** Returns the tag's name. For tags that are not named, returns an empty string. */ inline AString GetName(int a_Tag) const { AString res; - res.assign(m_Data + m_Tags[static_cast(a_Tag)].m_NameStart, static_cast(m_Tags[static_cast(a_Tag)].m_NameLength)); + res.assign(reinterpret_cast(m_Data.data()) + m_Tags[static_cast(a_Tag)].m_NameStart, static_cast(m_Tags[static_cast(a_Tag)].m_NameLength)); return res; } protected: - const char * m_Data; - size_t m_Length; + + ContiguousByteBufferView m_Data; std::vector m_Tags; eNBTParseError m_Error; // npSuccess if parsing succeeded @@ -343,7 +347,7 @@ public: AddByteArray(a_Name, a_Value.data(), a_Value.size()); } - const AString & GetResult(void) const {return m_Result; } + ContiguousByteBufferView GetResult(void) const { return m_Result; } void Finish(void); @@ -363,11 +367,11 @@ protected: sParent m_Stack[MAX_STACK]; int m_CurrentStack; - AString m_Result; + ContiguousByteBuffer m_Result; bool IsStackTopCompound(void) const { return (m_Stack[m_CurrentStack].m_Type == TAG_Compound); } - void WriteString(const char * a_Data, UInt16 a_Length); + void WriteString(std::string_view a_Data); inline void TagCommon(const AString & a_Name, eTagType a_Type) { @@ -377,8 +381,8 @@ protected: if (IsStackTopCompound()) { // Compound: add the type and name: - m_Result.push_back(static_cast(a_Type)); - WriteString(a_Name.c_str(), static_cast(a_Name.length())); + m_Result.push_back(std::byte(a_Type)); + WriteString(a_Name); } else { @@ -387,7 +391,3 @@ protected: } } } ; - - - - diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp index 7cf3c3eea..fa411b4e9 100644 --- a/src/WorldStorage/FireworksSerializer.cpp +++ b/src/WorldStorage/FireworksSerializer.cpp @@ -105,7 +105,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB continue; } - const char * ColourData = (a_NBT.GetData(explosiontag)); + const auto * ColourData = (a_NBT.GetData(explosiontag)); for (size_t i = 0; i < DataLength; i += 4) { a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i)); @@ -121,7 +121,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB continue; } - const char * FadeColourData = (a_NBT.GetData(explosiontag)); + const auto * FadeColourData = (a_NBT.GetData(explosiontag)); for (size_t i = 0; i < DataLength; i += 4) { a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i)); diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp index d030b5a32..40d428dab 100644 --- a/src/WorldStorage/MapSerializer.cpp +++ b/src/WorldStorage/MapSerializer.cpp @@ -4,8 +4,7 @@ #include "Globals.h" #include "MapSerializer.h" -#include "../StringCompression.h" -#include "zlib/zlib.h" +#include "OSSupport/GZipFile.h" #include "FastNBT.h" #include "../Map.h" @@ -32,22 +31,9 @@ cMapSerializer::cMapSerializer(const AString & a_WorldName, cMap * a_Map): bool cMapSerializer::Load(void) { - AString Data = cFile::ReadWholeFile(m_Path); - if (Data.empty()) - { - return false; - } + const auto Data = GZipFile::ReadRestOfFile(m_Path); + const cParsedNBT NBT(Data.GetView()); - AString Uncompressed; - int res = UncompressStringGZIP(Data.data(), Data.size(), Uncompressed); - - if (res != Z_OK) - { - return false; - } - - // Parse the NBT data: - cParsedNBT NBT(Uncompressed.data(), Uncompressed.size()); if (!NBT.IsValid()) { // NBT Parsing failed @@ -64,32 +50,15 @@ bool cMapSerializer::Load(void) bool cMapSerializer::Save(void) { cFastNBTWriter Writer; - SaveMapToNBT(Writer); - Writer.Finish(); #ifdef _DEBUG - cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size()); + cParsedNBT TestParse(Writer.GetResult()); ASSERT(TestParse.IsValid()); #endif // _DEBUG - cFile File; - if (!File.Open(m_Path, cFile::fmWrite)) - { - return false; - } - - AString Compressed; - int res = CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - - if (res != Z_OK) - { - return false; - } - - File.Write(Compressed.data(), Compressed.size()); - File.Close(); + GZipFile::Write(m_Path, Writer.GetResult()); return true; } @@ -225,7 +194,7 @@ bool cIDCountSerializer::Load(void) // NOTE: idcounts.dat is not compressed (raw format) // Parse the NBT data: - cParsedNBT NBT(Data.data(), Data.size()); + cParsedNBT NBT({ reinterpret_cast(Data.data()), Data.size() }); if (!NBT.IsValid()) { // NBT Parsing failed @@ -261,7 +230,7 @@ bool cIDCountSerializer::Save(void) Writer.Finish(); #ifdef _DEBUG - cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size()); + cParsedNBT TestParse(Writer.GetResult()); ASSERT(TestParse.IsValid()); #endif // _DEBUG @@ -278,11 +247,3 @@ bool cIDCountSerializer::Save(void) return true; } - - - - - - - - diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 0e3cdde76..2542cd2da 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -1177,17 +1177,14 @@ public: //////////////////////////////////////////////////////////////////////////////// // NBTChunkSerializer: -bool NBTChunkSerializer::serialize(const cWorld & aWorld, cChunkCoords aCoords, cFastNBTWriter & aWriter) +void NBTChunkSerializer::Serialize(const cWorld & aWorld, cChunkCoords aCoords, cFastNBTWriter & aWriter) { SerializerCollector serializer(aWriter); aWriter.BeginCompound("Level"); aWriter.AddInt("xPos", aCoords.m_ChunkX); aWriter.AddInt("zPos", aCoords.m_ChunkZ); - if (!aWorld.GetChunkData(aCoords, serializer)) - { - aWriter.EndCompound(); // "Level" - return false; - } + [[maybe_unused]] const bool Result = aWorld.GetChunkData(aCoords, serializer); // Chunk must be present in order to save + ASSERT(Result); serializer.Finish(); // Close NBT tags // Save biomes, both MCS (IntArray) and MC-vanilla (ByteArray): @@ -1240,5 +1237,4 @@ bool NBTChunkSerializer::serialize(const cWorld & aWorld, cChunkCoords aCoords, aWriter.AddByte("TerrainPopulated", 1); aWriter.EndCompound(); // "Level" - return true; } diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h index aeac9fc46..c2de79269 100644 --- a/src/WorldStorage/NBTChunkSerializer.h +++ b/src/WorldStorage/NBTChunkSerializer.h @@ -21,7 +21,6 @@ class NBTChunkSerializer { public: - /** Serializes the chunk into the specified writer. - Returns true on success, false on failure (chunk not present etc.) */ - static bool serialize(const cWorld & aWorld, cChunkCoords aCoords, cFastNBTWriter & aWriter); + /** Serializes the chunk into the specified writer. The chunk must be present. */ + static void Serialize(const cWorld & aWorld, cChunkCoords aCoords, cFastNBTWriter & aWriter); }; diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp index 44ce7ca9b..656a98709 100644 --- a/src/WorldStorage/SchematicFileSerializer.cpp +++ b/src/WorldStorage/SchematicFileSerializer.cpp @@ -7,7 +7,6 @@ #include "FastNBT.h" #include "SchematicFileSerializer.h" -#include "../StringCompression.h" #include "../OSSupport/GZipFile.h" @@ -17,118 +16,59 @@ //////////////////////////////////////////////////////////////////////////////// // cSchematicFileSerializer: -bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName) +void cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const std::string & a_FileName) { - // Un-GZip the contents: - AString Contents; - cGZipFile File; - if (!File.Open(a_FileName, cGZipFile::fmRead)) - { - LOG("Cannot open the schematic file \"%s\".", a_FileName.c_str()); - return false; - } - int NumBytesRead = File.ReadRestOfFile(Contents); - if (NumBytesRead < 0) - { - LOG("Cannot read GZipped data in the schematic file \"%s\", error %d", a_FileName.c_str(), NumBytesRead); - return false; - } - File.Close(); + const auto Data = GZipFile::ReadRestOfFile(a_FileName); + const cParsedNBT NBT(Data.GetView()); - // Parse the NBT: - cParsedNBT NBT(Contents.data(), Contents.size()); if (!NBT.IsValid()) { - LOG("Cannot parse the NBT in the schematic file \"%s\".", a_FileName.c_str()); - return false; + throw std::runtime_error(fmt::format("Cannot parse the NBT in the schematic file \"{}\".", a_FileName)); } - return LoadFromSchematicNBT(a_BlockArea, NBT); + LoadFromSchematicNBT(a_BlockArea, NBT); } -bool cSchematicFileSerializer::LoadFromSchematicString(cBlockArea & a_BlockArea, const AString & a_SchematicData) +void cSchematicFileSerializer::LoadFromSchematicString(cBlockArea & a_BlockArea, const ContiguousByteBufferView a_SchematicData) { - // Uncompress the data: - AString UngzippedData; - if (UncompressStringGZIP(a_SchematicData.data(), a_SchematicData.size(), UngzippedData) != Z_OK) - { - LOG("%s: Cannot unGZip the schematic data.", __FUNCTION__); - return false; - } + const auto Extracted = Compression::Extractor().ExtractGZip(a_SchematicData); + const cParsedNBT NBT(Extracted.GetView()); - // Parse the NBT: - cParsedNBT NBT(UngzippedData.data(), UngzippedData.size()); if (!NBT.IsValid()) { - LOG("%s: Cannot parse the NBT in the schematic data.", __FUNCTION__); - return false; + throw std::runtime_error("Cannot parse the NBT in the schematic data."); } - return LoadFromSchematicNBT(a_BlockArea, NBT); + LoadFromSchematicNBT(a_BlockArea, NBT); } -bool cSchematicFileSerializer::SaveToSchematicFile(const cBlockArea & a_BlockArea, const AString & a_FileName) +void cSchematicFileSerializer::SaveToSchematicFile(const cBlockArea & a_BlockArea, const std::string & a_FileName) { - // Serialize into NBT data: - AString NBT = SaveToSchematicNBT(a_BlockArea); - if (NBT.empty()) - { - LOG("%s: Cannot serialize the area into an NBT representation for file \"%s\".", __FUNCTION__, a_FileName.c_str()); - return false; - } - - // Save to file - cGZipFile File; - if (!File.Open(a_FileName, cGZipFile::fmWrite)) - { - LOG("%s: Cannot open file \"%s\" for writing.", __FUNCTION__, a_FileName.c_str()); - return false; - } - if (!File.Write(NBT)) - { - LOG("%s: Cannot write data to file \"%s\".", __FUNCTION__, a_FileName.c_str()); - return false; - } - return true; + GZipFile::Write(a_FileName, SaveToSchematicNBT(a_BlockArea)); } -bool cSchematicFileSerializer::SaveToSchematicString(const cBlockArea & a_BlockArea, AString & a_Out) +Compression::Result cSchematicFileSerializer::SaveToSchematicString(const cBlockArea & a_BlockArea) { - // Serialize into NBT data: - AString NBT = SaveToSchematicNBT(a_BlockArea); - if (NBT.empty()) - { - LOG("%s: Cannot serialize the area into an NBT representation.", __FUNCTION__); - return false; - } - - // Gzip the data: - int res = CompressStringGZIP(NBT.data(), NBT.size(), a_Out); - if (res != Z_OK) - { - LOG("%s: Cannot Gzip the area data NBT representation: %d", __FUNCTION__, res); - return false; - } - return true; + return Compression::Compressor().CompressGZip(SaveToSchematicNBT(a_BlockArea)); } -bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT) +void cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, const cParsedNBT & a_NBT) { int TMaterials = a_NBT.FindChildByName(a_NBT.GetRoot(), "Materials"); if ((TMaterials > 0) && (a_NBT.GetType(TMaterials) == TAG_String)) @@ -136,8 +76,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP AString Materials = a_NBT.GetString(TMaterials); if (Materials.compare("Alpha") != 0) { - LOG("Materials tag is present and \"%s\" instead of \"Alpha\". Possibly a wrong-format schematic file.", Materials.c_str()); - return false; + throw std::runtime_error(fmt::format("Materials tag is present and \"{}\" instead of \"Alpha\". Possibly a wrong-format schematic file.", Materials)); } } int TSizeX = a_NBT.FindChildByName(a_NBT.GetRoot(), "Width"); @@ -150,13 +89,13 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP (a_NBT.GetType(TSizeZ) != TAG_Short) ) { - LOG("Dimensions are missing from the schematic file (%d, %d, %d), (%d, %d, %d)", + throw std::runtime_error(fmt::format( + "Dimensions are missing from the schematic file ({}, {}, {}), ({}, {}, {})", TSizeX, TSizeY, TSizeZ, (TSizeX >= 0) ? a_NBT.GetType(TSizeX) : -1, (TSizeY >= 0) ? a_NBT.GetType(TSizeY) : -1, (TSizeZ >= 0) ? a_NBT.GetType(TSizeZ) : -1 - ); - return false; + )); } int SizeX = a_NBT.GetShort(TSizeX); @@ -164,16 +103,14 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP int SizeZ = a_NBT.GetShort(TSizeZ); if ((SizeX < 1) || (SizeX > 65535) || (SizeY < 1) || (SizeY > 65535) || (SizeZ < 1) || (SizeZ > 65535)) { - LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ); - return false; + throw std::runtime_error(fmt::format("Dimensions are invalid in the schematic file: {}, {}, {}", SizeX, SizeY, SizeZ)); } int TBlockTypes = a_NBT.FindChildByName(a_NBT.GetRoot(), "Blocks"); int TBlockMetas = a_NBT.FindChildByName(a_NBT.GetRoot(), "Data"); if ((TBlockTypes < 0) || (a_NBT.GetType(TBlockTypes) != TAG_ByteArray)) { - LOG("BlockTypes are invalid in the schematic file: %d", TBlockTypes); - return false; + throw std::runtime_error(fmt::format("BlockTypes are invalid in the schematic file: {}", TBlockTypes)); } bool AreMetasPresent = (TBlockMetas > 0) && (a_NBT.GetType(TBlockMetas) == TAG_ByteArray); @@ -222,15 +159,13 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP } memcpy(a_BlockArea.GetBlockMetas(), a_NBT.GetData(TBlockMetas), NumMetaBytes); } - - return true; } -AString cSchematicFileSerializer::SaveToSchematicNBT(const cBlockArea & a_BlockArea) +ContiguousByteBuffer cSchematicFileSerializer::SaveToSchematicNBT(const cBlockArea & a_BlockArea) { cFastNBTWriter Writer("Schematic"); Writer.AddShort("Width", static_cast(a_BlockArea.m_Size.x)); @@ -267,9 +202,5 @@ AString cSchematicFileSerializer::SaveToSchematicNBT(const cBlockArea & a_BlockA Writer.EndList(); Writer.Finish(); - return Writer.GetResult(); + return ContiguousByteBuffer(Writer.GetResult()); } - - - - diff --git a/src/WorldStorage/SchematicFileSerializer.h b/src/WorldStorage/SchematicFileSerializer.h index 6aaa0662f..d52f80da1 100644 --- a/src/WorldStorage/SchematicFileSerializer.h +++ b/src/WorldStorage/SchematicFileSerializer.h @@ -10,6 +10,7 @@ #pragma once #include "../BlockArea.h" +#include "../StringCompression.h" @@ -26,29 +27,23 @@ class cSchematicFileSerializer { public: - /** Loads an area from a .schematic file. Returns true if successful. */ - static bool LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName); + /** Loads an area from a .schematic file. */ + static void LoadFromSchematicFile(cBlockArea & a_BlockArea, const std::string & a_FileName); - /** Loads an area from a string containing the .schematic file data. Returns true if successful. */ - static bool LoadFromSchematicString(cBlockArea & a_BlockArea, const AString & a_SchematicData); + /** Loads an area from a string containing the .schematic file data. */ + static void LoadFromSchematicString(cBlockArea & a_BlockArea, ContiguousByteBufferView a_SchematicData); - /** Saves the area into a .schematic file. Returns true if successful. */ - static bool SaveToSchematicFile(const cBlockArea & a_BlockArea, const AString & a_FileName); + /** Saves the area into a .schematic file. */ + static void SaveToSchematicFile(const cBlockArea & a_BlockArea, const std::string & a_FileName); - /** Saves the area into a string containing the .schematic file data. - Returns true if successful, false on failure. The data is stored into a_Out. */ - static bool SaveToSchematicString(const cBlockArea & a_BlockArea, AString & a_Out); + /** Saves the area into a string containing the .schematic file data. */ + static Compression::Result SaveToSchematicString(const cBlockArea & a_BlockArea); private: - /** Loads the area from a schematic file uncompressed and parsed into a NBT tree. - Returns true if successful. */ - static bool LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT); - - /** Saves the area into a NBT representation and returns the NBT data as a string. - Returns an empty string if failed. */ - static AString SaveToSchematicNBT(const cBlockArea & a_BlockArea); -}; - - + /** Loads the area from a schematic file uncompressed and parsed into a NBT tree. */ + static void LoadFromSchematicNBT(cBlockArea & a_BlockArea, const cParsedNBT & a_NBT); + /** Saves the area into a NBT representation and returns the NBT data as a string. */ + static ContiguousByteBuffer SaveToSchematicNBT(const cBlockArea & a_BlockArea); +}; diff --git a/src/WorldStorage/ScoreboardSerializer.cpp b/src/WorldStorage/ScoreboardSerializer.cpp index 7b41f92b1..3ad4d42ee 100644 --- a/src/WorldStorage/ScoreboardSerializer.cpp +++ b/src/WorldStorage/ScoreboardSerializer.cpp @@ -4,8 +4,7 @@ #include "Globals.h" #include "ScoreboardSerializer.h" -#include "../StringCompression.h" -#include "zlib/zlib.h" +#include "OSSupport/GZipFile.h" #include "FastNBT.h" #include "../Scoreboard.h" @@ -31,29 +30,24 @@ cScoreboardSerializer::cScoreboardSerializer(const AString & a_WorldName, cScore bool cScoreboardSerializer::Load(void) { - AString Data = cFile::ReadWholeFile(m_Path); - if (Data.empty()) + try { - return false; - } + const auto Data = GZipFile::ReadRestOfFile(m_Path); + const cParsedNBT NBT(Data.GetView()); - AString Uncompressed; - int res = UncompressStringGZIP(Data.data(), Data.size(), Uncompressed); + if (!NBT.IsValid()) + { + // NBT Parsing failed + return false; + } - if (res != Z_OK) - { - return false; + return LoadScoreboardFromNBT(NBT); } - - // Parse the NBT data: - cParsedNBT NBT(Uncompressed.data(), Uncompressed.size()); - if (!NBT.IsValid()) + catch (const std::exception & Oops) { - // NBT Parsing failed + LOGWARNING("Failed to load scoreboard from \"%s\": %s", m_Path.c_str(), Oops.what()); return false; } - - return LoadScoreboardFromNBT(NBT); } @@ -63,32 +57,15 @@ bool cScoreboardSerializer::Load(void) bool cScoreboardSerializer::Save(void) { cFastNBTWriter Writer; - SaveScoreboardToNBT(Writer); - Writer.Finish(); - #ifdef _DEBUG - cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size()); +#ifdef _DEBUG + cParsedNBT TestParse(Writer.GetResult()); ASSERT(TestParse.IsValid()); - #endif // _DEBUG - - cFile File; - if (!File.Open(m_Path, cFile::fmWrite)) - { - return false; - } - - AString Compressed; - int res = CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - - if (res != Z_OK) - { - return false; - } +#endif // _DEBUG - File.Write(Compressed.data(), Compressed.size()); - File.Close(); + GZipFile::Write(m_Path, Writer.GetResult()); return true; } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 0e874df7c..78320d636 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -8,8 +8,8 @@ #include "NBTChunkSerializer.h" #include "EnchantmentSerializer.h" #include "NamespaceSerializer.h" -#include "zlib/zlib.h" #include "json/json.h" +#include "OSSupport/GZipFile.h" #include "../World.h" #include "../Item.h" #include "../ItemGrid.h" @@ -86,7 +86,7 @@ Since only the header is actually in the memory, this number can be high, but st cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) : Super(a_World), - m_CompressionFactor(a_CompressionFactor) + m_Compressor(a_CompressionFactor) { // Create a level.dat file for mapping tools, if it doesn't already exist: AString fnam; @@ -117,12 +117,7 @@ cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) : Writer.EndCompound(); Writer.Finish(); - gzFile gz = gzopen((fnam).c_str(), "wb"); - if (gz != nullptr) - { - gzwrite(gz, Writer.GetResult().data(), static_cast(Writer.GetResult().size())); - } - gzclose(gz); + GZipFile::Write(fnam, Writer.GetResult()); } } @@ -145,7 +140,7 @@ cWSSAnvil::~cWSSAnvil() bool cWSSAnvil::LoadChunk(const cChunkCoords & a_Chunk) { - AString ChunkData; + ContiguousByteBuffer ChunkData; if (!GetChunkData(a_Chunk, ChunkData)) { // The reason for failure is already printed in GetChunkData() @@ -161,15 +156,17 @@ bool cWSSAnvil::LoadChunk(const cChunkCoords & a_Chunk) bool cWSSAnvil::SaveChunk(const cChunkCoords & a_Chunk) { - AString ChunkData; - if (!SaveChunkToData(a_Chunk, ChunkData)) + try { - LOGWARNING("Cannot serialize chunk [%d, %d] into data", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); - return false; + if (!SetChunkData(a_Chunk, SaveChunkToData(a_Chunk).GetView())) + { + LOGWARNING("Cannot store chunk [%d, %d] data", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); + return false; + } } - if (!SetChunkData(a_Chunk, ChunkData)) + catch (const std::exception & Oops) { - LOGWARNING("Cannot store chunk [%d, %d] data", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); + LOGWARNING("Cannot serialize chunk [%d, %d] into data: %s", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Oops.what()); return false; } @@ -181,7 +178,7 @@ bool cWSSAnvil::SaveChunk(const cChunkCoords & a_Chunk) -void cWSSAnvil::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ, const AString & a_Reason, const AString & a_ChunkDataToSave) +void cWSSAnvil::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ, const AString & a_Reason, const ContiguousByteBufferView a_ChunkDataToSave) { // Construct the filename for offloading: AString OffloadFileName; @@ -202,7 +199,7 @@ void cWSSAnvil::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ, const AString & a_Re // Log the warning to console: const int RegionX = FAST_FLOOR_DIV(a_ChunkX, 32); const int RegionZ = FAST_FLOOR_DIV(a_ChunkZ, 32); - AString Info = Printf("Loading chunk [%d, %d] for world %s from file r.%d.%d.mca failed: %s. Offloading old chunk data to file %s and regenerating chunk.", + AString Info = Printf("Loading chunk [%d, %d] for world %s from file r.%d.%d.mca failed: %s Offloading old chunk data to file %s and regenerating chunk.", a_ChunkX, a_ChunkZ, m_World->GetName().c_str(), RegionX, RegionZ, a_Reason.c_str(), OffloadFileName.c_str() ); LOGWARNING("%s", Info.c_str()); @@ -231,7 +228,7 @@ void cWSSAnvil::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ, const AString & a_Re -bool cWSSAnvil::GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data) +bool cWSSAnvil::GetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data) { cCSLock Lock(m_CS); cMCAFile * File = LoadMCAFile(a_Chunk); @@ -246,7 +243,7 @@ bool cWSSAnvil::GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data) -bool cWSSAnvil::SetChunkData(const cChunkCoords & a_Chunk, const AString & a_Data) +bool cWSSAnvil::SetChunkData(const cChunkCoords & a_Chunk, const ContiguousByteBufferView a_Data) { cCSLock Lock(m_CS); cMCAFile * File = LoadMCAFile(a_Chunk); @@ -314,55 +311,47 @@ cWSSAnvil::cMCAFile * cWSSAnvil::LoadMCAFile(const cChunkCoords & a_Chunk) -bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & a_Data) +bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const ContiguousByteBufferView a_Data) { - // Uncompress the data: - AString Uncompressed; - int res = InflateString(a_Data.data(), a_Data.size(), Uncompressed); - if (res != Z_OK) + try { - LOGWARNING("Uncompressing chunk [%d, %d] failed: %d", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, res); - ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "InflateString() failed", a_Data); - return false; - } + const auto Extracted = m_Extractor.ExtractZLib(a_Data); + cParsedNBT NBT(Extracted.GetView()); - // Parse the NBT data: - cParsedNBT NBT(Uncompressed.data(), Uncompressed.size()); - if (!NBT.IsValid()) + if (!NBT.IsValid()) + { + // NBT Parsing failed: + throw std::runtime_error(fmt::format("NBT parsing failed. {} at position {}.", NBT.GetErrorCode().message(), NBT.GetErrorPos())); + } + + // Load the data from NBT: + return LoadChunkFromNBT(a_Chunk, NBT, a_Data); + } + catch (const std::exception & Oops) { - // NBT Parsing failed - auto msg = fmt::format("NBT parsing failed: {}, pos {}", NBT.GetErrorCode().message(), NBT.GetErrorPos()); - ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, msg, a_Data); + ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Oops.what(), a_Data); return false; } - - // Load the data from NBT: - return LoadChunkFromNBT(a_Chunk, NBT, a_Data); } -bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data) +Compression::Result cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk) { cFastNBTWriter Writer; - if (!SaveChunkToNBT(a_Chunk, Writer)) - { - LOGWARNING("Cannot save chunk [%d, %d] to NBT", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); - return false; - } + NBTChunkSerializer::Serialize(*m_World, a_Chunk, Writer); Writer.Finish(); - CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data, m_CompressionFactor); - return true; + return m_Compressor.CompressZLib(Writer.GetResult()); } -bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT, const AString & a_RawChunkData) +bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT, const ContiguousByteBufferView a_RawChunkData) { // The data arrays, in MCA-native y / z / x ordering (will be reordered for the final chunk data) cChunkDef::BlockTypes BlockTypes; @@ -496,20 +485,6 @@ void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & -bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_Writer) -{ - if (!NBTChunkSerializer::serialize(*m_World, a_Chunk, a_Writer)) - { - LOGWARNING("Failed to save chunk %s.", a_Chunk.ToString()); - return false; - } - return true; -} - - - - - cChunkDef::BiomeMap * cWSSAnvil::LoadVanillaBiomeMapFromNBT(cChunkDef::BiomeMap * a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx) { if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_ByteArray)) @@ -549,7 +524,7 @@ cChunkDef::BiomeMap * cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_Bio // The biomes stored don't match in size return nullptr; } - const char * BiomeData = (a_NBT.GetData(a_TagIdx)); + const auto * BiomeData = a_NBT.GetData(a_TagIdx); for (size_t i = 0; i < ARRAYCOUNT(*a_BiomeMap); i++) { (*a_BiomeMap)[i] = static_cast(GetBEInt(&BiomeData[i * 4])); @@ -587,7 +562,7 @@ void cWSSAnvil::LoadEntitiesFromNBT(cEntityList & a_Entities, const cParsedNBT & try { - LoadEntityFromNBT(a_Entities, a_NBT, Child, a_NBT.GetData(sID), a_NBT.GetDataLength(sID)); + LoadEntityFromNBT(a_Entities, a_NBT, Child, a_NBT.GetStringView(sID)); } catch (...) { @@ -690,14 +665,9 @@ OwnedBlockEntity cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int // All the other blocktypes should have no entities assigned to them. Report an error: // Get the "id" tag: int TagID = a_NBT.FindChildByName(a_Tag, "id"); - AString TypeName(""); - if (TagID >= 0) - { - TypeName.assign(a_NBT.GetData(TagID), static_cast(a_NBT.GetDataLength(TagID))); - } FLOGINFO("WorldLoader({0}): Block entity mismatch: block type {1} ({2}), type \"{3}\", at {4}; the entity will be lost.", m_World->GetName(), - ItemTypeToString(a_BlockType), a_BlockType, TypeName, + ItemTypeToString(a_BlockType), a_BlockType, (TagID >= 0) ? a_NBT.GetStringView(TagID) : "unknown", a_Pos ); return nullptr; @@ -887,10 +857,16 @@ bool cWSSAnvil::CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, con return false; } + // Check if the "id" tag is a string: + if (a_NBT.GetType(TagID) != eTagType::TAG_String) + { + return false; + } + // Compare the value: for (const auto & et: a_ExpectedTypes) { - if (strncmp(a_NBT.GetData(TagID), et.c_str(), static_cast(a_NBT.GetDataLength(TagID))) == 0) + if (a_NBT.GetStringView(TagID) == et) { return true; } @@ -906,8 +882,7 @@ bool cWSSAnvil::CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, con } FLOGWARNING("Block entity type mismatch: exp {0}, got \"{1}\". The block entity at {2} will lose all its properties.", expectedTypes.c_str() + 2, // Skip the first ", " that is extra in the string - AString(a_NBT.GetData(TagID), static_cast(a_NBT.GetDataLength(TagID))), - a_Pos + a_NBT.GetStringView(TagID), a_Pos ); return false; } @@ -1364,7 +1339,7 @@ OwnedBlockEntity cWSSAnvil::LoadMobSpawnerFromNBT(const cParsedNBT & a_NBT, int int Type = a_NBT.FindChildByName(a_TagIdx, "EntityId"); if ((Type >= 0) && (a_NBT.GetType(Type) == TAG_String)) { - const auto StatInfo = NamespaceSerializer::SplitNamespacedID(a_NBT.GetString(Type)); + const auto StatInfo = NamespaceSerializer::SplitNamespacedID(a_NBT.GetStringView(Type)); if (StatInfo.first == NamespaceSerializer::Namespace::Unknown) { return nullptr; @@ -1571,10 +1546,10 @@ OwnedBlockEntity cWSSAnvil::LoadSignFromNBT(const cParsedNBT & a_NBT, int a_TagI -void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength) +void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const std::string_view a_EntityName) { typedef void (cWSSAnvil::*EntityLoaderFunc)(cEntityList &, const cParsedNBT &, int a_EntityTagIdx); - typedef std::map EntityLoaderMap; + typedef std::map EntityLoaderMap; static const EntityLoaderMap EntityTypeToFunction { { "Boat", &cWSSAnvil::LoadBoatFromNBT }, @@ -1624,14 +1599,14 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a // TODO: flatten monster\projectile into one entity type enum - auto it = EntityTypeToFunction.find(AString(a_IDTag, a_IDTagLength)); + const auto it = EntityTypeToFunction.find(a_EntityName); if (it != EntityTypeToFunction.end()) { (this->*it->second)(a_Entities, a_NBT, a_EntityTagIdx); return; } - const auto StatInfo = NamespaceSerializer::SplitNamespacedID({ a_IDTag, a_IDTagLength }); + const auto StatInfo = NamespaceSerializer::SplitNamespacedID(a_EntityName); if (StatInfo.first == NamespaceSerializer::Namespace::Unknown) { return; @@ -3947,7 +3922,7 @@ bool cWSSAnvil::cMCAFile::OpenFile(bool a_IsForReading) -bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data) +bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data) { if (!OpenFile(true)) { @@ -3976,21 +3951,21 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a UInt32 ChunkSize = 0; if (m_File.Read(&ChunkSize, 4) != 4) { - m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Cannot read chunk size", ""); + m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Cannot read chunk size", {}); return false; } ChunkSize = ntohl(ChunkSize); if (ChunkSize < 1) { // Chunk size too small - m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Chunk size too small", ""); + m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Chunk size too small", {}); return false; } char CompressionType = 0; if (m_File.Read(&CompressionType, 1) != 1) { - m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Cannot read chunk compression", ""); + m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Cannot read chunk compression", {}); return false; } ChunkSize--; @@ -4015,7 +3990,7 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a -bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AString & a_Data) +bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const ContiguousByteBufferView a_Data) { if (!OpenFile(false)) { @@ -4034,7 +4009,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri LocalZ = 32 + LocalZ; } - unsigned ChunkSector = FindFreeLocation(LocalX, LocalZ, a_Data); + unsigned ChunkSector = FindFreeLocation(LocalX, LocalZ, a_Data.size()); // Store the chunk data: m_File.Seek(static_cast(ChunkSector * 4096)); @@ -4103,12 +4078,12 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri -unsigned cWSSAnvil::cMCAFile::FindFreeLocation(int a_LocalX, int a_LocalZ, const AString & a_Data) +unsigned cWSSAnvil::cMCAFile::FindFreeLocation(int a_LocalX, int a_LocalZ, const size_t a_DataSize) { // See if it fits the current location: unsigned ChunkLocation = ntohl(m_Header[a_LocalX + 32 * a_LocalZ]); unsigned ChunkLen = ChunkLocation & 0xff; - if (a_Data.size() + MCA_CHUNK_HEADER_LENGTH <= (ChunkLen * 4096)) + if (a_DataSize + MCA_CHUNK_HEADER_LENGTH <= (ChunkLen * 4096)) { return ChunkLocation >> 8; } @@ -4126,7 +4101,3 @@ unsigned cWSSAnvil::cMCAFile::FindFreeLocation(int a_LocalX, int a_LocalZ, const } // for i - m_Header[] return MaxLocation >> 8; } - - - - diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 6d9b49788..1751c6761 100755 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -11,6 +11,7 @@ #include "../BlockEntities/BlockEntity.h" #include "WorldStorage.h" #include "FastNBT.h" +#include "StringCompression.h" @@ -62,9 +63,8 @@ protected: cMCAFile(cWSSAnvil & a_ParentSchema, const AString & a_FileName, int a_RegionX, int a_RegionZ); - bool GetChunkData (const cChunkCoords & a_Chunk, AString & a_Data); - bool SetChunkData (const cChunkCoords & a_Chunk, const AString & a_Data); - bool EraseChunkData(const cChunkCoords & a_Chunk); + bool GetChunkData (const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data); + bool SetChunkData (const cChunkCoords & a_Chunk, ContiguousByteBufferView a_Data); int GetRegionX (void) const {return m_RegionX; } int GetRegionZ (void) const {return m_RegionZ; } @@ -86,8 +86,8 @@ protected: // Chunk timestamps, following the chunk headers unsigned m_TimeStamps[MCA_MAX_CHUNKS]; - /** Finds a free location large enough to hold a_Data. Gets a hint of the chunk coords, places the data there if it fits. Returns the sector number. */ - unsigned FindFreeLocation(int a_LocalX, int a_LocalZ, const AString & a_Data); + /** Finds a free location large enough to hold a_Data. Returns the sector number. */ + unsigned FindFreeLocation(int a_LocalX, int a_LocalZ, size_t a_DataSize); /** Opens a MCA file either for a Read operation (fails if doesn't exist) or for a Write operation (creates new if not found) */ bool OpenFile(bool a_IsForReading); @@ -97,30 +97,27 @@ protected: cCriticalSection m_CS; cMCAFiles m_Files; // a MRU cache of MCA files - int m_CompressionFactor; - + Compression::Extractor m_Extractor; + Compression::Compressor m_Compressor; /** Reports that the specified chunk failed to load and saves the chunk data to an external file. */ - void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ, const AString & a_Reason, const AString & a_ChunkDataToSave); + void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ, const AString & a_Reason, ContiguousByteBufferView a_ChunkDataToSave); /** Gets chunk data from the correct file; locks file CS as needed */ - bool GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data); + bool GetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data); /** Sets chunk data into the correct file; locks file CS as needed */ - bool SetChunkData(const cChunkCoords & a_Chunk, const AString & a_Data); + bool SetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBufferView a_Data); /** Loads the chunk from the data (no locking needed) */ - bool LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & a_Data); + bool LoadChunkFromData(const cChunkCoords & a_Chunk, ContiguousByteBufferView a_Data); /** Saves the chunk into datastream (no locking needed) */ - bool SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data); + Compression::Result SaveChunkToData(const cChunkCoords & a_Chunk); /** Loads the chunk from NBT data (no locking needed). a_RawChunkData is the raw (compressed) chunk data, used for offloading when chunk loading fails. */ - bool LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT, const AString & a_RawChunkData); - - /** Saves the chunk into NBT data using a_Writer; returns true on success */ - bool SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_Writer); + bool LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT, ContiguousByteBufferView a_RawChunkData); /** Loads the chunk's biome map from vanilla-format; returns a_BiomeMap if biomes present and valid, nullptr otherwise */ cChunkDef::BiomeMap * LoadVanillaBiomeMapFromNBT(cChunkDef::BiomeMap * a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx); @@ -175,7 +172,7 @@ protected: OwnedBlockEntity LoadNoteBlockFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); OwnedBlockEntity LoadSignFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength); + void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, std::string_view a_EntityName); void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadEnderCrystalFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); @@ -309,7 +306,3 @@ protected: virtual bool SaveChunk(const cChunkCoords & a_Chunk) override; virtual const AString GetName(void) const override {return "anvil"; } } ; - - - - -- cgit v1.2.3