This commit is contained in:
ktlo
2021-12-04 20:53:49 +03:00
parent 57561c859f
commit cb43446e86
4 changed files with 81 additions and 59 deletions

View File

@@ -213,28 +213,29 @@ void skip_space(std::istream & input);
std::size_t load_size(std::istream & input, const context & ctxt); std::size_t load_size(std::istream & input, const context & ctxt);
void dump_size(std::ostream & output, const context & ctxt, std::size_t size); void dump_size(std::ostream & output, const context & ctxt, std::size_t size);
template <typename number_t> template <typename F>
std::vector<number_t> load_array_text(std::istream & input) { void scan_sequence_text(std::istream & input, F element_action) {
std::vector<number_t> result;
for (;;) { for (;;) {
skip_space(input); skip_space(input);
char c = cheof(input); char c = cheof(input);
input.putback(c);
if (c == ']') { if (c == ']') {
break; break;
} }
result.push_back(load_text<number_t>(input)); input.putback(c);
element_action();
skip_space(input); skip_space(input);
char next = cheof(input); int next = cheof(input);
if (next != ',') { switch (next) {
input.putback(next); case ',': continue;
break; case ']': return;
default: throw std::runtime_error(std::string("unexpected character: ") + char(next));
} }
} }
result.shrink_to_fit();
return result;
} }
template <typename number_t>
std::vector<number_t> load_array_text(std::istream & input);
template <typename number_t> template <typename number_t>
std::vector<number_t> load_array_bin(std::istream & input, const context & ctxt) { std::vector<number_t> load_array_bin(std::istream & input, const context & ctxt) {
auto size = load_size(input, ctxt); auto size = load_size(input, ctxt);
@@ -311,17 +312,7 @@ inline void dump<std::uint64_t>(std::ostream & output, std::uint64_t number, con
} }
template <typename number_t> template <typename number_t>
void dump_array_text(std::ostream & output, const std::vector<number_t> & array) { void dump_array_text(std::ostream & output, const std::vector<number_t> & 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);
}
}
template <typename number_t> template <typename number_t>
void dump_array_bin(std::ostream & output, const std::vector<number_t> & array, const context & ctxt) { void dump_array_bin(std::ostream & output, const std::vector<number_t> & array, const context & ctxt) {
@@ -373,16 +364,11 @@ std::unique_ptr<tag_type> load_list(std::istream & input, F action) {
for (std::size_t i = 0; i < size; i++) for (std::size_t i = 0; i < size; i++)
result.emplace_back(action(ctxt)); result.emplace_back(action(ctxt));
} else { } else {
for (;;) { scan_sequence_text(input, [&] {
result.emplace_back(action(ctxt)); result.emplace_back(action(ctxt));
skip_space(input); });
int next = cheof(input);
if (next != ',') {
input.putback(next);
break;
}
}
} }
result.shrink_to_fit();
return ptr; return ptr;
} }
@@ -481,10 +467,11 @@ namespace tags {
# undef NUMERIC_TAG # undef NUMERIC_TAG
template <tag_id TID, typename number_t, char prefix> template <tag_id TID, typename number_t, char prefix_c>
struct array_tag final : public tag { struct array_tag final : public tag {
typedef number_t element_type; typedef number_t element_type;
typedef std::vector<element_type> value_type; typedef std::vector<element_type> value_type;
static constexpr char prefix = prefix_c;
value_type value; value_type value;
static constexpr tag_id tid = TID; static constexpr tag_id tid = TID;
virtual tag_id id() const noexcept override { virtual tag_id id() const noexcept override {
@@ -495,33 +482,12 @@ namespace tags {
array_tag(value_type && array) : value(std::move(array)) {} array_tag(value_type && array) : value(std::move(array)) {}
static std::unique_ptr<array_tag> read(std::istream & input) { static std::unique_ptr<array_tag> read(std::istream & input) {
const context & ctxt = context::get(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<array_tag>(load_array<element_type>(input, ctxt)); auto result = std::make_unique<array_tag>(load_array<element_type>(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; return result;
} }
virtual void write(std::ostream & output) const override { virtual void write(std::ostream & output) const override {
const context & ctxt = context::get(output); const context & ctxt = context::get(output);
if (ctxt.format == context::formats::mojangson)
output << '[' << prefix << ';';
dump_array(output, value, ctxt); dump_array(output, value, ctxt);
if (ctxt.format == context::formats::mojangson)
output << ']';
} }
virtual std::unique_ptr<tag> copy() const override { virtual std::unique_ptr<tag> copy() const override {
return std::make_unique<array_tag>(value); return std::make_unique<array_tag>(value);
@@ -923,6 +889,41 @@ namespace tags {
std::istream & operator>>(std::istream & input, tags::compound_tag & compound); std::istream & operator>>(std::istream & input, tags::compound_tag & compound);
std::ostream & operator<<(std::ostream & output, const tags::tag & tag); std::ostream & operator<<(std::ostream & output, const tags::tag & tag);
template <typename number_t>
std::vector<number_t> load_array_text(std::istream & input) {
std::vector<number_t> 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<std::vector<number_t>>::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<number_t>(input));
});
result.shrink_to_fit();
return result;
}
template <typename number_t>
void dump_array_text(std::ostream & output, const std::vector<number_t> & array) {
output << '[' << tags::tag_of<std::vector<number_t>>::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 nbt
namespace std { namespace std {

View File

@@ -518,12 +518,7 @@ std::unique_ptr<list_tag> list_tag::read(std::istream & input) {
if (a != '[') if (a != '[')
throw std::runtime_error("failed to open list tag"); throw std::runtime_error("failed to open list tag");
tag_id type = deduce_tag(input); tag_id type = deduce_tag(input);
auto result = read_list_content(type, input); return 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;
} else { } else {
tag_id type = static_cast<tag_id>(cheof(input)); tag_id type = static_cast<tag_id>(cheof(input));
return read_list_content(type, input); return read_list_content(type, input);

25
test/issue3.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include <sstream>
#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<const tags::bytearray_list_tag &>(*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());
}

View File

@@ -1,6 +1,7 @@
test_names = [ test_names = [
'nbt', 'nbt',
'issue2' 'issue2',
'issue3'
] ]
test_files = [] test_files = []