diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 19:56:58 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 19:56:58 +0300 |
| commit | a4b5ffbaadb591066e2a97f8d450fb1d93e56a6e (patch) | |
| tree | ae7c5841f264eea66484f9a413111ce012fa7a86 /libnbtplusplus/include | |
| parent | 7fb132859fda54aa96bc9dd46d302b343eeb5a02 (diff) | |
| parent | 1a0ffe372f4da8408c5d08a36013536a3396b9e6 (diff) | |
| download | Project-Tick-a4b5ffbaadb591066e2a97f8d450fb1d93e56a6e.tar.gz Project-Tick-a4b5ffbaadb591066e2a97f8d450fb1d93e56a6e.zip | |
Add 'libnbtplusplus/' from commit '1a0ffe372f4da8408c5d08a36013536a3396b9e6'
git-subtree-dir: libnbtplusplus
git-subtree-mainline: 7fb132859fda54aa96bc9dd46d302b343eeb5a02
git-subtree-split: 1a0ffe372f4da8408c5d08a36013536a3396b9e6
Diffstat (limited to 'libnbtplusplus/include')
21 files changed, 2636 insertions, 0 deletions
diff --git a/libnbtplusplus/include/crtp_tag.h b/libnbtplusplus/include/crtp_tag.h new file mode 100644 index 0000000000..91c629732d --- /dev/null +++ b/libnbtplusplus/include/crtp_tag.h @@ -0,0 +1,95 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef CRTP_TAG_H_INCLUDED +#define CRTP_TAG_H_INCLUDED + +#include "tag.h" +#include "nbt_visitor.h" +#include "make_unique.h" + +namespace nbt +{ + + namespace detail + { + + template <class Sub> class crtp_tag : public tag + { + public: + // Pure virtual destructor to make the class abstract + virtual ~crtp_tag() noexcept = 0; + + tag_type get_type() const noexcept override final + { + return Sub::type; + }; + + std::unique_ptr<tag> clone() const& override final + { + return make_unique<Sub>(sub_this()); + } + std::unique_ptr<tag> move_clone() && override final + { + return make_unique<Sub>(std::move(sub_this())); + } + + tag& assign(tag&& rhs) override final + { + return sub_this() = dynamic_cast<Sub&&>(rhs); + } + + void accept(nbt_visitor& visitor) override final + { + visitor.visit(sub_this()); + } + void accept(const_nbt_visitor& visitor) const override final + { + visitor.visit(sub_this()); + } + + private: + bool equals(const tag& rhs) const override final + { + return sub_this() == static_cast<const Sub&>(rhs); + } + + Sub& sub_this() + { + return static_cast<Sub&>(*this); + } + const Sub& sub_this() const + { + return static_cast<const Sub&>(*this); + } + }; + + template <class Sub> crtp_tag<Sub>::~crtp_tag() noexcept {} + + } // namespace detail + +} // namespace nbt + +#endif // CRTP_TAG_H_INCLUDED diff --git a/libnbtplusplus/include/endian_str.h b/libnbtplusplus/include/endian_str.h new file mode 100644 index 0000000000..a21a87f94b --- /dev/null +++ b/libnbtplusplus/include/endian_str.h @@ -0,0 +1,114 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef ENDIAN_STR_H_INCLUDED +#define ENDIAN_STR_H_INCLUDED + +#include <cstdint> +#include <iosfwd> +#include "nbt_export.h" + +/** + * @brief Reading and writing numbers from and to streams + * in binary format with different byte orders. + */ +namespace endian +{ + + enum endian { little, big }; + + /// Reads number from stream in specified endian + template <class T> void read(std::istream& is, T& x, endian e); + + /// Reads number from stream in little endian + NBT_EXPORT void read_little(std::istream& is, uint8_t& x); + NBT_EXPORT void read_little(std::istream& is, uint16_t& x); + NBT_EXPORT void read_little(std::istream& is, uint32_t& x); + NBT_EXPORT void read_little(std::istream& is, uint64_t& x); + NBT_EXPORT void read_little(std::istream& is, int8_t& x); + NBT_EXPORT void read_little(std::istream& is, int16_t& x); + NBT_EXPORT void read_little(std::istream& is, int32_t& x); + NBT_EXPORT void read_little(std::istream& is, int64_t& x); + NBT_EXPORT void read_little(std::istream& is, float& x); + NBT_EXPORT void read_little(std::istream& is, double& x); + + /// Reads number from stream in big endian + NBT_EXPORT void read_big(std::istream& is, uint8_t& x); + NBT_EXPORT void read_big(std::istream& is, uint16_t& x); + NBT_EXPORT void read_big(std::istream& is, uint32_t& x); + NBT_EXPORT void read_big(std::istream& is, uint64_t& x); + NBT_EXPORT void read_big(std::istream& is, int8_t& x); + NBT_EXPORT void read_big(std::istream& is, int16_t& x); + NBT_EXPORT void read_big(std::istream& is, int32_t& x); + NBT_EXPORT void read_big(std::istream& is, int64_t& x); + NBT_EXPORT void read_big(std::istream& is, float& x); + NBT_EXPORT void read_big(std::istream& is, double& x); + + /// Writes number to stream in specified endian + template <class T> void write(std::ostream& os, T x, endian e); + + /// Writes number to stream in little endian + NBT_EXPORT void write_little(std::ostream& os, uint8_t x); + NBT_EXPORT void write_little(std::ostream& os, uint16_t x); + NBT_EXPORT void write_little(std::ostream& os, uint32_t x); + NBT_EXPORT void write_little(std::ostream& os, uint64_t x); + NBT_EXPORT void write_little(std::ostream& os, int8_t x); + NBT_EXPORT void write_little(std::ostream& os, int16_t x); + NBT_EXPORT void write_little(std::ostream& os, int32_t x); + NBT_EXPORT void write_little(std::ostream& os, int64_t x); + NBT_EXPORT void write_little(std::ostream& os, float x); + NBT_EXPORT void write_little(std::ostream& os, double x); + + /// Writes number to stream in big endian + NBT_EXPORT void write_big(std::ostream& os, uint8_t x); + NBT_EXPORT void write_big(std::ostream& os, uint16_t x); + NBT_EXPORT void write_big(std::ostream& os, uint32_t x); + NBT_EXPORT void write_big(std::ostream& os, uint64_t x); + NBT_EXPORT void write_big(std::ostream& os, int8_t x); + NBT_EXPORT void write_big(std::ostream& os, int16_t x); + NBT_EXPORT void write_big(std::ostream& os, int32_t x); + NBT_EXPORT void write_big(std::ostream& os, int64_t x); + NBT_EXPORT void write_big(std::ostream& os, float x); + NBT_EXPORT void write_big(std::ostream& os, double x); + + template <class T> void read(std::istream& is, T& x, endian e) + { + if (e == little) + read_little(is, x); + else + read_big(is, x); + } + + template <class T> void write(std::ostream& os, T x, endian e) + { + if (e == little) + write_little(os, x); + else + write_big(os, x); + } + +} // namespace endian + +#endif // ENDIAN_STR_H_INCLUDED diff --git a/libnbtplusplus/include/io/izlibstream.h b/libnbtplusplus/include/io/izlibstream.h new file mode 100644 index 0000000000..c2a8e59b04 --- /dev/null +++ b/libnbtplusplus/include/io/izlibstream.h @@ -0,0 +1,107 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef IZLIBSTREAM_H_INCLUDED +#define IZLIBSTREAM_H_INCLUDED + +#include "io/zlib_streambuf.h" +#include <istream> +#include <zlib.h> + +namespace zlib +{ + + /** + * @brief Stream buffer used by zlib::izlibstream + * @sa izlibstream + */ + class NBT_EXPORT inflate_streambuf : public zlib_streambuf + { + public: + /** + * @param input the istream to wrap + * @param bufsize the size of the internal buffers + * @param window_bits the base two logarithm of the maximum window size + * that zlib will use. This parameter also determines which type of + * input to expect. The default argument will autodetect between zlib + * and gzip data. Refer to the zlib documentation of inflateInit2 for + * more details. + * + * @throw zlib_error if zlib encounters a problem during initialization + */ + explicit inflate_streambuf(std::istream& input, size_t bufsize = 32768, + int window_bits = 32 + 15); + ~inflate_streambuf() noexcept; + + ///@return the wrapped istream + std::istream& get_istr() const + { + return is; + } + + private: + std::istream& is; + bool stream_end; + + int_type underflow() override; + }; + + /** + * @brief An istream adapter that decompresses data using zlib + * + * This istream wraps another istream. The izlibstream will read compressed + * data from the wrapped istream and inflate (decompress) it with zlib. + * + * @note If you want to read more data from the wrapped istream after the + * end of the compressed data, then it must allow seeking. It is unavoidable + * for the izlibstream to consume more data after the compressed data. It + * will automatically attempt to seek the wrapped istream back to the point + * after the end of the compressed data. + * @sa inflate_streambuf + */ + class NBT_EXPORT izlibstream : public std::istream + { + public: + /** + * @param input the istream to wrap + * @param bufsize the size of the internal buffers + */ + explicit izlibstream(std::istream& input, size_t bufsize = 32768) + : std::istream(&buf), buf(input, bufsize) + { + } + ///@return the wrapped istream + std::istream& get_istr() const + { + return buf.get_istr(); + } + + private: + inflate_streambuf buf; + }; + +} // namespace zlib + +#endif // IZLIBSTREAM_H_INCLUDED diff --git a/libnbtplusplus/include/io/ozlibstream.h b/libnbtplusplus/include/io/ozlibstream.h new file mode 100644 index 0000000000..f04f33deef --- /dev/null +++ b/libnbtplusplus/include/io/ozlibstream.h @@ -0,0 +1,120 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef OZLIBSTREAM_H_INCLUDED +#define OZLIBSTREAM_H_INCLUDED + +#include "io/zlib_streambuf.h" +#include <ostream> +#include <zlib.h> + +namespace zlib +{ + + /** + * @brief Stream buffer used by zlib::ozlibstream + * @sa ozlibstream + */ + class NBT_EXPORT deflate_streambuf : public zlib_streambuf + { + public: + /** + * @param output the ostream to wrap + * @param bufsize the size of the internal buffers + * @param level the compression level, ranges from 0 to 9, or -1 for + * default + * + * Refer to the zlib documentation of deflateInit2 for details about the + * arguments. + * + * @throw zlib_error if zlib encounters a problem during initialization + */ + explicit deflate_streambuf(std::ostream& output, size_t bufsize = 32768, + int level = Z_DEFAULT_COMPRESSION, + int window_bits = 15, int mem_level = 8, + int strategy = Z_DEFAULT_STRATEGY); + ~deflate_streambuf() noexcept; + + ///@return the wrapped ostream + std::ostream& get_ostr() const + { + return os; + } + + /// Finishes compression and writes all pending data to the output + void close(); + + private: + std::ostream& os; + + void deflate_chunk(int flush = Z_NO_FLUSH); + + int_type overflow(int_type ch) override; + int sync() override; + }; + + /** + * @brief An ostream adapter that compresses data using zlib + * + * This ostream wraps another ostream. Data written to an ozlibstream will + * be deflated (compressed) with zlib and written to the wrapped ostream. + * + * @sa deflate_streambuf + */ + class NBT_EXPORT ozlibstream : public std::ostream + { + public: + /** + * @param output the ostream to wrap + * @param level the compression level, ranges from 0 to 9, or -1 for + * default + * @param gzip if true, the output will be in gzip format rather than + * zlib + * @param bufsize the size of the internal buffers + */ + explicit ozlibstream(std::ostream& output, + int level = Z_DEFAULT_COMPRESSION, + bool gzip = false, size_t bufsize = 32768) + : std::ostream(&buf), + buf(output, bufsize, level, 15 + (gzip ? 16 : 0)) + { + } + + ///@return the wrapped ostream + std::ostream& get_ostr() const + { + return buf.get_ostr(); + } + + /// Finishes compression and writes all pending data to the output + void close(); + + private: + deflate_streambuf buf; + }; + +} // namespace zlib + +#endif // OZLIBSTREAM_H_INCLUDED diff --git a/libnbtplusplus/include/io/stream_reader.h b/libnbtplusplus/include/io/stream_reader.h new file mode 100644 index 0000000000..05f8d99c92 --- /dev/null +++ b/libnbtplusplus/include/io/stream_reader.h @@ -0,0 +1,150 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef STREAM_READER_H_INCLUDED +#define STREAM_READER_H_INCLUDED + +#include "endian_str.h" +#include "tag.h" +#include "tag_compound.h" +#include <iosfwd> +#include <memory> +#include <stdexcept> +#include <utility> + +namespace nbt +{ + namespace io + { + + /// Exception that gets thrown when reading is not successful + class NBT_EXPORT input_error : public std::runtime_error + { + using std::runtime_error::runtime_error; + }; + + /** + * @brief Reads a named tag from the stream, making sure that it is a + * compound + * @param is the stream to read from + * @param e the byte order of the source data. The Java edition + * of Minecraft uses Big Endian, the Pocket edition uses Little Endian + * @throw input_error on failure, or if the tag in the stream is not a + * compound + */ + NBT_EXPORT std::pair<std::string, std::unique_ptr<tag_compound>> + read_compound(std::istream& is, endian::endian e = endian::big); + + /** + * @brief Reads a named tag from the stream + * @param is the stream to read from + * @param e the byte order of the source data. The Java edition + * of Minecraft uses Big Endian, the Pocket edition uses Little Endian + * @throw input_error on failure + */ + NBT_EXPORT std::pair<std::string, std::unique_ptr<tag>> + read_tag(std::istream& is, endian::endian e = endian::big); + + /** + * @brief Helper class for reading NBT tags from input streams + * + * Can be reused to read multiple tags + */ + class NBT_EXPORT stream_reader + { + public: + /** + * @param is the stream to read from + * @param e the byte order of the source data. The Java edition + * of Minecraft uses Big Endian, the Pocket edition uses Little + * Endian + */ + explicit stream_reader(std::istream& is, + endian::endian e = endian::big) noexcept; + + /// Returns the stream + std::istream& get_istr() const; + /// Returns the byte order + endian::endian get_endian() const; + + /** + * @brief Reads a named tag from the stream, making sure that it is + * a compound + * @throw input_error on failure, or if the tag in the stream is not + * a compound + */ + std::pair<std::string, std::unique_ptr<tag_compound>> + read_compound(); + + /** + * @brief Reads a named tag from the stream + * @throw input_error on failure + */ + std::pair<std::string, std::unique_ptr<tag>> read_tag(); + + /** + * @brief Reads a tag of the given type without name from the stream + * @throw input_error on failure + */ + std::unique_ptr<tag> read_payload(tag_type type); + + /** + * @brief Reads a tag type from the stream + * @param allow_end whether to consider tag_type::End valid + * @throw input_error on failure + */ + tag_type read_type(bool allow_end = false); + + /** + * @brief Reads a binary number from the stream + * + * On failure, will set the failbit on the stream. + */ + template <class T> void read_num(T& x); + + /** + * @brief Reads an NBT string from the stream + * + * An NBT string consists of two bytes indicating the length, + * followed by the characters encoded in modified UTF-8. + * @throw input_error on failure + */ + std::string read_string(); + + private: + std::istream& is; + int depth = 0; + const endian::endian endian; + }; + + template <class T> void stream_reader::read_num(T& x) + { + endian::read(is, x, endian); + } + + } // namespace io +} // namespace nbt + +#endif // STREAM_READER_H_INCLUDED diff --git a/libnbtplusplus/include/io/stream_writer.h b/libnbtplusplus/include/io/stream_writer.h new file mode 100644 index 0000000000..04f039948c --- /dev/null +++ b/libnbtplusplus/include/io/stream_writer.h @@ -0,0 +1,142 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef STREAM_WRITER_H_INCLUDED +#define STREAM_WRITER_H_INCLUDED + +#include "tag.h" +#include "endian_str.h" +#include <iosfwd> +#include <string> + +namespace nbt +{ + namespace io + { + + /* Not sure if that is even needed + ///Exception that gets thrown when writing is not successful + class output_error : public std::runtime_error + { + using std::runtime_error::runtime_error; + };*/ + + /** + * @brief Writes a named tag into the stream, including the tag type + * @param key the name of the tag + * @param t the tag + * @param os the stream to write to + * @param e the byte order of the written data. The Java edition + * of Minecraft uses Big Endian, the Pocket edition uses Little Endian + */ + NBT_EXPORT void write_tag(const std::string& key, const tag& t, + std::ostream& os, + endian::endian e = endian::big); + + /** + * @brief Helper class for writing NBT tags to output streams + * + * Can be reused to write multiple tags + */ + class NBT_EXPORT stream_writer + { + public: + /// Maximum length of an NBT string (16 bit unsigned) + static constexpr size_t max_string_len = UINT16_MAX; + /// Maximum length of an NBT list or array (32 bit signed) + static constexpr uint32_t max_array_len = INT32_MAX; + + /** + * @param os the stream to write to + * @param e the byte order of the written data. The Java edition + * of Minecraft uses Big Endian, the Pocket edition uses Little + * Endian + */ + explicit stream_writer(std::ostream& os, + endian::endian e = endian::big) noexcept + : os(os), endian(e) + { + } + + /// Returns the stream + std::ostream& get_ostr() const + { + return os; + } + /// Returns the byte order + endian::endian get_endian() const + { + return endian; + } + + /** + * @brief Writes a named tag into the stream, including the tag type + */ + void write_tag(const std::string& key, const tag& t); + + /** + * @brief Writes the given tag's payload into the stream + */ + void write_payload(const tag& t) + { + t.write_payload(*this); + } + + /** + * @brief Writes a tag type to the stream + */ + void write_type(tag_type tt) + { + write_num(static_cast<int8_t>(tt)); + } + + /** + * @brief Writes a binary number to the stream + */ + template <class T> void write_num(T x); + + /** + * @brief Writes an NBT string to the stream + * + * An NBT string consists of two bytes indicating the length, + * followed by the characters encoded in modified UTF-8. + * @throw std::length_error if the string is too long for NBT + */ + void write_string(const std::string& str); + + private: + std::ostream& os; + const endian::endian endian; + }; + + template <class T> void stream_writer::write_num(T x) + { + endian::write(os, x, endian); + } + + } // namespace io +} // namespace nbt + +#endif // STREAM_WRITER_H_INCLUDED diff --git a/libnbtplusplus/include/io/zlib_streambuf.h b/libnbtplusplus/include/io/zlib_streambuf.h new file mode 100644 index 0000000000..91a660b9f2 --- /dev/null +++ b/libnbtplusplus/include/io/zlib_streambuf.h @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +#ifndef ZLIB_STREAMBUF_H_INCLUDED +#define ZLIB_STREAMBUF_H_INCLUDED + +#include <stdexcept> +#include <streambuf> +#include <vector> +#include <zlib.h> +#include "nbt_export.h" + +namespace zlib +{ + + /// Exception thrown in case zlib encounters a problem + class NBT_EXPORT zlib_error : public std::runtime_error + { + public: + const int errcode; + + zlib_error(const char* msg, int errcode) + : std::runtime_error(msg ? std::string(zError(errcode)) + ": " + msg + : zError(errcode)), + errcode(errcode) + { + } + }; + + /// Base class for deflate_streambuf and inflate_streambuf + class zlib_streambuf : public std::streambuf + { + protected: + std::vector<char> in; + std::vector<char> out; + z_stream zstr; + + explicit zlib_streambuf(size_t bufsize) : in(bufsize), out(bufsize) + { + zstr.zalloc = Z_NULL; + zstr.zfree = Z_NULL; + zstr.opaque = Z_NULL; + } + }; + +} // namespace zlib + +#endif // ZLIB_STREAMBUF_H_INCLUDED diff --git a/libnbtplusplus/include/make_unique.h b/libnbtplusplus/include/make_unique.h new file mode 100644 index 0000000000..513cbcf69f --- /dev/null +++ b/libnbtplusplus/include/make_unique.h @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef MAKE_UNIQUE_H_INCLUDED +#define MAKE_UNIQUE_H_INCLUDED + +#include <memory> + +namespace nbt +{ + + /// Creates a new object of type T and returns a std::unique_ptr to it + template <class T, class... Args> + std::unique_ptr<T> make_unique(Args&&... args) + { + return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); + } + +} // namespace nbt + +#endif // MAKE_UNIQUE_H_INCLUDED diff --git a/libnbtplusplus/include/nbt_tags.h b/libnbtplusplus/include/nbt_tags.h new file mode 100644 index 0000000000..bcab332919 --- /dev/null +++ b/libnbtplusplus/include/nbt_tags.h @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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_primitive.h" +#include "tag_string.h" +#include "tag_array.h" +#include "tag_list.h" +#include "tag_compound.h" diff --git a/libnbtplusplus/include/nbt_visitor.h b/libnbtplusplus/include/nbt_visitor.h new file mode 100644 index 0000000000..e244162f83 --- /dev/null +++ b/libnbtplusplus/include/nbt_visitor.h @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef NBT_VISITOR_H_INCLUDED +#define NBT_VISITOR_H_INCLUDED + +#include "tagfwd.h" + +namespace nbt +{ + + /** + * @brief Base class for visitors of tags + * + * Implementing the Visitor pattern + */ + class nbt_visitor + { + public: + virtual ~nbt_visitor() noexcept = 0; // Abstract class + + virtual void visit(tag_byte&) {} + virtual void visit(tag_short&) {} + virtual void visit(tag_int&) {} + virtual void visit(tag_long&) {} + virtual void visit(tag_float&) {} + virtual void visit(tag_double&) {} + virtual void visit(tag_byte_array&) {} + virtual void visit(tag_string&) {} + virtual void visit(tag_list&) {} + virtual void visit(tag_compound&) {} + virtual void visit(tag_int_array&) {} + virtual void visit(tag_long_array&) {} + }; + + /** + * @brief Base class for visitors of constant tags + * + * Implementing the Visitor pattern + */ + class const_nbt_visitor + { + public: + virtual ~const_nbt_visitor() noexcept = 0; // Abstract class + + virtual void visit(const tag_byte&) {} + virtual void visit(const tag_short&) {} + virtual void visit(const tag_int&) {} + virtual void visit(const tag_long&) {} + virtual void visit(const tag_float&) {} + virtual void visit(const tag_double&) {} + virtual void visit(const tag_byte_array&) {} + virtual void visit(const tag_string&) {} + virtual void visit(const tag_list&) {} + virtual void visit(const tag_compound&) {} + virtual void visit(const tag_int_array&) {} + virtual void visit(const tag_long_array&) {} + }; + + inline nbt_visitor::~nbt_visitor() noexcept {} + + inline const_nbt_visitor::~const_nbt_visitor() noexcept {} + +} // namespace nbt + +#endif // NBT_VISITOR_H_INCLUDED diff --git a/libnbtplusplus/include/primitive_detail.h b/libnbtplusplus/include/primitive_detail.h new file mode 100644 index 0000000000..c55cd18398 --- /dev/null +++ b/libnbtplusplus/include/primitive_detail.h @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef PRIMITIVE_DETAIL_H_INCLUDED +#define PRIMITIVE_DETAIL_H_INCLUDED + +#include <type_traits> + +///@cond +namespace nbt +{ + + namespace detail + { + /// Meta-struct that holds the tag_type value for a specific primitive + /// type + template <class T> struct get_primitive_type { + static_assert(sizeof(T) != sizeof(T), + "Invalid type paramter for tag_primitive, can only " + "use types that NBT uses"); + }; + + template <> + struct get_primitive_type<int8_t> + : public std::integral_constant<tag_type, tag_type::Byte> { + }; + template <> + struct get_primitive_type<int16_t> + : public std::integral_constant<tag_type, tag_type::Short> { + }; + template <> + struct get_primitive_type<int32_t> + : public std::integral_constant<tag_type, tag_type::Int> { + }; + template <> + struct get_primitive_type<int64_t> + : public std::integral_constant<tag_type, tag_type::Long> { + }; + template <> + struct get_primitive_type<float> + : public std::integral_constant<tag_type, tag_type::Float> { + }; + template <> + struct get_primitive_type<double> + : public std::integral_constant<tag_type, tag_type::Double> { + }; + } // namespace detail + +} // namespace nbt +///@endcond + +#endif // PRIMITIVE_DETAIL_H_INCLUDED diff --git a/libnbtplusplus/include/tag.h b/libnbtplusplus/include/tag.h new file mode 100644 index 0000000000..92432cf55a --- /dev/null +++ b/libnbtplusplus/include/tag.h @@ -0,0 +1,175 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef TAG_H_INCLUDED +#define TAG_H_INCLUDED + +#include <cstdint> +#include <iosfwd> +#include <memory> +#include "nbt_export.h" + +namespace nbt +{ + + /// Tag type values used in the binary format + enum class tag_type : int8_t { + End = 0, + Byte = 1, + Short = 2, + Int = 3, + Long = 4, + Float = 5, + Double = 6, + Byte_Array = 7, + String = 8, + List = 9, + Compound = 10, + Int_Array = 11, + Long_Array = 12, + Null = -1 ///< Used to denote empty @ref value s + }; + + /** + * @brief Returns whether the given number falls within the range of valid + * tag types + * @param allow_end whether to consider tag_type::End (0) valid + */ + NBT_EXPORT bool is_valid_type(int type, bool allow_end = false); + + // Forward declarations + class nbt_visitor; + class const_nbt_visitor; + namespace io + { + class stream_reader; + class stream_writer; + } // namespace io + + /// Base class for all NBT tag classes + class NBT_EXPORT tag + { + public: + // Virtual destructor + virtual ~tag() noexcept {} + + /// Returns the type of the tag + virtual tag_type get_type() const noexcept = 0; + + // Polymorphic clone methods + virtual std::unique_ptr<tag> clone() const& = 0; + virtual std::unique_ptr<tag> move_clone() && = 0; + std::unique_ptr<tag> clone() &&; + + /** + * @brief Returns a reference to the tag as an instance of T + * @throw std::bad_cast if the tag is not of type T + */ + template <class T> T& as(); + template <class T> const T& as() const; + + /** + * @brief Move-assigns the given tag if the class is the same + * @throw std::bad_cast if @c rhs is not the same type as @c *this + */ + virtual tag& assign(tag&& rhs) = 0; + + /** + * @brief Calls the appropriate overload of @c visit() on the visitor + * with + * @c *this as argument + * + * Implementing the Visitor pattern + */ + virtual void accept(nbt_visitor& visitor) = 0; + virtual void accept(const_nbt_visitor& visitor) const = 0; + + /** + * @brief Reads the tag's payload from the stream + * @throw io::stream_reader::input_error on failure + */ + virtual void read_payload(io::stream_reader& reader) = 0; + + /** + * @brief Writes the tag's payload into the stream + */ + virtual void write_payload(io::stream_writer& writer) const = 0; + + /** + * @brief Default-constructs a new tag of the given type + * @throw std::invalid_argument if the type is not valid (e.g. End or + * Null) + */ + static std::unique_ptr<tag> create(tag_type type); + /** + * @brief Constructs a numeric tag of the given type and value + * @throw std::invalid_argument if the type is not numeric + */ + static std::unique_ptr<tag> create(tag_type type, int8_t val); + static std::unique_ptr<tag> create(tag_type type, int16_t val); + static std::unique_ptr<tag> create(tag_type type, int32_t val); + static std::unique_ptr<tag> create(tag_type type, int64_t val); + static std::unique_ptr<tag> create(tag_type type, float val); + static std::unique_ptr<tag> create(tag_type type, double val); + + friend NBT_EXPORT bool operator==(const tag& lhs, const tag& rhs); + friend NBT_EXPORT bool operator!=(const tag& lhs, const tag& rhs); + + private: + /** + * @brief Checks for equality to a tag of the same type + * @param rhs an instance of the same class as @c *this + */ + virtual bool equals(const tag& rhs) const = 0; + }; + + /// Output operator for tag types + NBT_EXPORT std::ostream& operator<<(std::ostream& os, tag_type tt); + + /** + * @brief Output operator for tags + * + * Uses @ref text::json_formatter + * @relates tag + */ + NBT_EXPORT std::ostream& operator<<(std::ostream& os, const tag& t); + + template <class T> T& tag::as() + { + static_assert(std::is_base_of<tag, T>::value, + "T must be a subclass of tag"); + return dynamic_cast<T&>(*this); + } + + template <class T> const T& tag::as() const + { + static_assert(std::is_base_of<tag, T>::value, + "T must be a subclass of tag"); + return dynamic_cast<const T&>(*this); + } + +} // namespace nbt + +#endif // TAG_H_INCLUDED diff --git a/libnbtplusplus/include/tag_array.h b/libnbtplusplus/include/tag_array.h new file mode 100644 index 0000000000..290680573f --- /dev/null +++ b/libnbtplusplus/include/tag_array.h @@ -0,0 +1,306 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef TAG_ARRAY_H_INCLUDED +#define TAG_ARRAY_H_INCLUDED + +#include "crtp_tag.h" +#include "io/stream_reader.h" +#include "io/stream_writer.h" +#include <type_traits> +#include <vector> +#include <istream> + +namespace nbt +{ + + ///@cond + namespace detail + { + /// Meta-struct that holds the tag_type value for a specific array type + template <class T> struct get_array_type { + static_assert(sizeof(T) != sizeof(T), + "Invalid type paramter for tag_array, can only use " + "byte or int"); + }; + + template <> + struct get_array_type<int8_t> + : public std::integral_constant<tag_type, tag_type::Byte_Array> { + }; + template <> + struct get_array_type<int32_t> + : public std::integral_constant<tag_type, tag_type::Int_Array> { + }; + template <> + struct get_array_type<int64_t> + : public std::integral_constant<tag_type, tag_type::Long_Array> { + }; + } // namespace detail + ///@cond + + /** + * @brief Tag that contains an array of byte or int values + * + * Common class for tag_byte_array, tag_int_array and tag_long_array. + */ + template <class T> + class tag_array final : public detail::crtp_tag<tag_array<T>> + { + public: + // Iterator types + typedef typename std::vector<T>::iterator iterator; + typedef typename std::vector<T>::const_iterator const_iterator; + + /// The type of the contained values + typedef T value_type; + + /// The type of the tag + static constexpr tag_type type = detail::get_array_type<T>::value; + + /// Constructs an empty array + tag_array() {} + + /// Constructs an array with the given values + tag_array(std::initializer_list<T> init) : data(init) {} + tag_array(std::vector<T>&& vec) noexcept : data(std::move(vec)) {} + + /// Returns a reference to the vector that contains the values + std::vector<T>& get() + { + return data; + } + const std::vector<T>& get() const + { + return data; + } + + /** + * @brief Accesses a value by index with bounds checking + * @throw std::out_of_range if the index is out of range + */ + T& at(size_t i) + { + return data.at(i); + } + T at(size_t i) const + { + return data.at(i); + } + + /** + * @brief Accesses a value by index + * + * No bounds checking is performed. + */ + T& operator[](size_t i) + { + return data[i]; + } + T operator[](size_t i) const + { + return data[i]; + } + + /// Appends a value at the end of the array + void push_back(T val) + { + data.push_back(val); + } + + /// Removes the last element from the array + void pop_back() + { + data.pop_back(); + } + + /// Returns the number of values in the array + size_t size() const + { + return data.size(); + } + + /// Erases all values from the array. + void clear() + { + data.clear(); + } + + // Iterators + iterator begin() + { + return data.begin(); + } + iterator end() + { + return data.end(); + } + const_iterator begin() const + { + return data.begin(); + } + const_iterator end() const + { + return data.end(); + } + const_iterator cbegin() const + { + return data.cbegin(); + } + const_iterator cend() const + { + return data.cend(); + } + + void read_payload(io::stream_reader& reader) override; + /** + * @inheritdoc + * @throw std::length_error if the array is too large for NBT + */ + void write_payload(io::stream_writer& writer) const override; + + private: + std::vector<T> data; + }; + + template <class T> + bool operator==(const tag_array<T>& lhs, const tag_array<T>& rhs) + { + return lhs.get() == rhs.get(); + } + template <class T> + bool operator!=(const tag_array<T>& lhs, const tag_array<T>& rhs) + { + return !(lhs == rhs); + } + + // Slightly different between byte_array and int_array + // Reading + template <> + inline 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 <typename T> + inline void tag_array<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 generic array tag"); + + data.clear(); + data.reserve(length); + for (T i = 0; i < length; ++i) { + T val; + reader.read_num(val); + data.push_back(val); + } + if (!reader.get_istr()) + throw io::input_error( + "Error reading contents of generic array tag"); + } + + template <> + inline void tag_array<int64_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_long_array"); + + data.clear(); + data.reserve(length); + for (int32_t i = 0; i < length; ++i) { + int64_t val; + reader.read_num(val); + data.push_back(val); + } + if (!reader.get_istr()) + throw io::input_error("Error reading contents of tag_long_array"); + } + + // Writing + template <> + inline 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 <typename T> + inline void tag_array<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("Generic array is too large for NBT"); + } + writer.write_num(static_cast<int32_t>(size())); + for (T i : data) + writer.write_num(i); + } + + template <> + inline void + tag_array<int64_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("Long array is too large for NBT"); + } + writer.write_num(static_cast<int32_t>(size())); + for (int64_t i : data) + writer.write_num(i); + } + + // Typedefs that should be used instead of the template tag_array. + typedef tag_array<int8_t> tag_byte_array; + typedef tag_array<int32_t> tag_int_array; + typedef tag_array<int64_t> tag_long_array; + +} // namespace nbt + +#endif // TAG_ARRAY_H_INCLUDED diff --git a/libnbtplusplus/include/tag_compound.h b/libnbtplusplus/include/tag_compound.h new file mode 100644 index 0000000000..3f342c6d2b --- /dev/null +++ b/libnbtplusplus/include/tag_compound.h @@ -0,0 +1,185 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef TAG_COMPOUND_H_INCLUDED +#define TAG_COMPOUND_H_INCLUDED + +#include "crtp_tag.h" +#include "value_initializer.h" +#include <map> +#include <string> + +namespace nbt +{ + + /// Tag that contains multiple unordered named tags of arbitrary types + class NBT_EXPORT tag_compound final : public detail::crtp_tag<tag_compound> + { + typedef std::map<std::string, value> map_t_; + + public: + // Iterator types + typedef map_t_::iterator iterator; + typedef map_t_::const_iterator const_iterator; + + /// The type of the tag + static constexpr tag_type type = tag_type::Compound; + + /// Constructs an empty compound + tag_compound() {} + + /// Constructs a compound with the given key-value pairs + tag_compound( + std::initializer_list<std::pair<std::string, value_initializer>> + init); + + /** + * @brief Accesses a tag by key with bounds checking + * + * Returns a value to the tag with the specified key, or throws an + * exception if it does not exist. + * @throw std::out_of_range if given key does not exist + */ + value& at(const std::string& key); + const value& at(const std::string& key) const; + + /** + * @brief Accesses a tag by key + * + * Returns a value to the tag with the specified key. If it does not + * exist, creates a new uninitialized entry under the key. + */ + value& operator[](const std::string& key) + { + return tags[key]; + } + + /** + * @brief Inserts or assigns a tag + * + * If the given key already exists, assigns the tag to it. + * Otherwise, it is inserted under the given key. + * @return a pair of the iterator to the value and a bool indicating + * whether the key did not exist + */ + std::pair<iterator, bool> put(const std::string& key, + value_initializer&& val); + + /** + * @brief Inserts a tag if the key does not exist + * @return a pair of the iterator to the value with the key and a bool + * indicating whether the value was actually inserted + */ + std::pair<iterator, bool> insert(const std::string& key, + value_initializer&& val); + + /** + * @brief Constructs and assigns or inserts a tag into the compound + * + * Constructs a new tag of type @c T with the given args and inserts + * or assigns it to the given key. + * @note Unlike std::map::emplace, this will overwrite existing values + * @return a pair of the iterator to the value and a bool indicating + * whether the key did not exist + */ + template <class T, class... Args> + std::pair<iterator, bool> emplace(const std::string& key, + Args&&... args); + + /** + * @brief Erases a tag from the compound + * @return true if a tag was erased + */ + bool erase(const std::string& key); + + /// Returns true if the given key exists in the compound + bool has_key(const std::string& key) const; + /// Returns true if the given key exists and the tag has the given type + bool has_key(const std::string& key, tag_type type) const; + + /// Returns the number of tags in the compound + size_t size() const + { + return tags.size(); + } + + /// Erases all tags from the compound + void clear() + { + tags.clear(); + } + + // Iterators + iterator begin() + { + return tags.begin(); + } + iterator end() + { + return tags.end(); + } + const_iterator begin() const + { + return tags.begin(); + } + const_iterator end() const + { + return tags.end(); + } + const_iterator cbegin() const + { + return tags.cbegin(); + } + const_iterator cend() const + { + return tags.cend(); + } + + void read_payload(io::stream_reader& reader) override; + void write_payload(io::stream_writer& writer) const override; + + friend bool operator==(const tag_compound& lhs, const tag_compound& rhs) + { + return lhs.tags == rhs.tags; + } + friend bool operator!=(const tag_compound& lhs, const tag_compound& rhs) + { + return !(lhs == rhs); + } + + private: + map_t_ tags; + }; + + template <class T, class... Args> + std::pair<tag_compound::iterator, bool> + tag_compound::emplace(const std::string& key, Args&&... args) + { + return put(key, value(make_unique<T>(std::forward<Args>(args)...))); + } + +} // namespace nbt + +#endif // TAG_COMPOUND_H_INCLUDED diff --git a/libnbtplusplus/include/tag_list.h b/libnbtplusplus/include/tag_list.h new file mode 100644 index 0000000000..eaa41bd65d --- /dev/null +++ b/libnbtplusplus/include/tag_list.h @@ -0,0 +1,269 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef TAG_LIST_H_INCLUDED +#define TAG_LIST_H_INCLUDED + +#include "crtp_tag.h" +#include "tagfwd.h" +#include "value_initializer.h" +#include <stdexcept> +#include <vector> + +namespace nbt +{ + + /** + * @brief Tag that contains multiple unnamed tags of the same type + * + * All the tags contained in the list have the same type, which can be + * queried with el_type(). The types of the values contained in the list + * should not be changed to mismatch the element type. + * + * If the list is empty, the type can be undetermined, in which case + * el_type() will return tag_type::Null. The type will then be set when the + * first tag is added to the list. + */ + class NBT_EXPORT tag_list final : public detail::crtp_tag<tag_list> + { + public: + // Iterator types + typedef std::vector<value>::iterator iterator; + typedef std::vector<value>::const_iterator const_iterator; + + /// The type of the tag + static constexpr tag_type type = tag_type::List; + + /** + * @brief Constructs a list of type T with the given values + * + * Example: @code tag_list::of<tag_byte>({3, 4, 5}) @endcode + * @param init list of values from which the elements are constructed + */ + template <class T> static tag_list of(std::initializer_list<T> init); + + /** + * @brief Constructs an empty list + * + * The content type is determined when the first tag is added. + */ + tag_list() : tag_list(tag_type::Null) {} + + /// Constructs an empty list with the given content type + explicit tag_list(tag_type content_type) : el_type_(content_type) {} + + /// Constructs a list with the given contents + tag_list(std::initializer_list<int8_t> init); + tag_list(std::initializer_list<int16_t> init); + tag_list(std::initializer_list<int32_t> init); + tag_list(std::initializer_list<int64_t> init); + tag_list(std::initializer_list<float> init); + tag_list(std::initializer_list<double> init); + tag_list(std::initializer_list<std::string> init); + tag_list(std::initializer_list<tag_byte_array> init); + tag_list(std::initializer_list<tag_list> init); + tag_list(std::initializer_list<tag_compound> init); + tag_list(std::initializer_list<tag_int_array> init); + tag_list(std::initializer_list<tag_long_array> init); + + /** + * @brief Constructs a list with the given contents + * @throw std::invalid_argument if the tags are not all of the same type + */ + tag_list(std::initializer_list<value> init); + + /** + * @brief Accesses a tag by index with bounds checking + * + * Returns a value to the tag at the specified index, or throws an + * exception if it is out of range. + * @throw std::out_of_range if the index is out of range + */ + value& at(size_t i); + const value& at(size_t i) const; + + /** + * @brief Accesses a tag by index + * + * Returns a value to the tag at the specified index. No bounds checking + * is performed. + */ + value& operator[](size_t i) + { + return tags[i]; + } + const value& operator[](size_t i) const + { + return tags[i]; + } + + /** + * @brief Assigns a value at the given index + * @throw std::invalid_argument if the type of the value does not match + * the list's content type + * @throw std::out_of_range if the index is out of range + */ + void set(size_t i, value&& val); + + /** + * @brief Appends the tag to the end of the list + * @throw std::invalid_argument if the type of the tag does not match + * the list's content type + */ + void push_back(value_initializer&& val); + + /** + * @brief Constructs and appends a tag to the end of the list + * @throw std::invalid_argument if the type of the tag does not match + * the list's content type + */ + template <class T, class... Args> void emplace_back(Args&&... args); + + /// Removes the last element of the list + void pop_back() + { + tags.pop_back(); + } + + /// Returns the content type of the list, or tag_type::Null if + /// undetermined + tag_type el_type() const + { + return el_type_; + } + + /// Returns the number of tags in the list + size_t size() const + { + return tags.size(); + } + + /// Erases all tags from the list. Preserves the content type. + void clear() + { + tags.clear(); + } + + /** + * @brief Erases all tags from the list and changes the content type. + * @param type the new content type. Can be tag_type::Null to leave it + * undetermined. + */ + void reset(tag_type type = tag_type::Null); + + // Iterators + iterator begin() + { + return tags.begin(); + } + iterator end() + { + return tags.end(); + } + const_iterator begin() const + { + return tags.begin(); + } + const_iterator end() const + { + return tags.end(); + } + const_iterator cbegin() const + { + return tags.cbegin(); + } + const_iterator cend() const + { + return tags.cend(); + } + + /** + * @inheritdoc + * In case of a list of tag_end, the content type will be undetermined. + */ + void read_payload(io::stream_reader& reader) override; + /** + * @inheritdoc + * In case of a list of undetermined content type, the written type will + * be tag_end. + * @throw std::length_error if the list is too long for NBT + */ + void write_payload(io::stream_writer& writer) const override; + + /** + * @brief Equality comparison for lists + * + * Lists are considered equal if their content types and the contained + * tags are equal. + */ + friend NBT_EXPORT bool operator==(const tag_list& lhs, + const tag_list& rhs); + friend NBT_EXPORT bool operator!=(const tag_list& lhs, + const tag_list& rhs); + + private: + std::vector<value> tags; + tag_type el_type_; + + /** + * Internally used initialization function that initializes the list + * with tags of type T, with the constructor arguments of each T given + * by il. + * @param il list of values that are, one by one, given to a constructor + * of T + */ + template <class T, class Arg> void init(std::initializer_list<Arg> il); + }; + + template <class T> tag_list tag_list::of(std::initializer_list<T> il) + { + tag_list result; + result.init<T, T>(il); + return result; + } + + template <class T, class... Args> + void tag_list::emplace_back(Args&&... args) + { + if (el_type_ == tag_type::Null) // set content type if undetermined + el_type_ = T::type; + else if (el_type_ != T::type) + throw std::invalid_argument( + "The tag type does not match the list's content type"); + tags.emplace_back(make_unique<T>(std::forward<Args>(args)...)); + } + + template <class T, class Arg> + void tag_list::init(std::initializer_list<Arg> init) + { + el_type_ = T::type; + tags.reserve(init.size()); + for (const Arg& arg : init) + tags.emplace_back(nbt::make_unique<T>(arg)); + } + +} // namespace nbt + +#endif // TAG_LIST_H_INCLUDED diff --git a/libnbtplusplus/include/tag_primitive.h b/libnbtplusplus/include/tag_primitive.h new file mode 100644 index 0000000000..e1b3fd28ea --- /dev/null +++ b/libnbtplusplus/include/tag_primitive.h @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef TAG_PRIMITIVE_H_INCLUDED +#define TAG_PRIMITIVE_H_INCLUDED + +#include "crtp_tag.h" +#include "primitive_detail.h" +#include "io/stream_reader.h" +#include "io/stream_writer.h" +#include <istream> +#include <sstream> + +namespace nbt +{ + + /** + * @brief Tag that contains an integral or floating-point value + * + * Common class for tag_byte, tag_short, tag_int, tag_long, tag_float and + * tag_double. + */ + template <class T> + class tag_primitive final : public detail::crtp_tag<tag_primitive<T>> + { + public: + /// The type of the value + typedef T value_type; + + /// The type of the tag + static constexpr tag_type type = detail::get_primitive_type<T>::value; + + // Constructor + constexpr tag_primitive(T val = 0) noexcept : value(val) {} + + // Getters + operator T&() + { + return value; + } + constexpr operator T() const + { + return value; + } + constexpr T get() const + { + return value; + } + + // Setters + tag_primitive& operator=(T val) + { + value = val; + return *this; + } + void set(T val) + { + value = val; + } + + void read_payload(io::stream_reader& reader) override; + void write_payload(io::stream_writer& writer) const override; + + private: + T value; + }; + + template <class T> + bool operator==(const tag_primitive<T>& lhs, const tag_primitive<T>& rhs) + { + return lhs.get() == rhs.get(); + } + template <class T> + bool operator!=(const tag_primitive<T>& lhs, const tag_primitive<T>& rhs) + { + return !(lhs == rhs); + } + + // Typedefs that should be used instead of the template tag_primitive. + typedef tag_primitive<int8_t> tag_byte; + typedef tag_primitive<int16_t> tag_short; + typedef tag_primitive<int32_t> tag_int; + typedef tag_primitive<int64_t> tag_long; + typedef tag_primitive<float> tag_float; + typedef tag_primitive<double> tag_double; + + // Explicit instantiation declarations + extern template class NBT_EXPORT tag_primitive<int8_t>; + extern template class NBT_EXPORT tag_primitive<int16_t>; + extern template class NBT_EXPORT tag_primitive<int32_t>; + extern template class NBT_EXPORT tag_primitive<int64_t>; + extern template class NBT_EXPORT tag_primitive<float>; + extern template class NBT_EXPORT tag_primitive<double>; + + template <class T> + void tag_primitive<T>::read_payload(io::stream_reader& reader) + { + reader.read_num(value); + if (!reader.get_istr()) { + std::ostringstream str; + str << "Error reading tag_" << type; + throw io::input_error(str.str()); + } + } + + template <class T> + void tag_primitive<T>::write_payload(io::stream_writer& writer) const + { + writer.write_num(value); + } + +} // namespace nbt + +#endif // TAG_PRIMITIVE_H_INCLUDED diff --git a/libnbtplusplus/include/tag_string.h b/libnbtplusplus/include/tag_string.h new file mode 100644 index 0000000000..ec08e3d7d5 --- /dev/null +++ b/libnbtplusplus/include/tag_string.h @@ -0,0 +1,109 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef TAG_STRING_H_INCLUDED +#define TAG_STRING_H_INCLUDED + +#include "crtp_tag.h" +#include <string> + +namespace nbt +{ + + /// Tag that contains a UTF-8 string + class NBT_EXPORT tag_string final : public detail::crtp_tag<tag_string> + { + public: + /// The type of the tag + static constexpr tag_type type = tag_type::String; + + // Constructors + tag_string() {} + tag_string(const std::string& str) : value(str) {} + tag_string(std::string&& str) noexcept : value(std::move(str)) {} + tag_string(const char* str) : value(str) {} + + // Getters + operator std::string&() + { + return value; + } + operator const std::string&() const + { + return value; + } + const std::string& get() const + { + return value; + } + + // Setters + tag_string& operator=(const std::string& str) + { + value = str; + return *this; + } + tag_string& operator=(std::string&& str) + { + value = std::move(str); + return *this; + } + tag_string& operator=(const char* str) + { + value = str; + return *this; + } + void set(const std::string& str) + { + value = str; + } + void set(std::string&& str) + { + value = std::move(str); + } + + void read_payload(io::stream_reader& reader) override; + /** + * @inheritdoc + * @throw std::length_error if the string is too long for NBT + */ + void write_payload(io::stream_writer& writer) const override; + + private: + std::string value; + }; + + inline bool operator==(const tag_string& lhs, const tag_string& rhs) + { + return lhs.get() == rhs.get(); + } + inline bool operator!=(const tag_string& lhs, const tag_string& rhs) + { + return !(lhs == rhs); + } + +} // namespace nbt + +#endif // TAG_STRING_H_INCLUDED diff --git a/libnbtplusplus/include/tagfwd.h b/libnbtplusplus/include/tagfwd.h new file mode 100644 index 0000000000..7459e7ba08 --- /dev/null +++ b/libnbtplusplus/include/tagfwd.h @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +/** @file + * @brief Provides forward declarations for all tag classes + */ +#ifndef TAGFWD_H_INCLUDED +#define TAGFWD_H_INCLUDED +#include <cstdint> + +namespace nbt +{ + + class tag; + + template <class T> class tag_primitive; + typedef tag_primitive<int8_t> tag_byte; + typedef tag_primitive<int16_t> tag_short; + typedef tag_primitive<int32_t> tag_int; + typedef tag_primitive<int64_t> tag_long; + typedef tag_primitive<float> tag_float; + typedef tag_primitive<double> tag_double; + + class tag_string; + + template <class T> class tag_array; + typedef tag_array<int8_t> tag_byte_array; + typedef tag_array<int32_t> tag_int_array; + typedef tag_array<int64_t> tag_long_array; + + class tag_list; + class tag_compound; + +} // namespace nbt + +#endif // TAGFWD_H_INCLUDED diff --git a/libnbtplusplus/include/text/json_formatter.h b/libnbtplusplus/include/text/json_formatter.h new file mode 100644 index 0000000000..923970f446 --- /dev/null +++ b/libnbtplusplus/include/text/json_formatter.h @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef JSON_FORMATTER_H_INCLUDED +#define JSON_FORMATTER_H_INCLUDED + +#include "tagfwd.h" +#include <ostream> +#include "nbt_export.h" + +namespace nbt +{ + namespace text + { + + /** + * @brief Prints tags in a JSON-like syntax into a stream + * + * @todo Make it configurable and able to produce actual + * standard-conformant JSON + */ + class NBT_EXPORT json_formatter + { + public: + json_formatter() {} + void print(std::ostream& os, const tag& t) const; + }; + + } // namespace text +} // namespace nbt + +#endif // JSON_FORMATTER_H_INCLUDED diff --git a/libnbtplusplus/include/value.h b/libnbtplusplus/include/value.h new file mode 100644 index 0000000000..08a23ab111 --- /dev/null +++ b/libnbtplusplus/include/value.h @@ -0,0 +1,255 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef TAG_REF_PROXY_H_INCLUDED +#define TAG_REF_PROXY_H_INCLUDED + +#include "tag.h" +#include <string> +#include <type_traits> + +namespace nbt +{ + + /** + * @brief Contains an NBT value of fixed type + * + * This class is a convenience wrapper for @c std::unique_ptr<tag>. + * A value can contain any kind of tag or no tag (nullptr) and provides + * operations for handling tags of which the type is not known at compile + * time. Assignment or the set method on a value with no tag will fill in + * the value. + * + * The rationale for the existance of this class is to provide a + * type-erasured means of storing tags, especially when they are contained + * in tag_compound or tag_list. The alternative would be directly using @c + * std::unique_ptr<tag> and @c tag&, which is how it was done in libnbt++1. + * The main drawback is that it becomes very cumbersome to deal with tags of + * unknown type. + * + * For example, in this case it would not be possible to allow a syntax like + * <tt>compound["foo"] = 42</tt>. If the key "foo" does not exist + * beforehand, the left hand side could not have any sensible value if it + * was of type + * @c tag&. + * Firstly, the compound tag would have to create a new tag_int there, but + * it cannot know that the new tag is going to be assigned an integer. Also, + * if the type was @c tag& and it allowed assignment of integers, that would + * mean the tag base class has assignments and conversions like this. Which + * means that all other tag classes would inherit them from the base class, + * even though it does not make any sense to allow converting a tag_compound + * into an integer. Attempts like this should be caught at compile time. + * + * This is why all the syntactic sugar for tags is contained in the value + * class while the tag class only contains common operations for all tag + * types. + */ + class NBT_EXPORT value + { + public: + // Constructors + value() noexcept {} + explicit value(std::unique_ptr<tag>&& t) noexcept : tag_(std::move(t)) + { + } + explicit value(tag&& t); + + // Moving + value(value&&) noexcept = default; + value& operator=(value&&) noexcept = default; + + // Copying + explicit value(const value& rhs); + value& operator=(const value& rhs); + + /** + * @brief Assigns the given value to the tag if the type matches + * @throw std::bad_cast if the type of @c t is not the same as the type + * of this value + */ + value& operator=(tag&& t); + void set(tag&& t); + + // Conversion to tag + /** + * @brief Returns the contained tag + * + * If the value is uninitialized, the behavior is undefined. + */ + operator tag&() + { + return get(); + } + operator const tag&() const + { + return get(); + } + tag& get() + { + return *tag_; + } + const tag& get() const + { + return *tag_; + } + + /** + * @brief Returns a reference to the contained tag as an instance of T + * @throw std::bad_cast if the tag is not of type T + */ + template <class T> T& as(); + template <class T> const T& as() const; + + // Assignment of primitives and string + /** + * @brief Assigns the given value to the tag if the type is compatible + * @throw std::bad_cast if the value is not convertible to the tag type + * via a widening conversion + */ + value& operator=(int8_t val); + value& operator=(int16_t val); + value& operator=(int32_t val); + value& operator=(int64_t val); + value& operator=(float val); + value& operator=(double val); + + /** + * @brief Assigns the given string to the tag if it is a tag_string + * @throw std::bad_cast if the contained tag is not a tag_string + */ + value& operator=(const std::string& str); + value& operator=(std::string&& str); + + // Conversions to primitives and string + /** + * @brief Returns the contained value if the type is compatible + * @throw std::bad_cast if the tag type is not convertible to the + * desired type via a widening conversion + */ + explicit operator int8_t() const; + explicit operator int16_t() const; + explicit operator int32_t() const; + explicit operator int64_t() const; + explicit operator float() const; + explicit operator double() const; + + /** + * @brief Returns the contained string if the type is tag_string + * + * If the value is uninitialized, the behavior is undefined. + * @throw std::bad_cast if the tag type is not tag_string + */ + explicit operator const std::string&() const; + + /// Returns true if the value is not uninitialized + explicit operator bool() const + { + return tag_ != nullptr; + } + + /** + * @brief In case of a tag_compound, accesses a tag by key with bounds + * checking + * + * If the value is uninitialized, the behavior is undefined. + * @throw std::bad_cast if the tag type is not tag_compound + * @throw std::out_of_range if given key does not exist + * @sa tag_compound::at + */ + value& at(const std::string& key); + const value& at(const std::string& key) const; + + /** + * @brief In case of a tag_compound, accesses a tag by key + * + * If the value is uninitialized, the behavior is undefined. + * @throw std::bad_cast if the tag type is not tag_compound + * @sa tag_compound::operator[] + */ + value& operator[](const std::string& key); + value& operator[](const char* key); // need this overload because of + // conflict with built-in operator[] + + /** + * @brief In case of a tag_list, accesses a tag by index with bounds + * checking + * + * If the value is uninitialized, the behavior is undefined. + * @throw std::bad_cast if the tag type is not tag_list + * @throw std::out_of_range if the index is out of range + * @sa tag_list::at + */ + value& at(size_t i); + const value& at(size_t i) const; + + /** + * @brief In case of a tag_list, accesses a tag by index + * + * No bounds checking is performed. If the value is uninitialized, the + * behavior is undefined. + * @throw std::bad_cast if the tag type is not tag_list + * @sa tag_list::operator[] + */ + value& operator[](size_t i); + const value& operator[](size_t i) const; + + /// Returns a reference to the underlying std::unique_ptr<tag> + std::unique_ptr<tag>& get_ptr() + { + return tag_; + } + const std::unique_ptr<tag>& get_ptr() const + { + return tag_; + } + /// Resets the underlying std::unique_ptr<tag> to a different value + void set_ptr(std::unique_ptr<tag>&& t) + { + tag_ = std::move(t); + } + + ///@sa tag::get_type + tag_type get_type() const; + + friend NBT_EXPORT bool operator==(const value& lhs, const value& rhs); + friend NBT_EXPORT bool operator!=(const value& lhs, const value& rhs); + + private: + std::unique_ptr<tag> tag_; + }; + + template <class T> T& value::as() + { + return tag_->as<T>(); + } + + template <class T> const T& value::as() const + { + return tag_->as<T>(); + } + +} // namespace nbt + +#endif // TAG_REF_PROXY_H_INCLUDED diff --git a/libnbtplusplus/include/value_initializer.h b/libnbtplusplus/include/value_initializer.h new file mode 100644 index 0000000000..ad83dc16ee --- /dev/null +++ b/libnbtplusplus/include/value_initializer.h @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2013, 2015 ljfa-ag <ljfa-ag@web.de> + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +/* + * 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/>. + */ +#ifndef VALUE_INITIALIZER_H_INCLUDED +#define VALUE_INITIALIZER_H_INCLUDED + +#include "value.h" + +namespace nbt +{ + + /** + * @brief Helper class for implicitly constructing value objects + * + * This type is a subclass of @ref value. However the only difference to + * value is that this class has additional constructors which allow implicit + * conversion of various types to value objects. These constructors are not + * part of the value class itself because implicit conversions like this + * (especially from @c tag&& to @c value) can cause problems and ambiguities + * in some cases. + * + * value_initializer is especially useful as function parameter type, it + * will allow convenient conversion of various values to tags on function + * call. + * + * As value_initializer objects are in no way different than value objects, + * they can just be converted to value after construction. + */ + class NBT_EXPORT value_initializer : public value + { + public: + value_initializer(std::unique_ptr<tag>&& t) noexcept + : value(std::move(t)) + { + } + value_initializer(std::nullptr_t) noexcept : value(nullptr) {} + value_initializer(value&& val) noexcept : value(std::move(val)) {} + value_initializer(tag&& t) : value(std::move(t)) {} + + value_initializer(int8_t val); + value_initializer(int16_t val); + value_initializer(int32_t val); + value_initializer(int64_t val); + value_initializer(float val); + value_initializer(double val); + value_initializer(const std::string& str); + value_initializer(std::string&& str); + value_initializer(const char* str); + }; + +} // namespace nbt + +#endif // VALUE_INITIALIZER_H_INCLUDED |
