summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/LuaState.cpp29
-rw-r--r--src/Bindings/LuaState.h2
-rw-r--r--src/Bindings/ManualBindings.cpp67
-rw-r--r--src/Bindings/ManualBindings_BlockArea.cpp50
-rw-r--r--src/Bindings/Plugin.h2
-rw-r--r--src/Bindings/PluginLua.cpp2
-rw-r--r--src/Bindings/PluginLua.h2
-rw-r--r--src/Bindings/PluginManager.cpp2
-rw-r--r--src/Bindings/PluginManager.h2
-rw-r--r--src/ByteBuffer.cpp37
-rw-r--r--src/ByteBuffer.h16
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Chunk.cpp1
-rw-r--r--src/ChunkMap.cpp3
-rw-r--r--src/CircularBufferCompressor.cpp67
-rw-r--r--src/CircularBufferCompressor.h43
-rw-r--r--src/ClientHandle.cpp55
-rw-r--r--src/ClientHandle.h23
-rw-r--r--src/Generating/ComposableGenerator.cpp39
-rw-r--r--src/Generating/FinishGen.cpp4
-rw-r--r--src/Generating/FinishGen.h5
-rw-r--r--src/Generating/PrefabPiecePool.cpp40
-rw-r--r--src/Generating/PrefabPiecePool.h4
-rw-r--r--src/Globals.h84
-rw-r--r--src/OSSupport/File.cpp67
-rw-r--r--src/OSSupport/File.h27
-rw-r--r--src/OSSupport/GZipFile.cpp96
-rw-r--r--src/OSSupport/GZipFile.h41
-rw-r--r--src/Protocol/ChunkDataSerializer.cpp9
-rw-r--r--src/Protocol/ChunkDataSerializer.h14
-rw-r--r--src/Protocol/ForgeHandshake.cpp77
-rw-r--r--src/Protocol/ForgeHandshake.h10
-rw-r--r--src/Protocol/Packetizer.h4
-rw-r--r--src/Protocol/Protocol.h6
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp13
-rw-r--r--src/Protocol/Protocol_1_10.cpp2
-rw-r--r--src/Protocol/Protocol_1_11.cpp2
-rw-r--r--src/Protocol/Protocol_1_12.cpp4
-rw-r--r--src/Protocol/Protocol_1_13.cpp15
-rw-r--r--src/Protocol/Protocol_1_14.cpp3
-rw-r--r--src/Protocol/Protocol_1_8.cpp361
-rw-r--r--src/Protocol/Protocol_1_8.h22
-rw-r--r--src/Protocol/Protocol_1_9.cpp14
-rw-r--r--src/Protocol/Protocol_1_9.h2
-rw-r--r--src/Server.cpp5
-rw-r--r--src/Server.h4
-rw-r--r--src/StringCompression.cpp345
-rw-r--r--src/StringCompression.h82
-rw-r--r--src/StringUtils.cpp28
-rw-r--r--src/StringUtils.h6
-rw-r--r--src/WorldStorage/FastNBT.cpp78
-rw-r--r--src/WorldStorage/FastNBT.h48
-rw-r--r--src/WorldStorage/FireworksSerializer.cpp4
-rw-r--r--src/WorldStorage/MapSerializer.cpp53
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp10
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h5
-rw-r--r--src/WorldStorage/SchematicFileSerializer.cpp115
-rw-r--r--src/WorldStorage/SchematicFileSerializer.h33
-rw-r--r--src/WorldStorage/ScoreboardSerializer.cpp55
-rw-r--r--src/WorldStorage/WSSAnvil.cpp147
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.h35
-rw-r--r--src/mbedTLS++/AesCfb128Decryptor.cpp9
-rw-r--r--src/mbedTLS++/AesCfb128Decryptor.h2
-rw-r--r--src/mbedTLS++/AesCfb128Encryptor.cpp9
-rw-r--r--src/mbedTLS++/AesCfb128Encryptor.h3
-rw-r--r--src/mbedTLS++/RsaPrivateKey.cpp52
-rw-r--r--src/mbedTLS++/RsaPrivateKey.h9
67 files changed, 1218 insertions, 1289 deletions
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index c6042ac62..81dcb0e67 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -863,7 +863,7 @@ void cLuaState::Push(const AStringVector & a_Vector)
int index = 1;
for (AStringVector::const_iterator itr = a_Vector.begin(), end = a_Vector.end(); itr != end; ++itr, ++index)
{
- tolua_pushstring(m_LuaState, itr->c_str());
+ Push(*itr);
lua_rawseti(m_LuaState, newTable, index);
}
}
@@ -916,6 +916,17 @@ void cLuaState::Push(const cLuaState::cRef & a_Ref)
+void cLuaState::Push(const ContiguousByteBufferView a_Data)
+{
+ ASSERT(IsValid());
+
+ lua_pushlstring(m_LuaState, reinterpret_cast<const char *>(a_Data.data()), a_Data.size());
+}
+
+
+
+
+
void cLuaState::Push(const Vector3d & a_Vector)
{
ASSERT(IsValid());
@@ -1355,6 +1366,22 @@ bool cLuaState::GetStackValue(int a_StackPos, cTrackedRefSharedPtr & a_Ref)
+bool cLuaState::GetStackValue(int a_StackPos, ContiguousByteBuffer & a_Data)
+{
+ size_t Length = 0;
+ const char * const Data = lua_tolstring(m_LuaState, a_StackPos, &Length);
+ if (Data != nullptr)
+ {
+ a_Data.assign(reinterpret_cast<const std::byte *>(Data), Length);
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
bool cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal)
{
if (lua_isnumber(m_LuaState, a_StackPos))
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index 0bdecdfc7..b3f567ecb 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -619,6 +619,7 @@ public:
void Push(const cItem & a_Item);
void Push(const cNil & a_Nil);
void Push(const cRef & a_Ref);
+ void Push(ContiguousByteBufferView a_Data);
void Push(const Vector3d & a_Vector);
void Push(const Vector3i & a_Vector);
@@ -658,6 +659,7 @@ public:
bool GetStackValue(int a_StackPos, cTrackedRef & a_Ref);
bool GetStackValue(int a_StackPos, cTrackedRefPtr & a_Ref);
bool GetStackValue(int a_StackPos, cTrackedRefSharedPtr & a_Ref);
+ bool GetStackValue(int a_StackPos, ContiguousByteBuffer & a_Data);
bool GetStackValue(int a_StackPos, double & a_Value);
bool GetStackValue(int a_StackPos, eBlockFace & a_Value);
bool GetStackValue(int a_StackPos, eWeather & a_Value);
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 92f7dd92b..20364100f 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -188,9 +188,7 @@ static int tolua_CompressStringZLIB(lua_State * tolua_S)
S.GetStackValues(1, ToCompress, CompressionLevel);
// Compress the string:
- AString res;
- CompressString(ToCompress.data(), ToCompress.size(), res, CompressionLevel);
- S.Push(res);
+ S.Push(Compression::Compressor(CompressionLevel).CompressZLib(ToCompress.data(), ToCompress.size()).GetView());
return 1;
}
@@ -211,14 +209,21 @@ static int tolua_UncompressStringZLIB(lua_State * tolua_S)
}
// Get the params:
- AString ToUncompress;
+ ContiguousByteBuffer ToUncompress;
size_t UncompressedSize = 0;
S.GetStackValues(1, ToUncompress, UncompressedSize);
- // Compress the string:
- AString res;
- UncompressString(ToUncompress.data(), ToUncompress.size(), res, UncompressedSize);
- S.Push(res);
+ try
+ {
+ // Decompress the string:
+ S.Push(Compression::Extractor().ExtractZLib(ToUncompress, UncompressedSize).GetView());
+ }
+ catch (const std::exception & Oops)
+ {
+ LOGWARNING(Oops.what());
+ cLuaState::LogStackTrace(tolua_S);
+ return 0;
+ }
return 1;
}
@@ -239,13 +244,11 @@ static int tolua_CompressStringGZIP(lua_State * tolua_S)
}
// Get the params:
- AString ToCompress;
+ ContiguousByteBuffer ToCompress;
S.GetStackValues(1, ToCompress);
// Compress the string:
- AString res;
- CompressStringGZIP(ToCompress.data(), ToCompress.size(), res);
- S.Push(res);
+ S.Push(Compression::Compressor().CompressGZip(ToCompress).GetView());
return 1;
}
@@ -253,7 +256,7 @@ static int tolua_CompressStringGZIP(lua_State * tolua_S)
-static int tolua_UncompressStringGZIP(lua_State * tolua_S)
+static int tolua_InflateString(lua_State * tolua_S)
{
cLuaState S(tolua_S);
if (
@@ -266,40 +269,20 @@ static int tolua_UncompressStringGZIP(lua_State * tolua_S)
}
// Get the params:
- AString ToUncompress;
+ ContiguousByteBuffer ToUncompress;
S.GetStackValues(1, ToUncompress);
- // Compress the string:
- AString res;
- UncompressStringGZIP(ToUncompress.data(), ToUncompress.size(), res);
- S.Push(res);
- return 1;
-}
-
-
-
-
-
-static int tolua_InflateString(lua_State * tolua_S)
-{
- cLuaState S(tolua_S);
- if (
- !S.CheckParamString(1) ||
- !S.CheckParamEnd(2)
- )
+ try
{
+ // Decompress the string:
+ S.Push(Compression::Extractor().ExtractZLib(ToUncompress).GetView());
+ }
+ catch (const std::exception & Oops)
+ {
+ LOGWARNING(Oops.what());
cLuaState::LogStackTrace(tolua_S);
return 0;
}
-
- // Get the params:
- AString ToUncompress;
- S.GetStackValues(1, ToUncompress);
-
- // Compress the string:
- AString res;
- InflateString(ToUncompress.data(), ToUncompress.size(), res);
- S.Push(res);
return 1;
}
@@ -4552,7 +4535,7 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "CompressStringZLIB", tolua_CompressStringZLIB);
tolua_function(tolua_S, "UncompressStringZLIB", tolua_UncompressStringZLIB);
tolua_function(tolua_S, "CompressStringGZIP", tolua_CompressStringGZIP);
- tolua_function(tolua_S, "UncompressStringGZIP", tolua_UncompressStringGZIP);
+ tolua_function(tolua_S, "UncompressStringGZIP", tolua_InflateString);
tolua_function(tolua_S, "InflateString", tolua_InflateString);
tolua_endmodule(tolua_S);
diff --git a/src/Bindings/ManualBindings_BlockArea.cpp b/src/Bindings/ManualBindings_BlockArea.cpp
index 5af150599..5f281fadc 100644
--- a/src/Bindings/ManualBindings_BlockArea.cpp
+++ b/src/Bindings/ManualBindings_BlockArea.cpp
@@ -435,7 +435,17 @@ static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * a_LuaState)
return L.ApiParamError("Invalid 'self', must not be nil");
}
- L.Push(cSchematicFileSerializer::LoadFromSchematicFile(*self, fileName));
+ try
+ {
+ cSchematicFileSerializer::LoadFromSchematicFile(*self, fileName);
+ L.Push(true);
+ }
+ catch (const std::exception & Oops)
+ {
+ LOGWARNING(Oops.what());
+ L.LogStackTrace();
+ L.Push(false);
+ }
return 1;
}
@@ -457,7 +467,7 @@ static int tolua_cBlockArea_LoadFromSchematicString(lua_State * a_LuaState)
return 0;
}
cBlockArea * self;
- AString data;
+ ContiguousByteBuffer data;
if (!L.GetStackValues(1, self, data))
{
return L.ApiParamError("Cannot read the parameters");
@@ -467,7 +477,17 @@ static int tolua_cBlockArea_LoadFromSchematicString(lua_State * a_LuaState)
return L.ApiParamError("Invalid 'self', must not be nil");
}
- L.Push(cSchematicFileSerializer::LoadFromSchematicString(*self, data));
+ try
+ {
+ cSchematicFileSerializer::LoadFromSchematicString(*self, data);
+ L.Push(true);
+ }
+ catch (const std::exception & Oops)
+ {
+ LOGWARNING(Oops.what());
+ L.LogStackTrace();
+ L.Push(false);
+ }
return 1;
}
@@ -625,7 +645,17 @@ static int tolua_cBlockArea_SaveToSchematicFile(lua_State * a_LuaState)
return L.ApiParamError("Invalid 'self', must not be nil");
}
- L.Push(cSchematicFileSerializer::SaveToSchematicFile(*self, fileName));
+ try
+ {
+ cSchematicFileSerializer::SaveToSchematicFile(*self, fileName);
+ L.Push(true);
+ }
+ catch (const std::exception & Oops)
+ {
+ LOGWARNING(Oops.what());
+ L.LogStackTrace();
+ L.Push(false);
+ }
return 1;
}
@@ -655,13 +685,17 @@ static int tolua_cBlockArea_SaveToSchematicString(lua_State * a_LuaState)
return L.ApiParamError("Invalid 'self', must not be nil");
}
- AString data;
- if (cSchematicFileSerializer::SaveToSchematicString(*self, data))
+ try
{
- L.Push(data);
+ L.Push(cSchematicFileSerializer::SaveToSchematicString(*self).GetView());
return 1;
}
- return 0;
+ catch (const std::exception & Oops)
+ {
+ LOGWARNING(Oops.what());
+ L.LogStackTrace();
+ return 0;
+ }
}
diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h
index e051ff61c..47f8820e8 100644
--- a/src/Bindings/Plugin.h
+++ b/src/Bindings/Plugin.h
@@ -95,7 +95,7 @@ public:
virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0;
virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0;
- virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) = 0;
+ virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, ContiguousByteBufferView a_Message) = 0;
virtual bool OnPluginsLoaded (void) = 0;
virtual bool OnPostCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) = 0;
virtual bool OnPreCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) = 0;
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index f4cfd4a86..9b6bccf7c 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -818,7 +818,7 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block
-bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message)
+bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const ContiguousByteBufferView a_Message)
{
return CallSimpleHooks(cPluginManager::HOOK_PLUGIN_MESSAGE, &a_Client, a_Channel, a_Message);
}
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index 2a48adb1e..c3064450f 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -117,7 +117,7 @@ public:
virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
- virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) override;
+ virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, ContiguousByteBufferView a_Message) override;
virtual bool OnPluginsLoaded (void) override;
virtual bool OnPostCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override;
virtual bool OnPreCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override;
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index 310a3968b..59761ead9 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -1009,7 +1009,7 @@ bool cPluginManager::CallHookPlayerUsingItem(cPlayer & a_Player, int a_BlockX, i
-bool cPluginManager::CallHookPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message)
+bool cPluginManager::CallHookPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const ContiguousByteBufferView a_Message)
{
return GenericCallHook(HOOK_PLUGIN_MESSAGE, [&](cPlugin * a_Plugin)
{
diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h
index 8d75509a1..c1f798291 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -288,7 +288,7 @@ public:
bool CallHookPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
bool CallHookPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
bool CallHookPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
- bool CallHookPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message);
+ bool CallHookPluginMessage (cClientHandle & a_Client, const AString & a_Channel, ContiguousByteBufferView a_Message);
bool CallHookPluginsLoaded (void);
bool CallHookPostCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe);
bool CallHookPreCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe);
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index f3a6e3a7d..2de6aec60 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -83,7 +83,7 @@ Unfortunately it is very slow, so it is disabled even for regular DEBUG builds.
// cByteBuffer:
cByteBuffer::cByteBuffer(size_t a_BufferSize) :
- m_Buffer(new char[a_BufferSize + 1]),
+ m_Buffer(new std::byte[a_BufferSize + 1]),
m_BufferSize(a_BufferSize + 1),
m_DataStart(0),
m_WritePos(0),
@@ -446,7 +446,15 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value)
{
LOGWARNING("%s: String too large: %u (%u KiB)", __FUNCTION__, Size, Size / 1024);
}
- return ReadString(a_Value, static_cast<size_t>(Size));
+ ContiguousByteBuffer Buffer;
+ if (!ReadSome(Buffer, static_cast<size_t>(Size)))
+ {
+ return false;
+ }
+ // "Convert" a UTF-8 encoded string into system-native char.
+ // This isn't great, better would be to use codecvt:
+ a_Value = { reinterpret_cast<const char *>(Buffer.data()), Buffer.size() };
+ return true;
}
@@ -552,6 +560,18 @@ bool cByteBuffer::WriteBEInt8(Int8 a_Value)
+bool cByteBuffer::WriteBEInt8(const std::byte a_Value)
+{
+ CHECK_THREAD
+ CheckValid();
+ PUTBYTES(1);
+ return WriteBuf(&a_Value, 1);
+}
+
+
+
+
+
bool cByteBuffer::WriteBEUInt8(UInt8 a_Value)
{
CHECK_THREAD
@@ -836,7 +856,7 @@ bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count)
-bool cByteBuffer::ReadString(AString & a_String, size_t a_Count)
+bool cByteBuffer::ReadSome(ContiguousByteBuffer & a_String, size_t a_Count)
{
CHECK_THREAD
CheckValid();
@@ -886,11 +906,11 @@ bool cByteBuffer::SkipRead(size_t a_Count)
-void cByteBuffer::ReadAll(AString & a_Data)
+void cByteBuffer::ReadAll(ContiguousByteBuffer & a_Data)
{
CHECK_THREAD
CheckValid();
- ReadString(a_Data, GetReadableSpace());
+ ReadSome(a_Data, GetReadableSpace());
}
@@ -944,7 +964,7 @@ void cByteBuffer::ResetRead(void)
-void cByteBuffer::ReadAgain(AString & a_Out)
+void cByteBuffer::ReadAgain(ContiguousByteBuffer & a_Out)
{
// Return the data between m_DataStart and m_ReadPos (the data that has been read but not committed)
// Used by ProtoProxy to repeat communication twice, once for parsing and the other time for the remote party
@@ -1004,8 +1024,3 @@ size_t cByteBuffer::GetVarIntSize(UInt32 a_Value)
return Count;
}
-
-
-
-
-
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index 1116de08c..cbf215f38 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -11,6 +11,8 @@
+
+
// fwd:
class cUUID;
@@ -87,6 +89,7 @@ public:
// Write the specified datatype; return true if successfully written
bool WriteBEInt8 (Int8 a_Value);
+ bool WriteBEInt8 (std::byte a_Value);
bool WriteBEInt16 (Int16 a_Value);
bool WriteBEInt32 (Int32 a_Value);
bool WriteBEInt64 (Int64 a_Value);
@@ -111,13 +114,13 @@ public:
bool WriteBuf(const void * a_Buffer, size_t a_Count);
/** Reads a_Count bytes into a_String; returns true if successful */
- bool ReadString(AString & a_String, size_t a_Count);
+ bool ReadSome(ContiguousByteBuffer & a_String, size_t a_Count);
/** Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer */
bool SkipRead(size_t a_Count);
/** Reads all available data into a_Data */
- void ReadAll(AString & a_Data);
+ void ReadAll(ContiguousByteBuffer & a_Data);
/** Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. */
bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes);
@@ -129,7 +132,7 @@ public:
void ResetRead(void);
/** Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication */
- void ReadAgain(AString & a_Out);
+ void ReadAgain(ContiguousByteBuffer & a_Out);
/** Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs */
void CheckValid(void) const;
@@ -138,7 +141,8 @@ public:
static size_t GetVarIntSize(UInt32 a_Value);
protected:
- char * m_Buffer;
+
+ std::byte * m_Buffer;
size_t m_BufferSize; // Total size of the ringbuffer
size_t m_DataStart; // Where the data starts in the ringbuffer
@@ -154,7 +158,3 @@ protected:
/** Advances the m_ReadPos by a_Count bytes */
void AdvanceReadPos(size_t a_Count);
} ;
-
-
-
-
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3844c6c10..02c372a1f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -18,6 +18,7 @@ target_sources(
ChunkMap.cpp
ChunkSender.cpp
ChunkStay.cpp
+ CircularBufferCompressor.cpp
ClientHandle.cpp
Color.cpp
CommandOutput.cpp
@@ -88,6 +89,7 @@ target_sources(
ChunkMap.h
ChunkSender.h
ChunkStay.h
+ CircularBufferCompressor.h
ClientHandle.h
Color.h
CommandOutput.h
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index ff5757703..5a6cca3eb 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -11,7 +11,6 @@
#include "World.h"
#include "ClientHandle.h"
#include "Server.h"
-#include "zlib/zlib.h"
#include "Defines.h"
#include "BlockEntities/BeaconEntity.h"
#include "BlockEntities/BedEntity.h"
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index a2cd621d7..f06dd057f 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -22,9 +22,6 @@
#include "DeadlockDetect.h"
#include "BlockEntities/BlockEntity.h"
-#include "zlib/zlib.h"
-#include "json/json.h"
-
diff --git a/src/CircularBufferCompressor.cpp b/src/CircularBufferCompressor.cpp
new file mode 100644
index 000000000..823dd8862
--- /dev/null
+++ b/src/CircularBufferCompressor.cpp
@@ -0,0 +1,67 @@
+
+#include "Globals.h"
+#include "CircularBufferCompressor.h"
+#include "ByteBuffer.h"
+
+
+
+
+
+ContiguousByteBufferView CircularBufferCompressor::GetView() const
+{
+ return m_ContiguousIntermediate;
+}
+
+
+
+
+
+Compression::Result CircularBufferCompressor::Compress()
+{
+ return m_Compressor.CompressZLib(m_ContiguousIntermediate);
+}
+
+
+
+
+
+void CircularBufferCompressor::ReadFrom(cByteBuffer & Buffer)
+{
+ Buffer.ReadAll(m_ContiguousIntermediate);
+}
+
+
+
+
+
+void CircularBufferCompressor::ReadFrom(cByteBuffer & Buffer, size_t Size)
+{
+ Buffer.ReadSome(m_ContiguousIntermediate, Size);
+}
+
+
+
+
+
+ContiguousByteBufferView CircularBufferExtractor::GetView() const
+{
+ return m_ContiguousIntermediate;
+}
+
+
+
+
+
+Compression::Result CircularBufferExtractor::Extract(size_t UncompressedSize)
+{
+ return m_Extractor.ExtractZLib(m_ContiguousIntermediate, UncompressedSize);
+}
+
+
+
+
+
+void CircularBufferExtractor::ReadFrom(cByteBuffer & Buffer, size_t Size)
+{
+ Buffer.ReadSome(m_ContiguousIntermediate, Size);
+}
diff --git a/src/CircularBufferCompressor.h b/src/CircularBufferCompressor.h
new file mode 100644
index 000000000..12c708baf
--- /dev/null
+++ b/src/CircularBufferCompressor.h
@@ -0,0 +1,43 @@
+
+#pragma once
+
+#include "StringCompression.h"
+
+
+
+
+
+class CircularBufferCompressor
+{
+public:
+
+ ContiguousByteBufferView GetView() const;
+
+ Compression::Result Compress();
+ void ReadFrom(cByteBuffer & Buffer);
+ void ReadFrom(cByteBuffer & Buffer, size_t Size);
+
+private:
+
+ Compression::Compressor m_Compressor;
+ std::basic_string<std::byte> m_ContiguousIntermediate;
+};
+
+
+
+
+
+class CircularBufferExtractor
+{
+public:
+
+ ContiguousByteBufferView GetView() const;
+
+ Compression::Result Extract(size_t UncompressedSize);
+ void ReadFrom(cByteBuffer & Buffer, size_t Size);
+
+private:
+
+ Compression::Extractor m_Extractor;
+ std::basic_string<std::byte> m_ContiguousIntermediate;
+};
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 89fe3d3b9..4ec01744b 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -678,7 +678,7 @@ void cClientHandle::HandlePing(void)
-bool cClientHandle::HandleLogin(const AString & a_Username)
+bool cClientHandle::HandleLogin()
{
{
cCSLock lock(m_CSState);
@@ -694,10 +694,8 @@ bool cClientHandle::HandleLogin(const AString & a_Username)
// LOGD("Handling login for client %s @ %s (%p), state = %d", a_Username.c_str(), m_IPString.c_str(), static_cast<void *>(this), m_State.load());
- m_Username = a_Username;
-
// Let the plugins know about this event, they may refuse the player:
- if (cRoot::Get()->GetPluginManager()->CallHookLogin(*this, m_ProtocolVersion, a_Username))
+ if (cRoot::Get()->GetPluginManager()->CallHookLogin(*this, m_ProtocolVersion, GetUsername()))
{
SendDisconnect("Login Rejected!");
return false;
@@ -885,7 +883,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
-void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message)
+void cClientHandle::HandlePluginMessage(const AString & a_Channel, const ContiguousByteBufferView a_Message)
{
if (a_Channel == "REGISTER")
{
@@ -903,7 +901,7 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
}
else if (a_Channel == "FML|HS")
{
- m_ForgeHandshake.DataReceived(this, a_Message.c_str(), a_Message.size());
+ m_ForgeHandshake.DataReceived(this, a_Message);
}
else if (!HasPluginChannel(a_Channel))
{
@@ -920,7 +918,7 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
-AStringVector cClientHandle::BreakApartPluginChannels(const AString & a_PluginChannels)
+AStringVector cClientHandle::BreakApartPluginChannels(const ContiguousByteBufferView a_PluginChannels)
{
// Break the string on each NUL character.
// Note that StringSplit() doesn't work on this because NUL is a special char - string terminator
@@ -929,19 +927,21 @@ AStringVector cClientHandle::BreakApartPluginChannels(const AString & a_PluginCh
AStringVector res;
for (size_t i = 0; i < len; i++)
{
- if (a_PluginChannels[i] != 0)
+ if (a_PluginChannels[i] != std::byte(0))
{
continue;
}
if (i > first)
{
- res.push_back(a_PluginChannels.substr(first, i - first));
+ const auto Part = a_PluginChannels.substr(first, i - first);
+ res.emplace_back(reinterpret_cast<const char *>(Part.data()), Part.size());
}
first = i + 1;
} // for i - a_PluginChannels[]
if (first < len)
{
- res.push_back(a_PluginChannels.substr(first, len - first));
+ const auto Part = a_PluginChannels.substr(first, len - first);
+ res.emplace_back(reinterpret_cast<const char *>(Part.data()), Part.size());
}
return res;
}
@@ -2001,7 +2001,7 @@ void cClientHandle::HandleTabCompletion(const AString & a_Text)
-void cClientHandle::SendData(const char * a_Data, size_t a_Size)
+void cClientHandle::SendData(const ContiguousByteBufferView a_Data)
{
if (m_HasSentDC)
{
@@ -2010,7 +2010,7 @@ void cClientHandle::SendData(const char * a_Data, size_t a_Size)
}
cCSLock Lock(m_CSOutgoingData);
- m_OutgoingData.append(a_Data, a_Size);
+ m_OutgoingData += a_Data;
}
@@ -2085,7 +2085,15 @@ void cClientHandle::Tick(float a_Dt)
m_BreakProgress += m_Player->GetMiningProgressPerTick(Block);
}
- ProcessProtocolInOut();
+ try
+ {
+ ProcessProtocolInOut();
+ }
+ catch (const std::exception & Oops)
+ {
+ Kick(Oops.what());
+ return; // Return early to give a chance to send the kick packet before link shutdown
+ }
// If player has been kicked, terminate the connection:
if (m_State == csKicked)
@@ -2451,7 +2459,7 @@ void cClientHandle::SendChatSystem(const cCompositeChat & a_Message)
-void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, const std::string_view a_ChunkData)
+void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, const ContiguousByteBufferView a_ChunkData)
{
ASSERT(m_Player != nullptr);
@@ -2486,7 +2494,7 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, const std::string_
// Add the chunk to the list of chunks sent to the player:
{
cCSLock Lock(m_CSChunkLists);
- m_SentChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
+ m_SentChunks.emplace_back(a_ChunkX, a_ChunkZ);
}
}
@@ -2860,7 +2868,16 @@ void cClientHandle::SendPlayerSpawn(const cPlayer & a_Player)
-void cClientHandle::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
+void cClientHandle::SendPluginMessage(const AString & a_Channel, const std::string_view a_Message)
+{
+ m_Protocol->SendPluginMessage(a_Channel, { reinterpret_cast<const std::byte *>(a_Message.data()), a_Message.size() });
+}
+
+
+
+
+
+void cClientHandle::SendPluginMessage(const AString & a_Channel, const ContiguousByteBufferView a_Message)
{
m_Protocol->SendPluginMessage(a_Channel, a_Message);
}
@@ -3231,9 +3248,9 @@ const AString & cClientHandle::GetUsername(void) const
-void cClientHandle::SetUsername(const AString & a_Username)
+void cClientHandle::SetUsername(AString && a_Username)
{
- m_Username = a_Username;
+ m_Username = std::move(a_Username);
}
@@ -3398,7 +3415,7 @@ void cClientHandle::ProcessProtocolInOut(void)
}
// Send any queued outgoing data:
- AString OutgoingData;
+ ContiguousByteBuffer OutgoingData;
{
cCSLock Lock(m_CSOutgoingData);
std::swap(OutgoingData, m_OutgoingData);
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index e52236411..555c4396a 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -153,7 +153,7 @@ public: // tolua_export
void SendChatAboveActionBar (const cCompositeChat & a_Message);
void SendChatSystem (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = "");
void SendChatSystem (const cCompositeChat & a_Message);
- void SendChunkData (int a_ChunkX, int a_ChunkZ, const std::string_view a_ChunkData);
+ void SendChunkData (int a_ChunkX, int a_ChunkZ, ContiguousByteBufferView a_ChunkData);
void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count);
void SendDestroyEntity (const cEntity & a_Entity);
void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle);
@@ -192,7 +192,8 @@ public: // tolua_export
void SendPlayerMoveLook (void);
void SendPlayerPosition (void);
void SendPlayerSpawn (const cPlayer & a_Player);
- void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp
+ void SendPluginMessage (const AString & a_Channel, std::string_view a_Message); // Exported in ManualBindings.cpp
+ void SendPluginMessage (const AString & a_Channel, ContiguousByteBufferView a_Message);
void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID);
void SendResourcePack (const AString & a_ResourcePackUrl);
void SendResetTitle (void); // tolua_export
@@ -231,9 +232,10 @@ public: // tolua_export
void SendWindowOpen (const cWindow & a_Window);
void SendWindowProperty (const cWindow & a_Window, size_t a_Property, short a_Value);
+ const AString & GetUsername(void) const; // tolua_export
+ void SetUsername(AString && a_Username);
+
// tolua_begin
- const AString & GetUsername(void) const;
- void SetUsername( const AString & a_Username);
inline short GetPing(void) const { return static_cast<short>(std::chrono::duration_cast<std::chrono::milliseconds>(m_Ping).count()); }
@@ -357,7 +359,7 @@ public: // tolua_export
void HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround);
- void HandlePluginMessage (const AString & a_Channel, const AString & a_Message);
+ void HandlePluginMessage (const AString & a_Channel, ContiguousByteBufferView a_Message);
void HandleRespawn (void);
void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, eHand a_Hand);
void HandleSlotSelected (Int16 a_SlotNum);
@@ -379,11 +381,10 @@ public: // tolua_export
void HandleCraftRecipe (UInt32 a_RecipeId);
/** Called when the protocol has finished logging the user in.
- Return true to allow the user in; false to kick them.
- */
- bool HandleLogin(const AString & a_Username);
+ Return true to allow the user in; false to kick them. */
+ bool HandleLogin();
- void SendData(const char * a_Data, size_t a_Size);
+ void SendData(ContiguousByteBufferView a_Data);
/** Called when the player moves into a different world.
Sends an UnloadChunk packet for each loaded chunk and resets the streamed chunks. */
@@ -448,7 +449,7 @@ private:
/** Buffer for storing outgoing data from any thread; will get sent in Tick() (to prevent deadlocks).
Protected by m_CSOutgoingData. */
- AString m_OutgoingData;
+ ContiguousByteBuffer m_OutgoingData;
Vector3d m_ConfirmPosition;
@@ -580,7 +581,7 @@ private:
void FinishDigAnimation();
/** Converts the protocol-formatted channel list (NUL-separated) into a proper string vector. */
- AStringVector BreakApartPluginChannels(const AString & a_PluginChannels);
+ AStringVector BreakApartPluginChannels(ContiguousByteBufferView a_PluginChannels);
/** Adds all of the channels to the list of current plugin channels. Handles duplicates gracefully. */
void RegisterPluginChannels(const AStringVector & a_ChannelList);
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index 8b7d998d0..5b75402b8 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -430,10 +430,8 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
else if (NoCaseCompare(finisher, "DirtPockets") == 0)
{
auto gen = std::make_shared<cFinishGenOrePockets>(m_Seed + 1, cFinishGenOrePockets::DefaultNaturalPatches());
- if (gen->Initialize(a_IniFile, "DirtPockets"))
- {
- m_FinishGens.push_back(gen);
- }
+ gen->Initialize(a_IniFile, "DirtPockets");
+ m_FinishGens.push_back(gen);
}
else if (NoCaseCompare(finisher, "DistortedMembraneOverhangs") == 0)
{
@@ -508,15 +506,6 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
m_FinishGens.push_back(cFinishGenPtr(new cFinishGenNetherClumpFoliage(m_Seed)));
}
- else if (NoCaseCompare(*itr, "NetherForts") == 0)
- {
- LOGINFO("The NetherForts finisher is obsolete, you should use \"PieceStructures: NetherFort\" instead.");
- auto gen = std::make_shared<cPieceStructuresGen>(m_Seed);
- if (gen->Initialize("NetherFort", seaLevel, m_BiomeGen, m_CompositedHeightCache))
- {
- m_FinishGens.push_back(gen);
- }
- }
else if (NoCaseCompare(finisher, "NetherOreNests") == 0)
{
m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(m_Seed + 2, cFinishGenOreNests::DefaultNetherOres()));
@@ -528,10 +517,8 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
else if (NoCaseCompare(finisher, "OrePockets") == 0)
{
auto gen = std::make_shared<cFinishGenOrePockets>(m_Seed + 2, cFinishGenOrePockets::DefaultOverworldOres());
- if (gen->Initialize(a_IniFile, "OrePockets"))
- {
- m_FinishGens.push_back(gen);
- }
+ gen->Initialize(a_IniFile, "OrePockets");
+ m_FinishGens.push_back(gen);
}
else if (NoCaseCompare(finisher, "OverworldClumpFlowers") == 0)
{
@@ -561,15 +548,6 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
m_FinishGens.push_back(cFinishGenPtr(new cFinishGenPreSimulator(PreSimulateFallingBlocks, PreSimulateWater, PreSimulateLava)));
}
- else if (NoCaseCompare(finisher, "RainbowRoads") == 0)
- {
- LOGINFO("The RainbowRoads finisher is obsolete, you should use \"PieceStructures: RainbowRoads\" instead.");
- auto gen = std::make_shared<cPieceStructuresGen>(m_Seed);
- if (gen->Initialize("RainbowRoads", seaLevel, m_BiomeGen, m_CompositedHeightCache))
- {
- m_FinishGens.push_back(gen);
- }
- }
else if (NoCaseCompare(finisher, "Ravines") == 0)
{
m_FinishGens.push_back(cFinishGenPtr(new cStructGenRavines(m_Seed, 128)));
@@ -645,15 +623,6 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(m_Seed, m_BiomeGen, m_ShapeGen, m_CompositionGen)));
}
- else if (NoCaseCompare(finisher, "UnderwaterBases") == 0)
- {
- LOGINFO("The UnderwaterBases finisher is obsolete, you should use \"PieceStructures: UnderwaterBases\" instead.");
- auto gen = std::make_shared<cPieceStructuresGen>(m_Seed);
- if (gen->Initialize("UnderwaterBases", seaLevel, m_BiomeGen, m_CompositedHeightCache))
- {
- m_FinishGens.push_back(gen);
- }
- }
else if (NoCaseCompare(finisher, "Villages") == 0)
{
int GridSize = a_IniFile.GetValueSetI("Generator", "VillageGridSize", 384);
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index 10bd4eac9..6e3f8b446 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -1985,7 +1985,7 @@ void cFinishGenOreNests::GenerateOre(
////////////////////////////////////////////////////////////////////////////////
// cFinishGenOrePockets:
-bool cFinishGenOrePockets::Initialize(cIniFile & a_IniFile, const AString & a_GenName)
+void cFinishGenOrePockets::Initialize(cIniFile & a_IniFile, const AString & a_GenName)
{
// Read the OreInfos configuration:
auto valueName = a_GenName + "Blocks";
@@ -2003,8 +2003,6 @@ bool cFinishGenOrePockets::Initialize(cIniFile & a_IniFile, const AString & a_Ge
// Read the optional seed configuration (but do not store the default):
valueName = a_GenName + "Seed";
SetSeed(a_IniFile.GetValueI("Generator", valueName, m_Noise.GetSeed()));
-
- return true;
}
diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h
index d6458e4fc..76b58e60d 100644
--- a/src/Generating/FinishGen.h
+++ b/src/Generating/FinishGen.h
@@ -589,9 +589,8 @@ public:
{}
/** Reads the configuration from the specified INI file.
- a_GenName is the name of the generator (this class may be used for OrePockets and DirtPockets, each has a different default).
- Returns true on success, false and logs errors to console on failure. */
- bool Initialize(cIniFile & a_IniFile, const AString & a_GenName);
+ a_GenName is the name of the generator (this class may be used for OrePockets and DirtPockets, each has a different default). */
+ void Initialize(cIniFile & a_IniFile, const AString & a_GenName);
protected:
diff --git a/src/Generating/PrefabPiecePool.cpp b/src/Generating/PrefabPiecePool.cpp
index e52bb1621..28355660c 100644
--- a/src/Generating/PrefabPiecePool.cpp
+++ b/src/Generating/PrefabPiecePool.cpp
@@ -78,15 +78,6 @@ cPrefabPiecePool::cPrefabPiecePool(
-cPrefabPiecePool::cPrefabPiecePool(const AString & a_FileName, bool a_LogWarnings)
-{
- LoadFromFile(a_FileName, a_LogWarnings);
-}
-
-
-
-
-
cPrefabPiecePool::~cPrefabPiecePool()
{
Clear();
@@ -174,21 +165,28 @@ bool cPrefabPiecePool::LoadFromString(const AString & a_Contents, const AString
// If the contents start with GZip signature, ungzip and retry:
if (a_Contents.substr(0, 3) == "\x1f\x8b\x08")
{
- AString Uncompressed;
- auto res = UncompressStringGZIP(a_Contents.data(), a_Contents.size(), Uncompressed);
- if (res == Z_OK)
+ try
{
- return LoadFromString(Uncompressed, a_FileName, a_LogWarnings);
+ const auto Extracted = Compression::Extractor().ExtractGZip(
+ {
+ reinterpret_cast<const std::byte *>(a_Contents.data()), a_Contents.size()
+ });
+
+ // Here we do an extra std::string conversion, hardly efficient, but...
+ // Better would be refactor into LoadFromByteView for the GZip decompression path, and getting cFile to support std::byte.
+ // ...so it'll do for now.
+
+ return LoadFromString(std::string(Extracted.GetStringView()), a_FileName, a_LogWarnings);
}
- else
+ catch (const std::exception & Oops)
{
- CONDWARNING(a_LogWarnings, "Failed to decompress Gzip data in file %s: %d", a_FileName.c_str(), res);
+ CONDWARNING(a_LogWarnings, "Failed to decompress Gzip data in file %s. %s", a_FileName.c_str(), Oops.what());
return false;
}
}
// Search the first 8 KiB of the file for the format auto-detection string:
- auto Header = a_Contents.substr(0, 8192);
+ const auto Header = a_Contents.substr(0, 8 KiB);
if (Header.find("CubesetFormatVersion =") != AString::npos)
{
return LoadFromCubeset(a_Contents, a_FileName, a_LogWarnings);
@@ -391,10 +389,14 @@ std::unique_ptr<cPrefab> cPrefabPiecePool::LoadPrefabFromCubesetVer1(
SchematicFileName = a_FileName.substr(0, PathEnd) + SchematicFileName;
}
cBlockArea area;
- if (!cSchematicFileSerializer::LoadFromSchematicFile(area, SchematicFileName))
+ try
+ {
+ cSchematicFileSerializer::LoadFromSchematicFile(area, SchematicFileName);
+ }
+ catch (const std::exception & Oops)
{
- CONDWARNING(a_LogWarnings, "Cannot load schematic file \"%s\" for piece %s in cubeset %s.",
- SchematicFileName.c_str(), a_PieceName.c_str(), a_FileName.c_str()
+ CONDWARNING(a_LogWarnings, "Cannot load schematic file \"%s\" for piece %s in cubeset %s. %s",
+ SchematicFileName.c_str(), a_PieceName.c_str(), a_FileName.c_str(), Oops.what()
);
return nullptr;
}
diff --git a/src/Generating/PrefabPiecePool.h b/src/Generating/PrefabPiecePool.h
index 84aba92d1..6bbb7ac13 100644
--- a/src/Generating/PrefabPiecePool.h
+++ b/src/Generating/PrefabPiecePool.h
@@ -44,10 +44,6 @@ public:
int a_DefaultStartingPieceHeight = -1
);
- /** Creates a pool and loads the contents of the specified file into it.
- If a_LogWarnings is true, logs a warning to console when loading fails. */
- cPrefabPiecePool(const AString & a_FileName, bool a_LogWarnings);
-
/** Destroys the pool, freeing all pieces. */
virtual ~cPrefabPiecePool() override;
diff --git a/src/Globals.h b/src/Globals.h
index 192969fa5..cdfea9e5a 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -75,39 +75,8 @@
#endif
-#include <stddef.h>
-// Integral types with predefined sizes:
-typedef signed long long Int64;
-typedef signed int Int32;
-typedef signed short Int16;
-typedef signed char Int8;
-
-typedef unsigned long long UInt64;
-typedef unsigned int UInt32;
-typedef unsigned short UInt16;
-typedef unsigned char UInt8;
-
-typedef unsigned char Byte;
-typedef Byte ColourID;
-
-
-template <typename T, size_t Size>
-class SizeChecker
-{
- static_assert(sizeof(T) == Size, "Check the size of integral types");
-};
-
-template class SizeChecker<Int64, 8>;
-template class SizeChecker<Int32, 4>;
-template class SizeChecker<Int16, 2>;
-template class SizeChecker<Int8, 1>;
-
-template class SizeChecker<UInt64, 8>;
-template class SizeChecker<UInt32, 4>;
-template class SizeChecker<UInt16, 2>;
-template class SizeChecker<UInt8, 1>;
// A macro to disallow the copy constructor and operator = functions
// This should be used in the declarations for any class that shouldn't allow copying itself
@@ -130,6 +99,7 @@ template class SizeChecker<UInt8, 1>;
+
// OS-dependent stuff:
#ifdef _WIN32
@@ -161,6 +131,7 @@ template class SizeChecker<UInt8, 1>;
#include <cstdio>
#include <cmath>
#include <cstdarg>
+#include <cstddef>
@@ -188,10 +159,43 @@ template class SizeChecker<UInt8, 1>;
#include <unordered_map>
#include <unordered_set>
#include <vector>
+#include <variant>
+
+// Integral types with predefined sizes:
+typedef signed long long Int64;
+typedef signed int Int32;
+typedef signed short Int16;
+typedef signed char Int8;
+
+typedef unsigned long long UInt64;
+typedef unsigned int UInt32;
+typedef unsigned short UInt16;
+typedef unsigned char UInt8;
+
+typedef unsigned char Byte;
+typedef Byte ColourID;
+
+
+template <typename T, size_t Size>
+class SizeChecker
+{
+ static_assert(sizeof(T) == Size, "Check the size of integral types");
+};
+
+template class SizeChecker<Int64, 8>;
+template class SizeChecker<Int32, 4>;
+template class SizeChecker<Int16, 2>;
+template class SizeChecker<Int8, 1>;
+
+template class SizeChecker<UInt64, 8>;
+template class SizeChecker<UInt32, 4>;
+template class SizeChecker<UInt16, 2>;
+template class SizeChecker<UInt8, 1>;
+
// Common headers (part 1, without macros):
#include "fmt.h"
#include "StringUtils.h"
@@ -301,6 +305,20 @@ template class SizeChecker<UInt8, 1>;
+
+namespace cpp20
+{
+ template <class T>
+ std::enable_if_t<std::is_array_v<T> && (std::extent_v<T> == 0), std::unique_ptr<T>> make_unique_for_overwrite(std::size_t a_Size)
+ {
+ return std::unique_ptr<T>(new std::remove_extent_t<T>[a_Size]);
+ }
+}
+
+
+
+
+
/** Clamp X to the specified range. */
template <typename T>
T Clamp(T a_Value, T a_Min, T a_Max)
@@ -334,6 +352,9 @@ typename std::enable_if<std::is_arithmetic<T>::value, C>::type CeilC(T a_Value)
using cTickTime = std::chrono::duration<int, std::ratio_multiply<std::chrono::milliseconds::period, std::ratio<50>>>;
using cTickTimeLong = std::chrono::duration<Int64, cTickTime::period>;
+using ContiguousByteBuffer = std::basic_string<std::byte>;
+using ContiguousByteBufferView = std::basic_string_view<std::byte>;
+
#ifndef TOLUA_TEMPLATE_BIND
#define TOLUA_TEMPLATE_BIND(x)
#endif
@@ -355,4 +376,3 @@ auto ToUnsigned(T a_Val)
// Common headers (part 2, with macros):
#include "Vector3.h"
-
diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp
index 8c5eb92a4..618463bd6 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -157,19 +157,18 @@ int cFile::Read (void * a_Buffer, size_t a_NumBytes)
-AString cFile::Read(size_t a_NumBytes)
+ContiguousByteBuffer cFile::Read(size_t a_NumBytes)
{
ASSERT(IsOpen());
if (!IsOpen())
{
- return AString();
+ return {};
}
- // HACK: This depends on the knowledge that AString::data() returns the internal buffer, rather than a copy of it.
- AString res;
- res.resize(a_NumBytes);
- auto newSize = fread(const_cast<char *>(res.data()), 1, a_NumBytes, m_File);
+ ContiguousByteBuffer res;
+ res.resize(a_NumBytes); // TODO: investigate if worth hacking around std::string internals to avoid initialisation
+ auto newSize = fread(res.data(), sizeof(std::byte), a_NumBytes, m_File);
res.resize(newSize);
return res;
}
@@ -284,9 +283,8 @@ int cFile::ReadRestOfFile(AString & a_Contents)
auto DataSize = static_cast<size_t>(TotalSize - Position);
- // HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly
- a_Contents.assign(DataSize, '\0');
- return Read(static_cast<void *>(const_cast<char *>(a_Contents.data())), DataSize);
+ a_Contents.resize(DataSize); // TODO: investigate if worth hacking around std::string internals to avoid initialisation
+ return Read(a_Contents.data(), DataSize);
}
@@ -709,3 +707,54 @@ void cFile::Flush(void)
{
fflush(m_File);
}
+
+
+
+
+
+template <class StreamType>
+FileStream<StreamType>::FileStream(const std::string & Path)
+{
+ // Except on failbit, which is what open sets on failure:
+ FileStream::exceptions(FileStream::failbit | FileStream::badbit);
+
+ // Open the file:
+ FileStream::open(Path);
+
+ // Only subsequently except on serious errors, and not on conditions like EOF or malformed input:
+ FileStream::exceptions(FileStream::badbit);
+}
+
+
+
+
+
+template <class StreamType>
+FileStream<StreamType>::FileStream(const std::string & Path, const typename FileStream::openmode Mode)
+{
+ // Except on failbit, which is what open sets on failure:
+ FileStream::exceptions(FileStream::failbit | FileStream::badbit);
+
+ // Open the file:
+ FileStream::open(Path, Mode);
+
+ // Only subsequently except on serious errors, and not on conditions like EOF or malformed input:
+ FileStream::exceptions(FileStream::badbit);
+}
+
+
+
+
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-template-vtables" // http://bugs.llvm.org/show_bug.cgi?id=18733
+#endif
+
+// Instantiate the templated wrapper for input and output:
+template class FileStream<std::ifstream>;
+template class FileStream<std::ofstream>;
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h
index 59f3a5558..7a3333483 100644
--- a/src/OSSupport/File.h
+++ b/src/OSSupport/File.h
@@ -75,7 +75,7 @@ public:
int Read(void * a_Buffer, size_t a_NumBytes);
/** Reads up to a_NumBytes bytes, returns the bytes actually read, or empty string on failure; asserts if not open */
- AString Read(size_t a_NumBytes);
+ std::basic_string<std::byte> Read(size_t a_NumBytes);
/** Writes up to a_NumBytes bytes from a_Buffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */
int Write(const void * a_Buffer, size_t a_NumBytes);
@@ -192,17 +192,8 @@ class FileStream final : public StreamType
{
public:
- FileStream(const std::string & Path)
- {
- // Except on failbit, which is what open sets on failure:
- FileStream::exceptions(FileStream::failbit | FileStream::badbit);
-
- // Open the file:
- FileStream::open(Path);
-
- // Only subsequently except on serious errors, and not on conditions like EOF or malformed input:
- FileStream::exceptions(FileStream::badbit);
- }
+ FileStream(const std::string & Path);
+ FileStream(const std::string & Path, const typename FileStream::openmode Mode);
};
@@ -211,3 +202,15 @@ public:
using InputFileStream = FileStream<std::ifstream>;
using OutputFileStream = FileStream<std::ofstream>;
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-template-vtables" // http://bugs.llvm.org/show_bug.cgi?id=18733
+#endif
+
+extern template class FileStream<std::ifstream>;
+extern template class FileStream<std::ofstream>;
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp
index e83d42583..0bf26dfed 100644
--- a/src/OSSupport/GZipFile.cpp
+++ b/src/OSSupport/GZipFile.cpp
@@ -4,107 +4,27 @@
// Implements the cGZipFile class representing a RAII wrapper over zlib's GZip file routines
#include "Globals.h"
+#include "File.h"
#include "GZipFile.h"
-cGZipFile::cGZipFile(void) :
- m_File(nullptr), m_Mode(fmRead)
+Compression::Result GZipFile::ReadRestOfFile(const std::string & a_FileName)
{
-}
-
-
-
-
-
-cGZipFile::~cGZipFile()
-{
- Close();
-}
-
+ InputFileStream File(a_FileName, InputFileStream::binary);
+ const std::string Input{ std::istreambuf_iterator<char>(File), std::istreambuf_iterator<char>() };
+ const ContiguousByteBufferView Data{ reinterpret_cast<const std::byte *>(Input.data()), Input.size() };
-
-
-
-bool cGZipFile::Open(const AString & a_FileName, eMode a_Mode)
-{
- if (m_File != nullptr)
- {
- ASSERT(!"A file is already open in this object");
- return false;
- }
- m_File = gzopen(a_FileName.c_str(), (a_Mode == fmRead) ? "r" : "w");
- m_Mode = a_Mode;
- return (m_File != nullptr);
+ return Compression::Extractor().ExtractGZip(Data);
}
-void cGZipFile::Close(void)
+void GZipFile::Write(const std::string & a_FileName, ContiguousByteBufferView a_Contents)
{
- if (m_File != nullptr)
- {
- gzclose(m_File);
- m_File = nullptr;
- }
+ OutputFileStream(a_FileName, OutputFileStream::binary) << Compression::Compressor().CompressGZip(a_Contents).GetStringView();
}
-
-
-
-
-
-int cGZipFile::ReadRestOfFile(AString & a_Contents)
-{
- if (m_File == nullptr)
- {
- ASSERT(!"No file has been opened");
- return -1;
- }
-
- if (m_Mode != fmRead)
- {
- ASSERT(!"Bad file mode, cannot read");
- return -1;
- }
-
- // Since the gzip format doesn't really support getting the uncompressed length, we need to read incrementally. Yuck!
- int NumBytesRead = 0;
- int TotalBytes = 0;
- char Buffer[64 KiB];
- while ((NumBytesRead = gzread(m_File, Buffer, sizeof(Buffer))) > 0)
- {
- TotalBytes += NumBytesRead;
- a_Contents.append(Buffer, static_cast<size_t>(NumBytesRead));
- }
- // NumBytesRead is < 0 on error
- return (NumBytesRead >= 0) ? TotalBytes : NumBytesRead;
-}
-
-
-
-
-
-bool cGZipFile::Write(const char * a_Contents, int a_Size)
-{
- if (m_File == nullptr)
- {
- ASSERT(!"No file has been opened");
- return false;
- }
-
- if (m_Mode != fmWrite)
- {
- ASSERT(!"Bad file mode, cannot write");
- return false;
- }
-
- return (gzwrite(m_File, a_Contents, static_cast<unsigned int>(a_Size)) != 0);
-}
-
-
-
-
diff --git a/src/OSSupport/GZipFile.h b/src/OSSupport/GZipFile.h
index 00a2fd717..dd4999339 100644
--- a/src/OSSupport/GZipFile.h
+++ b/src/OSSupport/GZipFile.h
@@ -1,7 +1,7 @@
// GZipFile.h
-// Declares the cGZipFile class representing a RAII wrapper over zlib's GZip file routines
+// Declares the GZipFile namespace representing a wrapper over a file stream that can read and write to GZip'd files
@@ -9,44 +9,17 @@
#pragma once
-#include "zlib/zlib.h"
+#include "StringCompression.h"
-class cGZipFile
+namespace GZipFile
{
-public:
- enum eMode
- {
- fmRead, // Read-only. If the file doesn't exist, object will not be valid
- fmWrite, // Write-only. If the file already exists, it will be overwritten
- } ;
+ /** Reads the rest of the file and returns the decompressed contents. */
+ Compression::Result ReadRestOfFile(const std::string & a_FileName);
- cGZipFile(void);
- ~cGZipFile();
-
- /** Opens the file. Returns true if successful. Fails if a file has already been opened through this object. */
- bool Open(const AString & a_FileName, eMode a_Mode);
-
- /** Closes the file, flushing all buffers. This object may be then reused for a different file and / or mode */
- void Close(void);
-
- /** Reads the rest of the file and decompresses it into a_Contents. Returns the number of decompressed bytes, <0 for error */
- int ReadRestOfFile(AString & a_Contents);
-
- /** Writes a_Contents into file, compressing it along the way. Returns true if successful. Multiple writes are supported. */
- bool Write(const AString & a_Contents) { return Write(a_Contents.data(), static_cast<int>(a_Contents.size())); }
-
- bool Write(const char * a_Data, int a_Size);
-
-protected:
- gzFile m_File;
- eMode m_Mode;
+ /** Writes a_Contents into file, compressing it along the way. */
+ void Write(const std::string & a_FileName, ContiguousByteBufferView a_Contents);
} ;
-
-
-
-
-
diff --git a/src/Protocol/ChunkDataSerializer.cpp b/src/Protocol/ChunkDataSerializer.cpp
index ac740a145..a16cce02b 100644
--- a/src/Protocol/ChunkDataSerializer.cpp
+++ b/src/Protocol/ChunkDataSerializer.cpp
@@ -1,6 +1,5 @@
#include "Globals.h"
#include "ChunkDataSerializer.h"
-#include "zlib/zlib.h"
#include "Protocol_1_8.h"
#include "Protocol_1_9.h"
#include "../ClientHandle.h"
@@ -543,14 +542,10 @@ inline void cChunkDataSerializer::WriteSectionDataSeamless(const cChunkData::sCh
inline void cChunkDataSerializer::CompressPacketInto(ChunkDataCache & a_Cache)
{
- m_Packet.ReadAll(a_Cache.PacketData);
+ m_Compressor.ReadFrom(m_Packet);
m_Packet.CommitRead();
- if (!cProtocol_1_8_0::CompressPacket(a_Cache.PacketData, a_Cache.ToSend))
- {
- ASSERT(!"Packet compression failed.");
- return;
- }
+ cProtocol_1_8_0::CompressPacket(m_Compressor, a_Cache.ToSend);
a_Cache.Engaged = true;
}
diff --git a/src/Protocol/ChunkDataSerializer.h b/src/Protocol/ChunkDataSerializer.h
index aeff7c356..ea0b0be11 100644
--- a/src/Protocol/ChunkDataSerializer.h
+++ b/src/Protocol/ChunkDataSerializer.h
@@ -3,6 +3,8 @@
#include "../ByteBuffer.h"
#include "../ChunkData.h"
#include "../Defines.h"
+#include "CircularBufferCompressor.h"
+#include "StringCompression.h"
@@ -37,8 +39,7 @@ class cChunkDataSerializer
/** A single cache entry containing the raw data, compressed data, and a validity flag. */
struct ChunkDataCache
{
- std::string PacketData;
- std::string ToSend;
+ ContiguousByteBuffer ToSend;
bool Engaged = false;
};
@@ -50,7 +51,7 @@ public:
Parameters are the coordinates of the chunk to serialise, and the data and biome data read from the chunk. */
void SendToClients(int a_ChunkX, int a_ChunkZ, const cChunkData & a_Data, const unsigned char * a_BiomeData, const ClientHandles & a_SendTo);
-protected:
+private:
/** Serialises the given chunk, storing the result into the given cache entry, and sends the data.
If the cache entry is already present, simply re-uses it. */
@@ -74,6 +75,9 @@ protected:
/** A staging area used to construct the chunk packet, persistent to avoid reallocating. */
cByteBuffer m_Packet;
+ /** A compressor used to compress the chunk data. */
+ CircularBufferCompressor m_Compressor;
+
/** The dimension for the World this Serializer is tied to. */
const eDimension m_Dimension;
@@ -81,7 +85,3 @@ protected:
It is used during a single invocation of SendToClients with more than one client. */
std::array<ChunkDataCache, static_cast<size_t>(CacheVersion::Last) + 1> m_Cache;
} ;
-
-
-
-
diff --git a/src/Protocol/ForgeHandshake.cpp b/src/Protocol/ForgeHandshake.cpp
index 8c16d4f0c..99b585894 100644
--- a/src/Protocol/ForgeHandshake.cpp
+++ b/src/Protocol/ForgeHandshake.cpp
@@ -36,8 +36,8 @@ namespace ClientPhase
/** Server handshake state phases. */
namespace ServerPhase
{
- static const Int8 WAITINGCACK = 2;
- static const Int8 COMPLETE = 3;
+ static const auto WAITINGCACK = std::byte(2);
+ static const auto COMPLETE = std::byte(3);
}
@@ -105,12 +105,12 @@ void cForgeHandshake::BeginForgeHandshake(const AString & a_Name, const cUUID &
m_UUID = a_UUID;
m_Properties = a_Properties;
- static const std::array<AString, 5> Channels{{ "FML|HS", "FML", "FML|MP", "FML", "FORGE" }};
- AString ChannelsString;
+ static const std::array<std::string_view, 5> Channels{{ "FML|HS", "FML", "FML|MP", "FML", "FORGE" }};
+ ContiguousByteBuffer ChannelsString;
for (auto & Channel: Channels)
{
- ChannelsString.append(Channel);
- ChannelsString.push_back('\0');
+ ChannelsString.append({ reinterpret_cast<const std::byte *>(Channel.data()), Channel.size() });
+ ChannelsString.push_back(std::byte(0));
}
m_Client->SendPluginMessage("REGISTER", ChannelsString);
@@ -123,7 +123,6 @@ void cForgeHandshake::BeginForgeHandshake(const AString & a_Name, const cUUID &
void cForgeHandshake::SendServerHello()
{
- AString Message;
cByteBuffer Buf(6);
// Discriminator | Byte | Always 0 for ServerHello
Buf.WriteBEInt8(Discriminator::ServerHello);
@@ -131,6 +130,8 @@ void cForgeHandshake::SendServerHello()
Buf.WriteBEInt8(2);
// Dimension TODO
Buf.WriteBEInt32(0);
+
+ ContiguousByteBuffer Message;
Buf.ReadAll(Message);
m_Client->SendPluginMessage("FML|HS", Message);
@@ -140,18 +141,18 @@ void cForgeHandshake::SendServerHello()
-AStringMap cForgeHandshake::ParseModList(const char * a_Data, size_t a_Size)
+AStringMap cForgeHandshake::ParseModList(const ContiguousByteBufferView a_Data)
{
AStringMap Mods;
- if (a_Size < 4)
+ if (a_Data.size() < 4)
{
- SetError(Printf("ParseModList invalid packet, missing length (size = %zu)", a_Size));
+ SetError(Printf("ParseModList invalid packet, missing length (size = %zu)", a_Data.size()));
return Mods;
}
- cByteBuffer Buf(a_Size);
- Buf.Write(a_Data, a_Size);
+ cByteBuffer Buf(a_Data.size());
+ Buf.Write(a_Data.data(), a_Data.size());
UInt32 NumMods;
if (!Buf.ReadVarInt32(NumMods))
{
@@ -182,11 +183,11 @@ AStringMap cForgeHandshake::ParseModList(const char * a_Data, size_t a_Size)
-void cForgeHandshake::HandleClientHello(cClientHandle * a_Client, const char * a_Data, size_t a_Size)
+void cForgeHandshake::HandleClientHello(cClientHandle * a_Client, const ContiguousByteBufferView a_Data)
{
- if (a_Size == 2)
+ if (a_Data.size() == 2)
{
- int FmlProtocolVersion = a_Data[1];
+ const auto FmlProtocolVersion = static_cast<Int8>(a_Data[1]);
LOGD("Received ClientHello with FML protocol version %d", FmlProtocolVersion);
if (FmlProtocolVersion != 2)
{
@@ -195,7 +196,7 @@ void cForgeHandshake::HandleClientHello(cClientHandle * a_Client, const char * a
}
else
{
- SetError(Printf("Received unexpected length of ClientHello: %zu", a_Size));
+ SetError(Printf("Received unexpected length of ClientHello: %zu", a_Data.size()));
}
}
@@ -203,11 +204,11 @@ void cForgeHandshake::HandleClientHello(cClientHandle * a_Client, const char * a
-void cForgeHandshake::HandleModList(cClientHandle * a_Client, const char * a_Data, size_t a_Size)
+void cForgeHandshake::HandleModList(cClientHandle * a_Client, const ContiguousByteBufferView a_Data)
{
LOGD("Received ModList");
- auto ClientMods = ParseModList(a_Data + 1, a_Size - 1);
+ auto ClientMods = ParseModList(a_Data.substr(1));
AString ClientModsString;
for (auto & item: ClientMods)
{
@@ -241,7 +242,8 @@ void cForgeHandshake::HandleModList(cClientHandle * a_Client, const char * a_Dat
Buf.WriteVarUTF8String(item.first); // name
Buf.WriteVarUTF8String(item.second); // version
}
- AString ServerModList;
+
+ ContiguousByteBuffer ServerModList;
Buf.ReadAll(ServerModList);
m_Client->SendPluginMessage("FML|HS", ServerModList);
@@ -251,15 +253,15 @@ void cForgeHandshake::HandleModList(cClientHandle * a_Client, const char * a_Dat
-void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char * a_Data, size_t a_Size)
+void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const ContiguousByteBufferView a_Data)
{
- if (a_Size != 2)
+ if (a_Data.size() != 2)
{
- SetError(Printf("Unexpected HandshakeAck packet length: %zu", a_Size));
+ SetError(Printf("Unexpected HandshakeAck packet length: %zu", a_Data.size()));
return;
}
- auto Phase = a_Data[1];
+ const auto Phase = static_cast<Int8>(a_Data[1]);
LOGD("Received client HandshakeAck with phase = %d", Phase);
switch (Phase)
@@ -282,7 +284,7 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
Buf.WriteVarInt32(NumSubstitutions);
Buf.WriteVarInt32(NumDummies);
- AString RegistryData;
+ ContiguousByteBuffer RegistryData;
Buf.ReadAll(RegistryData);
m_Client->SendPluginMessage("FML|HS", RegistryData);
break;
@@ -292,8 +294,8 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
{
LOGD("Client finished receiving registry data; acknowledging");
- AString Ack;
- Ack.push_back(Discriminator::HandshakeAck);
+ ContiguousByteBuffer Ack;
+ Ack.push_back(std::byte(Discriminator::HandshakeAck));
Ack.push_back(ServerPhase::WAITINGCACK);
m_Client->SendPluginMessage("FML|HS", Ack);
break;
@@ -303,8 +305,8 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
{
LOGD("Client is pending completion; sending complete ack");
- AString Ack;
- Ack.push_back(Discriminator::HandshakeAck);
+ ContiguousByteBuffer Ack;
+ Ack.push_back(std::byte(Discriminator::HandshakeAck));
Ack.push_back(ServerPhase::COMPLETE);
m_Client->SendPluginMessage("FML|HS", Ack);
@@ -320,7 +322,7 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
default:
{
- SetError(Printf("Received unknown phase in Forge handshake acknowledgement: %d", Phase));
+ SetError(fmt::format("Received unknown phase in Forge handshake acknowledgement: {}", Phase));
break;
}
}
@@ -330,11 +332,11 @@ void cForgeHandshake::HandleHandshakeAck(cClientHandle * a_Client, const char *
-void cForgeHandshake::DataReceived(cClientHandle * a_Client, const char * a_Data, size_t a_Size)
+void cForgeHandshake::DataReceived(cClientHandle * a_Client, const ContiguousByteBufferView a_Data)
{
if (!m_IsForgeClient)
{
- SetError(Printf("Received unexpected Forge data from non-Forge client (%zu bytes)", a_Size));
+ SetError(Printf("Received unexpected Forge data from non-Forge client (%zu bytes)", a_Data.size()));
return;
}
if (m_Errored)
@@ -343,19 +345,18 @@ void cForgeHandshake::DataReceived(cClientHandle * a_Client, const char * a_Data
return;
}
- if (a_Size <= 1)
+ if (a_Data.size() <= 1)
{
- SetError(Printf("Received unexpectedly short Forge data (%zu bytes)", a_Size));
+ SetError(Printf("Received unexpectedly short Forge data (%zu bytes)", a_Data.size()));
return;
}
- auto Discriminator = a_Data[0];
-
+ const auto Discriminator = static_cast<Int8>(a_Data[0]);
switch (Discriminator)
{
- case Discriminator::ClientHello: HandleClientHello(a_Client, a_Data, a_Size); break;
- case Discriminator::ModList: HandleModList(a_Client, a_Data, a_Size); break;
- case Discriminator::HandshakeAck: HandleHandshakeAck(a_Client, a_Data, a_Size); break;
+ case Discriminator::ClientHello: HandleClientHello(a_Client, a_Data); break;
+ case Discriminator::ModList: HandleModList(a_Client, a_Data); break;
+ case Discriminator::HandshakeAck: HandleHandshakeAck(a_Client, a_Data); break;
default:
{
diff --git a/src/Protocol/ForgeHandshake.h b/src/Protocol/ForgeHandshake.h
index 46e0efaa6..061369c15 100644
--- a/src/Protocol/ForgeHandshake.h
+++ b/src/Protocol/ForgeHandshake.h
@@ -34,7 +34,7 @@ public:
void SendServerHello();
/** Process received data from the client advancing the Forge handshake. */
- void DataReceived(cClientHandle * a_Client, const char * a_Data, size_t a_Size);
+ void DataReceived(cClientHandle * a_Client, ContiguousByteBufferView a_Data);
private:
/** True if the Forge handshake is in an errored state. */
@@ -48,13 +48,13 @@ private:
cUUID m_UUID;
Json::Value m_Properties;
- void HandleClientHello(cClientHandle * a_Client, const char * a_Data, size_t a_Size);
- void HandleModList(cClientHandle * a_Client, const char * a_Data, size_t a_Size);
- void HandleHandshakeAck(cClientHandle * a_Client, const char * a_Data, size_t a_Size);
+ void HandleClientHello(cClientHandle * a_Client, ContiguousByteBufferView a_Data);
+ void HandleModList(cClientHandle * a_Client, ContiguousByteBufferView a_Data);
+ void HandleHandshakeAck(cClientHandle * a_Client, ContiguousByteBufferView a_Data);
/** Set errored state to prevent further handshake message processing. */
void SetError(const AString & message);
/** Parse the client ModList packet of installed Forge mods and versions. */
- AStringMap ParseModList(const char * a_Data, size_t a_Size);
+ AStringMap ParseModList(ContiguousByteBufferView a_Data);
};
diff --git a/src/Protocol/Packetizer.h b/src/Protocol/Packetizer.h
index 4ece6e4fa..f4d632a27 100644
--- a/src/Protocol/Packetizer.h
+++ b/src/Protocol/Packetizer.h
@@ -119,9 +119,9 @@ public:
}
- inline void WriteBuf(const char * a_Data, size_t a_Size)
+ inline void WriteBuf(const ContiguousByteBufferView a_Data)
{
- VERIFY(m_Out.Write(a_Data, a_Size));
+ VERIFY(m_Out.Write(a_Data.data(), a_Data.size()));
}
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 5c9d5105f..341e0b0f4 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -365,7 +365,7 @@ public:
virtual void SendChat (const AString & a_Message, eChatType a_Type) = 0;
virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) = 0;
virtual void SendChatRaw (const AString & a_MessageRaw, eChatType a_Type) = 0;
- virtual void SendChunkData (const std::string_view a_ChunkData) = 0;
+ virtual void SendChunkData (ContiguousByteBufferView a_ChunkData) = 0;
virtual void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) = 0;
virtual void SendDestroyEntity (const cEntity & a_Entity) = 0;
virtual void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) = 0;
@@ -405,7 +405,7 @@ public:
virtual void SendPlayerMoveLook (void) = 0;
virtual void SendPlayerPosition (void) = 0;
virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0;
- virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0;
+ virtual void SendPluginMessage (const AString & a_Channel, ContiguousByteBufferView a_Message) = 0;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0;
virtual void SendResetTitle (void) = 0;
virtual void SendResourcePack (const AString & a_ResourcePackUrl) = 0;
@@ -468,7 +468,7 @@ protected:
virtual Version GetProtocolVersion() = 0;
/** A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it. */
- virtual void SendData(const char * a_Data, size_t a_Size) = 0;
+ virtual void SendData(ContiguousByteBufferView a_Data) = 0;
/** Sends a single packet contained within the cPacketizer class.
The cPacketizer's destructor calls this to send the contained packet; protocol may transform the data (compression in 1.8 etc). */
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 5d146c46a..dc6b93b01 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -123,11 +123,6 @@ void cMultiVersionProtocol::HandleIncomingDataInRecognitionStage(cClientHandle &
HandleIncomingDataInOldPingResponseStage(a_Clyent, a_In);
};
}
- catch (const std::exception & Oops)
- {
- a_Client.Kick(Oops.what());
- return;
- }
// Explicitly process any remaining data with the new handler:
HandleIncomingData(a_Client, a_Data);
@@ -341,15 +336,15 @@ void cMultiVersionProtocol::SendPacket(cClientHandle & a_Client, cByteBuffer & a
// Compression doesn't apply to this state, send raw data:
VERIFY(OutPacketLenBuffer.WriteVarInt32(PacketLen));
- AString LengthData;
+ ContiguousByteBuffer LengthData;
OutPacketLenBuffer.ReadAll(LengthData);
- a_Client.SendData(LengthData.data(), LengthData.size());
+ a_Client.SendData(LengthData);
// Send the packet's payload:
- AString PacketData;
+ ContiguousByteBuffer PacketData;
a_OutPacketBuffer.ReadAll(PacketData);
a_OutPacketBuffer.CommitRead();
- a_Client.SendData(PacketData.data(), PacketData.size());
+ a_Client.SendData(PacketData);
}
diff --git a/src/Protocol/Protocol_1_10.cpp b/src/Protocol/Protocol_1_10.cpp
index 0efef360c..b3a3205d5 100644
--- a/src/Protocol/Protocol_1_10.cpp
+++ b/src/Protocol/Protocol_1_10.cpp
@@ -679,7 +679,7 @@ void cProtocol_1_10_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity
}
Writer.Finish();
- a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ a_Pkt.WriteBuf(Writer.GetResult());
}
diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp
index 05bf35562..ff0c34223 100644
--- a/src/Protocol/Protocol_1_11.cpp
+++ b/src/Protocol/Protocol_1_11.cpp
@@ -520,7 +520,7 @@ void cProtocol_1_11_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity
}
Writer.Finish();
- a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ a_Pkt.WriteBuf(Writer.GetResult());
}
diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp
index 93a1160ee..30a975d18 100644
--- a/src/Protocol/Protocol_1_12.cpp
+++ b/src/Protocol/Protocol_1_12.cpp
@@ -1045,7 +1045,7 @@ void cProtocol_1_12::HandlePacketCraftingBookData(cByteBuffer & a_ByteBuffer)
{
// TODO not yet used, not sure if it is needed
// https://wiki.vg/index.php?title=Protocol&oldid=14204#Crafting_Book_Data
- a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
+ a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace());
}
@@ -1054,7 +1054,7 @@ void cProtocol_1_12::HandlePacketCraftingBookData(cByteBuffer & a_ByteBuffer)
void cProtocol_1_12::HandlePacketAdvancementTab(cByteBuffer & a_ByteBuffer)
{
- a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
+ a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace());
m_Client->GetPlayer()->SendMessageInfo("The new advancements are not implemented.");
}
diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp
index 251f8cf55..4da065af7 100644
--- a/src/Protocol/Protocol_1_13.cpp
+++ b/src/Protocol/Protocol_1_13.cpp
@@ -298,13 +298,14 @@ void cProtocol_1_13::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
m_Client->SetClientBrand(Brand);
// Send back our brand, including the length:
- SendPluginMessage("minecraft:brand", "\x08""Cuberite");
+ m_Client->SendPluginMessage("minecraft:brand", "\x08""Cuberite");
return;
}
+ ContiguousByteBuffer Data;
+
// Read the plugin message and relay to clienthandle:
- AString Data;
- VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds
+ VERIFY(a_ByteBuffer.ReadSome(Data, a_ByteBuffer.GetReadableSpace())); // Always succeeds
m_Client->HandlePluginMessage(Channel, Data);
}
@@ -694,8 +695,8 @@ bool cProtocol_1_13::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t
a_Item.Empty();
}
- AString Metadata;
- if (!a_ByteBuffer.ReadString(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes - 1) || (Metadata.size() == 0) || (Metadata[0] == 0))
+ ContiguousByteBuffer Metadata;
+ if (!a_ByteBuffer.ReadSome(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes) || Metadata.empty() || (Metadata[0] == std::byte(0)))
{
// No metadata
return true;
@@ -1423,8 +1424,8 @@ bool cProtocol_1_13_2::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size
a_Item.Empty();
}
- AString Metadata;
- if (!a_ByteBuffer.ReadString(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes - 1) || (Metadata.size() == 0) || (Metadata[0] == 0))
+ ContiguousByteBuffer Metadata;
+ if (!a_ByteBuffer.ReadSome(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes) || Metadata.empty() || (Metadata[0] == std::byte(0)))
{
// No metadata
return true;
diff --git a/src/Protocol/Protocol_1_14.cpp b/src/Protocol/Protocol_1_14.cpp
index e015c6cd1..bc0e68d94 100644
--- a/src/Protocol/Protocol_1_14.cpp
+++ b/src/Protocol/Protocol_1_14.cpp
@@ -231,8 +231,7 @@ bool cProtocol_1_14::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTyp
// Game
switch (a_PacketType)
{
- default: AString dum; a_ByteBuffer.ReadAll(dum); a_ByteBuffer.CommitRead(); a_ByteBuffer.Write(" ", 1);
- return true;
+ default: a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace()); a_ByteBuffer.CommitRead(); return true;
}
}
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index d9d18b41a..12e2d441c 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -85,7 +85,6 @@ Implements the 1.8 protocol classes:
const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows...
-const uLongf MAX_COMPRESSED_PACKET_LEN = 200 KiB; // Maximum size of compressed packets.
static const UInt32 CompressionThreshold = 256; // After how large a packet should we compress it.
@@ -178,7 +177,7 @@ void cProtocol_1_8_0::DataReceived(cByteBuffer & a_Buffer, const char * a_Data,
{
if (m_IsEncrypted)
{
- Byte Decrypted[512];
+ std::byte Decrypted[512];
while (a_Size > 0)
{
size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
@@ -320,12 +319,12 @@ void cProtocol_1_8_0::SendChatRaw(const AString & a_MessageRaw, eChatType a_Type
-void cProtocol_1_8_0::SendChunkData(const std::string_view a_ChunkData)
+void cProtocol_1_8_0::SendChunkData(const ContiguousByteBufferView a_ChunkData)
{
ASSERT(m_State == 3); // In game mode?
cCSLock Lock(m_CSPacket);
- SendData(a_ChunkData.data(), a_ChunkData.size());
+ SendData(a_ChunkData);
}
@@ -1143,13 +1142,13 @@ void cProtocol_1_8_0::SendPlayerSpawn(const cPlayer & a_Player)
-void cProtocol_1_8_0::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
+void cProtocol_1_8_0::SendPluginMessage(const AString & a_Channel, const ContiguousByteBufferView a_Message)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, pktPluginMessage);
Pkt.WriteString(a_Channel);
- Pkt.WriteBuf(a_Message.data(), a_Message.size());
+ Pkt.WriteBuf(a_Message);
}
@@ -1717,11 +1716,11 @@ void cProtocol_1_8_0::SendWindowProperty(const cWindow & a_Window, size_t a_Prop
-bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_CompressedData)
+void cProtocol_1_8_0::CompressPacket(CircularBufferCompressor & a_Packet, ContiguousByteBuffer & a_CompressedData)
{
- const auto UncompressedSize = a_Packet.size();
+ const auto Uncompressed = a_Packet.GetView();
- if (UncompressedSize < CompressionThreshold)
+ if (Uncompressed.size() < CompressionThreshold)
{
/* Size doesn't reach threshold, not worth compressing.
@@ -1734,7 +1733,7 @@ bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_Compr
----------------------------------------------
*/
const UInt32 DataSize = 0;
- const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + UncompressedSize);
+ const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + Uncompressed.size());
cByteBuffer LengthHeaderBuffer(
cByteBuffer::GetVarIntSize(PacketSize) +
@@ -1744,14 +1743,14 @@ bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_Compr
LengthHeaderBuffer.WriteVarInt32(PacketSize);
LengthHeaderBuffer.WriteVarInt32(DataSize);
- AString LengthData;
+ ContiguousByteBuffer LengthData;
LengthHeaderBuffer.ReadAll(LengthData);
- a_CompressedData.reserve(LengthData.size() + UncompressedSize);
- a_CompressedData.assign(LengthData.data(), LengthData.size());
- a_CompressedData.append(a_Packet);
+ a_CompressedData.reserve(LengthData.size() + Uncompressed.size());
+ a_CompressedData = LengthData;
+ a_CompressedData += Uncompressed;
- return true;
+ return;
}
/* Definitely worth compressing.
@@ -1765,28 +1764,11 @@ bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_Compr
----------------------------------------------
*/
- // Compress the data:
- char CompressedData[MAX_COMPRESSED_PACKET_LEN];
-
- uLongf CompressedSize = compressBound(static_cast<uLongf>(a_Packet.size()));
- if (CompressedSize >= MAX_COMPRESSED_PACKET_LEN)
- {
- ASSERT(!"Too high packet size.");
- return false;
- }
-
- if (
- compress2(
- reinterpret_cast<Bytef *>(CompressedData), &CompressedSize,
- reinterpret_cast<const Bytef *>(a_Packet.data()), static_cast<uLongf>(a_Packet.size()), Z_DEFAULT_COMPRESSION
- ) != Z_OK
- )
- {
- return false;
- }
+ const auto CompressedData = a_Packet.Compress();
+ const auto Compressed = CompressedData.GetView();
- const UInt32 DataSize = static_cast<UInt32>(UncompressedSize);
- const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + CompressedSize);
+ const UInt32 DataSize = static_cast<UInt32>(Uncompressed.size());
+ const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + Compressed.size());
cByteBuffer LengthHeaderBuffer(
cByteBuffer::GetVarIntSize(PacketSize) +
@@ -1796,14 +1778,12 @@ bool cProtocol_1_8_0::CompressPacket(const AString & a_Packet, AString & a_Compr
LengthHeaderBuffer.WriteVarInt32(PacketSize);
LengthHeaderBuffer.WriteVarInt32(DataSize);
- AString LengthData;
+ ContiguousByteBuffer LengthData;
LengthHeaderBuffer.ReadAll(LengthData);
- a_CompressedData.reserve(LengthData.size() + CompressedSize);
- a_CompressedData.assign(LengthData.data(), LengthData.size());
- a_CompressedData.append(CompressedData, CompressedSize);
-
- return true;
+ a_CompressedData.reserve(LengthData.size() + Compressed.size());
+ a_CompressedData = LengthData;
+ a_CompressedData += Compressed;
}
@@ -1947,7 +1927,7 @@ void cProtocol_1_8_0::AddReceivedData(cByteBuffer & a_Buffer, const char * a_Dat
{
if (a_Buffer.GetReadableSpace() > 0)
{
- AString AllData;
+ ContiguousByteBuffer AllData;
size_t OldReadableSpace = a_Buffer.GetReadableSpace();
a_Buffer.ReadAll(AllData);
a_Buffer.ResetRead();
@@ -1992,12 +1972,11 @@ void cProtocol_1_8_0::AddReceivedData(cByteBuffer & a_Buffer, const char * a_Dat
}
// Check packet for compression:
- UInt32 UncompressedSize = 0;
- AString UncompressedData;
if (m_State == 3)
{
UInt32 NumBytesRead = static_cast<UInt32>(a_Buffer.GetReadableSpace());
+ UInt32 UncompressedSize;
if (!a_Buffer.ReadVarInt(UncompressedSize))
{
m_Client->Kick("Compression packet incomplete");
@@ -2011,113 +1990,35 @@ void cProtocol_1_8_0::AddReceivedData(cByteBuffer & a_Buffer, const char * a_Dat
if (UncompressedSize > 0)
{
// Decompress the data:
- AString CompressedData;
- VERIFY(a_Buffer.ReadString(CompressedData, PacketLen));
- if (InflateString(CompressedData.data(), PacketLen, UncompressedData) != Z_OK)
- {
- m_Client->Kick("Compression failure");
- return;
- }
- PacketLen = static_cast<UInt32>(UncompressedData.size());
- if (PacketLen != UncompressedSize)
- {
- m_Client->Kick("Wrong uncompressed packet size given");
- return;
- }
- }
- }
-
- // Move the packet payload to a separate cByteBuffer, bb:
- cByteBuffer bb(PacketLen + 1);
- if (UncompressedSize == 0)
- {
- // No compression was used, move directly
- VERIFY(a_Buffer.ReadToByteBuffer(bb, static_cast<size_t>(PacketLen)));
- }
- else
- {
- // Compression was used, move the uncompressed data:
- VERIFY(bb.Write(UncompressedData.data(), UncompressedData.size()));
- }
- a_Buffer.CommitRead();
+ m_Extractor.ReadFrom(a_Buffer, PacketLen);
+ a_Buffer.CommitRead();
- UInt32 PacketType;
- if (!bb.ReadVarInt(PacketType))
- {
- // Not enough data
- break;
- }
-
- // Write one NUL extra, so that we can detect over-reads
- bb.Write("\0", 1);
+ const auto UncompressedData = m_Extractor.Extract(UncompressedSize);
+ const auto Uncompressed = UncompressedData.GetView();
+ cByteBuffer bb(Uncompressed.size());
- // Log the packet info into the comm log file:
- if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
- {
- AString PacketData;
- bb.ReadAll(PacketData);
- bb.ResetRead();
- bb.ReadVarInt(PacketType); // We have already read the packet type once, it will be there again
- ASSERT(PacketData.size() > 0); // We have written an extra NUL, so there had to be at least one byte read
- PacketData.resize(PacketData.size() - 1);
- AString PacketDataHex;
- CreateHexDump(PacketDataHex, PacketData.data(), PacketData.size(), 16);
- m_CommLogFile.Printf("Next incoming packet is type %u (0x%x), length %u (0x%x) at state %d. Payload:\n%s\n",
- PacketType, PacketType, PacketLen, PacketLen, m_State, PacketDataHex.c_str()
- );
- }
+ // Compression was used, move the uncompressed data:
+ VERIFY(bb.Write(Uncompressed.data(), Uncompressed.size()));
- if (!HandlePacket(bb, PacketType))
- {
- // Unknown packet, already been reported, but without the length. Log the length here:
- LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen);
-
- #ifdef _DEBUG
- // Dump the packet contents into the log:
- bb.ResetRead();
- AString Packet;
- bb.ReadAll(Packet);
- Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
- AString Out;
- CreateHexDump(Out, Packet.data(), Packet.size(), 24);
- LOGD("Packet contents:\n%s", Out.c_str());
- #endif // _DEBUG
-
- // Put a message in the comm log:
- if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
- {
- m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
+ HandlePacket(bb);
+ continue;
}
-
- return;
}
- // The packet should have 1 byte left in the buffer - the NUL we had added
- if (bb.GetReadableSpace() != 1)
- {
- // Read more or less than packet length, report as error
- LOGWARNING("Protocol 1.8: Wrong number of bytes read for packet 0x%x, state %d. Read %zu bytes, packet contained %u bytes",
- PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
- );
+ // Move the packet payload to a separate cByteBuffer, bb:
+ cByteBuffer bb(PacketLen);
- // Put a message in the comm log:
- if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
- {
- m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %zu left) ^^^^^^\n\n\n",
- 1, bb.GetReadableSpace()
- );
- m_CommLogFile.Flush();
- }
+ // No compression was used, move directly:
+ VERIFY(a_Buffer.ReadToByteBuffer(bb, static_cast<size_t>(PacketLen)));
+ a_Buffer.CommitRead();
- ASSERT(!"Read wrong number of bytes!");
- m_Client->PacketError(PacketType);
- }
+ HandlePacket(bb);
} // for (ever)
// Log any leftover bytes into the logfile:
if (g_ShouldLogCommIn && (a_Buffer.GetReadableSpace() > 0) && m_CommLogFile.IsOpen())
{
- AString AllData;
+ ContiguousByteBuffer AllData;
size_t OldReadableSpace = a_Buffer.GetReadableSpace();
a_Buffer.ReadAll(AllData);
a_Buffer.ResetRead();
@@ -2367,8 +2268,8 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
{
return;
}
- AString EncKey;
- if (!a_ByteBuffer.ReadString(EncKey, EncKeyLength))
+ ContiguousByteBuffer EncKey;
+ if (!a_ByteBuffer.ReadSome(EncKey, EncKeyLength))
{
return;
}
@@ -2376,8 +2277,8 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
{
return;
}
- AString EncNonce;
- if (!a_ByteBuffer.ReadString(EncNonce, EncNonceLength))
+ ContiguousByteBuffer EncNonce;
+ if (!a_ByteBuffer.ReadSome(EncNonce, EncNonceLength))
{
return;
}
@@ -2391,7 +2292,7 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
// Decrypt EncNonce using privkey
cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
UInt32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
- int res = rsaDecryptor.Decrypt(reinterpret_cast<const Byte *>(EncNonce.data()), EncNonce.size(), reinterpret_cast<Byte *>(DecryptedNonce), sizeof(DecryptedNonce));
+ int res = rsaDecryptor.Decrypt(EncNonce, reinterpret_cast<Byte *>(DecryptedNonce), sizeof(DecryptedNonce));
if (res != 4)
{
LOGD("Bad nonce length: got %d, exp %d", res, 4);
@@ -2407,7 +2308,7 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
// Decrypt the symmetric encryption key using privkey:
Byte DecryptedKey[MAX_ENC_LEN];
- res = rsaDecryptor.Decrypt(reinterpret_cast<const Byte *>(EncKey.data()), EncKey.size(), DecryptedKey, sizeof(DecryptedKey));
+ res = rsaDecryptor.Decrypt(EncKey, DecryptedKey, sizeof(DecryptedKey));
if (res != 16)
{
LOGD("Bad key length");
@@ -2416,7 +2317,7 @@ void cProtocol_1_8_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBu
}
StartEncryption(DecryptedKey);
- m_Client->HandleLogin(m_Client->GetUsername());
+ m_Client->HandleLogin();
}
@@ -2438,22 +2339,22 @@ void cProtocol_1_8_0::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
return;
}
- cServer * Server = cRoot::Get()->GetServer();
+ m_Client->SetUsername(std::move(Username));
+
// If auth is required, then send the encryption request:
- if (Server->ShouldAuthenticate())
+ if (const auto Server = cRoot::Get()->GetServer(); Server->ShouldAuthenticate())
{
cPacketizer Pkt(*this, pktEncryptionRequest);
Pkt.WriteString(Server->GetServerID());
- const AString & PubKeyDer = Server->GetPublicKeyDER();
+ const auto PubKeyDer = Server->GetPublicKeyDER();
Pkt.WriteVarInt32(static_cast<UInt32>(PubKeyDer.size()));
- Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size());
+ Pkt.WriteBuf(PubKeyDer);
Pkt.WriteVarInt32(4);
Pkt.WriteBEInt32(static_cast<int>(reinterpret_cast<intptr_t>(this))); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
- m_Client->SetUsername(Username);
return;
}
- m_Client->HandleLogin(Username);
+ m_Client->HandleLogin();
}
@@ -2704,20 +2605,20 @@ void cProtocol_1_8_0::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
HandleVanillaPluginMessage(a_ByteBuffer, Channel);
// Skip any unread data (vanilla sometimes sends garbage at the end of a packet; #1692):
- if (a_ByteBuffer.GetReadableSpace() > 1)
+ if (a_ByteBuffer.GetReadableSpace() > 0)
{
LOGD("Protocol 1.8: Skipping garbage data at the end of a vanilla PluginMessage packet, %u bytes",
- static_cast<unsigned>(a_ByteBuffer.GetReadableSpace() - 1)
+ static_cast<unsigned>(a_ByteBuffer.GetReadableSpace())
);
- a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
+ a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace());
}
return;
}
// Read the plugin message and relay to clienthandle:
- AString Data;
- VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds
+ ContiguousByteBuffer Data;
+ VERIFY(a_ByteBuffer.ReadSome(Data, a_ByteBuffer.GetReadableSpace())); // Always succeeds
m_Client->HandlePluginMessage(Channel, Data);
}
@@ -2976,7 +2877,7 @@ void cProtocol_1_8_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, con
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand);
m_Client->SetClientBrand(Brand);
// Send back our brand, including the length:
- SendPluginMessage("MC|Brand", "\x08""Cuberite");
+ m_Client->SendPluginMessage("MC|Brand", "\x08""Cuberite");
return;
}
else if (a_Channel == "MC|Beacon")
@@ -3001,8 +2902,8 @@ void cProtocol_1_8_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, con
LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str());
// Read the payload and send it through to the clienthandle:
- AString Message;
- VERIFY(a_ByteBuffer.ReadString(Message, a_ByteBuffer.GetReadableSpace() - 1));
+ ContiguousByteBuffer Message;
+ VERIFY(a_ByteBuffer.ReadSome(Message, a_ByteBuffer.GetReadableSpace() - 1));
m_Client->HandlePluginMessage(a_Channel, Message);
}
@@ -3010,23 +2911,24 @@ void cProtocol_1_8_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, con
-void cProtocol_1_8_0::SendData(const char * a_Data, size_t a_Size)
+void cProtocol_1_8_0::SendData(ContiguousByteBufferView a_Data)
{
if (m_IsEncrypted)
{
- Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
- while (a_Size > 0)
+ std::byte Encrypted[8 KiB]; // Larger buffer, we may be sending lots of data (chunks)
+
+ while (a_Data.size() > 0)
{
- size_t NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
- m_Encryptor.ProcessData(Encrypted, reinterpret_cast<const Byte *>(a_Data), NumBytes);
- m_Client->SendData(reinterpret_cast<const char *>(Encrypted), NumBytes);
- a_Size -= NumBytes;
- a_Data += NumBytes;
+ const auto NumBytes = (a_Data.size() > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Data.size();
+ m_Encryptor.ProcessData(Encrypted, a_Data.data(), NumBytes);
+ m_Client->SendData({ Encrypted, NumBytes });
+
+ a_Data = a_Data.substr(NumBytes);
}
}
else
{
- m_Client->SendData(a_Data, a_Size);
+ m_Client->SendData(a_Data);
}
}
@@ -3054,8 +2956,8 @@ bool cProtocol_1_8_0::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_
a_Item.Empty();
}
- AString Metadata;
- if (!a_ByteBuffer.ReadString(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes - 1) || (Metadata.size() == 0) || (Metadata[0] == 0))
+ ContiguousByteBuffer Metadata;
+ if (!a_ByteBuffer.ReadSome(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes) || Metadata.empty() || (Metadata[0] == std::byte(0)))
{
// No metadata
return true;
@@ -3069,10 +2971,10 @@ bool cProtocol_1_8_0::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_
-void cProtocol_1_8_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
+void cProtocol_1_8_0::ParseItemMetadata(cItem & a_Item, const ContiguousByteBufferView a_Metadata)
{
// Parse into NBT:
- cParsedNBT NBT(a_Metadata.data(), a_Metadata.size());
+ cParsedNBT NBT(a_Metadata);
if (!NBT.IsValid())
{
AString HexDump;
@@ -3189,33 +3091,34 @@ eBlockFace cProtocol_1_8_0::FaceIntToBlockFace(const Int32 a_BlockFace)
void cProtocol_1_8_0::SendPacket(cPacketizer & a_Pkt)
{
- UInt32 PacketLen = static_cast<UInt32>(m_OutPacketBuffer.GetUsedSpace());
- AString PacketData, CompressedPacket;
- m_OutPacketBuffer.ReadAll(PacketData);
+ ASSERT(m_OutPacketBuffer.GetReadableSpace() == m_OutPacketBuffer.GetUsedSpace());
+
+ m_Compressor.ReadFrom(m_OutPacketBuffer);
m_OutPacketBuffer.CommitRead();
+ const auto PacketData = m_Compressor.GetView();
+
if (m_State == 3)
{
+ ContiguousByteBuffer CompressedPacket;
+
// Compress the packet payload:
- if (!cProtocol_1_8_0::CompressPacket(PacketData, CompressedPacket))
- {
- return;
- }
+ cProtocol_1_8_0::CompressPacket(m_Compressor, CompressedPacket);
// Send the packet's payload compressed:
- SendData(CompressedPacket.data(), CompressedPacket.size());
+ SendData(CompressedPacket);
}
else
{
// Compression doesn't apply to this state, send raw data:
- m_OutPacketLenBuffer.WriteVarInt32(PacketLen);
- AString LengthData;
+ m_OutPacketLenBuffer.WriteVarInt32(static_cast<UInt32>(PacketData.size()));
+ ContiguousByteBuffer LengthData;
m_OutPacketLenBuffer.ReadAll(LengthData);
- SendData(LengthData.data(), LengthData.size());
+ m_OutPacketLenBuffer.CommitRead();
+ SendData(LengthData);
// Send the packet's payload directly:
- m_OutPacketLenBuffer.CommitRead();
- SendData(PacketData.data(), PacketData.size());
+ SendData(PacketData);
}
// Log the comm into logfile:
@@ -3226,7 +3129,7 @@ void cProtocol_1_8_0::SendPacket(cPacketizer & a_Pkt)
CreateHexDump(Hex, PacketData.data(), PacketData.size(), 16);
m_CommLogFile.Printf("Outgoing packet: type %s (translated to 0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n",
cPacketizer::PacketTypeToStr(a_Pkt.GetPacketType()), GetPacketID(a_Pkt.GetPacketType()),
- PacketLen, PacketLen, m_State, Hex
+ PacketData.size(), PacketData.size(), m_State, Hex
);
/*
// Useful for debugging a new protocol:
@@ -3346,13 +3249,13 @@ void cProtocol_1_8_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item)
}
Writer.Finish();
- AString Result = Writer.GetResult();
- if (Result.size() == 0)
+ const auto Result = Writer.GetResult();
+ if (Result.empty())
{
a_Pkt.WriteBEInt8(0);
return;
}
- a_Pkt.WriteBuf(Result.data(), Result.size());
+ a_Pkt.WriteBuf(Result);
}
@@ -3479,7 +3382,7 @@ void cProtocol_1_8_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity &
}
Writer.Finish();
- a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ a_Pkt.WriteBuf(Writer.GetResult());
}
@@ -3978,6 +3881,82 @@ void cProtocol_1_8_0::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity &
+void cProtocol_1_8_0::HandlePacket(cByteBuffer & a_Buffer)
+{
+ UInt32 PacketType;
+ if (!a_Buffer.ReadVarInt(PacketType))
+ {
+ // Not enough data
+ return;
+ }
+
+ // Log the packet info into the comm log file:
+ if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
+ {
+ ContiguousByteBuffer PacketData;
+ a_Buffer.ReadAll(PacketData);
+ a_Buffer.ResetRead();
+ a_Buffer.ReadVarInt(PacketType); // We have already read the packet type once, it will be there again
+ ASSERT(PacketData.size() > 0); // We have written an extra NUL, so there had to be at least one byte read
+ PacketData.resize(PacketData.size() - 1);
+ AString PacketDataHex;
+ CreateHexDump(PacketDataHex, PacketData.data(), PacketData.size(), 16);
+ m_CommLogFile.Printf("Next incoming packet is type %u (0x%x), length %u (0x%x) at state %d. Payload:\n%s\n",
+ PacketType, PacketType, a_Buffer.GetUsedSpace(), a_Buffer.GetUsedSpace(), m_State, PacketDataHex.c_str()
+ );
+ }
+
+ if (!HandlePacket(a_Buffer, PacketType))
+ {
+ // Unknown packet, already been reported, but without the length. Log the length here:
+ LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, a_Buffer.GetUsedSpace());
+
+#ifdef _DEBUG
+ // Dump the packet contents into the log:
+ a_Buffer.ResetRead();
+ ContiguousByteBuffer Packet;
+ a_Buffer.ReadAll(Packet);
+ Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
+ AString Out;
+ CreateHexDump(Out, Packet.data(), Packet.size(), 24);
+ LOGD("Packet contents:\n%s", Out.c_str());
+#endif // _DEBUG
+
+ // Put a message in the comm log:
+ if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
+ {
+ m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
+ }
+
+ return;
+ }
+
+ // The packet should have nothing left in the buffer:
+ if (a_Buffer.GetReadableSpace() != 0)
+ {
+ // Read more or less than packet length, report as error
+ LOGWARNING("Protocol 1.8: Wrong number of bytes read for packet 0x%x, state %d. Read %zu bytes, packet contained %u bytes",
+ PacketType, m_State, a_Buffer.GetUsedSpace() - a_Buffer.GetReadableSpace(), a_Buffer.GetUsedSpace()
+ );
+
+ // Put a message in the comm log:
+ if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
+ {
+ m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %zu left) ^^^^^^\n\n\n",
+ 1, a_Buffer.GetReadableSpace()
+ );
+ m_CommLogFile.Flush();
+ }
+
+ ASSERT(!"Read wrong number of bytes!");
+ m_Client->PacketError(PacketType);
+ }
+}
+
+
+
+
+
void cProtocol_1_8_0::SendEntityTeleport(const cEntity & a_Entity)
{
cPacketizer Pkt(*this, pktTeleportEntity);
diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h
index 44415758f..f5800cb21 100644
--- a/src/Protocol/Protocol_1_8.h
+++ b/src/Protocol/Protocol_1_8.h
@@ -20,6 +20,9 @@ Declares the 1.8 protocol classes:
#include "../mbedTLS++/AesCfb128Decryptor.h"
#include "../mbedTLS++/AesCfb128Encryptor.h"
+#include "CircularBufferCompressor.h"
+#include "StringCompression.h"
+
@@ -46,7 +49,7 @@ public:
virtual void SendChat (const AString & a_Message, eChatType a_Type) override;
virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) override;
virtual void SendChatRaw (const AString & a_MessageRaw, eChatType a_Type) override;
- virtual void SendChunkData (const std::string_view a_ChunkData) override;
+ virtual void SendChunkData (ContiguousByteBufferView a_ChunkData) override;
virtual void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) override;
virtual void SendDestroyEntity (const cEntity & a_Entity) override;
virtual void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override;
@@ -88,7 +91,7 @@ public:
virtual void SendPlayerMoveLook (void) override;
virtual void SendPlayerPosition (void) override;
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
- virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
+ virtual void SendPluginMessage (const AString & a_Channel, ContiguousByteBufferView a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
virtual void SendResetTitle (void) override;
virtual void SendResourcePack (const AString & a_ResourcePackUrl) override;
@@ -125,9 +128,8 @@ public:
virtual AString GetAuthServerID(void) override { return m_AuthServerID; }
/** Compress the packet. a_Packet must be without packet length.
- a_Compressed will be set to the compressed packet includes packet length and data length.
- If compression fails, the function returns false. */
- static bool CompressPacket(const AString & a_Packet, AString & a_Compressed);
+ a_Compressed will be set to the compressed packet includes packet length and data length. */
+ static void CompressPacket(CircularBufferCompressor & a_Packet, ContiguousByteBuffer & a_Compressed);
/** The 1.8 protocol use a particle id instead of a string. This function converts the name to the id. If the name is incorrect, it returns 0. */
static int GetParticleID(const AString & a_ParticleName);
@@ -194,7 +196,7 @@ protected:
virtual void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel);
/** Sends the data to the client, encrypting them if needed. */
- virtual void SendData(const char * a_Data, size_t a_Size) override;
+ virtual void SendData(ContiguousByteBufferView a_Size) override;
/** Sends the packet to the client. Called by the cPacketizer's destructor. */
virtual void SendPacket(cPacketizer & a_Packet) override;
@@ -205,7 +207,7 @@ protected:
virtual bool ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes = 0);
/** Parses item metadata as read by ReadItem(), into the item enchantments. */
- virtual void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata);
+ virtual void ParseItemMetadata(cItem & a_Item, ContiguousByteBufferView a_Metadata);
virtual void StartEncryption(const Byte * a_Key);
@@ -242,9 +244,15 @@ private:
cAesCfb128Decryptor m_Decryptor;
cAesCfb128Encryptor m_Encryptor;
+ CircularBufferCompressor m_Compressor;
+ CircularBufferExtractor m_Extractor;
+
/** The logfile where the comm is logged, when g_ShouldLogComm is true */
cFile m_CommLogFile;
+ /** Handle a complete packet stored in the given buffer. */
+ void HandlePacket(cByteBuffer & a_Buffer);
+
/** Sends an entity teleport packet.
Mitigates a 1.8 bug where the position in the entity spawn packet is ignored,
and so entities don't show up until a teleport is sent. */
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index 72d3fd4b1..67e920925 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -1031,10 +1031,10 @@ void cProtocol_1_9_0::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
-void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
+void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const ContiguousByteBufferView a_Metadata)
{
// Parse into NBT:
- cParsedNBT NBT(a_Metadata.data(), a_Metadata.size());
+ cParsedNBT NBT(a_Metadata);
if (!NBT.IsValid())
{
AString HexDump;
@@ -1438,13 +1438,13 @@ void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item)
Writer.Finish();
- AString Result = Writer.GetResult();
- if (Result.size() == 0)
+ const auto Result = Writer.GetResult();
+ if (Result.empty())
{
a_Pkt.WriteBEInt8(0);
return;
}
- a_Pkt.WriteBuf(Result.data(), Result.size());
+ a_Pkt.WriteBuf(Result);
}
@@ -1550,7 +1550,7 @@ void cProtocol_1_9_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity &
}
Writer.Finish();
- a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ a_Pkt.WriteBuf(Writer.GetResult());
}
@@ -2289,7 +2289,7 @@ void cProtocol_1_9_4::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, c
Writer.AddString("Text4", JsonUtils::WriteFastString(Line4));
Writer.Finish();
- Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ Pkt.WriteBuf(Writer.GetResult());
}
diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h
index 0339ddeb3..27b005bd4 100644
--- a/src/Protocol/Protocol_1_9.h
+++ b/src/Protocol/Protocol_1_9.h
@@ -98,7 +98,7 @@ protected:
virtual void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer) override;
/** Parses item metadata as read by ReadItem(), into the item enchantments. */
- virtual void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) override;
+ virtual void ParseItemMetadata(cItem & a_Item, ContiguousByteBufferView a_Metadata) override;
/** Converts the hand parameter received by the protocol into eHand constants.
If the received value doesn't match any of the know value, raise an assertion fail or return hMain. */
diff --git a/src/Server.cpp b/src/Server.cpp
index 114c38946..eb8b3de36 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -24,11 +24,6 @@
#include <sstream>
#include <iostream>
-extern "C"
-{
- #include "zlib/zlib.h"
-}
-
diff --git a/src/Server.h b/src/Server.h
index 5ac7fc998..d9d3a09af 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -133,7 +133,7 @@ public:
const AString & GetFaviconData(void) const { return m_FaviconData; }
cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
- const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
+ ContiguousByteBufferView GetPublicKeyDER(void) const { return m_PublicKeyDER; }
/** Returns true if authentication has been turned on in server settings. */
bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; } // tolua_export
@@ -214,7 +214,7 @@ private:
cRsaPrivateKey m_PrivateKey;
/** Public key for m_PrivateKey, ASN1-DER-encoded */
- AString m_PublicKeyDER;
+ ContiguousByteBuffer m_PublicKeyDER;
cRCONServer m_RCONServer;
diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp
index ff434bbb1..6678fe1bd 100644
--- a/src/StringCompression.cpp
+++ b/src/StringCompression.cpp
@@ -1,242 +1,251 @@
// StringCompression.cpp
-// Implements the wrapping functions for compression and decompression using AString as their data
+// Implements the wrapping functions for compression and decompression
#include "Globals.h"
+#include "ByteBuffer.h"
#include "StringCompression.h"
+#include <libdeflate.h>
-int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor)
+
+std::string_view Compression::Result::GetStringView() const
{
- uLongf CompressedSize = compressBound(static_cast<uLong>(a_Length));
-
- // HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
- // It saves us one allocation and one memcpy of the entire compressed data
- // It may not work on some STL implementations! (Confirmed working on all currently used MSVC, GCC and Clang versions)
- a_Compressed.resize(CompressedSize);
- int errorcode = compress2(reinterpret_cast<Bytef *>(const_cast<char *>(a_Compressed.data())), &CompressedSize, reinterpret_cast<const Bytef *>(a_Data), static_cast<uLong>(a_Length), a_Factor);
- if (errorcode != Z_OK)
+ const auto View = GetView();
+ return { reinterpret_cast<const char *>(View.data()), View.size() };
+}
+
+
+
+
+
+ContiguousByteBufferView Compression::Result::GetView() const
+{
+ // Get a generic std::byte * to what the variant is currently storing:
+ return
{
- return errorcode;
- }
- a_Compressed.resize(CompressedSize);
- return Z_OK;
+ std::visit([](const auto & Buffer) -> const std::byte *
+ {
+ using Variant = std::decay_t<decltype(Buffer)>;
+
+ if constexpr (std::is_same_v<Variant, Compression::Result::Static>)
+ {
+ return Buffer.data();
+ }
+ else
+ {
+ return Buffer.get();
+ }
+ }, Storage), Size
+ };
}
-int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t a_UncompressedSize)
+Compression::Compressor::Compressor(int CompressionFactor)
{
- // HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
- // It saves us one allocation and one memcpy of the entire compressed data
- // It may not work on some STL implementations! (Confirmed working on all currently used MSVC, GCC and Clang versions)
- a_Uncompressed.resize(a_UncompressedSize);
- uLongf UncompressedSize = static_cast<uLongf>(a_UncompressedSize); // On some architectures the uLongf is different in size to int, that may be the cause of the -5 error
- int errorcode = uncompress(reinterpret_cast<Bytef *>(const_cast<char *>(a_Uncompressed.data())), &UncompressedSize, reinterpret_cast<const Bytef *>(a_Data), static_cast<uLong>(a_Length));
- if (errorcode != Z_OK)
+ m_Handle = libdeflate_alloc_compressor(CompressionFactor);
+
+ if (m_Handle == nullptr)
{
- return errorcode;
+ throw std::bad_alloc();
}
- a_Uncompressed.resize(UncompressedSize);
- return Z_OK;
}
-int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed)
+Compression::Compressor::~Compressor()
{
- // Compress a_Data into a_Compressed using GZIP; return Z_XXX error constants same as zlib's compress2()
+ libdeflate_free_compressor(m_Handle);
+}
+
+
- a_Compressed.reserve(a_Length);
- char Buffer[64 KiB];
- z_stream strm;
- memset(&strm, 0, sizeof(strm));
- strm.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(a_Data));
- strm.avail_in = static_cast<uInt>(a_Length);
- strm.next_out = reinterpret_cast<Bytef *>(Buffer);
- strm.avail_out = sizeof(Buffer);
- int res = deflateInit2(&strm, 9, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY);
- if (res != Z_OK)
+template <auto Algorithm>
+Compression::Result Compression::Compressor::Compress(const void * const Input, const size_t Size)
+{
+ // First see if the stack buffer has enough space:
{
- LOG("%s: compression initialization failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
- return res;
+ Result::Static Buffer;
+ const auto BytesWrittenOut = Algorithm(m_Handle, Input, Size, Buffer.data(), Buffer.size());
+
+ if (BytesWrittenOut != 0)
+ {
+ return { Buffer, BytesWrittenOut };
+ }
}
- for (;;)
+ // No it doesn't. Allocate space on the heap to write the compression result, increasing in powers of 2.
+ // This will either succeed, or except with bad_alloc.
+
+ auto DynamicCapacity = Result::StaticCapacity * 2;
+ while (true)
{
- res = deflate(&strm, Z_FINISH);
- switch (res)
+ auto Dynamic = cpp20::make_unique_for_overwrite<Result::Dynamic::element_type[]>(DynamicCapacity);
+ const auto BytesWrittenOut = Algorithm(m_Handle, Input, Size, Dynamic.get(), DynamicCapacity);
+
+ if (BytesWrittenOut != 0)
{
- case Z_OK:
- {
- // Some data has been compressed. Consume the buffer and continue compressing
- a_Compressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
- strm.next_out = reinterpret_cast<Bytef *>(Buffer);
- strm.avail_out = sizeof(Buffer);
- if (strm.avail_in == 0)
- {
- // All data has been compressed
- deflateEnd(&strm);
- return Z_OK;
- }
- break;
- }
+ return { std::move(Dynamic), BytesWrittenOut };
+ }
- case Z_STREAM_END:
- {
- // Finished compressing. Consume the rest of the buffer and return
- a_Compressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
- deflateEnd(&strm);
- return Z_OK;
- }
+ DynamicCapacity *= 2;
+ }
+}
- default:
- {
- // An error has occurred, log it and return the error value
- LOG("%s: compression failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
- deflateEnd(&strm);
- return res;
- }
- } // switch (res)
- } // while (true)
+
+
+
+
+Compression::Result Compression::Compressor::CompressGZip(const ContiguousByteBufferView Input)
+{
+ return Compress<&libdeflate_gzip_compress>(Input.data(), Input.size());
}
-extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
+Compression::Result Compression::Compressor::CompressZLib(const ContiguousByteBufferView Input)
{
- // Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
+ return Compress<&libdeflate_zlib_compress>(Input.data(), Input.size());
+}
- a_Uncompressed.reserve(a_Length);
- char Buffer[64 KiB];
- z_stream strm;
- memset(&strm, 0, sizeof(strm));
- strm.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(a_Data));
- strm.avail_in = static_cast<uInt>(a_Length);
- strm.next_out = reinterpret_cast<Bytef *>(Buffer);
- strm.avail_out = sizeof(Buffer);
- int res = inflateInit2(&strm, 31); // Force GZIP decoding
- if (res != Z_OK)
+
+
+Compression::Result Compression::Compressor::CompressZLib(const void * const Input, const size_t Size)
+{
+ return Compress<&libdeflate_zlib_compress>(Input, Size);
+}
+
+
+
+
+
+Compression::Extractor::Extractor()
+{
+ m_Handle = libdeflate_alloc_decompressor();
+
+ if (m_Handle == nullptr)
{
- LOG("%s: uncompression initialization failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
- return res;
+ throw std::bad_alloc();
}
+}
- for (;;)
- {
- res = inflate(&strm, Z_NO_FLUSH);
- switch (res)
- {
- case Z_OK:
- {
- // Some data has been uncompressed. Consume the buffer and continue uncompressing
- a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
- strm.next_out = reinterpret_cast<Bytef *>(Buffer);
- strm.avail_out = sizeof(Buffer);
- if (strm.avail_in == 0)
- {
- // All data has been uncompressed
- inflateEnd(&strm);
- return Z_OK;
- }
- break;
- }
- case Z_STREAM_END:
- {
- // Finished uncompressing. Consume the rest of the buffer and return
- a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
- inflateEnd(&strm);
- return Z_OK;
- }
- default:
- {
- // An error has occurred, log it and return the error value
- LOG("%s: uncompression failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
- inflateEnd(&strm);
- return res;
- }
- } // switch (res)
- } // while (true)
+
+
+Compression::Extractor::~Extractor()
+{
+ libdeflate_free_decompressor(m_Handle);
+}
+
+
+
+
+
+Compression::Result Compression::Extractor::ExtractGZip(ContiguousByteBufferView Input)
+{
+ return Extract<&libdeflate_gzip_decompress>(Input);
+}
+
+
+
+
+
+Compression::Result Compression::Extractor::ExtractZLib(ContiguousByteBufferView Input)
+{
+ return Extract<&libdeflate_zlib_decompress>(Input);
}
-extern int InflateString(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
+Compression::Result Compression::Extractor::ExtractZLib(ContiguousByteBufferView Input, size_t UncompressedSize)
{
- a_Uncompressed.reserve(a_Length);
-
- char Buffer[64 KiB];
- z_stream strm;
- memset(&strm, 0, sizeof(strm));
- strm.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(a_Data));
- strm.avail_in = static_cast<uInt>(a_Length);
- strm.next_out = reinterpret_cast<Bytef *>(Buffer);
- strm.avail_out = sizeof(Buffer);
-
- int res = inflateInit(&strm); // Force GZIP decoding
- if (res != Z_OK)
+ return Extract<&libdeflate_zlib_decompress>(Input, UncompressedSize);
+}
+
+
+
+
+
+template <auto Algorithm>
+Compression::Result Compression::Extractor::Extract(const ContiguousByteBufferView Input)
+{
+ // First see if the stack buffer has enough space:
{
- LOG("%s: inflation initialization failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
- return res;
+ Result::Static Buffer;
+ size_t BytesWrittenOut;
+
+ switch (Algorithm(m_Handle, Input.data(), Input.size(), Buffer.data(), Buffer.size(), &BytesWrittenOut))
+ {
+ case LIBDEFLATE_SUCCESS: return { Buffer, BytesWrittenOut };
+ case LIBDEFLATE_INSUFFICIENT_SPACE: break;
+ default: throw std::runtime_error("Data extraction failed.");
+ }
}
- for (;;)
+ // No it doesn't. Allocate space on the heap to write the compression result, increasing in powers of 2.
+
+ auto DynamicCapacity = Result::StaticCapacity * 2;
+ while (true)
{
- res = inflate(&strm, Z_NO_FLUSH);
- switch (res)
+ size_t BytesWrittenOut;
+ auto Dynamic = cpp20::make_unique_for_overwrite<Result::Dynamic::element_type[]>(DynamicCapacity);
+
+ switch (Algorithm(m_Handle, Input.data(), Input.size(), Dynamic.get(), DynamicCapacity, &BytesWrittenOut))
{
- case Z_OK:
+ case libdeflate_result::LIBDEFLATE_SUCCESS: return { std::move(Dynamic), BytesWrittenOut };
+ case libdeflate_result::LIBDEFLATE_INSUFFICIENT_SPACE:
{
- // Some data has been uncompressed. Consume the buffer and continue uncompressing
- a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
- strm.next_out = reinterpret_cast<Bytef *>(Buffer);
- strm.avail_out = sizeof(Buffer);
- if (strm.avail_in == 0)
- {
- // All data has been uncompressed
- inflateEnd(&strm);
- return Z_OK;
- }
- break;
+ DynamicCapacity *= 2;
+ continue;
}
+ default: throw std::runtime_error("Data extraction failed.");
+ }
+ }
+}
- case Z_STREAM_END:
- {
- // Finished uncompressing. Consume the rest of the buffer and return
- a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
- inflateEnd(&strm);
- return Z_OK;
- }
- default:
- {
- // An error has occurred, log it and return the error value
- LOG("%s: inflation failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
- inflateEnd(&strm);
- return res;
- }
- } // switch (res)
- } // while (true)
-}
+template <auto Algorithm>
+Compression::Result Compression::Extractor::Extract(const ContiguousByteBufferView Input, size_t UncompressedSize)
+{
+ // Here we have the expected size after extraction, so directly use a suitable buffer size:
+ if (UncompressedSize <= Result::StaticCapacity)
+ {
+ if (
+ Result::Static Buffer;
+ Algorithm(m_Handle, Input.data(), Input.size(), Buffer.data(), UncompressedSize, nullptr) == libdeflate_result::LIBDEFLATE_SUCCESS
+ )
+ {
+ return { Buffer, UncompressedSize };
+ }
+ }
+ else if (
+ auto Dynamic = cpp20::make_unique_for_overwrite<Result::Dynamic::element_type[]>(UncompressedSize);
+ Algorithm(m_Handle, Input.data(), Input.size(), Dynamic.get(), UncompressedSize, nullptr) == libdeflate_result::LIBDEFLATE_SUCCESS
+ )
+ {
+ return { std::move(Dynamic), UncompressedSize };
+ }
+ throw std::runtime_error("Data extraction failed.");
+}
diff --git a/src/StringCompression.h b/src/StringCompression.h
index 10c00a804..c091c27a0 100644
--- a/src/StringCompression.h
+++ b/src/StringCompression.h
@@ -1,27 +1,85 @@
// StringCompression.h
-// Interfaces to the wrapping functions for compression and decompression using AString as their data
+// Interfaces to the wrapping functions for compression and decompression
-#include "zlib/zlib.h" // Needed for the Z_XXX return values
+#pragma once
-/** Compresses a_Data into a_Compressed using ZLIB; returns Z_XXX error constants same as zlib's compress2() */
-extern int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor);
+class cByteBuffer;
-/** Uncompresses a_Data into a_Uncompressed; returns Z_XXX error constants same as zlib's decompress() */
-extern int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t a_UncompressedSize);
+struct libdeflate_compressor;
+struct libdeflate_decompressor;
-/** Compresses a_Data into a_Compressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib */
-extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed);
-/** Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib */
-extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
-/** Uncompresses a_Data into a_Uncompressed using Inflate; returns Z_OK for success or Z_XXX error constants same as zlib */
-extern int InflateString(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
+namespace Compression
+{
+ /** Contains the result of a compression or extraction operation. */
+ struct Result
+ {
+ using Static = std::array<std::byte, 128 KiB>;
+ using Dynamic = std::unique_ptr<std::byte[]>;
+
+ static constexpr size_t StaticCapacity = sizeof(Compression::Result::Static) / sizeof(Compression::Result::Static::value_type);
+
+ /** Returns a view (of type char) of the internal store. */
+ std::string_view GetStringView() const;
+
+ /** Returns a view (of type std::byte) of the internal store. */
+ ContiguousByteBufferView GetView() const;
+
+ /** A store allocated on either the stack or heap. */
+ std::variant<Static, Dynamic> Storage;
+
+ /** The length of valid data in the store. */
+ size_t Size;
+ };
+
+ /** Contains routines for data compression. */
+ class Compressor
+ {
+ public:
+
+ /** Creates a new compressor instance with a compression factor [0-12]. */
+ Compressor(int CompressionFactor = 6);
+ ~Compressor();
+
+ Result CompressGZip(ContiguousByteBufferView Input);
+ Result CompressZLib(ContiguousByteBufferView Input);
+ Result CompressZLib(const void * Input, size_t Size);
+
+ private:
+
+ template <auto Algorithm>
+ Result Compress(const void * Input, size_t Size);
+
+ libdeflate_compressor * m_Handle;
+ };
+
+ /** Contains routines for data extraction. */
+ class Extractor
+ {
+ public:
+
+ /** Creates a new extractor instance. */
+ Extractor();
+ ~Extractor();
+
+ Result ExtractGZip(ContiguousByteBufferView Input);
+ Result ExtractZLib(ContiguousByteBufferView Input);
+ Result ExtractZLib(ContiguousByteBufferView Input, size_t UncompressedSize);
+
+ private:
+
+ template <auto Algorithm> Result Extract(ContiguousByteBufferView Input);
+ template <auto Algorithm> Result Extract(ContiguousByteBufferView Input, size_t UncompressedSize);
+
+ libdeflate_decompressor * m_Handle;
+ };
+}
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index e6fbcc6fe..c55456e24 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -972,10 +972,12 @@ AString Base64Encode(const AString & a_Input)
-short GetBEShort(const char * a_Mem)
+short GetBEShort(const std::byte * const a_Mem)
{
- const Byte * Bytes = reinterpret_cast<const Byte *>(a_Mem);
- return static_cast<short>((Bytes[0] << 8) | Bytes[1]);
+ return static_cast<short>(
+ (static_cast<short>(a_Mem[0]) << 8) |
+ static_cast<short>(a_Mem[1])
+ );
}
@@ -992,22 +994,26 @@ unsigned short GetBEUShort(const char * a_Mem)
-int GetBEInt(const char * a_Mem)
+int GetBEInt(const std::byte * const a_Mem)
{
- const Byte * Bytes = reinterpret_cast<const Byte *>(a_Mem);
- return (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 8) | Bytes[3];
+ return
+ (static_cast<int>(a_Mem[0]) << 24) |
+ (static_cast<int>(a_Mem[1]) << 16) |
+ (static_cast<int>(a_Mem[2]) << 8) |
+ static_cast<int>(a_Mem[3])
+ ;
}
-void SetBEInt(char * a_Mem, Int32 a_Value)
+void SetBEInt(std::byte * a_Mem, Int32 a_Value)
{
- a_Mem[0] = a_Value >> 24;
- a_Mem[1] = static_cast<char>((a_Value >> 16) & 0xff);
- a_Mem[2] = static_cast<char>((a_Value >> 8) & 0xff);
- a_Mem[3] = static_cast<char>(a_Value & 0xff);
+ a_Mem[0] = std::byte(a_Value >> 24);
+ a_Mem[1] = std::byte((a_Value >> 16) & 0xff);
+ a_Mem[2] = std::byte((a_Value >> 8) & 0xff);
+ a_Mem[3] = std::byte(a_Value & 0xff);
}
diff --git a/src/StringUtils.h b/src/StringUtils.h
index a8cd41090..94e44c3f6 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -126,16 +126,16 @@ extern AString Base64Decode(const AString & a_Base64String); // Exported manual
extern AString Base64Encode(const AString & a_Input); // Exported manually due to embedded NULs and extra parameter
/** Reads two bytes from the specified memory location and interprets them as BigEndian short */
-extern short GetBEShort(const char * a_Mem);
+extern short GetBEShort(const std::byte * a_Mem);
/** Reads two bytes from the specified memory location and interprets them as BigEndian unsigned short */
extern unsigned short GetBEUShort(const char * a_Mem);
/** Reads four bytes from the specified memory location and interprets them as BigEndian int */
-extern int GetBEInt(const char * a_Mem);
+extern int GetBEInt(const std::byte * a_Mem);
/** Writes four bytes to the specified memory location so that they interpret as BigEndian int */
-extern void SetBEInt(char * a_Mem, Int32 a_Value);
+extern void SetBEInt(std::byte * a_Mem, Int32 a_Value);
/** Splits a string that has embedded \0 characters, on those characters.
a_Output is first cleared and then each separate string is pushed back into a_Output.
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<size_t>(N)) \
+ if (m_Data.size() - m_Pos < static_cast<size_t>(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<size_t>(GetBEShort(m_Data + m_Pos));
+ a_StringLen = static_cast<size_t>(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<int>((m_Length - m_Pos) / MinChildSize)))
+ if ((Count < 0) || (Count > static_cast<int>((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<size_t>(Child)].m_NameLength == a_NameLength) &&
- (memcmp(m_Data + m_Tags[static_cast<size_t>(Child)].m_NameStart, a_Name, a_NameLength) == 0)
+ (memcmp(m_Data.data() + m_Tags[static_cast<size_t>(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<UInt16>(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<char>(a_ChildrenType));
- m_Result.append(4, static_cast<char>(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<char *>(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<char>(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<UInt16>(a_Value));
- m_Result.append(reinterpret_cast<const char *>(&Value), 2);
+ m_Result.append(reinterpret_cast<const std::byte *>(&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<UInt32>(a_Value));
- m_Result.append(reinterpret_cast<const char *>(&Value), 4);
+ m_Result.append(reinterpret_cast<const std::byte *>(&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<const char *>(&Value), 8);
+ m_Result.append(reinterpret_cast<const std::byte *>(&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<const char *>(&Value), 4);
+ m_Result.append(reinterpret_cast<const std::byte *>(&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<const char *>(&Value), 8);
+ m_Result.append(reinterpret_cast<const std::byte *>(&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<UInt16>(a_Value.size()));
- m_Result.append(reinterpret_cast<const char *>(&Length), sizeof(Length));
- m_Result.append(a_Value);
+ m_Result.append(reinterpret_cast<const std::byte *>(&Length), sizeof(Length));
+ m_Result.append({ reinterpret_cast<const std::byte *>(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<UInt32>(a_NumElements));
- m_Result.append(reinterpret_cast<const char *>(&len), 4);
- m_Result.append(a_Value, a_NumElements);
+ m_Result.append(reinterpret_cast<const std::byte *>(&len), 4);
+ m_Result.append(reinterpret_cast<const std::byte *>(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<const char *>(&len), 4);
+ m_Result.append(reinterpret_cast<const std::byte *>(&len), sizeof(len));
for (size_t i = 0; i < a_NumElements; i++)
{
UInt32 Element = htonl(static_cast<UInt32>(a_Value[i]));
- m_Result.append(reinterpret_cast<const char *>(&Element), 4);
+ m_Result.append(reinterpret_cast<const std::byte *>(&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<const char *>(&Len), 2);
- m_Result.append(a_Data, a_Length);
+ // TODO check size <= short max
+ UInt16 Len = htons(static_cast<unsigned short>(a_Data.size()));
+ m_Result.append(reinterpret_cast<const std::byte *>(&Len), sizeof(Len));
+ m_Result.append(reinterpret_cast<const std::byte *>(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<size_t>(a_Tag)].m_Type != TAG_List);
ASSERT(m_Tags[static_cast<size_t>(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<size_t>(a_Tag)].m_Type != TAG_List);
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type != TAG_Compound);
- return m_Data + m_Tags[static_cast<size_t>(a_Tag)].m_DataStart;
+ return m_Data.data() + m_Tags[static_cast<size_t>(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<size_t>(a_Tag)].m_Type == TAG_Short);
- return GetBEShort(m_Data + m_Tags[static_cast<size_t>(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<size_t>(a_Tag)].m_Type == TAG_Int);
- return GetBEInt(m_Data + m_Tags[static_cast<size_t>(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<size_t>(a_Tag)].m_Type == TAG_Long);
- return NetworkToHostLong8(m_Data + m_Tags[static_cast<size_t>(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<size_t>(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<size_t>(a_Tag)].m_Type == TAG_Double);
- return NetworkToHostDouble8(m_Data + m_Tags[static_cast<size_t>(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<size_t>(a_Tag)].m_Type == TAG_String);
- AString res;
- res.assign(m_Data + m_Tags[static_cast<size_t>(a_Tag)].m_DataStart, static_cast<size_t>(m_Tags[static_cast<size_t>(a_Tag)].m_DataLength));
- return res;
+ return { reinterpret_cast<const char *>(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<size_t>(a_Tag)].m_NameStart, static_cast<size_t>(m_Tags[static_cast<size_t>(a_Tag)].m_NameLength));
+ res.assign(reinterpret_cast<const char *>(m_Data.data()) + m_Tags[static_cast<size_t>(a_Tag)].m_NameStart, static_cast<size_t>(m_Tags[static_cast<size_t>(a_Tag)].m_NameLength));
return res;
}
protected:
- const char * m_Data;
- size_t m_Length;
+
+ ContiguousByteBufferView m_Data;
std::vector<cFastNBTTag> 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<char>(a_Type));
- WriteString(a_Name.c_str(), static_cast<UInt16>(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<const std::byte *>(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<Int16>(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<unsigned>(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<EMCSBiome>(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("<unknown>");
- if (TagID >= 0)
- {
- TypeName.assign(a_NBT.GetData(TagID), static_cast<size_t>(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<size_t>(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<size_t>(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<AString, EntityLoaderFunc> EntityLoaderMap;
+ typedef std::map<std::string_view, EntityLoaderFunc> 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<int>(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"; }
} ;
-
-
-
-
diff --git a/src/mbedTLS++/AesCfb128Decryptor.cpp b/src/mbedTLS++/AesCfb128Decryptor.cpp
index 0a5896e52..523e06161 100644
--- a/src/mbedTLS++/AesCfb128Decryptor.cpp
+++ b/src/mbedTLS++/AesCfb128Decryptor.cpp
@@ -43,13 +43,8 @@ void cAesCfb128Decryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
-void cAesCfb128Decryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
+void cAesCfb128Decryptor::ProcessData(std::byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
{
ASSERT(IsValid()); // Must Init() first
- mbedtls_aes_crypt_cfb8(&m_Aes, MBEDTLS_AES_DECRYPT, a_Length, m_IV, a_EncryptedIn, a_DecryptedOut);
+ mbedtls_aes_crypt_cfb8(&m_Aes, MBEDTLS_AES_DECRYPT, a_Length, m_IV, a_EncryptedIn, reinterpret_cast<unsigned char *>(a_DecryptedOut));
}
-
-
-
-
-
diff --git a/src/mbedTLS++/AesCfb128Decryptor.h b/src/mbedTLS++/AesCfb128Decryptor.h
index 99d479381..601699998 100644
--- a/src/mbedTLS++/AesCfb128Decryptor.h
+++ b/src/mbedTLS++/AesCfb128Decryptor.h
@@ -27,7 +27,7 @@ public:
void Init(const Byte a_Key[16], const Byte a_IV[16]);
/** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
- void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
+ void ProcessData(std::byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
/** Returns true if the object has been initialized with the Key / IV */
bool IsValid(void) const { return m_IsValid; }
diff --git a/src/mbedTLS++/AesCfb128Encryptor.cpp b/src/mbedTLS++/AesCfb128Encryptor.cpp
index a7b423a77..7c2ae8b2b 100644
--- a/src/mbedTLS++/AesCfb128Encryptor.cpp
+++ b/src/mbedTLS++/AesCfb128Encryptor.cpp
@@ -43,13 +43,8 @@ void cAesCfb128Encryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
-void cAesCfb128Encryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
+void cAesCfb128Encryptor::ProcessData(std::byte * const a_EncryptedOut, const std::byte * const a_PlainIn, size_t a_Length)
{
ASSERT(IsValid()); // Must Init() first
- mbedtls_aes_crypt_cfb8(&m_Aes, MBEDTLS_AES_ENCRYPT, a_Length, m_IV, a_PlainIn, a_EncryptedOut);
+ mbedtls_aes_crypt_cfb8(&m_Aes, MBEDTLS_AES_ENCRYPT, a_Length, m_IV, reinterpret_cast<const unsigned char *>(a_PlainIn), reinterpret_cast<unsigned char *>(a_EncryptedOut));
}
-
-
-
-
-
diff --git a/src/mbedTLS++/AesCfb128Encryptor.h b/src/mbedTLS++/AesCfb128Encryptor.h
index 8048e2d61..f25998c15 100644
--- a/src/mbedTLS++/AesCfb128Encryptor.h
+++ b/src/mbedTLS++/AesCfb128Encryptor.h
@@ -19,6 +19,7 @@
class cAesCfb128Encryptor
{
public:
+
cAesCfb128Encryptor(void);
~cAesCfb128Encryptor();
@@ -26,7 +27,7 @@ public:
void Init(const Byte a_Key[16], const Byte a_IV[16]);
/** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
- void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
+ void ProcessData(std::byte * a_EncryptedOut, const std::byte * a_PlainIn, size_t a_Length);
/** Returns true if the object has been initialized with the Key / IV */
bool IsValid(void) const { return m_IsValid; }
diff --git a/src/mbedTLS++/RsaPrivateKey.cpp b/src/mbedTLS++/RsaPrivateKey.cpp
index 704a2a1d0..3fd429dc0 100644
--- a/src/mbedTLS++/RsaPrivateKey.cpp
+++ b/src/mbedTLS++/RsaPrivateKey.cpp
@@ -55,7 +55,7 @@ bool cRsaPrivateKey::Generate(unsigned a_KeySizeBits)
-AString cRsaPrivateKey::GetPubKeyDER(void)
+ContiguousByteBuffer cRsaPrivateKey::GetPubKeyDER(void)
{
class cPubKey
{
@@ -96,21 +96,21 @@ AString cRsaPrivateKey::GetPubKeyDER(void)
int res = mbedtls_pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
if (res < 0)
{
- return AString();
+ return {};
}
- return AString(reinterpret_cast<const char *>(buf + sizeof(buf) - res), static_cast<size_t>(res));
+ return { reinterpret_cast<const std::byte *>(buf + sizeof(buf) - res), static_cast<size_t>(res) };
}
-int cRsaPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
+int cRsaPrivateKey::Decrypt(const ContiguousByteBufferView a_EncryptedData, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
{
- if (a_EncryptedLength < m_Rsa.len)
+ if (a_EncryptedData.size() < m_Rsa.len)
{
LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
- __FUNCTION__, static_cast<unsigned>(a_EncryptedLength), static_cast<unsigned>(m_Rsa.len)
+ __FUNCTION__, static_cast<unsigned>(a_EncryptedData.size()), static_cast<unsigned>(m_Rsa.len)
);
ASSERT(!"Invalid a_DecryptedMaxLength!");
return -1;
@@ -126,7 +126,7 @@ int cRsaPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLeng
size_t DecryptedLength;
int res = mbedtls_rsa_pkcs1_decrypt(
&m_Rsa, mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal(), MBEDTLS_RSA_PRIVATE, &DecryptedLength,
- a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
+ reinterpret_cast<const unsigned char *>(a_EncryptedData.data()), a_DecryptedData, a_DecryptedMaxLength
);
if (res != 0)
{
@@ -134,41 +134,3 @@ int cRsaPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLeng
}
return static_cast<int>(DecryptedLength);
}
-
-
-
-
-
-int cRsaPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
-{
- if (a_EncryptedMaxLength < m_Rsa.len)
- {
- LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
- __FUNCTION__, static_cast<unsigned>(a_EncryptedMaxLength), static_cast<unsigned>(m_Rsa.len)
- );
- ASSERT(!"Invalid a_DecryptedMaxLength!");
- return -1;
- }
- if (a_PlainLength < m_Rsa.len)
- {
- LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
- __FUNCTION__, static_cast<unsigned>(a_PlainLength), static_cast<unsigned>(m_Rsa.len)
- );
- ASSERT(!"Invalid a_PlainLength!");
- return -1;
- }
- int res = mbedtls_rsa_pkcs1_encrypt(
- &m_Rsa, mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal(), MBEDTLS_RSA_PRIVATE,
- a_PlainLength, a_PlainData, a_EncryptedData
- );
- if (res != 0)
- {
- return -1;
- }
- return static_cast<int>(m_Rsa.len);
-}
-
-
-
-
-
diff --git a/src/mbedTLS++/RsaPrivateKey.h b/src/mbedTLS++/RsaPrivateKey.h
index 63e648b60..33a016edc 100644
--- a/src/mbedTLS++/RsaPrivateKey.h
+++ b/src/mbedTLS++/RsaPrivateKey.h
@@ -35,17 +35,12 @@ public:
bool Generate(unsigned a_KeySizeBits = 1024);
/** Returns the public key part encoded in ASN1 DER encoding */
- AString GetPubKeyDER(void);
+ ContiguousByteBuffer GetPubKeyDER(void);
/** Decrypts the data using RSAES-PKCS#1 algorithm.
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
Returns the number of bytes decrypted, or negative number for error. */
- int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
-
- /** Encrypts the data using RSAES-PKCS#1 algorithm.
- Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
- Returns the number of bytes decrypted, or negative number for error. */
- int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
+ int Decrypt(ContiguousByteBufferView a_EncryptedData, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
protected:
/** The mbedTLS key context */