summaryrefslogtreecommitdiffstats
path: root/depends/libnbtplusplus/src
diff options
context:
space:
mode:
Diffstat (limited to 'depends/libnbtplusplus/src')
-rw-r--r--depends/libnbtplusplus/src/endian_str.cpp284
-rw-r--r--depends/libnbtplusplus/src/io/stream_reader.cpp110
-rw-r--r--depends/libnbtplusplus/src/io/stream_writer.cpp54
-rw-r--r--depends/libnbtplusplus/src/tag.cpp105
-rw-r--r--depends/libnbtplusplus/src/tag_array.cpp110
-rw-r--r--depends/libnbtplusplus/src/tag_compound.cpp109
-rw-r--r--depends/libnbtplusplus/src/tag_list.cpp150
-rw-r--r--depends/libnbtplusplus/src/tag_string.cpp44
-rw-r--r--depends/libnbtplusplus/src/text/json_formatter.cpp195
-rw-r--r--depends/libnbtplusplus/src/value.cpp376
-rw-r--r--depends/libnbtplusplus/src/value_initializer.cpp36
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)) {}
+
+}