diff options
Diffstat (limited to 'depends/libnbtplusplus/src')
-rw-r--r-- | depends/libnbtplusplus/src/endian_str.cpp | 284 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/io/stream_reader.cpp | 110 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/io/stream_writer.cpp | 54 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/tag.cpp | 105 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/tag_array.cpp | 110 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/tag_compound.cpp | 109 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/tag_list.cpp | 150 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/tag_string.cpp | 44 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/text/json_formatter.cpp | 195 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/value.cpp | 376 | ||||
-rw-r--r-- | depends/libnbtplusplus/src/value_initializer.cpp | 36 |
11 files changed, 1573 insertions, 0 deletions
diff --git a/depends/libnbtplusplus/src/endian_str.cpp b/depends/libnbtplusplus/src/endian_str.cpp new file mode 100644 index 00000000..8d136b09 --- /dev/null +++ b/depends/libnbtplusplus/src/endian_str.cpp @@ -0,0 +1,284 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "endian_str.h" +#include <climits> +#include <cstring> +#include <iostream> + +static_assert(CHAR_BIT == 8, "Assuming that a byte has 8 bits"); +static_assert(sizeof(float) == 4, "Assuming that a float is 4 byte long"); +static_assert(sizeof(double) == 8, "Assuming that a double is 8 byte long"); + +namespace endian +{ + +namespace //anonymous +{ + void pun_int_to_float(float& f, uint32_t i) + { + //Yes we need to do it this way to avoid undefined behavior + memcpy(&f, &i, 4); + } + + uint32_t pun_float_to_int(float f) + { + uint32_t ret; + memcpy(&ret, &f, 4); + return ret; + } + + void pun_int_to_double(double& d, uint64_t i) + { + memcpy(&d, &i, 8); + } + + uint64_t pun_double_to_int(double f) + { + uint64_t ret; + memcpy(&ret, &f, 8); + return ret; + } +} + +//------------------------------------------------------------------------------ + +void read_little(std::istream& is, uint8_t& x) +{ + is.get(reinterpret_cast<char&>(x)); +} + +void read_little(std::istream& is, uint16_t& x) +{ + uint8_t tmp[2]; + is.read(reinterpret_cast<char*>(tmp), 2); + x = uint16_t(tmp[0]) + | (uint16_t(tmp[1]) << 8); +} + +void read_little(std::istream& is, uint32_t& x) +{ + uint8_t tmp[4]; + is.read(reinterpret_cast<char*>(tmp), 4); + x = uint32_t(tmp[0]) + | (uint32_t(tmp[1]) << 8) + | (uint32_t(tmp[2]) << 16) + | (uint32_t(tmp[3]) << 24); +} + +void read_little(std::istream& is, uint64_t& x) +{ + uint8_t tmp[8]; + is.read(reinterpret_cast<char*>(tmp), 8); + x = uint64_t(tmp[0]) + | (uint64_t(tmp[1]) << 8) + | (uint64_t(tmp[2]) << 16) + | (uint64_t(tmp[3]) << 24) + | (uint64_t(tmp[4]) << 32) + | (uint64_t(tmp[5]) << 40) + | (uint64_t(tmp[6]) << 48) + | (uint64_t(tmp[7]) << 56); +} + +void read_little(std::istream& is, int8_t & x) { read_little(is, reinterpret_cast<uint8_t &>(x)); } +void read_little(std::istream& is, int16_t& x) { read_little(is, reinterpret_cast<uint16_t&>(x)); } +void read_little(std::istream& is, int32_t& x) { read_little(is, reinterpret_cast<uint32_t&>(x)); } +void read_little(std::istream& is, int64_t& x) { read_little(is, reinterpret_cast<uint64_t&>(x)); } + +void read_little(std::istream& is, float& x) +{ + uint32_t tmp; + read_little(is, tmp); + pun_int_to_float(x, tmp); +} + +void read_little(std::istream& is, double& x) +{ + uint64_t tmp; + read_little(is, tmp); + pun_int_to_double(x, tmp); +} + +//------------------------------------------------------------------------------ + +void read_big(std::istream& is, uint8_t& x) +{ + is.read(reinterpret_cast<char*>(&x), 1); +} + +void read_big(std::istream& is, uint16_t& x) +{ + uint8_t tmp[2]; + is.read(reinterpret_cast<char*>(tmp), 2); + x = uint16_t(tmp[1]) + | (uint16_t(tmp[0]) << 8); +} + +void read_big(std::istream& is, uint32_t& x) +{ + uint8_t tmp[4]; + is.read(reinterpret_cast<char*>(tmp), 4); + x = uint32_t(tmp[3]) + | (uint32_t(tmp[2]) << 8) + | (uint32_t(tmp[1]) << 16) + | (uint32_t(tmp[0]) << 24); +} + +void read_big(std::istream& is, uint64_t& x) +{ + uint8_t tmp[8]; + is.read(reinterpret_cast<char*>(tmp), 8); + x = uint64_t(tmp[7]) + | (uint64_t(tmp[6]) << 8) + | (uint64_t(tmp[5]) << 16) + | (uint64_t(tmp[4]) << 24) + | (uint64_t(tmp[3]) << 32) + | (uint64_t(tmp[2]) << 40) + | (uint64_t(tmp[1]) << 48) + | (uint64_t(tmp[0]) << 56); +} + +void read_big(std::istream& is, int8_t & x) { read_big(is, reinterpret_cast<uint8_t &>(x)); } +void read_big(std::istream& is, int16_t& x) { read_big(is, reinterpret_cast<uint16_t&>(x)); } +void read_big(std::istream& is, int32_t& x) { read_big(is, reinterpret_cast<uint32_t&>(x)); } +void read_big(std::istream& is, int64_t& x) { read_big(is, reinterpret_cast<uint64_t&>(x)); } + +void read_big(std::istream& is, float& x) +{ + uint32_t tmp; + read_big(is, tmp); + pun_int_to_float(x, tmp); +} + +void read_big(std::istream& is, double& x) +{ + uint64_t tmp; + read_big(is, tmp); + pun_int_to_double(x, tmp); +} + +//------------------------------------------------------------------------------ + +void write_little(std::ostream& os, uint8_t x) +{ + os.put(x); +} + +void write_little(std::ostream& os, uint16_t x) +{ + uint8_t tmp[2] { + uint8_t(x), + uint8_t(x >> 8)}; + os.write(reinterpret_cast<const char*>(tmp), 2); +} + +void write_little(std::ostream& os, uint32_t x) +{ + uint8_t tmp[4] { + uint8_t(x), + uint8_t(x >> 8), + uint8_t(x >> 16), + uint8_t(x >> 24)}; + os.write(reinterpret_cast<const char*>(tmp), 4); +} + +void write_little(std::ostream& os, uint64_t x) +{ + uint8_t tmp[8] { + uint8_t(x), + uint8_t(x >> 8), + uint8_t(x >> 16), + uint8_t(x >> 24), + uint8_t(x >> 32), + uint8_t(x >> 40), + uint8_t(x >> 48), + uint8_t(x >> 56)}; + os.write(reinterpret_cast<const char*>(tmp), 8); +} + +void write_little(std::ostream& os, int8_t x) { write_little(os, static_cast<uint8_t >(x)); } +void write_little(std::ostream& os, int16_t x) { write_little(os, static_cast<uint16_t>(x)); } +void write_little(std::ostream& os, int32_t x) { write_little(os, static_cast<uint32_t>(x)); } +void write_little(std::ostream& os, int64_t x) { write_little(os, static_cast<uint64_t>(x)); } + +void write_little(std::ostream& os, float x) +{ + write_little(os, pun_float_to_int(x)); +} + +void write_little(std::ostream& os, double x) +{ + write_little(os, pun_double_to_int(x)); +} + +//------------------------------------------------------------------------------ + +void write_big(std::ostream& os, uint8_t x) +{ + os.put(x); +} + +void write_big(std::ostream& os, uint16_t x) +{ + uint8_t tmp[2] { + uint8_t(x >> 8), + uint8_t(x)}; + os.write(reinterpret_cast<const char*>(tmp), 2); +} + +void write_big(std::ostream& os, uint32_t x) +{ + uint8_t tmp[4] { + uint8_t(x >> 24), + uint8_t(x >> 16), + uint8_t(x >> 8), + uint8_t(x)}; + os.write(reinterpret_cast<const char*>(tmp), 4); +} + +void write_big(std::ostream& os, uint64_t x) +{ + uint8_t tmp[8] { + uint8_t(x >> 56), + uint8_t(x >> 48), + uint8_t(x >> 40), + uint8_t(x >> 32), + uint8_t(x >> 24), + uint8_t(x >> 16), + uint8_t(x >> 8), + uint8_t(x)}; + os.write(reinterpret_cast<const char*>(tmp), 8); +} + +void write_big(std::ostream& os, int8_t x) { write_big(os, static_cast<uint8_t >(x)); } +void write_big(std::ostream& os, int16_t x) { write_big(os, static_cast<uint16_t>(x)); } +void write_big(std::ostream& os, int32_t x) { write_big(os, static_cast<uint32_t>(x)); } +void write_big(std::ostream& os, int64_t x) { write_big(os, static_cast<uint64_t>(x)); } + +void write_big(std::ostream& os, float x) +{ + write_big(os, pun_float_to_int(x)); +} + +void write_big(std::ostream& os, double x) +{ + write_big(os, pun_double_to_int(x)); +} + +} diff --git a/depends/libnbtplusplus/src/io/stream_reader.cpp b/depends/libnbtplusplus/src/io/stream_reader.cpp new file mode 100644 index 00000000..f6f30a5b --- /dev/null +++ b/depends/libnbtplusplus/src/io/stream_reader.cpp @@ -0,0 +1,110 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "io/stream_reader.h" +#include "make_unique.h" +#include "tag_compound.h" +#include <istream> + +namespace nbt +{ +namespace io +{ + +std::pair<std::string, std::unique_ptr<tag_compound>> read_compound(std::istream& is, endian::endian e) +{ + return stream_reader(is, e).read_compound(); +} + +std::pair<std::string, std::unique_ptr<tag>> read_tag(std::istream& is, endian::endian e) +{ + return stream_reader(is, e).read_tag(); +} + +stream_reader::stream_reader(std::istream& is, endian::endian e) noexcept: + is(is), endian(e) +{} + +std::istream& stream_reader::get_istr() const +{ + return is; +} + +endian::endian stream_reader::get_endian() const +{ + return endian; +} + +std::pair<std::string, std::unique_ptr<tag_compound>> stream_reader::read_compound() +{ + if(read_type() != tag_type::Compound) + { + is.setstate(std::ios::failbit); + throw input_error("Tag is not a compound"); + } + std::string key = read_string(); + auto comp = make_unique<tag_compound>(); + comp->read_payload(*this); + return {std::move(key), std::move(comp)}; +} + +std::pair<std::string, std::unique_ptr<tag>> stream_reader::read_tag() +{ + tag_type type = read_type(); + std::string key = read_string(); + std::unique_ptr<tag> t = read_payload(type); + return {std::move(key), std::move(t)}; +} + +std::unique_ptr<tag> stream_reader::read_payload(tag_type type) +{ + std::unique_ptr<tag> t = tag::create(type); + t->read_payload(*this); + return t; +} + +tag_type stream_reader::read_type(bool allow_end) +{ + int type = is.get(); + if(!is) + throw input_error("Error reading tag type"); + if(!is_valid_type(type, allow_end)) + { + is.setstate(std::ios::failbit); + throw input_error("Invalid tag type: " + std::to_string(type)); + } + return static_cast<tag_type>(type); +} + +std::string stream_reader::read_string() +{ + uint16_t len; + read_num(len); + if(!is) + throw input_error("Error reading string"); + + std::string ret(len, '\0'); + is.read(&ret[0], len); //C++11 allows us to do this + if(!is) + throw input_error("Error reading string"); + return ret; +} + +} +} diff --git a/depends/libnbtplusplus/src/io/stream_writer.cpp b/depends/libnbtplusplus/src/io/stream_writer.cpp new file mode 100644 index 00000000..036c5d40 --- /dev/null +++ b/depends/libnbtplusplus/src/io/stream_writer.cpp @@ -0,0 +1,54 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "io/stream_writer.h" +#include <sstream> + +namespace nbt +{ +namespace io +{ + +void write_tag(const std::string& key, const tag& t, std::ostream& os, endian::endian e) +{ + stream_writer(os, e).write_tag(key, t); +} + +void stream_writer::write_tag(const std::string& key, const tag& t) +{ + write_type(t.get_type()); + write_string(key); + write_payload(t); +} + +void stream_writer::write_string(const std::string& str) +{ + if(str.size() > max_string_len) + { + os.setstate(std::ios::failbit); + std::ostringstream sstr; + sstr << "String is too long for NBT (" << str.size() << " > " << max_string_len << ")"; + throw std::length_error(sstr.str()); + } + write_num(static_cast<uint16_t>(str.size())); + os.write(str.data(), str.size()); +} + +} +} diff --git a/depends/libnbtplusplus/src/tag.cpp b/depends/libnbtplusplus/src/tag.cpp new file mode 100644 index 00000000..df4d8cb5 --- /dev/null +++ b/depends/libnbtplusplus/src/tag.cpp @@ -0,0 +1,105 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "tag.h" +#include "nbt_tags.h" +#include "text/json_formatter.h" +#include <limits> +#include <ostream> +#include <stdexcept> +#include <typeinfo> + +namespace nbt +{ + +static_assert(std::numeric_limits<float>::is_iec559 && std::numeric_limits<double>::is_iec559, + "The floating point values for NBT must conform to IEC 559/IEEE 754"); + +bool is_valid_type(int type, bool allow_end) +{ + return (allow_end ? 0 : 1) <= type && type <= 11; +} + +std::unique_ptr<tag> tag::clone() && +{ + return std::move(*this).move_clone(); +} + +std::unique_ptr<tag> tag::create(tag_type type) +{ + switch(type) + { + case tag_type::Byte: return make_unique<tag_byte>(); + case tag_type::Short: return make_unique<tag_short>(); + case tag_type::Int: return make_unique<tag_int>(); + case tag_type::Long: return make_unique<tag_long>(); + case tag_type::Float: return make_unique<tag_float>(); + case tag_type::Double: return make_unique<tag_double>(); + case tag_type::Byte_Array: return make_unique<tag_byte_array>(); + case tag_type::String: return make_unique<tag_string>(); + case tag_type::List: return make_unique<tag_list>(); + case tag_type::Compound: return make_unique<tag_compound>(); + case tag_type::Int_Array: return make_unique<tag_int_array>(); + + default: throw std::invalid_argument("Invalid tag type"); + } +} + +bool operator==(const tag& lhs, const tag& rhs) +{ + if(typeid(lhs) != typeid(rhs)) + return false; + return lhs.equals(rhs); +} + +bool operator!=(const tag& lhs, const tag& rhs) +{ + return !(lhs == rhs); +} + +std::ostream& operator<<(std::ostream& os, tag_type tt) +{ + switch(tt) + { + case tag_type::End: return os << "end"; + case tag_type::Byte: return os << "byte"; + case tag_type::Short: return os << "short"; + case tag_type::Int: return os << "int"; + case tag_type::Long: return os << "long"; + case tag_type::Float: return os << "float"; + case tag_type::Double: return os << "double"; + case tag_type::Byte_Array: return os << "byte_array"; + case tag_type::String: return os << "string"; + case tag_type::List: return os << "list"; + case tag_type::Compound: return os << "compound"; + case tag_type::Int_Array: return os << "int_array"; + case tag_type::Null: return os << "null"; + + default: return os << "invalid"; + } +} + +std::ostream& operator<<(std::ostream& os, const tag& t) +{ + static const text::json_formatter formatter; + formatter.print(os, t); + return os; +} + +} diff --git a/depends/libnbtplusplus/src/tag_array.cpp b/depends/libnbtplusplus/src/tag_array.cpp new file mode 100644 index 00000000..99e32549 --- /dev/null +++ b/depends/libnbtplusplus/src/tag_array.cpp @@ -0,0 +1,110 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "tag_array.h" +#include "io/stream_reader.h" +#include "io/stream_writer.h" +#include <istream> + +namespace nbt +{ + +template<class T> +T& tag_array<T>::at(size_t i) +{ + return data.at(i); +} + +template<class T> +T tag_array<T>::at(size_t i) const +{ + return data.at(i); +} + +//Slightly different between byte_array and int_array +//Reading +template<> +void tag_array<int8_t>::read_payload(io::stream_reader& reader) +{ + int32_t length; + reader.read_num(length); + if(length < 0) + reader.get_istr().setstate(std::ios::failbit); + if(!reader.get_istr()) + throw io::input_error("Error reading length of tag_byte_array"); + + data.resize(length); + reader.get_istr().read(reinterpret_cast<char*>(data.data()), length); + if(!reader.get_istr()) + throw io::input_error("Error reading contents of tag_byte_array"); +} + +template<> +void tag_array<int32_t>::read_payload(io::stream_reader& reader) +{ + int32_t length; + reader.read_num(length); + if(length < 0) + reader.get_istr().setstate(std::ios::failbit); + if(!reader.get_istr()) + throw io::input_error("Error reading length of tag_int_array"); + + data.clear(); + data.reserve(length); + for(int32_t i = 0; i < length; ++i) + { + int32_t val; + reader.read_num(val); + data.push_back(val); + } + if(!reader.get_istr()) + throw io::input_error("Error reading contents of tag_int_array"); +} + +//Writing +template<> +void tag_array<int8_t>::write_payload(io::stream_writer& writer) const +{ + if(size() > io::stream_writer::max_array_len) + { + writer.get_ostr().setstate(std::ios::failbit); + throw std::length_error("Byte array is too large for NBT"); + } + writer.write_num(static_cast<int32_t>(size())); + writer.get_ostr().write(reinterpret_cast<const char*>(data.data()), data.size()); +} + +template<> +void tag_array<int32_t>::write_payload(io::stream_writer& writer) const +{ + if(size() > io::stream_writer::max_array_len) + { + writer.get_ostr().setstate(std::ios::failbit); + throw std::length_error("Int array is too large for NBT"); + } + writer.write_num(static_cast<int32_t>(size())); + for(int32_t i: data) + writer.write_num(i); +} + +//Enforce template instantiations +template class tag_array<int8_t>; +template class tag_array<int32_t>; + +} diff --git a/depends/libnbtplusplus/src/tag_compound.cpp b/depends/libnbtplusplus/src/tag_compound.cpp new file mode 100644 index 00000000..4085bb4e --- /dev/null +++ b/depends/libnbtplusplus/src/tag_compound.cpp @@ -0,0 +1,109 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "tag_compound.h" +#include "io/stream_reader.h" +#include "io/stream_writer.h" +#include <istream> +#include <sstream> + +namespace nbt +{ + +tag_compound::tag_compound(std::initializer_list<std::pair<std::string, value_initializer>> init) +{ + for(const auto& pair: init) + tags.emplace(std::move(pair.first), std::move(pair.second)); +} + +value& tag_compound::at(const std::string& key) +{ + return tags.at(key); +} + +const value& tag_compound::at(const std::string& key) const +{ + return tags.at(key); +} + +std::pair<tag_compound::iterator, bool> tag_compound::put(const std::string& key, value_initializer&& val) +{ + auto it = tags.find(key); + if(it != tags.end()) + { + it->second = std::move(val); + return {it, false}; + } + else + { + return tags.emplace(key, std::move(val)); + } +} + +std::pair<tag_compound::iterator, bool> tag_compound::insert(const std::string& key, value_initializer&& val) +{ + return tags.emplace(key, std::move(val)); +} + +bool tag_compound::erase(const std::string& key) +{ + return tags.erase(key) != 0; +} + +bool tag_compound::has_key(const std::string& key) const +{ + return tags.find(key) != tags.end(); +} + +bool tag_compound::has_key(const std::string& key, tag_type type) const +{ + auto it = tags.find(key); + return it != tags.end() && it->second.get_type() == type; +} + +void tag_compound::read_payload(io::stream_reader& reader) +{ + clear(); + tag_type tt; + while((tt = reader.read_type(true)) != tag_type::End) + { + std::string key; + try + { + key = reader.read_string(); + } + catch(io::input_error& ex) + { + std::ostringstream str; + str << "Error reading key of tag_" << tt; + throw io::input_error(str.str()); + } + auto tptr = reader.read_payload(tt); + tags.emplace(std::move(key), value(std::move(tptr))); + } +} + +void tag_compound::write_payload(io::stream_writer& writer) const +{ + for(const auto& pair: tags) + writer.write_tag(pair.first, pair.second); + writer.write_type(tag_type::End); +} + +} diff --git a/depends/libnbtplusplus/src/tag_list.cpp b/depends/libnbtplusplus/src/tag_list.cpp new file mode 100644 index 00000000..67a3d4c1 --- /dev/null +++ b/depends/libnbtplusplus/src/tag_list.cpp @@ -0,0 +1,150 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "tag_list.h" +#include "nbt_tags.h" +#include "io/stream_reader.h" +#include "io/stream_writer.h" +#include <istream> + +namespace nbt +{ + +tag_list::tag_list(std::initializer_list<int8_t> il) { init<tag_byte>(il); } +tag_list::tag_list(std::initializer_list<int16_t> il) { init<tag_short>(il); } +tag_list::tag_list(std::initializer_list<int32_t> il) { init<tag_int>(il); } +tag_list::tag_list(std::initializer_list<int64_t> il) { init<tag_long>(il); } +tag_list::tag_list(std::initializer_list<float> il) { init<tag_float>(il); } +tag_list::tag_list(std::initializer_list<double> il) { init<tag_double>(il); } +tag_list::tag_list(std::initializer_list<std::string> il) { init<tag_string>(il); } +tag_list::tag_list(std::initializer_list<tag_byte_array> il) { init<tag_byte_array>(il); } +tag_list::tag_list(std::initializer_list<tag_list> il) { init<tag_list>(il); } +tag_list::tag_list(std::initializer_list<tag_compound> il) { init<tag_compound>(il); } +tag_list::tag_list(std::initializer_list<tag_int_array> il) { init<tag_int_array>(il); } + +tag_list::tag_list(std::initializer_list<value> init) +{ + if(init.size() == 0) + el_type_ = tag_type::Null; + else + { + el_type_ = init.begin()->get_type(); + for(const value& val: init) + { + if(!val || val.get_type() != el_type_) + throw std::invalid_argument("The values are not all the same type"); + } + tags.assign(init.begin(), init.end()); + } +} + +value& tag_list::at(size_t i) +{ + return tags.at(i); +} + +const value& tag_list::at(size_t i) const +{ + return tags.at(i); +} + +void tag_list::set(size_t i, value&& val) +{ + if(val.get_type() != el_type_) + throw std::invalid_argument("The tag type does not match the list's content type"); + tags.at(i) = std::move(val); +} + +void tag_list::push_back(value_initializer&& val) +{ + if(!val) //don't allow null values + throw std::invalid_argument("The value must not be null"); + if(el_type_ == tag_type::Null) //set content type if undetermined + el_type_ = val.get_type(); + else if(el_type_ != val.get_type()) + throw std::invalid_argument("The tag type does not match the list's content type"); + tags.push_back(std::move(val)); +} + +void tag_list::reset(tag_type type) +{ + clear(); + el_type_ = type; +} + +void tag_list::read_payload(io::stream_reader& reader) +{ + tag_type lt = reader.read_type(true); + + int32_t length; + reader.read_num(length); + if(length < 0) + reader.get_istr().setstate(std::ios::failbit); + if(!reader.get_istr()) + throw io::input_error("Error reading length of tag_list"); + + if(lt != tag_type::End) + { + reset(lt); + tags.reserve(length); + + for(int32_t i = 0; i < length; ++i) + tags.emplace_back(reader.read_payload(lt)); + } + else + { + //In case of tag_end, ignore the length and leave the type undetermined + reset(tag_type::Null); + } +} + +void tag_list::write_payload(io::stream_writer& writer) const +{ + if(size() > io::stream_writer::max_array_len) + { + writer.get_ostr().setstate(std::ios::failbit); + throw std::length_error("List is too large for NBT"); + } + writer.write_type(el_type_ != tag_type::Null + ? el_type_ + : tag_type::End); + writer.write_num(static_cast<int32_t>(size())); + for(const auto& val: tags) + { + //check if the value is of the correct type + if(val.get_type() != el_type_) + { + writer.get_ostr().setstate(std::ios::failbit); + throw std::logic_error("The tags in the list do not all match the content type"); + } + writer.write_payload(val); + } +} + +bool operator==(const tag_list& lhs, const tag_list& rhs) +{ + return lhs.el_type_ == rhs.el_type_ && lhs.tags == rhs.tags; +} + +bool operator!=(const tag_list& lhs, const tag_list& rhs) +{ + return !(lhs == rhs); +} + +} diff --git a/depends/libnbtplusplus/src/tag_string.cpp b/depends/libnbtplusplus/src/tag_string.cpp new file mode 100644 index 00000000..30347818 --- /dev/null +++ b/depends/libnbtplusplus/src/tag_string.cpp @@ -0,0 +1,44 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "tag_string.h" +#include "io/stream_reader.h" +#include "io/stream_writer.h" + +namespace nbt +{ + +void tag_string::read_payload(io::stream_reader& reader) +{ + try + { + value = reader.read_string(); + } + catch(io::input_error& ex) + { + throw io::input_error("Error reading tag_string"); + } +} + +void tag_string::write_payload(io::stream_writer& writer) const +{ + writer.write_string(value); +} + +} diff --git a/depends/libnbtplusplus/src/text/json_formatter.cpp b/depends/libnbtplusplus/src/text/json_formatter.cpp new file mode 100644 index 00000000..9b47210c --- /dev/null +++ b/depends/libnbtplusplus/src/text/json_formatter.cpp @@ -0,0 +1,195 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "text/json_formatter.h" +#include "nbt_tags.h" +#include "nbt_visitor.h" +#include <cmath> +#include <iomanip> +#include <limits> + +namespace nbt +{ +namespace text +{ + +namespace //anonymous +{ + ///Helper class which uses the Visitor pattern to pretty-print tags + class json_fmt_visitor : public const_nbt_visitor + { + public: + json_fmt_visitor(std::ostream& os, const json_formatter& fmt): + os(os) + {} + + void visit(const tag_byte& b) override + { os << static_cast<int>(b.get()) << "b"; } //We don't want to print a character + + void visit(const tag_short& s) override + { os << s.get() << "s"; } + + void visit(const tag_int& i) override + { os << i.get(); } + + void visit(const tag_long& l) override + { os << l.get() << "l"; } + + void visit(const tag_float& f) override + { + write_float(f.get()); + os << "f"; + } + + void visit(const tag_double& d) override + { + write_float(d.get()); + os << "d"; + } + + void visit(const tag_byte_array& ba) override + { os << "[" << ba.size() << " bytes]"; } + + void visit(const tag_string& s) override + { os << '"' << s.get() << '"'; } //TODO: escape special characters + + void visit(const tag_list& l) override + { + //Wrap lines for lists of lists or compounds. + //Lists of other types can usually be on one line without problem. + const bool break_lines = l.size() > 0 && + (l.el_type() == tag_type::List || l.el_type() == tag_type::Compound); + + os << "["; + if(break_lines) + { + os << "\n"; + ++indent_lvl; + for(unsigned int i = 0; i < l.size(); ++i) + { + indent(); + if(l[i]) + l[i].get().accept(*this); + else + write_null(); + if(i != l.size()-1) + os << ","; + os << "\n"; + } + --indent_lvl; + indent(); + } + else + { + for(unsigned int i = 0; i < l.size(); ++i) + { + if(l[i]) + l[i].get().accept(*this); + else + write_null(); + if(i != l.size()-1) + os << ", "; + } + } + os << "]"; + } + + void visit(const tag_compound& c) override + { + if(c.size() == 0) //No line breaks inside empty compounds please + { + os << "{}"; + return; + } + + os << "{\n"; + ++indent_lvl; + unsigned int i = 0; + for(const auto& kv: c) + { + indent(); + os << kv.first << ": "; + if(kv.second) + kv.second.get().accept(*this); + else + write_null(); + if(i != c.size()-1) + os << ","; + os << "\n"; + ++i; + } + --indent_lvl; + indent(); + os << "}"; + } + + void visit(const tag_int_array& ia) override + { + os << "["; + for(unsigned int i = 0; i < ia.size(); ++i) + { + os << ia[i]; + if(i != ia.size()-1) + os << ", "; + } + os << "]"; + } + + private: + const std::string indent_str = " "; + + std::ostream& os; + int indent_lvl = 0; + + void indent() + { + for(int i = 0; i < indent_lvl; ++i) + os << indent_str; + } + + template<class T> + void write_float(T val, int precision = std::numeric_limits<T>::max_digits10) + { + if(std::isfinite(val)) + os << std::setprecision(precision) << val; + else if(std::isinf(val)) + { + if(std::signbit(val)) + os << "-"; + os << "Infinity"; + } + else + os << "NaN"; + } + + void write_null() + { + os << "null"; + } + }; +} + +void json_formatter::print(std::ostream& os, const tag& t) const +{ + json_fmt_visitor v(os, *this); + t.accept(v); +} + +} +} diff --git a/depends/libnbtplusplus/src/value.cpp b/depends/libnbtplusplus/src/value.cpp new file mode 100644 index 00000000..8376dc9b --- /dev/null +++ b/depends/libnbtplusplus/src/value.cpp @@ -0,0 +1,376 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "value.h" +#include "nbt_tags.h" +#include <typeinfo> + +namespace nbt +{ + +value::value(tag&& t): + tag_(std::move(t).move_clone()) +{} + +value::value(const value& rhs): + tag_(rhs.tag_ ? rhs.tag_->clone() : nullptr) +{} + +value& value::operator=(const value& rhs) +{ + if(this != &rhs) + { + tag_ = rhs.tag_ ? rhs.tag_->clone() : nullptr; + } + return *this; +} + +value& value::operator=(tag&& t) +{ + set(std::move(t)); + return *this; +} + +void value::set(tag&& t) +{ + if(tag_) + tag_->assign(std::move(t)); + else + tag_ = std::move(t).move_clone(); +} + +//Primitive assignment +//FIXME: Make this less copypaste! +value& value::operator=(int8_t val) +{ + if(!tag_) + set(tag_byte(val)); + else switch(tag_->get_type()) + { + case tag_type::Byte: + static_cast<tag_byte&>(*tag_).set(val); + break; + case tag_type::Short: + static_cast<tag_short&>(*tag_).set(val); + break; + case tag_type::Int: + static_cast<tag_int&>(*tag_).set(val); + break; + case tag_type::Long: + static_cast<tag_long&>(*tag_).set(val); + break; + case tag_type::Float: + static_cast<tag_float&>(*tag_).set(val); + break; + case tag_type::Double: + static_cast<tag_double&>(*tag_).set(val); + break; + + default: + throw std::bad_cast(); + } + return *this; +} + +value& value::operator=(int16_t val) +{ + if(!tag_) + set(tag_short(val)); + else switch(tag_->get_type()) + { + case tag_type::Short: + static_cast<tag_short&>(*tag_).set(val); + break; + case tag_type::Int: + static_cast<tag_int&>(*tag_).set(val); + break; + case tag_type::Long: + static_cast<tag_long&>(*tag_).set(val); + break; + case tag_type::Float: + static_cast<tag_float&>(*tag_).set(val); + break; + case tag_type::Double: + static_cast<tag_double&>(*tag_).set(val); + break; + + default: + throw std::bad_cast(); + } + return *this; +} + +value& value::operator=(int32_t val) +{ + if(!tag_) + set(tag_int(val)); + else switch(tag_->get_type()) + { + case tag_type::Int: + static_cast<tag_int&>(*tag_).set(val); + break; + case tag_type::Long: + static_cast<tag_long&>(*tag_).set(val); + break; + case tag_type::Float: + static_cast<tag_float&>(*tag_).set(val); + break; + case tag_type::Double: + static_cast<tag_double&>(*tag_).set(val); + break; + + default: + throw std::bad_cast(); + } + return *this; +} + +value& value::operator=(int64_t val) +{ + if(!tag_) + set(tag_long(val)); + else switch(tag_->get_type()) + { + case tag_type::Long: + static_cast<tag_long&>(*tag_).set(val); + break; + case tag_type::Float: + static_cast<tag_float&>(*tag_).set(val); + break; + case tag_type::Double: + static_cast<tag_double&>(*tag_).set(val); + break; + + default: + throw std::bad_cast(); + } + return *this; +} + +value& value::operator=(float val) +{ + if(!tag_) + set(tag_float(val)); + else switch(tag_->get_type()) + { + case tag_type::Float: + static_cast<tag_float&>(*tag_).set(val); + break; + case tag_type::Double: + static_cast<tag_double&>(*tag_).set(val); + break; + + default: + throw std::bad_cast(); + } + return *this; +} + +value& value::operator=(double val) +{ + if(!tag_) + set(tag_double(val)); + else switch(tag_->get_type()) + { + case tag_type::Double: + static_cast<tag_double&>(*tag_).set(val); + break; + + default: + throw std::bad_cast(); + } + return *this; +} + +//Primitive conversion +value::operator int8_t() const +{ + switch(tag_->get_type()) + { + case tag_type::Byte: + return static_cast<tag_byte&>(*tag_).get(); + + default: + throw std::bad_cast(); + } +} + +value::operator int16_t() const +{ + switch(tag_->get_type()) + { + case tag_type::Byte: + return static_cast<tag_byte&>(*tag_).get(); + case tag_type::Short: + return static_cast<tag_short&>(*tag_).get(); + + default: + throw std::bad_cast(); + } +} + +value::operator int32_t() const +{ + switch(tag_->get_type()) + { + case tag_type::Byte: + return static_cast<tag_byte&>(*tag_).get(); + case tag_type::Short: + return static_cast<tag_short&>(*tag_).get(); + case tag_type::Int: + return static_cast<tag_int&>(*tag_).get(); + + default: + throw std::bad_cast(); + } +} + +value::operator int64_t() const +{ + switch(tag_->get_type()) + { + case tag_type::Byte: + return static_cast<tag_byte&>(*tag_).get(); + case tag_type::Short: + return static_cast<tag_short&>(*tag_).get(); + case tag_type::Int: + return static_cast<tag_int&>(*tag_).get(); + case tag_type::Long: + return static_cast<tag_long&>(*tag_).get(); + + default: + throw std::bad_cast(); + } +} + +value::operator float() const +{ + switch(tag_->get_type()) + { + case tag_type::Byte: + return static_cast<tag_byte&>(*tag_).get(); + case tag_type::Short: + return static_cast<tag_short&>(*tag_).get(); + case tag_type::Int: + return static_cast<tag_int&>(*tag_).get(); + case tag_type::Long: + return static_cast<tag_long&>(*tag_).get(); + case tag_type::Float: + return static_cast<tag_float&>(*tag_).get(); + + default: + throw std::bad_cast(); + } +} + +value::operator double() const +{ + switch(tag_->get_type()) + { + case tag_type::Byte: + return static_cast<tag_byte&>(*tag_).get(); + case tag_type::Short: + return static_cast<tag_short&>(*tag_).get(); + case tag_type::Int: + return static_cast<tag_int&>(*tag_).get(); + case tag_type::Long: + return static_cast<tag_long&>(*tag_).get(); + case tag_type::Float: + return static_cast<tag_float&>(*tag_).get(); + case tag_type::Double: + return static_cast<tag_double&>(*tag_).get(); + + default: + throw std::bad_cast(); + } +} + +value& value::operator=(std::string&& str) +{ + if(!tag_) + set(tag_string(std::move(str))); + else + dynamic_cast<tag_string&>(*tag_).set(std::move(str)); + return *this; +} + +value::operator const std::string&() const +{ + return dynamic_cast<tag_string&>(*tag_).get(); +} + +value& value::at(const std::string& key) +{ + return dynamic_cast<tag_compound&>(*tag_).at(key); +} + +const value& value::at(const std::string& key) const +{ + return dynamic_cast<const tag_compound&>(*tag_).at(key); +} + +value& value::operator[](const std::string& key) +{ + return dynamic_cast<tag_compound&>(*tag_)[key]; +} + +value& value::operator[](const char* key) +{ + return (*this)[std::string(key)]; +} + +value& value::at(size_t i) +{ + return dynamic_cast<tag_list&>(*tag_).at(i); +} + +const value& value::at(size_t i) const +{ + return dynamic_cast<const tag_list&>(*tag_).at(i); +} + +value& value::operator[](size_t i) +{ + return dynamic_cast<tag_list&>(*tag_)[i]; +} + +const value& value::operator[](size_t i) const +{ + return dynamic_cast<const tag_list&>(*tag_)[i]; +} + +tag_type value::get_type() const +{ + return tag_ ? tag_->get_type() : tag_type::Null; +} + +bool operator==(const value& lhs, const value& rhs) +{ + if(lhs.tag_ != nullptr && rhs.tag_ != nullptr) + return *lhs.tag_ == *rhs.tag_; + else + return lhs.tag_ == nullptr && rhs.tag_ == nullptr; +} + +bool operator!=(const value& lhs, const value& rhs) +{ + return !(lhs == rhs); +} + +} diff --git a/depends/libnbtplusplus/src/value_initializer.cpp b/depends/libnbtplusplus/src/value_initializer.cpp new file mode 100644 index 00000000..3735bfdf --- /dev/null +++ b/depends/libnbtplusplus/src/value_initializer.cpp @@ -0,0 +1,36 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#include "value_initializer.h" +#include "nbt_tags.h" + +namespace nbt +{ + +value_initializer::value_initializer(int8_t val) : value(tag_byte(val)) {} +value_initializer::value_initializer(int16_t val) : value(tag_short(val)) {} +value_initializer::value_initializer(int32_t val) : value(tag_int(val)) {} +value_initializer::value_initializer(int64_t val) : value(tag_long(val)) {} +value_initializer::value_initializer(float val) : value(tag_float(val)) {} +value_initializer::value_initializer(double val) : value(tag_double(val)) {} +value_initializer::value_initializer(const std::string& str): value(tag_string(str)) {} +value_initializer::value_initializer(std::string&& str) : value(tag_string(std::move(str))) {} +value_initializer::value_initializer(const char* str) : value(tag_string(str)) {} + +} |