diff --git a/Minecraft.World/IO/NBT/ByteArrayTag.h b/Minecraft.World/IO/NBT/ByteArrayTag.h index d43c43d97..fe9aa6597 100644 --- a/Minecraft.World/IO/NBT/ByteArrayTag.h +++ b/Minecraft.World/IO/NBT/ByteArrayTag.h @@ -5,18 +5,24 @@ class ByteArrayTag : public Tag { public: byteArray data; + bool m_ownData; - ByteArrayTag(const std::wstring& name) : Tag(name) {} - ByteArrayTag(const std::wstring& name, byteArray data) : Tag(name) { + ByteArrayTag(const std::wstring& name) : Tag(name) { m_ownData = false; } + ByteArrayTag(const std::wstring& name, byteArray data, bool ownData = false) + : Tag(name) { this->data = data; + m_ownData = ownData; } // 4J - added ownData param + ~ByteArrayTag() { + if (m_ownData) delete[] data.data; + } void write(DataOutput* dos) { dos->writeInt(data.length); dos->write(data); } - void load(DataInput* dis) { + void load(DataInput* dis, int tagDepth) { int length = dis->readInt(); if (data.data) delete[] data.data; @@ -45,6 +51,6 @@ public: Tag* copy() { byteArray cp = byteArray(data.length); System::arraycopy(data, 0, &cp, 0, data.length); - return new ByteArrayTag(getName(), cp); + return new ByteArrayTag(getName(), cp, true); } }; \ No newline at end of file diff --git a/Minecraft.World/IO/NBT/ByteTag.h b/Minecraft.World/IO/NBT/ByteTag.h index 6285eb7f9..33d8929ba 100644 --- a/Minecraft.World/IO/NBT/ByteTag.h +++ b/Minecraft.World/IO/NBT/ByteTag.h @@ -10,7 +10,7 @@ public: } void write(DataOutput* dos) { dos->writeByte(data); } - void load(DataInput* dis) { data = dis->readByte(); } + void load(DataInput* dis, int tagDepth) { data = dis->readByte(); } uint8_t getId() { return TAG_Byte; } std::wstring toString() { diff --git a/Minecraft.World/IO/NBT/CompoundTag.h b/Minecraft.World/IO/NBT/CompoundTag.h index bc3e0bf6a..f30adf82d 100644 --- a/Minecraft.World/IO/NBT/CompoundTag.h +++ b/Minecraft.World/IO/NBT/CompoundTag.h @@ -28,7 +28,15 @@ public: dos->writeByte(Tag::TAG_End); } - void load(DataInput* dis) { + void load(DataInput* dis, int tagDepth) { + if (tagDepth > MAX_DEPTH) { +#ifndef _CONTENT_PACKAGE + printf("Tried to read NBT tag with too high complexity, depth > %d", + MAX_DEPTH); + __debugbreak(); +#endif + return; + } tags.clear(); Tag* tag; while ((tag = Tag::readNamedTag(dis))->getId() != Tag::TAG_End) { @@ -52,123 +60,121 @@ public: uint8_t getId() { return TAG_Compound; } - void put(const wchar_t* name, Tag* tag) { - tags[name] = tag->setName(std::wstring(name)); + void put(const std::wstring& name, Tag* tag) { + tags[name] = tag->setName(name); } - void putByte(const wchar_t* name, uint8_t value) { + void putByte(const std::wstring& name, uint8_t value) { tags[name] = (new ByteTag(name, value)); } - void putShort(const wchar_t* name, short value) { + void putShort(const std::wstring& name, short value) { tags[name] = (new ShortTag(name, value)); } - void putInt(const wchar_t* name, int value) { + void putInt(const std::wstring& name, int value) { tags[name] = (new IntTag(name, value)); } - void putLong(const wchar_t* name, int64_t value) { + void putLong(const std::wstring& name, int64_t value) { tags[name] = (new LongTag(name, value)); } - void putFloat(const wchar_t* name, float value) { + void putFloat(const std::wstring& name, float value) { tags[name] = (new FloatTag(name, value)); } - void putDouble(const wchar_t* name, double value) { + void putDouble(const std::wstring& name, double value) { tags[name] = (new DoubleTag(name, value)); } - void putString(const wchar_t* name, const std::wstring& value) { + void putString(const std::wstring& name, const std::wstring& value) { tags[name] = (new StringTag(name, value)); } - void putByteArray(const wchar_t* name, byteArray value) { + void putByteArray(const std::wstring& name, byteArray value) { tags[name] = (new ByteArrayTag(name, value)); } - void putIntArray(const wchar_t* name, intArray value) { + void putIntArray(const std::wstring& name, intArray value) { tags[name] = (new IntArrayTag(name, value)); } - void putCompound(const wchar_t* name, CompoundTag* value) { + void putCompound(const std::wstring& name, CompoundTag* value) { tags[name] = value->setName(std::wstring(name)); } - void putBoolean(const wchar_t* string, bool val) { - putByte(string, - val ? static_cast(1) : static_cast(0)); + void putBoolean(const std::wstring& name, bool val) { + putByte(name, val ? (uint8_t)1 : 0); } - Tag* get(const wchar_t* name) { + Tag* get(const std::wstring& name) { AUTO_VAR(it, tags.find(name)); if (it != tags.end()) return it->second; return NULL; } - bool contains(const wchar_t* name) { return tags.find(name) != tags.end(); } + bool contains(const std::wstring& name) { + return tags.find(name) != tags.end(); + } - uint8_t getByte(const wchar_t* name) { + uint8_t getByte(const std::wstring& name) { if (tags.find(name) == tags.end()) return (uint8_t)0; return ((ByteTag*)tags[name])->data; } - short getShort(const wchar_t* name) { + short getShort(const std::wstring& name) { if (tags.find(name) == tags.end()) return (short)0; return ((ShortTag*)tags[name])->data; } - int getInt(const wchar_t* name) { + int getInt(const std::wstring& name) { if (tags.find(name) == tags.end()) return (int)0; return ((IntTag*)tags[name])->data; } - int64_t getLong(const wchar_t* name) { + int64_t getLong(const std::wstring& name) { if (tags.find(name) == tags.end()) return (int64_t)0; return ((LongTag*)tags[name])->data; } - float getFloat(const wchar_t* name) { + float getFloat(const std::wstring& name) { if (tags.find(name) == tags.end()) return (float)0; return ((FloatTag*)tags[name])->data; } - double getDouble(const wchar_t* name) { + double getDouble(const std::wstring& name) { if (tags.find(name) == tags.end()) return (double)0; return ((DoubleTag*)tags[name])->data; } - std::wstring getString(const wchar_t* name) { + std::wstring getString(const std::wstring& name) { if (tags.find(name) == tags.end()) return std::wstring(L""); return ((StringTag*)tags[name])->data; } - byteArray getByteArray(const wchar_t* name) { + byteArray getByteArray(const std::wstring& name) { if (tags.find(name) == tags.end()) return byteArray(); return ((ByteArrayTag*)tags[name])->data; } - intArray getIntArray(const wchar_t* name) { - if (tags.find(name) == tags.end()) return intArray(0); + intArray getIntArray(const std::wstring& name) { + if (tags.find(name) == tags.end()) return intArray(); return ((IntArrayTag*)tags[name])->data; } - CompoundTag* getCompound(const wchar_t* name) { + CompoundTag* getCompound(const std::wstring& name) { if (tags.find(name) == tags.end()) return new CompoundTag(name); return (CompoundTag*)tags[name]; } - ListTag* getList(const wchar_t* name) { - // 4jcraft changed this function to not do a c style cast - // of a templated class - auto it = tags.find(name); - if (it == tags.end()) return new ListTag(name); - return dynamic_cast*>(it->second); + ListTag* getList(const std::wstring& name) { + if (tags.find(name) == tags.end()) return new ListTag(name); + return (ListTag*)tags[name]; } - bool getBoolean(const wchar_t* string) { - return getByte(string) != static_cast(0); + bool getBoolean(const std::wstring& std::string) { + return getByte(std::string) != 0; } void remove(const std::wstring& name) { @@ -186,21 +192,21 @@ public: void print(char* prefix, std::ostream out) { /* -Tag::print(prefix, out); - out << prefix << "{" << std::endl; + Tag::print(prefix, out); + out << prefix << "{" << endl; char *newPrefix = new char[ strlen(prefix) + 4 ]; strcpy( newPrefix, prefix); strcat( newPrefix, " "); AUTO_VAR(itEnd, tags.end()); - for( std::unordered_map::iterator it = tags.begin(); it -!= itEnd; it++ ) + for( unordered_map::iterator it = tags.begin(); it != + itEnd; it++ ) { - it->second->print(newPrefix, out); + it->second->print(newPrefix, out); } delete[] newPrefix; - out << prefix << "}" << std::endl; + out << prefix << "}" << endl; */ } diff --git a/Minecraft.World/IO/NBT/DoubleTag.h b/Minecraft.World/IO/NBT/DoubleTag.h index 5df0e1bb6..319c9bb33 100644 --- a/Minecraft.World/IO/NBT/DoubleTag.h +++ b/Minecraft.World/IO/NBT/DoubleTag.h @@ -11,7 +11,7 @@ public: } void write(DataOutput* dos) { dos->writeDouble(data); } - void load(DataInput* dis) { data = dis->readDouble(); } + void load(DataInput* dis, int tagDepth) { data = dis->readDouble(); } uint8_t getId() { return TAG_Double; } std::wstring toString() { diff --git a/Minecraft.World/IO/NBT/EndTag.h b/Minecraft.World/IO/NBT/EndTag.h index 33ee95469..94b87c7e6 100644 --- a/Minecraft.World/IO/NBT/EndTag.h +++ b/Minecraft.World/IO/NBT/EndTag.h @@ -6,7 +6,7 @@ public: EndTag() : Tag(L"") {} EndTag(const std::wstring& name) : Tag(name) {} - void load(DataInput* dis) {}; + void load(DataInput* dis, int tagDepth) {}; void write(DataOutput* dos) {}; uint8_t getId() { return TAG_End; } diff --git a/Minecraft.World/IO/NBT/FloatTag.h b/Minecraft.World/IO/NBT/FloatTag.h index a61d2c54b..7651d761c 100644 --- a/Minecraft.World/IO/NBT/FloatTag.h +++ b/Minecraft.World/IO/NBT/FloatTag.h @@ -11,7 +11,7 @@ public: } void write(DataOutput* dos) { dos->writeFloat(data); } - void load(DataInput* dis) { data = dis->readFloat(); } + void load(DataInput* dis, int tagDepth) { data = dis->readFloat(); } uint8_t getId() { return TAG_Float; } std::wstring toString() { diff --git a/Minecraft.World/IO/NBT/IntArrayTag.h b/Minecraft.World/IO/NBT/IntArrayTag.h index 7b3a9c22f..a95519b05 100644 --- a/Minecraft.World/IO/NBT/IntArrayTag.h +++ b/Minecraft.World/IO/NBT/IntArrayTag.h @@ -7,12 +7,14 @@ class IntArrayTag : public Tag { public: intArray data; - IntArrayTag(const std::wstring& name) : Tag(name) {} + IntArrayTag(const std::wstring& name) : Tag(name) { data = intArray(); } IntArrayTag(const std::wstring& name, intArray data) : Tag(name) { this->data = data; } + ~IntArrayTag() { delete[] data.data; } + void write(DataOutput* dos) { dos->writeInt(data.length); for (unsigned int i = 0; i < data.length; i++) { @@ -20,7 +22,7 @@ public: } } - void load(DataInput* dis) { + void load(DataInput* dis, int tagDepth) { int length = dis->readInt(); if (data.data) delete[] data.data; diff --git a/Minecraft.World/IO/NBT/IntTag.h b/Minecraft.World/IO/NBT/IntTag.h index 3ec50cf8c..5da7fb233 100644 --- a/Minecraft.World/IO/NBT/IntTag.h +++ b/Minecraft.World/IO/NBT/IntTag.h @@ -10,7 +10,7 @@ public: } void write(DataOutput* dos) { dos->writeInt(data); } - void load(DataInput* dis) { data = dis->readInt(); } + void load(DataInput* dis, int tagDepth) { data = dis->readInt(); } uint8_t getId() { return TAG_Int; } std::wstring toString() { diff --git a/Minecraft.World/IO/NBT/ListTag.h b/Minecraft.World/IO/NBT/ListTag.h index 133c59c61..c112795cd 100644 --- a/Minecraft.World/IO/NBT/ListTag.h +++ b/Minecraft.World/IO/NBT/ListTag.h @@ -1,5 +1,4 @@ #pragma once - #include "Tag.h" template @@ -25,14 +24,22 @@ public: for (AUTO_VAR(it, list.begin()); it != itEnd; it++) (*it)->write(dos); } - void load(DataInput* dis) { + void load(DataInput* dis, int tagDepth) { + if (tagDepth > MAX_DEPTH) { +#ifndef _CONTENT_PACKAGE + printf("Tried to read NBT tag with too high complexity, depth > %d", + MAX_DEPTH); + __debugbreak(); +#endif + return; + } type = dis->readByte(); int size = dis->readInt(); list.clear(); for (int i = 0; i < size; i++) { Tag* tag = Tag::newTag(type, L""); - tag->load(dis); + tag->load(dis, tagDepth); list.push_back(tag); } } @@ -55,9 +62,8 @@ public: strcpy(newPrefix, prefix); strcat(newPrefix, " "); AUTO_VAR(itEnd, list.end()); - for (AUTO_VAR(it, list.begin()); it != itEnd; it++) { + for (AUTO_VAR(it, list.begin()); it != itEnd; it++) (*it)->print(newPrefix, out); - } delete[] newPrefix; out << prefix << "}" << std::endl; } @@ -65,7 +71,10 @@ public: void add(T* tag) { type = tag->getId(); // 4J: List tag write/load doesn't preserve tag names so remove them so - // we can safely do comparisons. This is the least invasive fix. + // we can safely do comparisons There are a few ways I could have fixed + // this but this seems the least invasive, most complete fix (covers + // other items that also use list tags and require equality checks to + // work) considering we can't change the write/load functions. tag->setName(L""); list.push_back(tag); } @@ -100,8 +109,9 @@ public: if (list.size() == o->list.size()) { equal = true; AUTO_VAR(itEnd, list.end()); - // 4J Stu - Pretty inefficient method, but acceptable for - // how small and infrequent these comparisons are. + // 4J Stu - Pretty inefficient method, but I think we can + // live with it give how often it will happen, and the small + // sizes of the data sets for (AUTO_VAR(it, list.begin()); it != itEnd; ++it) { bool thisMatches = false; for (AUTO_VAR(it2, o->list.begin()); diff --git a/Minecraft.World/IO/NBT/LongTag.h b/Minecraft.World/IO/NBT/LongTag.h index 810e52946..5e8018669 100644 --- a/Minecraft.World/IO/NBT/LongTag.h +++ b/Minecraft.World/IO/NBT/LongTag.h @@ -10,7 +10,7 @@ public: } void write(DataOutput* dos) { dos->writeLong(data); } - void load(DataInput* dis) { data = dis->readLong(); } + void load(DataInput* dis, int tagDepth) { data = dis->readLong(); } uint8_t getId() { return TAG_Long; } std::wstring toString() { diff --git a/Minecraft.World/IO/NBT/ShortTag.h b/Minecraft.World/IO/NBT/ShortTag.h index be04c8c57..e47b99341 100644 --- a/Minecraft.World/IO/NBT/ShortTag.h +++ b/Minecraft.World/IO/NBT/ShortTag.h @@ -10,7 +10,7 @@ public: } void write(DataOutput* dos) { dos->writeShort(data); } - void load(DataInput* dis) { data = dis->readShort(); } + void load(DataInput* dis, int tagDepth) { data = dis->readShort(); } uint8_t getId() { return TAG_Short; } std::wstring toString() { diff --git a/Minecraft.World/IO/NBT/StringTag.h b/Minecraft.World/IO/NBT/StringTag.h index bf5c2dcc9..a7b72eee3 100644 --- a/Minecraft.World/IO/NBT/StringTag.h +++ b/Minecraft.World/IO/NBT/StringTag.h @@ -11,7 +11,7 @@ public: void write(DataOutput* dos) { dos->writeUTF(data); } - void load(DataInput* dis) { data = dis->readUTF(); } + void load(DataInput* dis, int tagDepth) { data = dis->readUTF(); } uint8_t getId() { return TAG_String; } diff --git a/Minecraft.World/IO/NBT/Tag.cpp b/Minecraft.World/IO/NBT/Tag.cpp index 9e157eef7..74bc4a802 100644 --- a/Minecraft.World/IO/NBT/Tag.cpp +++ b/Minecraft.World/IO/NBT/Tag.cpp @@ -61,7 +61,9 @@ Tag* Tag::setName(const std::wstring& name) { return this; } -Tag* Tag::readNamedTag(DataInput* dis) { +Tag* Tag::readNamedTag(DataInput* dis) { return readNamedTag(dis, 0); } + +Tag* Tag::readNamedTag(DataInput* dis, int tagDepth) { uint8_t type = dis->readByte(); if (static_cast(type) == 0) return new EndTag(); @@ -82,7 +84,7 @@ Tag* Tag::readNamedTag(DataInput* dis) { // byte[] bytes = new uint8_t[length]; // dis.readFully(bytes); - tag->load(dis); + tag->load(dis, tagDepth); return tag; } @@ -156,4 +158,4 @@ const wchar_t* Tag::getTagName(uint8_t type) { return L"TAG_Compound"; } return L"UNKNOWN"; -} +} \ No newline at end of file diff --git a/Minecraft.World/IO/NBT/Tag.h b/Minecraft.World/IO/NBT/Tag.h index 68adeeda2..c80209d72 100644 --- a/Minecraft.World/IO/NBT/Tag.h +++ b/Minecraft.World/IO/NBT/Tag.h @@ -16,6 +16,7 @@ public: static const uint8_t TAG_List = static_cast(9); static const uint8_t TAG_Compound = static_cast(10); static const uint8_t TAG_Int_Array = static_cast(11); + static const int MAX_DEPTH = static_cast(512); private: std::wstring name; @@ -25,7 +26,7 @@ protected: public: virtual void write(DataOutput* dos) = 0; - virtual void load(DataInput* dis) = 0; + virtual void load(DataInput* dis, int tagDepth) = 0; virtual std::wstring toString() = 0; virtual uint8_t getId() = 0; void print(std::ostream out); @@ -33,6 +34,7 @@ public: std::wstring getName(); Tag* setName(const std::wstring& name); static Tag* readNamedTag(DataInput* dis); + static Tag* readNamedTag(DataInput* dis, int tagDepth); static void writeNamedTag(Tag* tag, DataOutput* dos); static Tag* newTag(uint8_t type, const std::wstring& name); static const wchar_t* getTagName(uint8_t type);