summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Protocol/Protocol18x.cpp168
-rw-r--r--src/Protocol/Protocol18x.h3
2 files changed, 168 insertions, 3 deletions
diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp
index 4b78bc4cd..07e21923c 100644
--- a/src/Protocol/Protocol18x.cpp
+++ b/src/Protocol/Protocol18x.cpp
@@ -1652,6 +1652,169 @@ void cProtocol180::FixItemFramePositions(int a_ObjectData, double & a_PosX, doub
+AString cProtocol180::ReadNBTDataFromBuffer(cByteBuffer & a_ByteBuffer, int a_ListTag)
+{
+ cByteBuffer BufferCache(64 KiB);
+ AString Data;
+
+ while (a_ByteBuffer.GetReadableSpace() != 0)
+ {
+ unsigned char TypeID;
+ if (a_ListTag != 0)
+ {
+ TypeID = (unsigned char)a_ListTag;
+ }
+ else
+ {
+ if (!a_ByteBuffer.ReadByte(TypeID))
+ {
+ // Can't read the next byte
+ break;
+ }
+ BufferCache.WriteByte(TypeID);
+ }
+
+ if ((TypeID <= eTagType::TAG_Min) || (TypeID > eTagType::TAG_Max))
+ {
+ // Bad type id (or TAG_End)
+ break;
+ }
+ eTagType TagType = static_cast<eTagType>(TypeID);
+
+ // Read the following string length:
+ if (a_ListTag == 0)
+ {
+ short StrLength = 0;
+ if (!a_ByteBuffer.ReadBEShort(StrLength))
+ {
+ // Can't read string length
+ return Data;
+ }
+ BufferCache.WriteBEShort(StrLength);
+
+ // Read string and write to BufferCache:
+ AString TagTitle;
+ if (!a_ByteBuffer.ReadString(TagTitle, (size_t)StrLength))
+ {
+ // Can't read string
+ return Data;
+ }
+ BufferCache.WriteBuf(TagTitle.data(), TagTitle.size());
+ }
+
+ size_t TagLength = 0;
+ switch (TagType)
+ {
+ case eTagType::TAG_Byte: TagLength = sizeof(Byte); break;
+ case eTagType::TAG_Short: TagLength = sizeof(short); break;
+ case eTagType::TAG_Int: TagLength = sizeof(int); break;
+ case eTagType::TAG_Long: TagLength = sizeof(long); break;
+ case eTagType::TAG_Float: TagLength = sizeof(float); break;
+ case eTagType::TAG_Double: TagLength = sizeof(double); break;
+ case eTagType::TAG_End: break;
+ case eTagType::TAG_Compound:
+ {
+ AString CompoundData = ReadNBTDataFromBuffer(a_ByteBuffer);
+ Data.append(CompoundData.data(), CompoundData.size());
+ break;
+ }
+ case eTagType::TAG_List:
+ {
+ Byte ListType;
+ int ListLength;
+ if (!a_ByteBuffer.ReadByte(ListType) || !a_ByteBuffer.ReadBEInt(ListLength) || (ListLength < 0))
+ {
+ // Bad list type or list length
+ return Data;
+ }
+ LOGWARNING("LIST, Type: %i", (int)ListType);
+
+ BufferCache.WriteByte(ListType);
+ BufferCache.WriteBEInt(ListLength);
+
+ if ((ListType <= eTagType::TAG_Min) || (ListType > eTagType::TAG_Max))
+ {
+ // Bad tag type
+ return Data;
+ }
+
+ for (int i = 0; i < ListLength; i++)
+ {
+ AString EntryData = ReadNBTDataFromBuffer(a_ByteBuffer, ListType);
+ BufferCache.WriteBuf(EntryData.data(), EntryData.size());
+ }
+ break;
+ }
+ case eTagType::TAG_String:
+ {
+ // Read the following string length:
+ short StrLength;
+ if (!a_ByteBuffer.ReadBEShort(StrLength))
+ {
+ // Can't read string length
+ return Data;
+ }
+ BufferCache.WriteBEShort(StrLength);
+ TagLength += (size_t)StrLength;
+ break;
+ }
+ case eTagType::TAG_ByteArray:
+ {
+ int ArrayLength;
+ if (!a_ByteBuffer.ReadBEInt(ArrayLength) || (ArrayLength < 0) || (ArrayLength >= 16777216))
+ {
+ // Bad array length
+ return Data;
+ }
+ BufferCache.WriteBEInt(ArrayLength);
+ TagLength += (size_t) ArrayLength;
+ break;
+ }
+ case eTagType::TAG_IntArray:
+ {
+ int ArrayLength;
+ if (!a_ByteBuffer.ReadBEInt(ArrayLength) || (ArrayLength < 0) || (ArrayLength >= 16777216))
+ {
+ // Bad array length
+ return Data;
+ }
+ BufferCache.WriteBEInt(ArrayLength);
+ TagLength += (size_t)ArrayLength * sizeof(int);
+ break;
+ }
+ }
+
+ // Copy tag bytes to the cache:
+ AString TagBytes;
+ if (!a_ByteBuffer.ReadString(TagBytes, TagLength))
+ {
+ break;
+ }
+ BufferCache.WriteBuf(TagBytes.data(), TagBytes.size());
+
+ // Write cache to Data and clean:
+ AString Bytes;
+ BufferCache.ReadAll(Bytes);
+ BufferCache.CommitRead();
+ Data.append(Bytes.data(), Bytes.size());
+ }
+
+ // Read the rest from cache
+ if (BufferCache.GetUsedSpace() != 0)
+ {
+ AString Bytes;
+ BufferCache.ReadAll(Bytes);
+ BufferCache.CommitRead();
+ Data.append(Bytes.data(), Bytes.size());
+ }
+
+ return Data;
+}
+
+
+
+
+
void cProtocol180::AddReceivedData(const char * a_Data, size_t a_Size)
{
// Write the incoming data into the comm log file:
@@ -2530,9 +2693,8 @@ bool cProtocol180::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item)
a_Item.Empty();
}
- AString Metadata;
- a_ByteBuffer.ReadAll(Metadata);
- if ((Metadata.size() == 0) || (Metadata[0] == 0))
+ AString Metadata = ReadNBTDataFromBuffer(a_ByteBuffer);
+ if (Metadata.size() == 0 || (Metadata[0] == 0))
{
// No metadata
return true;
diff --git a/src/Protocol/Protocol18x.h b/src/Protocol/Protocol18x.h
index fd3121d7f..2275f6298 100644
--- a/src/Protocol/Protocol18x.h
+++ b/src/Protocol/Protocol18x.h
@@ -269,6 +269,9 @@ protected:
/** The dimension that was last sent to a player in a Respawn or Login packet.
Used to avoid Respawning into the same dimension, which confuses the client. */
eDimension m_LastSentDimension;
+
+ /** Read a nbt data from the buffer. (It's needed because the 1.8 protocol doesn't send the nbt length) */
+ AString ReadNBTDataFromBuffer(cByteBuffer & a_ByteBuffer, int a_ListTag = 0);
/** Adds the received (unencrypted) data to m_ReceivedData, parses complete packets */