From c4c23e9cc6ca131a512dffa9e39a4d2f670b020c Mon Sep 17 00:00:00 2001 From: Brett Date: Wed, 26 Jul 2023 13:09:41 -0400 Subject: [PATCH] NBT finished, need to add decoder / tests - evil hacks are not fun (blt::nbt::_internal_ forward declares list and compound for use inside list / compound) - list could be made faster by bulk allocating when type is known however i believe the compiler is smart enough to do this for me - testing that should be a todo! --- include/blt/nbt/nbt.h | 119 ++++++++++++++++++++++------------- include/blt/std/filesystem.h | 10 +++ 2 files changed, 84 insertions(+), 45 deletions(-) diff --git a/include/blt/nbt/nbt.h b/include/blt/nbt/nbt.h index 31b6f15..9cb9372 100755 --- a/include/blt/nbt/nbt.h +++ b/include/blt/nbt/nbt.h @@ -97,6 +97,7 @@ namespace blt::nbt { [[nodiscard]] inline const std::string& getName() const { return name; } + virtual ~tag_t() = default; }; template @@ -116,6 +117,7 @@ namespace blt::nbt { } [[nodiscard]] inline const T& get() const {return t;} inline T& get() {return t;} + ~tag() override = default; }; class tag_end : public tag { @@ -229,11 +231,45 @@ namespace blt::nbt { } }; - // EVIL HACK - static tag_t* newCompound(); - #define BLT_NBT_POPULATE_VEC(type, vec, length) for (int i = 0; i < length; i++) vec.push_back(type); + namespace _internal_ { + // EVIL HACK + static tag_t* newCompound(); + static tag_t* newList(); + static tag_t* toType(char id){ + switch ((nbt_tag) id) { + case nbt_tag::END: + return nullptr; + break; + case nbt_tag::BYTE: + return new blt::nbt::tag_byte; + case nbt_tag::SHORT: + return new blt::nbt::tag_short; + case nbt_tag::INT: + return new blt::nbt::tag_int; + case nbt_tag::LONG: + return new blt::nbt::tag_long; + case nbt_tag::FLOAT: + return new blt::nbt::tag_float; + case nbt_tag::DOUBLE: + return new blt::nbt::tag_double; + case nbt_tag::BYTE_ARRAY: + return new blt::nbt::tag_byte_array; + case nbt_tag::STRING: + return new blt::nbt::tag_string; + case nbt_tag::LIST: + return _internal_::newList(); + case nbt_tag::COMPOUND: + return _internal_::newCompound(); + case nbt_tag::INT_ARRAY: + return new blt::nbt::tag_int_array; + case nbt_tag::LONG_ARRAY: + return new blt::nbt::tag_long_array; + } + } + } + class tag_list : public tag> { public: tag_list(): tag(nbt_tag::LIST) {} @@ -255,54 +291,47 @@ namespace blt::nbt { readData(in, length); if (length == 0 || id == 0) return; - switch ((nbt_tag) id) { - case nbt_tag::END: - break; - case nbt_tag::BYTE: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_byte, t, length); - break; - case nbt_tag::SHORT: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_short, t, length); - break; - case nbt_tag::INT: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_int, t, length); - break; - case nbt_tag::LONG: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_long, t, length); - break; - case nbt_tag::FLOAT: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_float, t, length); - break; - case nbt_tag::DOUBLE: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_double, t, length); - break; - case nbt_tag::BYTE_ARRAY: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_byte_array, t, length); - break; - case nbt_tag::STRING: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_string, t, length); - break; - case nbt_tag::LIST: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_list, t, length); - break; - case nbt_tag::COMPOUND: - BLT_NBT_POPULATE_VEC(newCompound(), t, length); - break; - case nbt_tag::INT_ARRAY: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_int_array, t, length); - break; - case nbt_tag::LONG_ARRAY: - BLT_NBT_POPULATE_VEC(new blt::nbt::tag_long_array, t, length); - break; - } - for (int i = 0; i < length; i++) + t.reserve(length); + for (int i = 0; i < length; i++) { + t[i] = _internal_::toType(id); t[i]->readPayload(in); + } + } + ~tag_list() override { + for (auto* p : t) + delete p; } }; + class tag_compound : public tag> { + public: + tag_compound(): tag(nbt_tag::COMPOUND) {} + tag_compound(const std::string& name, const std::vector& v): tag(nbt_tag::COMPOUND, name, v) {} + void writePayload(blt::fs::block_writer& out) final { + for (auto*& v : t){ + out.put((char) v->getType()); + v->writeName(out); + v->writePayload(out); + } + out.put('\0'); + } + void readPayload(blt::fs::block_reader& in) final { + char type; + while ((type = in.get()) != (char)nbt_tag::END){ + auto* v = _internal_::toType(type); + v->readName(in); + v->readPayload(in); + t.push_back(v); + } + } + }; - static tag_t* newCompound(){ + static tag_t* _internal_::newCompound(){ + return new blt::nbt::tag_compound; + } + static tag_t* _internal_::newList() { + return new blt::nbt::tag_list; } class NBTDecoder { diff --git a/include/blt/std/filesystem.h b/include/blt/std/filesystem.h index 70d1ee5..9e6527b 100755 --- a/include/blt/std/filesystem.h +++ b/include/blt/std/filesystem.h @@ -34,6 +34,11 @@ namespace blt::fs { * @return status code. non-zero return codes indicates a failure has occurred. */ virtual int read(char* buffer, size_t bytes) = 0; + virtual char get(){ + char c[1]; + read(c, 1); + return c[0]; + } }; /** @@ -52,6 +57,11 @@ namespace blt::fs { * @return non-zero code if failure */ virtual int write(char* buffer, size_t bytes) = 0; + virtual int put(char c){ + char a[1]; + a[0] = c; + return write(a, 1); + } /** * Ensures that the internal buffer is written to the filesystem.