diff --git a/minutor.pro b/minutor.pro index 6fc0fb61..2fea0387 100644 --- a/minutor.pro +++ b/minutor.pro @@ -35,6 +35,8 @@ HEADERS += \ mapview.h \ minutor.h \ nbt.h \ + nbt_tag.h \ + nbt_tagdatastream.h \ overlayitem.h \ properties.h \ propertietreecreator.h \ @@ -75,6 +77,8 @@ SOURCES += \ mapview.cpp \ minutor.cpp \ nbt.cpp \ + nbt_tag.cpp \ + nbt_tagdatastream.cpp \ properties.cpp \ propertietreecreator.cpp \ searchblockpluginwidget.cpp \ diff --git a/nbt.cpp b/nbt.cpp index 4805295c..92a3d43a 100644 --- a/nbt.cpp +++ b/nbt.cpp @@ -1,16 +1,15 @@ /** Copyright (c) 2013, Sean Kasun */ + #include #include -#include -#include -#include -#include "./nbt.h" +#include "nbt.h" -// this handles decoding the gzipped level.dat -NBT::NBT(const QString level) { - root = &NBT::Null; // just in case we die +// this handles decoding the gzipped level.dat +NBT::NBT(const QString level) + : root(&NBT::Null) // just in case we die +{ QFile f(level); f.open(QIODevice::ReadOnly); QByteArray data = f.readAll(); @@ -44,9 +43,9 @@ NBT::NBT(const QString level) { } // this handles decoding a compressed() section of a region file -NBT::NBT(const uchar *chunk) { - root = &NBT::Null; // just in case - +NBT::NBT(const uchar *chunk) + : root(&NBT::Null) // just in case we die +{ // find chunk size int length = (chunk[0] << 24) | (chunk[1] << 16) | (chunk[2] << 8) | chunk[3]; @@ -95,457 +94,3 @@ NBT::~NBT() { if (root != &NBT::Null) delete root; } - -/********** TAGS ****************/ - -Tag::Tag() { -} -Tag::~Tag() { -} -int Tag::length() const { - qWarning() << "Unhandled length"; - return 0; -} -bool Tag::has(const QString) const { - return false; -} -const Tag *Tag::at(const QString) const { - return &NBT::Null; -} -const Tag *Tag::at(int /* idx */) const { - return &NBT::Null; -} -const QString Tag::toString() const { - qWarning() << "Unhandled toString"; - return ""; -} -qint32 Tag::toInt() const { - qWarning() << "Unhandled toInt"; - return 0; -} -double Tag::toDouble() const { - qWarning() << "Unhandled toDouble"; - return 0.0; -} -const std::vector& Tag::toByteArray() const { - qWarning() << "Unhandled toByteArray"; - static const std::vector dummy; - return dummy; -} -const std::vector& Tag::toIntArray() const { - qWarning() << "Unhandled toIntArray"; - static const std::vector dummy; - return dummy; -} -const std::vector& Tag::toLongArray() const { - qWarning() << "Unhandled toLongArray"; - static const std::vector dummy; - return dummy; -} -const QVariant Tag::getData() const { - qWarning() << "Unhandled getData"; - return QVariant(); -} - -// Tag_Byte - -Tag_Byte::Tag_Byte(TagDataStream *s) { - data = s->r8(); -} - -int Tag_Byte::toInt() const { - return (signed char)data; -} - -unsigned int Tag_Byte::toUInt() const { - return (unsigned char)data; -} - -const QString Tag_Byte::toString() const { - return QString::number(data); -} - -const QVariant Tag_Byte::getData() const { - return data; -} - -// Tag_Short - -Tag_Short::Tag_Short(TagDataStream *s) { - data = s->r16(); -} - -int Tag_Short::toInt() const { - return (signed short)data; -} - -unsigned int Tag_Short::toUInt() const { - return (unsigned short)data; -} - -const QString Tag_Short::toString() const { - return QString::number(data); -} - -const QVariant Tag_Short::getData() const { - return data; -} - -// Tag_Int - -Tag_Int::Tag_Int(TagDataStream *s) { - data = s->r32(); -} -qint32 Tag_Int::toInt() const { - return data; -} - -const QString Tag_Int::toString() const { - return QString::number(data); -} - -const QVariant Tag_Int::getData() const { - return data; -} - -double Tag_Int::toDouble() const { - return static_cast(data); -} - -// Tag_Long - -Tag_Long::Tag_Long(TagDataStream *s) { - data = s->r64(); -} - -double Tag_Long::toDouble() const { - return static_cast(data); -} - -qint32 Tag_Long::toInt() const { - return static_cast(data); -} - -const QString Tag_Long::toString() const { - return QString::number(data); -} - -const QVariant Tag_Long::getData() const { - return data; -} - -// Tag_Float - -Tag_Float::Tag_Float(TagDataStream *s) { - union {qint32 d; float f;} fl; - fl.d = s->r32(); - data = fl.f; -} -double Tag_Float::toDouble() const { - return data; -} - -const QString Tag_Float::toString() const { - return QString::number(data); -} - -const QVariant Tag_Float::getData() const { - return data; -} - -// Tag_Double - -Tag_Double::Tag_Double(TagDataStream *s) { - union {qint64 d; double f;} fl; - fl.d = s->r64(); - data = fl.f; -} -double Tag_Double::toDouble() const { - return data; -} - -const QVariant Tag_Double::getData() const { - return data; -} - -const QString Tag_Double::toString() const { - return QString::number(data); -} - -// Tag_Byte_Array - -Tag_Byte_Array::Tag_Byte_Array(TagDataStream *s) { - len = s->r32(); - if (len) { - s->r(len, data); - } -} -Tag_Byte_Array::~Tag_Byte_Array() { -} -int Tag_Byte_Array::length() const { - return len; -} -const std::vector &Tag_Byte_Array::toByteArray() const { - return data; -} - -const QVariant Tag_Byte_Array::getData() const { - return QByteArray(reinterpret_cast(&data[0]), len); -} - -const QString Tag_Byte_Array::toString() const { - try { - return QString::fromLatin1(reinterpret_cast(&data[0])); - } catch(...) {} - - return ""; -} - -// Tag_String - -Tag_String::Tag_String(TagDataStream *s) { - int len = s->r16(); - data = s->utf8(len); -} -const QString Tag_String::toString() const { - return data; -} - -const QVariant Tag_String::getData() const { - return data; -} - -// Tag_List - -template -static void setListData(QList *data, int len, - TagDataStream *s) { - for (int i = 0; i < len; i++) - data->append(new T(s)); -} - -Tag_List::Tag_List(TagDataStream *s) { - quint8 type = s->r8(); - int len = s->r32(); - if (len == 0) // empty list, type is invalid - return; - - switch (type) { - case 1: setListData(&data, len, s); break; - case 2: setListData(&data, len, s); break; - case 3: setListData(&data, len, s); break; - case 4: setListData(&data, len, s); break; - case 5: setListData(&data, len, s); break; - case 6: setListData(&data, len, s); break; - case 7: setListData(&data, len, s); break; - case 8: setListData(&data, len, s); break; - case 9: setListData(&data, len, s); break; - case 10: setListData(&data, len, s); break; - case 11: setListData(&data, len, s); break; - case 12: setListData(&data, len, s); break; - default: throw "Unknown type"; - } -} - -Tag_List::~Tag_List() { - for (auto i = data.constBegin(); i != data.constEnd(); i++) - delete *i; -} -int Tag_List::length() const { - return data.count(); -} -const Tag *Tag_List::at(int index) const { - return data[index]; -} - -const QString Tag_List::toString() const { - QStringList ret; - ret << "["; - for (auto i = data.constBegin(); i != data.constEnd(); i++) { - ret << (*i)->toString(); - ret << ", "; - } - ret.last() = "]"; - return ret.join(""); -} - -const QVariant Tag_List::getData() const { - QList lst; - for (auto i = data.constBegin(); i != data.constEnd(); i++) { - lst << (*i)->getData(); - } - return lst; -} - -// Tag_Compound - -Tag_Compound::Tag_Compound(TagDataStream *s) { - quint8 type; - while ((type = s->r8()) != 0) { - // until tag_end - quint16 len = s->r16(); - QString key = s->utf8(len); - Tag *child; - switch (type) { - case 1: child = new Tag_Byte(s); break; - case 2: child = new Tag_Short(s); break; - case 3: child = new Tag_Int(s); break; - case 4: child = new Tag_Long(s); break; - case 5: child = new Tag_Float(s); break; - case 6: child = new Tag_Double(s); break; - case 7: child = new Tag_Byte_Array(s); break; - case 8: child = new Tag_String(s); break; - case 9: child = new Tag_List(s); break; - case 10: child = new Tag_Compound(s); break; - case 11: child = new Tag_Int_Array(s); break; - case 12: child = new Tag_Long_Array(s); break; - default: throw "Unknown tag"; - } - children[key] = child; - } -} -Tag_Compound::~Tag_Compound() { - for (auto i = children.constBegin(); i != children.constEnd(); i++) - delete i.value(); -} -bool Tag_Compound::has(const QString key) const { - return children.contains(key); -} -const Tag *Tag_Compound::at(const QString key) const { - if (!children.contains(key)) - return &NBT::Null; - return children[key]; -} - -const QString Tag_Compound::toString() const { - QStringList ret; - ret << "{\n"; - for (auto i = children.constBegin(); i != children.constEnd(); i++) { - ret << "\t" << i.key() << " = '" << i.value()->toString() << "',\n"; - } - ret.last() = "}"; - return ret.join(""); -} - -const QVariant Tag_Compound::getData() const { - QMap map; - for (auto i = children.constBegin(); i != children.constEnd(); i++) { - map.insert(i.key(), i.value()->getData()); - } - return map; -} - -// Tag_Int_Array - -Tag_Int_Array::Tag_Int_Array(TagDataStream *s) { - len = s->r32(); - data.resize(len); - for (int i = 0; i < len; i++) - data[i] = s->r32(); -} -Tag_Int_Array::~Tag_Int_Array() { -} -const std::vector& Tag_Int_Array::toIntArray() const { - return data; -} -int Tag_Int_Array::length() const { - return len; -} - -const QString Tag_Int_Array::toString() const { - QStringList ret; - ret << "["; - for (int i = 0; i < len; ++i) { - ret << QString::number(data[i]) << ","; - } - ret.last() = "]"; - return ret.join(""); -} - -const QVariant Tag_Int_Array::getData() const { - QList ret; - for (int i = 0; i < len; ++i) { - ret.push_back(data[i]); - } - - return ret; -} - -// Tag_Long_Array - -Tag_Long_Array::Tag_Long_Array(TagDataStream *s) { - len = s->r32(); - data.resize(len); - for (int i = 0; i < len; i++) - data[i] = s->r64(); -} -Tag_Long_Array::~Tag_Long_Array() { -} -const std::vector &Tag_Long_Array::toLongArray() const { - return data; -} -int Tag_Long_Array::length() const { - return len; -} - -const QString Tag_Long_Array::toString() const { - QStringList ret; - ret << "["; - for (int i = 0; i < len; ++i) { - ret << QString::number(data[i]) << ","; - } - ret.last() = "]"; - return ret.join(""); -} - -const QVariant Tag_Long_Array::getData() const { - QList ret; - for (int i = 0; i < len; ++i) { - ret.push_back(data[i]); - } - - return ret; -} - -// TagDataStream - -TagDataStream::TagDataStream(const char *data, int len) { - this->data = (const quint8 *)data; - this->len = len; - pos = 0; -} - -quint8 TagDataStream::r8() { - return data[pos++]; -} -quint16 TagDataStream::r16() { - quint16 r = data[pos++] << 8; - r |= data[pos++]; - return r; -} -quint32 TagDataStream::r32() { - quint32 r = data[pos++] << 24; - r |= data[pos++] << 16; - r |= data[pos++] << 8; - r |= data[pos++]; - return r; -} -quint64 TagDataStream::r64() { - quint64 r = (quint64)r32() << 32; - r |= r32(); - return r; -} -void TagDataStream::r(int len, std::vector& data_out) { - // you need to free anything read with this - data_out.resize(len); - memcpy(&data_out[0], data + pos, len); - pos += len; -} -QString TagDataStream::utf8(int len) { - int old = pos; - pos += len; - return QString::fromUtf8((const char *)data + old, len); -} -void TagDataStream::skip(int len) { - pos += len; -} diff --git a/nbt.h b/nbt.h index 6bf4e8ed..fc1d0ddc 100644 --- a/nbt.h +++ b/nbt.h @@ -2,44 +2,10 @@ #ifndef NBT_H_ #define NBT_H_ -class QString; -class QByteArray; - -#include #include -#include -class TagDataStream { - public: - TagDataStream(const char *data, int len); - quint8 r8(); - quint16 r16(); - quint32 r32(); - quint64 r64(); - void r(int len, std::vector &data_out); - QString utf8(int len); - void skip(int len); - private: - const quint8 *data; - int pos, len; -}; +#include "nbt_tag.h" -class Tag { - public: - Tag(); - virtual ~Tag(); - virtual bool has(const QString key) const; - virtual int length() const; - virtual const Tag *at(const QString key) const; - virtual const Tag *at(int index) const; - virtual const QString toString() const; - virtual qint32 toInt() const; - virtual double toDouble() const; - virtual const std::vector &toByteArray() const; - virtual const std::vector &toIntArray() const; - virtual const std::vector &toLongArray() const; - virtual const QVariant getData() const; -}; class NBT { public: @@ -47,150 +13,12 @@ class NBT { explicit NBT(const uchar *chunk); ~NBT(); - bool has(const QString key) const; - const Tag *at(const QString key) const; + bool has(const QString key) const; + const Tag * at(const QString key) const; static Tag Null; private: Tag *root; }; -class Tag_Byte : public Tag { - public: - explicit Tag_Byte(TagDataStream *s); - signed int toInt() const; - unsigned int toUInt() const; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - quint8 data; -}; - -class Tag_Short : public Tag { - public: - explicit Tag_Short(TagDataStream *s); - signed int toInt() const; - unsigned int toUInt() const; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - qint16 data; -}; - -class Tag_Int : public Tag { - public: - explicit Tag_Int(TagDataStream *s); - qint32 toInt() const; - double toDouble() const; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - qint32 data; -}; - -class Tag_Long : public Tag { - public: - explicit Tag_Long(TagDataStream *s); - qint32 toInt() const; - double toDouble() const; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - qint64 data; -}; - -class Tag_Float : public Tag { - public: - explicit Tag_Float(TagDataStream *s); - - virtual double toDouble() const; - virtual const QString toString() const; - virtual const QVariant getData() const; - - private: - float data; -}; - -class Tag_Double : public Tag { - public: - explicit Tag_Double(TagDataStream *s); - double toDouble() const; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - double data; -}; - -class Tag_Byte_Array : public Tag { - public: - explicit Tag_Byte_Array(TagDataStream *s); - ~Tag_Byte_Array(); - int length() const; - const std::vector& toByteArray() const override; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - std::vector data; - int len; -}; - -class Tag_String : public Tag { - public: - explicit Tag_String(TagDataStream *s); - const QString toString() const; - virtual const QVariant getData() const; - private: - QString data; -}; - -class Tag_List : public Tag { - public: - explicit Tag_List(TagDataStream *s); - ~Tag_List(); - const Tag *at(int index) const; - int length() const; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - QList data; -}; - -class Tag_Compound : public Tag { - public: - explicit Tag_Compound(TagDataStream *s); - ~Tag_Compound(); - bool has(const QString key) const; - const Tag *at(const QString key) const; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - QHash children; -}; - -class Tag_Int_Array : public Tag { - public: - explicit Tag_Int_Array(TagDataStream *s); - ~Tag_Int_Array(); - int length() const; - const std::vector& toIntArray() const override; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - int len; - std::vector data; -}; - -class Tag_Long_Array : public Tag { - public: - explicit Tag_Long_Array(TagDataStream *s); - ~Tag_Long_Array(); - int length() const; - const std::vector& toLongArray() const override; - virtual const QString toString() const; - virtual const QVariant getData() const; - private: - int len; - std::vector data; -}; - #endif // NBT_H_ diff --git a/nbt_tag.cpp b/nbt_tag.cpp new file mode 100644 index 00000000..13a99c71 --- /dev/null +++ b/nbt_tag.cpp @@ -0,0 +1,454 @@ +/** Copyright (c) 2013, Sean Kasun */ +#include +#include +#include + +#include "nbt_tag.h" +#include "nbt.h" + + +Tag::Tag() { +} + +Tag::~Tag() { +} + +int Tag::length() const { + qWarning() << "Tag::length unhandled in base class"; + return 0; +} + +bool Tag::has(const QString) const { + return false; +} + +const Tag *Tag::at(const QString) const { + return &NBT::Null; +} + +const Tag *Tag::at(int /* idx */) const { + return &NBT::Null; +} + +const QString Tag::toString() const { + qWarning() << "Tag::toString unhandled in base class"; + return ""; +} + +qint32 Tag::toInt() const { + qWarning() << "Tag::toInt unhandled in base class"; + return 0; +} + +double Tag::toDouble() const { + qWarning() << "Tag::toDouble unhandled in base class"; + return 0.0; +} + +const std::vector& Tag::toByteArray() const { + qWarning() << "Tag:: toByteArray unhandled in base class"; + static const std::vector dummy; + return dummy; +} + +const std::vector& Tag::toIntArray() const { + qWarning() << "Tag::toIntArray unhandled in base class"; + static const std::vector dummy; + return dummy; +} + +const std::vector& Tag::toLongArray() const { + qWarning() << "Tag::toLongArray unhandled in base class"; + static const std::vector dummy; + return dummy; +} + +const QVariant Tag::getData() const { + qWarning() << "tag::getData unhandled in base class"; + return QVariant(); +} + + +// Tag_Byte + +Tag_Byte::Tag_Byte(TagDataStream *s) { + data = s->r8(); +} + +int Tag_Byte::toInt() const { + return (signed char)data; +} + +unsigned int Tag_Byte::toUInt() const { + return (unsigned char)data; +} + +const QString Tag_Byte::toString() const { + return QString::number(data); +} + +const QVariant Tag_Byte::getData() const { + return data; +} + + +// Tag_Short + +Tag_Short::Tag_Short(TagDataStream *s) { + data = s->r16(); +} + +int Tag_Short::toInt() const { + return (signed short)data; +} + +unsigned int Tag_Short::toUInt() const { + return (unsigned short)data; +} + +const QString Tag_Short::toString() const { + return QString::number(data); +} + +const QVariant Tag_Short::getData() const { + return data; +} + + +// Tag_Int + +Tag_Int::Tag_Int(TagDataStream *s) { + data = s->r32(); +} + +qint32 Tag_Int::toInt() const { + return data; +} + +unsigned int Tag_Int::toUInt() const { + return (unsigned int)data; +} + +const QString Tag_Int::toString() const { + return QString::number(data); +} + +const QVariant Tag_Int::getData() const { + return data; +} + +double Tag_Int::toDouble() const { + return static_cast(data); +} + + +// Tag_Long + +Tag_Long::Tag_Long(TagDataStream *s) { + data = s->r64(); +} + +double Tag_Long::toDouble() const { + return static_cast(data); +} + +qint32 Tag_Long::toInt() const { + return static_cast(data); +} + +const QString Tag_Long::toString() const { + return QString::number(data); +} + +const QVariant Tag_Long::getData() const { + return data; +} + + +// Tag_Float + +Tag_Float::Tag_Float(TagDataStream *s) { + union {qint32 d; float f;} fl; + fl.d = s->r32(); + data = fl.f; +} +double Tag_Float::toDouble() const { + return data; +} + +const QString Tag_Float::toString() const { + return QString::number(data); +} + +const QVariant Tag_Float::getData() const { + return data; +} + + +// Tag_Double + +Tag_Double::Tag_Double(TagDataStream *s) { + union {qint64 d; double f;} fl; + fl.d = s->r64(); + data = fl.f; +} + +double Tag_Double::toDouble() const { + return data; +} + +const QVariant Tag_Double::getData() const { + return data; +} + +const QString Tag_Double::toString() const { + return QString::number(data); +} + + +// Tag_Byte_Array + +Tag_Byte_Array::Tag_Byte_Array(TagDataStream *s) { + len = s->r32(); + if (len) { + s->r(len, data); + } +} + +int Tag_Byte_Array::length() const { + return len; +} + +const std::vector &Tag_Byte_Array::toByteArray() const { + return data; +} + +const QVariant Tag_Byte_Array::getData() const { + return QByteArray(reinterpret_cast(&data[0]), len); +} + +const QString Tag_Byte_Array::toString() const { + try { + return QString::fromLatin1(reinterpret_cast(&data[0])); + } catch(...) {} + + return ""; +} + + +// Tag_String + +Tag_String::Tag_String(TagDataStream *s) { + int len = s->r16(); + data = s->utf8(len); +} + +const QString Tag_String::toString() const { + return data; +} + +const QVariant Tag_String::getData() const { + return data; +} + + +// Tag_List + +template +static void setListData(QList *data, int len, + TagDataStream *s) { + for (int i = 0; i < len; i++) + data->append(new T(s)); +} + +Tag_List::Tag_List(TagDataStream *s) { + quint8 type = s->r8(); + int len = s->r32(); + if (len == 0) // empty list, type is invalid + return; + + switch (type) { + case Tag::TAG_END: /* should be sorted out as len==0 */ break; + case Tag::TAG_BYTE: setListData(&data, len, s); break; + case Tag::TAG_SHORT: setListData(&data, len, s); break; + case Tag::TAG_INT: setListData(&data, len, s); break; + case Tag::TAG_LONG: setListData(&data, len, s); break; + case Tag::TAG_FLOAT: setListData(&data, len, s); break; + case Tag::TAG_DOUBLE: setListData(&data, len, s); break; + case Tag::TAG_BYTE_ARRAY: setListData(&data, len, s); break; + case Tag::TAG_STRING: setListData(&data, len, s); break; + case Tag::TAG_LIST: setListData(&data, len, s); break; + case Tag::TAG_COMPOUND: setListData(&data, len, s); break; + case Tag::TAG_INT_ARRAY: setListData(&data, len, s); break; + case Tag::TAG_LONG_ARRAY: setListData(&data, len, s); break; + default: throw "Unknown type"; + } +} + +Tag_List::~Tag_List() { + for (auto i = data.constBegin(); i != data.constEnd(); i++) + delete *i; +} + +int Tag_List::length() const { + return data.count(); +} + +const Tag *Tag_List::at(int index) const { + return data[index]; +} + +const QString Tag_List::toString() const { + QStringList ret; + ret << "["; + for (auto i = data.constBegin(); i != data.constEnd(); i++) { + ret << (*i)->toString(); + ret << ", "; + } + ret.last() = "]"; + return ret.join(""); +} + +const QVariant Tag_List::getData() const { + QList lst; + for (auto i = data.constBegin(); i != data.constEnd(); i++) { + lst << (*i)->getData(); + } + return lst; +} + + +// Tag_Compound + +Tag_Compound::Tag_Compound(TagDataStream *s) { + quint8 type; + while ((type = s->r8()) != 0) { + // until tag_end + quint16 len = s->r16(); + QString key = s->utf8(len); + Tag *child; + switch (type) { + case Tag::TAG_BYTE: child = new Tag_Byte(s); break; + case Tag::TAG_SHORT: child = new Tag_Short(s); break; + case Tag::TAG_INT: child = new Tag_Int(s); break; + case Tag::TAG_LONG: child = new Tag_Long(s); break; + case Tag::TAG_FLOAT: child = new Tag_Float(s); break; + case Tag::TAG_DOUBLE: child = new Tag_Double(s); break; + case Tag::TAG_BYTE_ARRAY: child = new Tag_Byte_Array(s); break; + case Tag::TAG_STRING: child = new Tag_String(s); break; + case Tag::TAG_LIST: child = new Tag_List(s); break; + case Tag::TAG_COMPOUND: child = new Tag_Compound(s); break; + case Tag::TAG_INT_ARRAY: child = new Tag_Int_Array(s); break; + case Tag::TAG_LONG_ARRAY: child = new Tag_Long_Array(s); break; + default: throw "Unknown tag"; + } + children[key] = child; + } +} + +Tag_Compound::~Tag_Compound() { + for (auto i = children.constBegin(); i != children.constEnd(); i++) + delete i.value(); +} + +bool Tag_Compound::has(const QString key) const { + return children.contains(key); +} + +const Tag *Tag_Compound::at(const QString key) const { + if (!children.contains(key)) + return &NBT::Null; + return children[key]; +} + +const QString Tag_Compound::toString() const { + QStringList ret; + ret << "{\n"; + for (auto i = children.constBegin(); i != children.constEnd(); i++) { + ret << "\t" << i.key() << " = '" << i.value()->toString() << "',\n"; + } + ret.last() = "}"; + return ret.join(""); +} + +const QVariant Tag_Compound::getData() const { + QMap map; + for (auto i = children.constBegin(); i != children.constEnd(); i++) { + map.insert(i.key(), i.value()->getData()); + } + return map; +} + + +// Tag_Int_Array + +Tag_Int_Array::Tag_Int_Array(TagDataStream *s) { + len = s->r32(); + data.resize(len); + for (int i = 0; i < len; i++) + data[i] = s->r32(); +} + +const std::vector& Tag_Int_Array::toIntArray() const { + return data; +} + +int Tag_Int_Array::length() const { + return len; +} + +const QString Tag_Int_Array::toString() const { + QStringList ret; + ret << "["; + for (int i = 0; i < len; ++i) { + ret << QString::number(data[i]) << ","; + } + ret.last() = "]"; + return ret.join(""); +} + +const QVariant Tag_Int_Array::getData() const { + QList ret; + for (int i = 0; i < len; ++i) { + ret.push_back(data[i]); + } + + return ret; +} + + +// Tag_Long_Array + +Tag_Long_Array::Tag_Long_Array(TagDataStream *s) { + len = s->r32(); + data.resize(len); + for (int i = 0; i < len; i++) + data[i] = s->r64(); +} + +const std::vector &Tag_Long_Array::toLongArray() const { + return data; +} + +int Tag_Long_Array::length() const { + return len; +} + +const QString Tag_Long_Array::toString() const { + QStringList ret; + ret << "["; + for (int i = 0; i < len; ++i) { + ret << QString::number(data[i]) << ","; + } + ret.last() = "]"; + return ret.join(""); +} + +const QVariant Tag_Long_Array::getData() const { + QList ret; + for (int i = 0; i < len; ++i) { + ret.push_back(data[i]); + } + + return ret; +} diff --git a/nbt_tag.h b/nbt_tag.h new file mode 100644 index 00000000..ee46b8f6 --- /dev/null +++ b/nbt_tag.h @@ -0,0 +1,195 @@ +#ifndef TAG_H +#define TAG_H + +#include +#include +#include + +#include "nbt_tagdatastream.h" + + +class Tag { + public: + Tag(); + virtual ~Tag(); + + virtual bool has(const QString key) const; + virtual int length() const; + virtual const Tag * at(const QString key) const; + virtual const Tag * at(int index) const; + virtual const QString toString() const; + virtual qint32 toInt() const; + virtual double toDouble() const; + virtual const std::vector & toByteArray() const; + virtual const std::vector & toIntArray() const; + virtual const std::vector & toLongArray() const; + virtual const QVariant getData() const; + + enum TagType { + TAG_END = 0, + TAG_BYTE = 1, + TAG_SHORT = 2, + TAG_INT = 3, + TAG_LONG = 4, + TAG_FLOAT = 5, + TAG_DOUBLE = 6, + TAG_BYTE_ARRAY = 7, + TAG_STRING = 8, + TAG_LIST = 9, + TAG_COMPOUND = 10, + TAG_INT_ARRAY = 11, + TAG_LONG_ARRAY = 12 + }; +}; + + +// all sub variants of Tag_* + +class Tag_Byte : public Tag { + public: + explicit Tag_Byte(TagDataStream *s); + + signed int toInt() const override; + unsigned int toUInt() const; + const QString toString() const override; + const QVariant getData() const override; + private: + quint8 data; +}; + +class Tag_Short : public Tag { + public: + explicit Tag_Short(TagDataStream *s); + + signed int toInt() const override; + unsigned int toUInt() const; + const QString toString() const override; + const QVariant getData() const override; + private: + qint16 data; +}; + +class Tag_Int : public Tag { + public: + explicit Tag_Int(TagDataStream *s); + + qint32 toInt() const override; + unsigned int toUInt() const; + double toDouble() const override; + const QString toString() const override; + const QVariant getData() const override; + private: + qint32 data; +}; + +class Tag_Long : public Tag { + public: + explicit Tag_Long(TagDataStream *s); + + qint32 toInt() const override; + double toDouble() const override; + const QString toString() const override; + const QVariant getData() const override; + private: + qint64 data; +}; + +class Tag_Float : public Tag { + public: + explicit Tag_Float(TagDataStream *s); + + double toDouble() const override; + const QString toString() const override; + const QVariant getData() const override; + + private: + float data; +}; + +class Tag_Double : public Tag { + public: + explicit Tag_Double(TagDataStream *s); + + double toDouble() const override; + const QString toString() const override; + const QVariant getData() const override; + private: + double data; +}; + +class Tag_Byte_Array : public Tag { + public: + explicit Tag_Byte_Array(TagDataStream *s); + + int length() const override; + const std::vector& toByteArray() const override; + const QString toString() const override; + const QVariant getData() const override; + private: + std::vector data; + int len; +}; + +class Tag_String : public Tag { + public: + explicit Tag_String(TagDataStream *s); + + const QString toString() const override; + const QVariant getData() const override; + private: + QString data; +}; + +class Tag_List : public Tag { + public: + explicit Tag_List(TagDataStream *s); + ~Tag_List(); + + const Tag * at(int index) const override; + int length() const override; + const QString toString() const override; + const QVariant getData() const override; + private: + QList data; +}; + +class Tag_Compound : public Tag { + public: + explicit Tag_Compound(TagDataStream *s); + ~Tag_Compound(); + + bool has(const QString key) const override; + const Tag * at(const QString key) const override; + const QString toString() const override; + const QVariant getData() const override; + private: + QHash children; +}; + +class Tag_Int_Array : public Tag { + public: + explicit Tag_Int_Array(TagDataStream *s); + + int length() const override; + const std::vector& toIntArray() const override; + const QString toString() const override; + const QVariant getData() const override; + private: + int len; + std::vector data; +}; + +class Tag_Long_Array : public Tag { + public: + explicit Tag_Long_Array(TagDataStream *s); + + int length() const override; + const std::vector& toLongArray() const override; + const QString toString() const override; + const QVariant getData() const override; + private: + int len; + std::vector data; +}; + +#endif // TAG_H diff --git a/nbt_tagdatastream.cpp b/nbt_tagdatastream.cpp new file mode 100644 index 00000000..387117f9 --- /dev/null +++ b/nbt_tagdatastream.cpp @@ -0,0 +1,51 @@ +/** Copyright (c) 2013, Sean Kasun */ + +#include "nbt_tagdatastream.h" + + +TagDataStream::TagDataStream(const char *data, int len) { + this->data = (const quint8 *)data; + this->len = len; + pos = 0; +} + +quint8 TagDataStream::r8() { + return data[pos++]; +} + +quint16 TagDataStream::r16() { + quint16 r = data[pos++] << 8; + r |= data[pos++]; + return r; +} + +quint32 TagDataStream::r32() { + quint32 r = data[pos++] << 24; + r |= data[pos++] << 16; + r |= data[pos++] << 8; + r |= data[pos++]; + return r; +} + +quint64 TagDataStream::r64() { + quint64 r = (quint64)r32() << 32; + r |= r32(); + return r; +} + +void TagDataStream::r(int len, std::vector& data_out) { + // you need to free anything read with this + data_out.resize(len); + memcpy(&data_out[0], data + pos, len); + pos += len; +} + +QString TagDataStream::utf8(int len) { + int old = pos; + pos += len; + return QString::fromUtf8((const char *)data + old, len); +} + +void TagDataStream::skip(int len) { + pos += len; +} diff --git a/nbt_tagdatastream.h b/nbt_tagdatastream.h new file mode 100644 index 00000000..c421de5f --- /dev/null +++ b/nbt_tagdatastream.h @@ -0,0 +1,23 @@ +#ifndef TAGDATASTREAM_H +#define TAGDATASTREAM_H + +#include +#include + + +class TagDataStream { + public: + TagDataStream(const char *data, int len); + quint8 r8(); // read 8 bit + quint16 r16(); // read 16 bit + quint32 r32(); // read 32 bit + quint64 r64(); // read 64 bit + void r(int len, std::vector &data_out); // read bytes + QString utf8(int len); // read UTF8 encoded string + void skip(int len); // skip bytes of data + private: + const quint8 *data; + int pos, len; +}; + +#endif // TAGDATASTREAM_H