TU19: update NBT library

This commit is contained in:
Tropical 2026-03-21 18:43:44 -05:00
parent 993617025b
commit 8df2c2bb47
14 changed files with 97 additions and 69 deletions

View file

@ -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);
}
};

View file

@ -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() {

View file

@ -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<uint8_t>(1) : static_cast<uint8_t>(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<Tag>* 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<Tag>(name);
return dynamic_cast<ListTag<Tag>*>(it->second);
ListTag<Tag>* getList(const std::wstring& name) {
if (tags.find(name) == tags.end()) return new ListTag<Tag>(name);
return (ListTag<Tag>*)tags[name];
}
bool getBoolean(const wchar_t* string) {
return getByte(string) != static_cast<uint8_t>(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<string, Tag *>::iterator it = tags.begin(); it
!= itEnd; it++ )
for( unordered_map<string, Tag *>::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;
*/
}

View file

@ -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() {

View file

@ -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; }

View file

@ -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() {

View file

@ -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;

View file

@ -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() {

View file

@ -1,5 +1,4 @@
#pragma once
#include "Tag.h"
template <class T>
@ -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());

View file

@ -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() {

View file

@ -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() {

View file

@ -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; }

View file

@ -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<int>(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";
}
}

View file

@ -16,6 +16,7 @@ public:
static const uint8_t TAG_List = static_cast<uint8_t>(9);
static const uint8_t TAG_Compound = static_cast<uint8_t>(10);
static const uint8_t TAG_Int_Array = static_cast<uint8_t>(11);
static const int MAX_DEPTH = static_cast<uint8_t>(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);