diff --git a/include/nbt.hpp b/include/nbt.hpp index f81d31e..efa4cbb 100644 --- a/include/nbt.hpp +++ b/include/nbt.hpp @@ -213,28 +213,29 @@ void skip_space(std::istream & input); std::size_t load_size(std::istream & input, const context & ctxt); void dump_size(std::ostream & output, const context & ctxt, std::size_t size); -template -std::vector load_array_text(std::istream & input) { - std::vector result; +template +void scan_sequence_text(std::istream & input, F element_action) { for (;;) { skip_space(input); char c = cheof(input); - input.putback(c); if (c == ']') { break; } - result.push_back(load_text(input)); + input.putback(c); + element_action(); skip_space(input); - char next = cheof(input); - if (next != ',') { - input.putback(next); - break; + int next = cheof(input); + switch (next) { + case ',': continue; + case ']': return; + default: throw std::runtime_error(std::string("unexpected character: ") + char(next)); } } - result.shrink_to_fit(); - return result; } +template +std::vector load_array_text(std::istream & input); + template std::vector load_array_bin(std::istream & input, const context & ctxt) { auto size = load_size(input, ctxt); @@ -311,17 +312,7 @@ inline void dump(std::ostream & output, std::uint64_t number, con } template -void dump_array_text(std::ostream & output, const std::vector & array) { - auto iter = array.cbegin(); - auto end = array.cend(); - if (iter == end) - return; - dump_text(output, *iter); - for (++iter; iter != end; ++iter) { - output << ','; - dump_text(output, *iter); - } -} +void dump_array_text(std::ostream & output, const std::vector & array); template void dump_array_bin(std::ostream & output, const std::vector & array, const context & ctxt) { @@ -373,16 +364,11 @@ std::unique_ptr load_list(std::istream & input, F action) { for (std::size_t i = 0; i < size; i++) result.emplace_back(action(ctxt)); } else { - for (;;) { + scan_sequence_text(input, [&] { result.emplace_back(action(ctxt)); - skip_space(input); - int next = cheof(input); - if (next != ',') { - input.putback(next); - break; - } - } + }); } + result.shrink_to_fit(); return ptr; } @@ -481,10 +467,11 @@ namespace tags { # undef NUMERIC_TAG - template + template struct array_tag final : public tag { typedef number_t element_type; typedef std::vector value_type; + static constexpr char prefix = prefix_c; value_type value; static constexpr tag_id tid = TID; virtual tag_id id() const noexcept override { @@ -495,33 +482,12 @@ namespace tags { array_tag(value_type && array) : value(std::move(array)) {} static std::unique_ptr read(std::istream & input) { const context & ctxt = context::get(input); - if (ctxt.format == context::formats::mojangson) { - skip_space(input); - char a = cheof(input); - if (a != '[') - throw std::runtime_error("failed to open array tag"); - a = cheof(input); - if (a != prefix) - throw std::runtime_error("wrong array tag type"); - a = cheof(input); - if (a != ';') - throw std::runtime_error("unexpected symbol in array tag"); - } auto result = std::make_unique(load_array(input, ctxt)); - if (ctxt.format == context::formats::mojangson) { - char a = cheof(input); - if (a != ']') - throw std::runtime_error("failed to close array tag"); - } return result; } virtual void write(std::ostream & output) const override { const context & ctxt = context::get(output); - if (ctxt.format == context::formats::mojangson) - output << '[' << prefix << ';'; dump_array(output, value, ctxt); - if (ctxt.format == context::formats::mojangson) - output << ']'; } virtual std::unique_ptr copy() const override { return std::make_unique(value); @@ -923,6 +889,41 @@ namespace tags { std::istream & operator>>(std::istream & input, tags::compound_tag & compound); std::ostream & operator<<(std::ostream & output, const tags::tag & tag); +template +std::vector load_array_text(std::istream & input) { + std::vector result; + skip_space(input); + char a = cheof(input); + if (a != '[') + throw std::runtime_error("failed to open array tag"); + a = cheof(input); + if (a != tags::tag_of>::prefix) + throw std::runtime_error("wrong array tag type"); + a = cheof(input); + if (a != ';') + throw std::runtime_error("unexpected symbol in array tag"); + scan_sequence_text(input, [&] { + result.push_back(load_text(input)); + }); + result.shrink_to_fit(); + return result; +} + +template +void dump_array_text(std::ostream & output, const std::vector & array) { + output << '[' << tags::tag_of>::prefix << ';'; + auto iter = array.cbegin(); + auto end = array.cend(); + if (iter == end) + return; + dump_text(output, *iter); + for (++iter; iter != end; ++iter) { + output << ','; + dump_text(output, *iter); + } + output << ']'; +} + } // namespace nbt namespace std { diff --git a/src/nbt.cpp b/src/nbt.cpp index 9ac4d60..2011398 100644 --- a/src/nbt.cpp +++ b/src/nbt.cpp @@ -518,12 +518,7 @@ std::unique_ptr list_tag::read(std::istream & input) { if (a != '[') throw std::runtime_error("failed to open list tag"); tag_id type = deduce_tag(input); - auto result = read_list_content(type, input); - skip_space(input); - a = cheof(input); - if (a != ']') - throw std::runtime_error(std::string("failed to close list tag, got: ") + a); - return result; + return read_list_content(type, input); } else { tag_id type = static_cast(cheof(input)); return read_list_content(type, input); diff --git a/test/issue3.cpp b/test/issue3.cpp new file mode 100644 index 0000000..059165b --- /dev/null +++ b/test/issue3.cpp @@ -0,0 +1,25 @@ +#include + +#include "nbt.hpp" + +#include "test.hpp" + +using namespace nbt; + +test { + const std::string subject = R"({"list":[[B;54b]]})"; + + std::stringstream input(subject); + tags::compound_tag root; + input >> contexts::mojangson >> root; + const std::string key("list"); + auto & list = dynamic_cast(*root.value[key]).value; + assert_equals(1u, list.size()); + const auto & bytes = list.front(); + assert_equals(1u, bytes.size()); + assert_equals(54, bytes.front()); + + std::stringstream output; + output << contexts::mojangson << root; + assert_equals(subject, output.str()); +} diff --git a/test/meson.build b/test/meson.build index 6761b5f..afebb00 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,6 +1,7 @@ test_names = [ 'nbt', - 'issue2' + 'issue2', + 'issue3' ] test_files = []