diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Protocol/Protocol18x.cpp | 168 | ||||
-rw-r--r-- | src/Protocol/Protocol18x.h | 3 |
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 */ |