Fix issue #3
This commit is contained in:
105
include/nbt.hpp
105
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 <typename number_t>
|
||||
std::vector<number_t> load_array_text(std::istream & input) {
|
||||
std::vector<number_t> result;
|
||||
template <typename F>
|
||||
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<number_t>(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 <typename number_t>
|
||||
std::vector<number_t> load_array_text(std::istream & input);
|
||||
|
||||
template <typename number_t>
|
||||
std::vector<number_t> load_array_bin(std::istream & input, const context & 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>
|
||||
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);
|
||||
}
|
||||
}
|
||||
void dump_array_text(std::ostream & output, const std::vector<number_t> & array);
|
||||
|
||||
template <typename number_t>
|
||||
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++)
|
||||
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 <tag_id TID, typename number_t, char prefix>
|
||||
template <tag_id TID, typename number_t, char prefix_c>
|
||||
struct array_tag final : public tag {
|
||||
typedef number_t element_type;
|
||||
typedef std::vector<element_type> 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<array_tag> 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<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;
|
||||
}
|
||||
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<tag> copy() const override {
|
||||
return std::make_unique<array_tag>(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 <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 std {
|
||||
|
||||
@@ -518,12 +518,7 @@ std::unique_ptr<list_tag> 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<tag_id>(cheof(input));
|
||||
return read_list_content(type, input);
|
||||
|
||||
25
test/issue3.cpp
Normal file
25
test/issue3.cpp
Normal 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());
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
test_names = [
|
||||
'nbt',
|
||||
'issue2'
|
||||
'issue2',
|
||||
'issue3'
|
||||
]
|
||||
|
||||
test_files = []
|
||||
|
||||
Reference in New Issue
Block a user