From 92cf81c1b4cf975d6f2835d8b5d020834a48e600 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Mon, 17 Oct 2022 06:40:56 +0200 Subject: [PATCH] tools/dumpnbt: Implement basic functionality. FINALLY!!! :^) --- src/tools/dumpnbt.cpp | 271 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 270 insertions(+), 1 deletion(-) diff --git a/src/tools/dumpnbt.cpp b/src/tools/dumpnbt.cpp index c5a5c9d..8bc3db3 100644 --- a/src/tools/dumpnbt.cpp +++ b/src/tools/dumpnbt.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "../lib/nbt.hpp" #include "../lib/cli.hpp" @@ -25,6 +26,265 @@ #define EXIT_USAGE 2 #define EXIT_UNIMPLEMENTED 3 +void printTagTypeName(NBT::Tag::Generic* tag, uint64_t offsetBytes) { + std::cout << "[" << offsetBytes << ": "; + switch (tag->getTagType()) { + case NBT::TagType::END: + std::cout << "End"; + break; + case NBT::TagType::INT8: + std::cout << "8 Bit Integer"; + break; + case NBT::TagType::INT16: + std::cout << "16 Bit Integer"; + break; + case NBT::TagType::INT32: + std::cout << "32 Bit Integer"; + break; + case NBT::TagType::INT64: + std::cout << "64 Bit Integer"; + break; + case NBT::TagType::FLOAT: + std::cout << "Float"; + break; + case NBT::TagType::DOUBLE: + std::cout << "Double"; + break; + case NBT::TagType::INT8_ARRAY: + std::cout << "Array of 8 Bit Integers"; + break; + case NBT::TagType::STRING: + std::cout << "String"; + break; + case NBT::TagType::LIST: + std::cout << "List"; + break; + case NBT::TagType::COMPOUND: + std::cout << "Compound"; + break; + case NBT::TagType::INT32_ARRAY: + std::cout << "Array of 32 Bit Integers"; + break; + case NBT::TagType::INT64_ARRAY: + std::cout << "Array of 64 Bit Integers"; + break; + default: + // WTF? How'd you even get here? + std::cout << "Unknown Type"; + } + std::cout << "]"; + if (tag->name == "") { + std::cout << ":"; + } else { + std::cout << " " << tag->name << ":"; + } +} + +void printNBytes(uint64_t bytes) { + std::cout << bytes << (bytes==1? " byte":" bytes"); +} + +void drawTree(NBT::Tag::Generic* tag, tiny_utf8::string prefix, uint64_t offsetBytes, bool listMode=false) { + std::vector serialized; + uint64_t headerSize = 0; + if (listMode) { + tag->serializeWithoutHeader(&serialized); + + std::cout << prefix << "|–Payload: "; + printNBytes(serialized.size()); + std::cout << std::endl; + } else { + tag->serialize(&serialized); + if (tag->getTagType() == NBT::TagType::END) { + headerSize = 1; + } else { + headerSize = (uint64_t) NBT::Helper::readInt16(serialized.data(), serialized.size(), 1).value+3; + } + + std::cout << prefix << "|–Header: "; + printNBytes(headerSize); + std::cout << std::endl; + std::cout << prefix << "|–Payload: "; + printNBytes(serialized.size() - headerSize); + std::cout << std::endl; + } + if (tag->getTagType() == NBT::TagType::END) { + std::cout << prefix << "'–Total: "; + } else { + std::cout << prefix << "|–Total: "; + } + printNBytes(serialized.size()); + std::cout << std::endl; + + switch (tag->getTagType()) { + case NBT::TagType::END: + break; + case NBT::TagType::INT8: + std::cout << prefix << "'–Value: " << (int32_t) reinterpret_cast(tag)->getValue() << std::endl; + break; + case NBT::TagType::INT16: + std::cout << prefix << "'–Value: " << (int32_t) reinterpret_cast(tag)->getValue() << std::endl; + break; + case NBT::TagType::INT32: + std::cout << prefix << "'–Value: " << reinterpret_cast(tag)->getValue() << std::endl; + break; + case NBT::TagType::INT64: + std::cout << prefix << "'–Value: " << reinterpret_cast(tag)->getValue() << std::endl; + break; + case NBT::TagType::FLOAT: + std::cout << prefix << "'–Value: " << reinterpret_cast(tag)->getValue() << std::endl; + break; + case NBT::TagType::DOUBLE: + std::cout << prefix << "'–Value: " << reinterpret_cast(tag)->getValue() << std::endl; + break; + case NBT::TagType::INT8_ARRAY: { + NBT::Tag::Int8Array* array = reinterpret_cast(tag); + std::cout << prefix << "|–Length: " << array->length() << std::endl; + std::cout << prefix << "'–Values: " << std::endl; + for (uint64_t i=0; ilength(); i++) { + if (i == array->length()-1) { + std::cout << prefix << " '–" << (int64_t) array->getValue(i).value << std::endl; + } else { + std::cout << prefix << " |–" << (int64_t) array->getValue(i).value << std::endl; + } + } + break; + } + case NBT::TagType::STRING: + std::cout << prefix << "'–Value: " << reinterpret_cast(tag)->getValue() << std::endl; + break; + case NBT::TagType::LIST: { + NBT::Tag::List* list = reinterpret_cast(tag); + + std::cout << prefix << "|–Contained Type: "; + switch (list->getContainedType()) { + case NBT::TagType::END: + std::cout << "End"; + break; + case NBT::TagType::INT8: + std::cout << "8 Bit Integer"; + break; + case NBT::TagType::INT16: + std::cout << "16 Bit Integer"; + break; + case NBT::TagType::INT32: + std::cout << "32 Bit Integer"; + break; + case NBT::TagType::INT64: + std::cout << "64 Bit Integer"; + break; + case NBT::TagType::FLOAT: + std::cout << "Float"; + break; + case NBT::TagType::DOUBLE: + std::cout << "Double"; + break; + case NBT::TagType::INT8_ARRAY: + std::cout << "Array of 8 Bit Integers"; + break; + case NBT::TagType::STRING: + std::cout << "String"; + break; + case NBT::TagType::LIST: + std::cout << "List"; + break; + case NBT::TagType::COMPOUND: + std::cout << "Compound"; + break; + case NBT::TagType::INT32_ARRAY: + std::cout << "Array of 32 Bit Integers"; + break; + case NBT::TagType::INT64_ARRAY: + std::cout << "Array of 64 Bit Integers"; + break; + default: + // WTF? How'd you even get here? + std::cout << "Unknown Type"; + } + std::cout << std::endl; + + std::cout << prefix << "|–Length: " << list->length() << std::endl; + std::cout << prefix << "|" << std::endl; + + offsetBytes = offsetBytes + headerSize + 5; + for (uint64_t i=0; ilength(); i++) { + if (i == list->length()-1) { + std::cout << prefix << "'–"; + printTagTypeName(list->getElementPointer(i).value, offsetBytes); + std::cout << std::endl; + drawTree(list->getElementPointer(i).value, prefix+" ", offsetBytes, true); + } else { + std::cout << prefix << "|–"; + printTagTypeName(list->getElementPointer(i).value, offsetBytes); + std::cout << std::endl; + drawTree(list->getElementPointer(i).value, prefix+"| ", offsetBytes, true); + } + + std::vector serializedElement; + list->getElementPointer(i).value->serializeWithoutHeader(&serializedElement); + offsetBytes += serializedElement.size(); + } + break; + } + case NBT::TagType::COMPOUND: { + NBT::Tag::Compound* compound = reinterpret_cast(tag); + + std::cout << prefix << "|–Length: " << compound->length() << std::endl; + std::cout << prefix << "|" << std::endl; + + offsetBytes = offsetBytes + headerSize; + for (uint64_t i=0; ilength(); i++) { + if (i == compound->length()-1) { + std::cout << prefix << "'–"; + printTagTypeName(compound->getElementPointer(i).value, offsetBytes); + std::cout << std::endl; + drawTree(compound->getElementPointer(i).value, prefix+" ", offsetBytes); + } else { + std::cout << prefix << "|–"; + printTagTypeName(compound->getElementPointer(i).value, offsetBytes); + std::cout << std::endl; + drawTree(compound->getElementPointer(i).value, prefix+"| ", offsetBytes); + } + + std::vector serializedElement; + compound->getElementPointer(i).value->serialize(&serializedElement); + offsetBytes += serializedElement.size(); + } + break; + } + case NBT::TagType::INT32_ARRAY: { + NBT::Tag::Int32Array* array = reinterpret_cast(tag); + std::cout << prefix << "|–Length: " << array->length() << std::endl; + std::cout << prefix << "'–Values: " << std::endl; + for (uint64_t i=0; ilength(); i++) { + if (i == array->length()-1) { + std::cout << prefix << " '–" << array->getValue(i).value << std::endl; + } else { + std::cout << prefix << " |–" << array->getValue(i).value << std::endl; + } + } + break; + } + case NBT::TagType::INT64_ARRAY: { + NBT::Tag::Int64Array* array = reinterpret_cast(tag); + std::cout << prefix << "|–Length: " << array->length() << std::endl; + std::cout << prefix << "'–Values: " << std::endl; + for (uint64_t i=0; ilength(); i++) { + if (i == array->length()-1) { + std::cout << prefix << " '–" << array->getValue(i).value << std::endl; + } else { + std::cout << prefix << " |–" << array->getValue(i).value << std::endl; + } + } + break; + } + default: + // WTF? How'd you even get here? + std::cout << prefix << "'–???" << std::endl; + } + + std::cout << prefix << std::endl; +} int main(int argc, char* argv[]) { std::vector flags; @@ -93,7 +353,16 @@ int main(int argc, char* argv[]) { return EXIT_RUNTIME; } - //TODO: print things here + uint64_t offsetBytes = 0; + for (uint64_t i=0; i serialized; + tags.value[i]->serialize(&serialized); + offsetBytes += serialized.size(); + } return EXIT_SUCCESS; }