diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 17:35:01 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 17:35:01 +0300 |
| commit | 1a0ffe372f4da8408c5d08a36013536a3396b9e6 (patch) | |
| tree | 440f2a9a325c9ab4cb5b16dc6a8193317cabf8d7 /src | |
| parent | f4d8ea0fa76174843adf7f77ebad0ad17d2377ed (diff) | |
| download | Project-Tick-1a0ffe372f4da8408c5d08a36013536a3396b9e6.tar.gz Project-Tick-1a0ffe372f4da8408c5d08a36013536a3396b9e6.zip | |
NOISSUE reformat libnbtplusplus to new MeshMC clang format rules
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'src')
| -rw-r--r-- | src/endian_str.cpp | 518 | ||||
| -rw-r--r-- | src/io/izlibstream.cpp | 123 | ||||
| -rw-r--r-- | src/io/ozlibstream.cpp | 155 | ||||
| -rw-r--r-- | src/io/stream_reader.cpp | 155 | ||||
| -rw-r--r-- | src/io/stream_writer.cpp | 53 | ||||
| -rw-r--r-- | src/tag.cpp | 300 | ||||
| -rw-r--r-- | src/tag_compound.cpp | 138 | ||||
| -rw-r--r-- | src/tag_list.cpp | 278 | ||||
| -rw-r--r-- | src/tag_string.cpp | 29 | ||||
| -rw-r--r-- | src/text/json_formatter.cpp | 426 | ||||
| -rw-r--r-- | src/value.cpp | 576 | ||||
| -rw-r--r-- | src/value_initializer.cpp | 29 |
12 files changed, 1443 insertions, 1337 deletions
diff --git a/src/endian_str.cpp b/src/endian_str.cpp index c6de84201d..e9553cd9d3 100644 --- a/src/endian_str.cpp +++ b/src/endian_str.cpp @@ -33,256 +33,268 @@ 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)); -} - -} + 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; + } + } // namespace + + //------------------------------------------------------------------------------ + + 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)); + } + +} // namespace endian diff --git a/src/io/izlibstream.cpp b/src/io/izlibstream.cpp index b361971081..9d57545360 100644 --- a/src/io/izlibstream.cpp +++ b/src/io/izlibstream.cpp @@ -27,76 +27,75 @@ namespace zlib { -inflate_streambuf::inflate_streambuf(std::istream& input, size_t bufsize, int window_bits): - zlib_streambuf(bufsize), is(input), stream_end(false) -{ - zstr.next_in = Z_NULL; - zstr.avail_in = 0; - int ret = inflateInit2(&zstr, window_bits); - if(ret != Z_OK) - throw zlib_error(zstr.msg, ret); + inflate_streambuf::inflate_streambuf(std::istream& input, size_t bufsize, + int window_bits) + : zlib_streambuf(bufsize), is(input), stream_end(false) + { + zstr.next_in = Z_NULL; + zstr.avail_in = 0; + int ret = inflateInit2(&zstr, window_bits); + if (ret != Z_OK) + throw zlib_error(zstr.msg, ret); - char* end = out.data() + out.size(); - setg(end, end, end); -} + char* end = out.data() + out.size(); + setg(end, end, end); + } -inflate_streambuf::~inflate_streambuf() noexcept -{ - inflateEnd(&zstr); -} + inflate_streambuf::~inflate_streambuf() noexcept + { + inflateEnd(&zstr); + } -inflate_streambuf::int_type inflate_streambuf::underflow() -{ - if(gptr() < egptr()) - return traits_type::to_int_type(*gptr()); + inflate_streambuf::int_type inflate_streambuf::underflow() + { + if (gptr() < egptr()) + return traits_type::to_int_type(*gptr()); - size_t have; - do - { - //Read if input buffer is empty - if(zstr.avail_in <= 0) - { - is.read(in.data(), in.size()); - if(is.bad()) - throw std::ios_base::failure("Input stream is bad"); - size_t count = is.gcount(); - if(count == 0 && !stream_end) - throw zlib_error("Unexpected end of stream", Z_DATA_ERROR); + size_t have; + do { + // Read if input buffer is empty + if (zstr.avail_in <= 0) { + is.read(in.data(), in.size()); + if (is.bad()) + throw std::ios_base::failure("Input stream is bad"); + size_t count = is.gcount(); + if (count == 0 && !stream_end) + throw zlib_error("Unexpected end of stream", Z_DATA_ERROR); - zstr.next_in = reinterpret_cast<Bytef*>(in.data()); - zstr.avail_in = count; - } + zstr.next_in = reinterpret_cast<Bytef*>(in.data()); + zstr.avail_in = count; + } - zstr.next_out = reinterpret_cast<Bytef*>(out.data()); - zstr.avail_out = out.size(); + zstr.next_out = reinterpret_cast<Bytef*>(out.data()); + zstr.avail_out = out.size(); - int ret = inflate(&zstr, Z_NO_FLUSH); - have = out.size() - zstr.avail_out; - switch(ret) - { - case Z_NEED_DICT: - case Z_DATA_ERROR: - throw zlib_error(zstr.msg, ret); + int ret = inflate(&zstr, Z_NO_FLUSH); + have = out.size() - zstr.avail_out; + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + throw zlib_error(zstr.msg, ret); - case Z_MEM_ERROR: - throw std::bad_alloc(); + case Z_MEM_ERROR: + throw std::bad_alloc(); - case Z_STREAM_END: - if(!stream_end) - { - stream_end = true; - //In case we consumed too much, we have to rewind the input stream - is.clear(); - is.seekg(-static_cast<std::streamoff>(zstr.avail_in), std::ios_base::cur); - } - if(have == 0) - return traits_type::eof(); - break; - } - } while(have == 0); + case Z_STREAM_END: + if (!stream_end) { + stream_end = true; + // In case we consumed too much, we have to rewind the + // input stream + is.clear(); + is.seekg(-static_cast<std::streamoff>(zstr.avail_in), + std::ios_base::cur); + } + if (have == 0) + return traits_type::eof(); + break; + } + } while (have == 0); - setg(out.data(), out.data(), out.data() + have); - return traits_type::to_int_type(*gptr()); -} + setg(out.data(), out.data(), out.data() + have); + return traits_type::to_int_type(*gptr()); + } -} +} // namespace zlib diff --git a/src/io/ozlibstream.cpp b/src/io/ozlibstream.cpp index eefe38a91c..c8a3e862a1 100644 --- a/src/io/ozlibstream.cpp +++ b/src/io/ozlibstream.cpp @@ -27,93 +27,88 @@ namespace zlib { -deflate_streambuf::deflate_streambuf(std::ostream& output, size_t bufsize, int level, int window_bits, int mem_level, int strategy): - zlib_streambuf(bufsize), os(output) -{ - int ret = deflateInit2(&zstr, level, Z_DEFLATED, window_bits, mem_level, strategy); - if(ret != Z_OK) - throw zlib_error(zstr.msg, ret); + deflate_streambuf::deflate_streambuf(std::ostream& output, size_t bufsize, + int level, int window_bits, + int mem_level, int strategy) + : zlib_streambuf(bufsize), os(output) + { + int ret = deflateInit2(&zstr, level, Z_DEFLATED, window_bits, mem_level, + strategy); + if (ret != Z_OK) + throw zlib_error(zstr.msg, ret); - setp(in.data(), in.data() + in.size()); -} + setp(in.data(), in.data() + in.size()); + } -deflate_streambuf::~deflate_streambuf() noexcept -{ - try - { - close(); - } - catch(...) - { - //ignore as we can't do anything about it - } - deflateEnd(&zstr); -} + deflate_streambuf::~deflate_streambuf() noexcept + { + try { + close(); + } catch (...) { + // ignore as we can't do anything about it + } + deflateEnd(&zstr); + } -void deflate_streambuf::close() -{ - deflate_chunk(Z_FINISH); -} + void deflate_streambuf::close() + { + deflate_chunk(Z_FINISH); + } -void deflate_streambuf::deflate_chunk(int flush) -{ - zstr.next_in = reinterpret_cast<Bytef*>(pbase()); - zstr.avail_in = pptr() - pbase(); - do - { - zstr.next_out = reinterpret_cast<Bytef*>(out.data()); - zstr.avail_out = out.size(); - int ret = deflate(&zstr, flush); - if(ret != Z_OK && ret != Z_STREAM_END) - { - os.setstate(std::ios_base::failbit); - throw zlib_error(zstr.msg, ret); - } - int have = out.size() - zstr.avail_out; - if(!os.write(out.data(), have)) - throw std::ios_base::failure("Could not write to the output stream"); - } while(zstr.avail_out == 0); - setp(in.data(), in.data() + in.size()); -} + void deflate_streambuf::deflate_chunk(int flush) + { + zstr.next_in = reinterpret_cast<Bytef*>(pbase()); + zstr.avail_in = pptr() - pbase(); + do { + zstr.next_out = reinterpret_cast<Bytef*>(out.data()); + zstr.avail_out = out.size(); + int ret = deflate(&zstr, flush); + if (ret != Z_OK && ret != Z_STREAM_END) { + os.setstate(std::ios_base::failbit); + throw zlib_error(zstr.msg, ret); + } + int have = out.size() - zstr.avail_out; + if (!os.write(out.data(), have)) + throw std::ios_base::failure( + "Could not write to the output stream"); + } while (zstr.avail_out == 0); + setp(in.data(), in.data() + in.size()); + } -deflate_streambuf::int_type deflate_streambuf::overflow(int_type ch) -{ - deflate_chunk(); - if(ch != traits_type::eof()) - { - *pptr() = ch; - pbump(1); - } - return ch; -} + deflate_streambuf::int_type deflate_streambuf::overflow(int_type ch) + { + deflate_chunk(); + if (ch != traits_type::eof()) { + *pptr() = ch; + pbump(1); + } + return ch; + } -int deflate_streambuf::sync() -{ - deflate_chunk(); - return 0; -} + int deflate_streambuf::sync() + { + deflate_chunk(); + return 0; + } -void ozlibstream::close() -{ - // Capture the exception mask so we can restore it if close() fails. - std::ios_base::iostate old_ex = exceptions(); - try - { - buf.close(); - return; - } - catch(...) - { - // fall through to mark the stream as bad - } + void ozlibstream::close() + { + // Capture the exception mask so we can restore it if close() fails. + std::ios_base::iostate old_ex = exceptions(); + try { + buf.close(); + return; + } catch (...) { + // fall through to mark the stream as bad + } - // Setting the stream state while exceptions are enabled may cause - // `setstate` to throw an `ios_base::failure` which would replace - // the original exception. Temporarily disable exceptions on this - // stream, set the `badbit`, then restore the exception mask. - exceptions(std::ios_base::goodbit); - setstate(std::ios_base::badbit); - exceptions(old_ex); -} + // Setting the stream state while exceptions are enabled may cause + // `setstate` to throw an `ios_base::failure` which would replace + // the original exception. Temporarily disable exceptions on this + // stream, set the `badbit`, then restore the exception mask. + exceptions(std::ios_base::goodbit); + setstate(std::ios_base::badbit); + exceptions(old_ex); + } } // namespace zlib diff --git a/src/io/stream_reader.cpp b/src/io/stream_reader.cpp index 06375ca0d5..43032b1120 100644 --- a/src/io/stream_reader.cpp +++ b/src/io/stream_reader.cpp @@ -28,92 +28,95 @@ namespace nbt { -namespace io -{ + namespace io + { -static constexpr int MAX_DEPTH = 1024; + static constexpr int MAX_DEPTH = 1024; -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_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(); -} + 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) -{} + stream_reader::stream_reader(std::istream& is, + endian::endian e) noexcept + : is(is), endian(e) + { + } -std::istream& stream_reader::get_istr() const -{ - return is; -} + std::istream& stream_reader::get_istr() const + { + return is; + } -endian::endian stream_reader::get_endian() const -{ - return endian; -} + 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_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::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) -{ - if (++depth > MAX_DEPTH) - throw input_error("Too deeply nested"); - std::unique_ptr<tag> t = tag::create(type); - t->read_payload(*this); - --depth; - return t; -} + std::unique_ptr<tag> stream_reader::read_payload(tag_type type) + { + if (++depth > MAX_DEPTH) + throw input_error("Too deeply nested"); + std::unique_ptr<tag> t = tag::create(type); + t->read_payload(*this); + --depth; + 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); -} + 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 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; -} + 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; + } -} -} + } // namespace io +} // namespace nbt diff --git a/src/io/stream_writer.cpp b/src/io/stream_writer.cpp index 0294a6d4e9..5275c5a1b4 100644 --- a/src/io/stream_writer.cpp +++ b/src/io/stream_writer.cpp @@ -26,33 +26,34 @@ namespace nbt { -namespace io -{ + 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 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_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()); -} + 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()); + } -} -} + } // namespace io +} // namespace nbt diff --git a/src/tag.cpp b/src/tag.cpp index 0446dfd3f8..8e57548f2d 100644 --- a/src/tag.cpp +++ b/src/tag.cpp @@ -32,136 +32,170 @@ namespace nbt { -//Explicit instantiation definitions for tag_primitive -template class tag_primitive<int8_t>; -template class tag_primitive<int16_t>; -template class tag_primitive<int32_t>; -template class tag_primitive<int64_t>; -template class tag_primitive<float>; -template class tag_primitive<double>; - -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 <= 12; -} - -std::unique_ptr<tag> tag::clone() && -{ - return std::move(*this).move_clone(); -} - -namespace -{ - template<typename T> - std::unique_ptr<tag> create_numeric_tag(tag_type type, T val) - { - switch(type) - { - case tag_type::Byte: return make_unique<tag_byte>(static_cast<int8_t>(val)); - case tag_type::Short: return make_unique<tag_short>(static_cast<int16_t>(val)); - case tag_type::Int: return make_unique<tag_int>(static_cast<int32_t>(val)); - case tag_type::Long: return make_unique<tag_long>(static_cast<int64_t>(val)); - case tag_type::Float: return make_unique<tag_float>(static_cast<float>(val)); - case tag_type::Double: return make_unique<tag_double>(static_cast<double>(val)); - default: throw std::invalid_argument("Invalid numeric tag type"); - } - } -} - -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>(); - case tag_type::Long_Array: return make_unique<tag_long_array>(); - - default: throw std::invalid_argument("Invalid tag type"); - } -} - -std::unique_ptr<tag> tag::create(tag_type type, int8_t val) -{ - return create_numeric_tag(type, val); -} - -std::unique_ptr<tag> tag::create(tag_type type, int16_t val) -{ - return create_numeric_tag(type, val); -} - -std::unique_ptr<tag> tag::create(tag_type type, int32_t val) -{ - return create_numeric_tag(type, val); -} - -std::unique_ptr<tag> tag::create(tag_type type, int64_t val) -{ - return create_numeric_tag(type, val); -} - -std::unique_ptr<tag> tag::create(tag_type type, float val) -{ - return create_numeric_tag(type, val); -} - -std::unique_ptr<tag> tag::create(tag_type type, double val) -{ - return create_numeric_tag(type, val); -} - -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::Long_Array: return os << "long_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; -} - -} + // Explicit instantiation definitions for tag_primitive + template class tag_primitive<int8_t>; + template class tag_primitive<int16_t>; + template class tag_primitive<int32_t>; + template class tag_primitive<int64_t>; + template class tag_primitive<float>; + template class tag_primitive<double>; + + 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 <= 12; + } + + std::unique_ptr<tag> tag::clone() && + { + return std::move(*this).move_clone(); + } + + namespace + { + template <typename T> + std::unique_ptr<tag> create_numeric_tag(tag_type type, T val) + { + switch (type) { + case tag_type::Byte: + return make_unique<tag_byte>(static_cast<int8_t>(val)); + case tag_type::Short: + return make_unique<tag_short>(static_cast<int16_t>(val)); + case tag_type::Int: + return make_unique<tag_int>(static_cast<int32_t>(val)); + case tag_type::Long: + return make_unique<tag_long>(static_cast<int64_t>(val)); + case tag_type::Float: + return make_unique<tag_float>(static_cast<float>(val)); + case tag_type::Double: + return make_unique<tag_double>(static_cast<double>(val)); + default: + throw std::invalid_argument("Invalid numeric tag type"); + } + } + } // namespace + + 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>(); + case tag_type::Long_Array: + return make_unique<tag_long_array>(); + + default: + throw std::invalid_argument("Invalid tag type"); + } + } + + std::unique_ptr<tag> tag::create(tag_type type, int8_t val) + { + return create_numeric_tag(type, val); + } + + std::unique_ptr<tag> tag::create(tag_type type, int16_t val) + { + return create_numeric_tag(type, val); + } + + std::unique_ptr<tag> tag::create(tag_type type, int32_t val) + { + return create_numeric_tag(type, val); + } + + std::unique_ptr<tag> tag::create(tag_type type, int64_t val) + { + return create_numeric_tag(type, val); + } + + std::unique_ptr<tag> tag::create(tag_type type, float val) + { + return create_numeric_tag(type, val); + } + + std::unique_ptr<tag> tag::create(tag_type type, double val) + { + return create_numeric_tag(type, val); + } + + 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::Long_Array: + return os << "long_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; + } + +} // namespace nbt diff --git a/src/tag_compound.cpp b/src/tag_compound.cpp index c71166de95..c35ef5d53f 100644 --- a/src/tag_compound.cpp +++ b/src/tag_compound.cpp @@ -30,84 +30,80 @@ 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)); -} + 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); -} + 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); -} + 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::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)); -} + 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::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) 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; -} + 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::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); -} + 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); + } -} +} // namespace nbt diff --git a/src/tag_list.cpp b/src/tag_list.cpp index f72f86bb24..413af779ae 100644 --- a/src/tag_list.cpp +++ b/src/tag_list.cpp @@ -30,126 +30,158 @@ 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<tag_long_array> il) { init<tag_long_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); -} - -} + 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<tag_long_array> il) + { + init<tag_long_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); + } + +} // namespace nbt diff --git a/src/tag_string.cpp b/src/tag_string.cpp index e630b1dfc4..481ad19dee 100644 --- a/src/tag_string.cpp +++ b/src/tag_string.cpp @@ -28,21 +28,18 @@ 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::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); -} + void tag_string::write_payload(io::stream_writer& writer) const + { + writer.write_string(value); + } -} +} // namespace nbt diff --git a/src/text/json_formatter.cpp b/src/text/json_formatter.cpp index 88f3a7c58e..46d726a3c9 100644 --- a/src/text/json_formatter.cpp +++ b/src/text/json_formatter.cpp @@ -30,209 +30,227 @@ namespace nbt { -namespace text -{ + 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): - 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 << '"'; - write_escaped_string(s.get()); - os << '"'; - } - - 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 << "]"; - } - - void visit(const tag_long_array& la) override - { - os << "["; - for(unsigned int i = 0; i < la.size(); ++i) - { - os << la[i]; - if(i != la.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 write_escaped_string(const std::string& str) - { - for (char c : str) { - switch (c) { - case '"': os << "\\\""; break; - case '\\': os << "\\\\"; break; - case '\b': os << "\\b"; break; - case '\f': os << "\\f"; break; - case '\n': os << "\\n"; break; - case '\r': os << "\\r"; break; - case '\t': os << "\\t"; break; - default: - if (c < 32 || c == 127) { - // Control characters, escape as \u00XX - os << "\\u00" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(c); - } else { - os << c; - } - break; - } - } - } - }; -} - -void json_formatter::print(std::ostream& os, const tag& t) const -{ - json_fmt_visitor v(os); - t.accept(v); -} + 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) : 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 << '"'; + write_escaped_string(s.get()); + os << '"'; + } + + 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 << "]"; + } + + void visit(const tag_long_array& la) override + { + os << "["; + for (unsigned int i = 0; i < la.size(); ++i) { + os << la[i]; + if (i != la.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 write_escaped_string(const std::string& str) + { + for (char c : str) { + switch (c) { + case '"': + os << "\\\""; + break; + case '\\': + os << "\\\\"; + break; + case '\b': + os << "\\b"; + break; + case '\f': + os << "\\f"; + break; + case '\n': + os << "\\n"; + break; + case '\r': + os << "\\r"; + break; + case '\t': + os << "\\t"; + break; + default: + if (c < 32 || c == 127) { + // Control characters, escape as \u00XX + os << "\\u00" << std::hex << std::setw(2) + << std::setfill('0') + << static_cast<int>(c); + } else { + os << c; + } + break; + } + } + } + }; + } // namespace + + void json_formatter::print(std::ostream& os, const tag& t) const + { + json_fmt_visitor v(os); + t.accept(v); + } -} -} + } // namespace text +} // namespace nbt diff --git a/src/value.cpp b/src/value.cpp index bf0ffcad78..3a9ccb71bc 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -32,286 +32,296 @@ 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 -namespace // helper functions local to this translation unit -{ - template<typename T> - void assign_numeric_impl(std::unique_ptr<tag>& tag_ptr, T val, - tag_type default_type) - { - using nbt::tag_type; - if(!tag_ptr) - { - tag_ptr = tag::create(default_type, val); - return; - } - - // Determine the incoming tag type for T - auto incoming_type = detail::get_primitive_type<T>::value; - - // If the existing tag is of a narrower type than the incoming type, - // reject the assignment to avoid widening the stored tag type. - auto existing_type = tag_ptr->get_type(); - - if(static_cast<int>(existing_type) < static_cast<int>(incoming_type)) - { - throw std::bad_cast(); - } - - // Existing type is same or wider: write into the existing tag (may narrow) - switch(existing_type) - { - case tag_type::Byte: static_cast<tag_byte&>(*tag_ptr).set(static_cast<int8_t>(val)); break; - case tag_type::Short: static_cast<tag_short&>(*tag_ptr).set(static_cast<int16_t>(val)); break; - case tag_type::Int: static_cast<tag_int&>(*tag_ptr).set(static_cast<int32_t>(val)); break; - case tag_type::Long: static_cast<tag_long&>(*tag_ptr).set(static_cast<int64_t>(val)); break; - case tag_type::Float: static_cast<tag_float&>(*tag_ptr).set(static_cast<float>(val)); break; - case tag_type::Double: static_cast<tag_double&>(*tag_ptr).set(static_cast<double>(val)); break; - default: throw std::bad_cast(); - } - } -} - -value& value::operator=(int8_t val) -{ - assign_numeric_impl(tag_, val, tag_type::Byte); - return *this; -} - -value& value::operator=(int16_t val) -{ - assign_numeric_impl(tag_, val, tag_type::Short); - return *this; -} - -value& value::operator=(int32_t val) -{ - assign_numeric_impl(tag_, val, tag_type::Int); - return *this; -} - -value& value::operator=(int64_t val) -{ - assign_numeric_impl(tag_, val, tag_type::Long); - return *this; -} - -value& value::operator=(float val) -{ - assign_numeric_impl(tag_, val, tag_type::Float); - return *this; -} - -value& value::operator=(double val) -{ - assign_numeric_impl(tag_, val, tag_type::Double); - 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); -} - -} + 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 + namespace // helper functions local to this translation unit + { + template <typename T> + void assign_numeric_impl(std::unique_ptr<tag>& tag_ptr, T val, + tag_type default_type) + { + using nbt::tag_type; + if (!tag_ptr) { + tag_ptr = tag::create(default_type, val); + return; + } + + // Determine the incoming tag type for T + auto incoming_type = detail::get_primitive_type<T>::value; + + // If the existing tag is of a narrower type than the incoming type, + // reject the assignment to avoid widening the stored tag type. + auto existing_type = tag_ptr->get_type(); + + if (static_cast<int>(existing_type) < + static_cast<int>(incoming_type)) { + throw std::bad_cast(); + } + + // Existing type is same or wider: write into the existing tag (may + // narrow) + switch (existing_type) { + case tag_type::Byte: + static_cast<tag_byte&>(*tag_ptr).set( + static_cast<int8_t>(val)); + break; + case tag_type::Short: + static_cast<tag_short&>(*tag_ptr).set( + static_cast<int16_t>(val)); + break; + case tag_type::Int: + static_cast<tag_int&>(*tag_ptr).set( + static_cast<int32_t>(val)); + break; + case tag_type::Long: + static_cast<tag_long&>(*tag_ptr).set( + static_cast<int64_t>(val)); + break; + case tag_type::Float: + static_cast<tag_float&>(*tag_ptr).set( + static_cast<float>(val)); + break; + case tag_type::Double: + static_cast<tag_double&>(*tag_ptr).set( + static_cast<double>(val)); + break; + default: + throw std::bad_cast(); + } + } + } // namespace + + value& value::operator=(int8_t val) + { + assign_numeric_impl(tag_, val, tag_type::Byte); + return *this; + } + + value& value::operator=(int16_t val) + { + assign_numeric_impl(tag_, val, tag_type::Short); + return *this; + } + + value& value::operator=(int32_t val) + { + assign_numeric_impl(tag_, val, tag_type::Int); + return *this; + } + + value& value::operator=(int64_t val) + { + assign_numeric_impl(tag_, val, tag_type::Long); + return *this; + } + + value& value::operator=(float val) + { + assign_numeric_impl(tag_, val, tag_type::Float); + return *this; + } + + value& value::operator=(double val) + { + assign_numeric_impl(tag_, val, tag_type::Double); + 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); + } + +} // namespace nbt diff --git a/src/value_initializer.cpp b/src/value_initializer.cpp index b0d0d3d747..ec52f544fe 100644 --- a/src/value_initializer.cpp +++ b/src/value_initializer.cpp @@ -27,14 +27,23 @@ 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)) {} + 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)) + { + } -} +} // namespace nbt |
