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);
|
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 {
|
||||||
|
|||||||
@@ -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
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 = [
|
test_names = [
|
||||||
'nbt',
|
'nbt',
|
||||||
'issue2'
|
'issue2',
|
||||||
|
'issue3'
|
||||||
]
|
]
|
||||||
|
|
||||||
test_files = []
|
test_files = []
|
||||||
|
|||||||
Reference in New Issue
Block a user