diff --git a/src/amulet_nbt/__init__.pyi b/src/amulet_nbt/__init__.pyi index 7d82ebc2..24194061 100644 --- a/src/amulet_nbt/__init__.pyi +++ b/src/amulet_nbt/__init__.pyi @@ -122,7 +122,7 @@ class AbstractBaseTag: compressed: bool = True, little_endian: bool = False, string_encoding: StringEncoding = mutf8_encoding, - name: str | bytes = b"", + name: str | bytes | None = b"", ) -> bytes: """Get the data in binary NBT format. @@ -130,7 +130,7 @@ class AbstractBaseTag: :param compressed: Should the bytes be compressed with gzip. :param little_endian: Should the bytes be saved in little endian format. Ignored if preset is defined. :param string_encoding: The StringEncoding to use. Ignored if preset is defined. - :param name: The root tag name. + :param name: The root tag name, or `None` for unnamed tag. :return: The binary NBT representation of the class. """ @@ -142,7 +142,7 @@ class AbstractBaseTag: compressed: bool = True, little_endian: bool = False, string_encoding: StringEncoding = mutf8_encoding, - name: str | bytes = b"", + name: str | bytes | None = b"", ) -> bytes: """Convert the data to the binary NBT format. Optionally write to a file. @@ -155,7 +155,7 @@ class AbstractBaseTag: :param compressed: Should the bytes be compressed with gzip. :param little_endian: Should the bytes be saved in little endian format. Ignored if preset is defined. :param string_encoding: The StringEncoding to use. Ignored if preset is defined. - :param name: The root tag name. + :param name: The root tag name, or `None` for unnamed tag. :return: The binary NBT representation of the class. """ @@ -1592,12 +1592,14 @@ def read_nbt( filepath_or_buffer: str | bytes | memoryview | _Readable | None, *, preset: EncodingPreset | None = None, + named: bool = True, read_offset: ReadOffset | None = None, ) -> NamedTag: """Load one binary NBT object. :param filepath_or_buffer: A string path to a file on disk, a bytes or memory view object containing the binary NBT or a file-like object to read the binary data from. :param preset: The encoding preset. If this is defined little_endian and string_encoding have no effect. + :param named: If the tag to read is named, if not, return NamedTag with empty name. :param read_offset: Optional ReadOffset object to get read end offset. :raises: IndexError if the data is not long enough. """ @@ -1609,6 +1611,7 @@ def read_nbt( compressed: bool = True, little_endian: bool = False, string_encoding: StringEncoding = mutf8_encoding, + named: bool = True, read_offset: ReadOffset | None = None, ) -> NamedTag: """Load one binary NBT object. @@ -1617,6 +1620,7 @@ def read_nbt( :param compressed: Is the binary data gzip compressed. :param little_endian: Are the numerical values stored as little endian. True for Bedrock, False for Java. :param string_encoding: The bytes decoder function to parse strings. mutf8_encoding for Java, utf8_escape_encoding for Bedrock. + :param named: If the tag to read is named, if not, return NamedTag with empty name. :param read_offset: Optional ReadOffset object to get read end offset. :raises: IndexError if the data is not long enough. """ @@ -1627,6 +1631,7 @@ def read_nbt_array( *, count: int = 1, preset: EncodingPreset | None = None, + named: bool = True, read_offset: ReadOffset | None = None, ) -> list[NamedTag]: """Load an array of binary NBT objects from a contiguous buffer. @@ -1634,6 +1639,7 @@ def read_nbt_array( :param filepath_or_buffer: A string path to a file on disk, a bytes or memory view object containing the binary NBT or a file-like object to read the binary data from. :param count: The number of binary NBT objects to read. Use -1 to exhaust the buffer. :param preset: The encoding preset. If this is defined little_endian and string_encoding have no effect. + :param named: If the tags to read are named, if not, return NamedTags with empty name. :param read_offset: Optional ReadOffset object to get read end offset. :raises: IndexError if the data is not long enough. """ @@ -1646,6 +1652,7 @@ def read_nbt_array( compressed: bool = True, little_endian: bool = False, string_encoding: StringEncoding = mutf8_encoding, + named: bool = True, read_offset: ReadOffset | None = None, ) -> list[NamedTag]: """Load an array of binary NBT objects from a contiguous buffer. @@ -1655,6 +1662,7 @@ def read_nbt_array( :param compressed: Is the binary data gzip compressed. This only supports the whole buffer compressed as one. :param little_endian: Are the numerical values stored as little endian. True for Bedrock, False for Java. :param string_encoding: The bytes decoder function to parse strings. mutf8.decode_modified_utf8 for Java, amulet_nbt.utf8_escape_decoder for Bedrock. + :param named: If the tags to read are named, if not, return NamedTags with empty name. :param read_offset: Optional ReadOffset object to get read end offset. :raises: IndexError if the data is not long enough. """ diff --git a/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp b/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp index 6557b444..0db0f0e8 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp @@ -163,41 +163,46 @@ inline AmuletNBT::TagNode read_node(AmuletNBT::BinaryReader& reader, std::uint8_ namespace AmuletNBT { - AmuletNBT::NamedTag read_nbt(AmuletNBT::BinaryReader& reader){ + AmuletNBT::NamedTag read_nbt(AmuletNBT::BinaryReader& reader, bool named){ std::uint8_t tag_id = reader.readNumeric(); - std::string name = read_string_tag(reader); + std::string name = named ? read_string_tag(reader) : ""; AmuletNBT::TagNode node = read_node(reader, tag_id); return AmuletNBT::NamedTag(name, node); } - // Read one named tag from the string at position offset. - AmuletNBT::NamedTag read_nbt(const std::string& raw, std::endian endianness, AmuletNBT::StringDecode string_decode, size_t& offset){ + // Read one (un)named tag from the string at position offset. + AmuletNBT::NamedTag read_nbt(const std::string& raw, std::endian endianness, AmuletNBT::StringDecode string_decode, bool named, size_t& offset){ AmuletNBT::BinaryReader reader(raw, offset, endianness, string_decode); - return read_nbt(reader); + return read_nbt(reader, named); + } + + // Read one (un)named tag from the string. + AmuletNBT::NamedTag read_nbt(const std::string& raw, std::endian endianness, AmuletNBT::StringDecode string_decode, bool named){ + size_t offset = 0; + return read_nbt(raw, endianness, string_decode, named, offset); } // Read one named tag from the string. AmuletNBT::NamedTag read_nbt(const std::string& raw, std::endian endianness, AmuletNBT::StringDecode string_decode){ - size_t offset = 0; - return read_nbt(raw, endianness, string_decode, offset); + return read_nbt(raw, endianness, string_decode, true); } - // Read count named tags from the string at position offset. - std::vector read_nbt_array(const std::string& raw, std::endian endianness, AmuletNBT::StringDecode string_decode, size_t& offset, size_t count){ + // Read count (un)named tags from the string at position offset. + std::vector read_nbt_array(const std::string& raw, std::endian endianness, AmuletNBT::StringDecode string_decode, bool named, size_t& offset, size_t count){ AmuletNBT::BinaryReader reader(raw, offset, endianness, string_decode); std::vector out; for (size_t i = 0; i < count; i++){ - out.push_back(read_nbt(reader)); + out.push_back(read_nbt(reader, named)); } return out; } - // Read all named tags from the string at position offset. - std::vector read_nbt_array(const std::string& raw, std::endian endianness, AmuletNBT::StringDecode string_decode, size_t& offset){ + // Read all (un)named tags from the string at position offset. + std::vector read_nbt_array(const std::string& raw, std::endian endianness, AmuletNBT::StringDecode string_decode, bool named, size_t& offset){ AmuletNBT::BinaryReader reader(raw, offset, endianness, string_decode); std::vector out; while (reader.has_more_data()){ - out.push_back(read_nbt(reader)); + out.push_back(read_nbt(reader, named)); } return out; } diff --git a/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp b/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp index 62451bda..292d4325 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -167,9 +168,9 @@ template < bool > = true > -inline void write_name_and_tag(AmuletNBT::BinaryWriter& writer, const std::string& name, const T& tag){ +inline void write_name_and_tag(AmuletNBT::BinaryWriter& writer, const std::optional& name, const T& tag){ writer.writeNumeric(AmuletNBT::tag_id_v); - write_string(writer, name); + if (name) write_string(writer, *name); write_payload(writer, tag); } @@ -184,7 +185,7 @@ template < bool > = true > -inline void write_name_and_tag(AmuletNBT::BinaryWriter & writer, const std::string & name, const T tag) { +inline void write_name_and_tag(AmuletNBT::BinaryWriter & writer, const std::optional& name, const T tag) { write_name_and_tag(writer, name, *tag); } @@ -193,7 +194,7 @@ template < typename T, std::enable_if_t, bool> = true > -inline void write_name_and_tag(AmuletNBT::BinaryWriter& writer, const std::string& name, const AmuletNBT::TagNode& node){ +inline void write_name_and_tag(AmuletNBT::BinaryWriter& writer, const std::optional& name, const AmuletNBT::TagNode& node){ std::visit([&writer, &name](auto&& tag) { using tagT = std::decay_t; write_name_and_tag(writer, name, tag); @@ -211,47 +212,47 @@ inline void write_payload(AmuletNBT::BinaryWriter& write template -inline std::string _write_nbt(const std::string& name, const T& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ +inline std::string _write_nbt(const std::optional& name, const T& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ AmuletNBT::BinaryWriter writer(endianness, string_encode); write_name_and_tag(writer, name, tag); return writer.getBuffer(); } namespace AmuletNBT { - void write_nbt(BinaryWriter& writer, const std::string& name, const ByteTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const ByteTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const ShortTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const ShortTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const IntTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const IntTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const LongTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const LongTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const FloatTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const FloatTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const DoubleTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const DoubleTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const ByteArrayTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const ByteArrayTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const StringTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const StringTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const ListTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const ListTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const CompoundTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const CompoundTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const IntArrayTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const IntArrayTag& tag) { write_name_and_tag(writer, name, tag); } - void write_nbt(BinaryWriter& writer, const std::string& name, const LongArrayTag& tag) { + void write_nbt(BinaryWriter& writer, const std::optional& name, const LongArrayTag& tag) { write_name_and_tag(writer, name, tag); } void write_nbt(BinaryWriter& writer, const std::string& name, const TagNode& tag) { @@ -261,40 +262,40 @@ namespace AmuletNBT { write_name_and_tag(writer, tag.name, tag.tag_node); } - std::string write_nbt(const std::string& name, const AmuletNBT::ByteTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::ByteTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::ShortTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::ShortTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::IntTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::IntTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::LongTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::LongTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::FloatTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::FloatTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::DoubleTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::DoubleTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::ByteArrayTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::ByteArrayTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::StringTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::StringTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::ListTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::ListTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::CompoundTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::CompoundTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::IntArrayTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::IntArrayTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::LongArrayTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::optional& name, const AmuletNBT::LongArrayTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; std::string write_nbt(const std::string& name, const AmuletNBT::TagNode& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ diff --git a/src/amulet_nbt/include/amulet_nbt/nbt_encoding/binary.hpp b/src/amulet_nbt/include/amulet_nbt/nbt_encoding/binary.hpp index d804adbe..90ae2498 100644 --- a/src/amulet_nbt/include/amulet_nbt/nbt_encoding/binary.hpp +++ b/src/amulet_nbt/include/amulet_nbt/nbt_encoding/binary.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -16,39 +17,40 @@ #include namespace AmuletNBT { - NamedTag read_nbt(BinaryReader& reader); - NamedTag read_nbt(const std::string&, std::endian, StringDecode, size_t& offset); + NamedTag read_nbt(BinaryReader& reader, bool named); + NamedTag read_nbt(const std::string&, std::endian, StringDecode, bool named, size_t& offset); + NamedTag read_nbt(const std::string&, std::endian, StringDecode, bool named); NamedTag read_nbt(const std::string&, std::endian, StringDecode); - std::vector read_nbt_array(const std::string&, std::endian, StringDecode, size_t& offset); - std::vector read_nbt_array(const std::string&, std::endian, StringDecode, size_t& offset, size_t count); + std::vector read_nbt_array(const std::string&, std::endian, StringDecode, bool named, size_t& offset); + std::vector read_nbt_array(const std::string&, std::endian, StringDecode, bool named, size_t& offset, size_t count); - void write_nbt(BinaryWriter&, const std::string& name, const ByteTag&); - void write_nbt(BinaryWriter&, const std::string& name, const ShortTag&); - void write_nbt(BinaryWriter&, const std::string& name, const IntTag&); - void write_nbt(BinaryWriter&, const std::string& name, const LongTag&); - void write_nbt(BinaryWriter&, const std::string& name, const FloatTag&); - void write_nbt(BinaryWriter&, const std::string& name, const DoubleTag&); - void write_nbt(BinaryWriter&, const std::string& name, const ByteArrayTag&); - void write_nbt(BinaryWriter&, const std::string& name, const StringTag&); - void write_nbt(BinaryWriter&, const std::string& name, const ListTag&); - void write_nbt(BinaryWriter&, const std::string& name, const CompoundTag&); - void write_nbt(BinaryWriter&, const std::string& name, const IntArrayTag&); - void write_nbt(BinaryWriter&, const std::string& name, const LongArrayTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const ByteTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const ShortTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const IntTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const LongTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const FloatTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const DoubleTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const ByteArrayTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const StringTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const ListTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const CompoundTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const IntArrayTag&); + void write_nbt(BinaryWriter&, const std::optional& name, const LongArrayTag&); void write_nbt(BinaryWriter&, const std::string& name, const TagNode&); void write_nbt(BinaryWriter&, const NamedTag& tag); - std::string write_nbt(const std::string& name, const ByteTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const ShortTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const IntTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const LongTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const FloatTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const DoubleTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const ByteArrayTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const StringTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const ListTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const CompoundTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const IntArrayTag&, std::endian, StringEncode); - std::string write_nbt(const std::string& name, const LongArrayTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const ByteTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const ShortTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const IntTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const LongTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const FloatTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const DoubleTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const ByteArrayTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const StringTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const ListTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const CompoundTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const IntArrayTag&, std::endian, StringEncode); + std::string write_nbt(const std::optional& name, const LongArrayTag&, std::endian, StringEncode); std::string write_nbt(const std::string& name, const TagNode&, std::endian, StringEncode); std::string write_nbt(const NamedTag& tag, std::endian, StringEncode); } diff --git a/src/amulet_nbt/include/amulet_nbt/pybind/serialisation.hpp b/src/amulet_nbt/include/amulet_nbt/pybind/serialisation.hpp index 12421365..e5a0abf6 100644 --- a/src/amulet_nbt/include/amulet_nbt/pybind/serialisation.hpp +++ b/src/amulet_nbt/include/amulet_nbt/pybind/serialisation.hpp @@ -1,7 +1,7 @@ #define SerialiseTag(CLSNAME)\ auto to_nbt_##CLSNAME = [compress](\ const AmuletNBT::CLSNAME& self,\ - std::string name,\ + std::optional name,\ bool compressed,\ std::endian endianness,\ AmuletNBT::StringEncode string_encoder\ @@ -17,7 +17,7 @@ [to_nbt_##CLSNAME](\ const AmuletNBT::CLSNAME& self,\ AmuletNBT::EncodingPreset preset,\ - std::string name\ + std::optional name\ ){\ return to_nbt_##CLSNAME(\ self,\ @@ -38,7 +38,7 @@ bool compressed,\ bool little_endian,\ AmuletNBT::StringEncoding string_encoding,\ - std::string name\ + std::optional name\ ){\ return to_nbt_##CLSNAME(\ self,\ @@ -57,7 +57,7 @@ auto save_to_##CLSNAME = [to_nbt_##CLSNAME](\ const AmuletNBT::CLSNAME& self,\ py::object filepath_or_writable,\ - std::string name,\ + std::optional name,\ bool compressed,\ std::endian endianness,\ AmuletNBT::StringEncode string_encoder\ @@ -80,7 +80,7 @@ const AmuletNBT::CLSNAME& self,\ py::object filepath_or_writable,\ AmuletNBT::EncodingPreset preset,\ - std::string name\ + std::optional name\ ){\ return save_to_##CLSNAME(\ self,\ @@ -105,7 +105,7 @@ bool compressed,\ bool little_endian,\ AmuletNBT::StringEncoding string_encoding,\ - std::string name\ + std::optional name\ ){\ return save_to_##CLSNAME(\ self,\ diff --git a/src/amulet_nbt/pybind/bnbt.cpp b/src/amulet_nbt/pybind/bnbt.cpp index 0c219b58..85f872ff 100644 --- a/src/amulet_nbt/pybind/bnbt.cpp +++ b/src/amulet_nbt/pybind/bnbt.cpp @@ -87,8 +87,9 @@ void init_bnbt(py::module& m) { bool compressed, std::endian endianness, AmuletNBT::StringDecode string_decoder, + bool named, py::object read_offset_py - ){ + ) { std::string buffer = get_buffer(filepath_or_buffer, compressed); if (py::isinstance(read_offset_py)){ AmuletNBT::ReadOffset& read_offset = read_offset_py.cast(); @@ -96,13 +97,15 @@ void init_bnbt(py::module& m) { buffer, endianness, string_decoder, + named, read_offset.offset ); } else if (read_offset_py.is(py::none())){ return AmuletNBT::read_nbt( buffer, endianness, - string_decoder + string_decoder, + named ); } else { throw std::invalid_argument("read_offset must be ReadOffset or None"); @@ -114,6 +117,7 @@ void init_bnbt(py::module& m) { [read_nbt]( py::object filepath_or_buffer, AmuletNBT::EncodingPreset preset, + bool named, py::object read_offset ){ return read_nbt( @@ -121,18 +125,21 @@ void init_bnbt(py::module& m) { preset.compressed, preset.endianness, preset.string_encoding.decode, + named, read_offset ); }, py::arg("filepath_or_buffer"), py::kw_only(), py::arg("preset") = java_encoding, + py::arg("named") = true, py::arg("read_offset") = py::none(), py::doc( "Load one binary NBT object.\n" "\n" ":param filepath_or_buffer: A string path to a file on disk, a bytes or memory view object containing the binary NBT or a file-like object to read the binary data from.\n" ":param preset: The encoding preset. If this is defined little_endian and string_encoding have no effect.\n" + ":param named: If the tag to read is named, if not, return NamedTag with empty name.\n" ":param read_offset: Optional ReadOffset object to get read end offset.\n" ":raises: IndexError if the data is not long enough." ) @@ -144,6 +151,7 @@ void init_bnbt(py::module& m) { bool compressed, bool little_endian, AmuletNBT::StringEncoding string_encoding, + bool named, py::object read_offset ){ return read_nbt( @@ -151,6 +159,7 @@ void init_bnbt(py::module& m) { compressed, little_endian ? std::endian::little : std::endian::big, string_encoding.decode, + named, read_offset ); }, @@ -159,6 +168,7 @@ void init_bnbt(py::module& m) { py::arg("compressed") = true, py::arg("little_endian") = false, py::arg("string_encoding") = mutf8_encoding, + py::arg("named") = true, py::arg("read_offset") = py::none(), py::doc( "Load one binary NBT object.\n" @@ -167,6 +177,7 @@ void init_bnbt(py::module& m) { ":param compressed: Is the binary data gzip compressed.\n" ":param little_endian: Are the numerical values stored as little endian. True for Bedrock, False for Java.\n" ":param string_encoding: The bytes decoder function to parse strings. mutf8_encoding for Java, utf8_escape_encoding for Bedrock.\n" + ":param named: If the tag to read is named, if not, return NamedTag with empty name.\n" ":param read_offset: Optional ReadOffset object to get read end offset.\n" ":raises: IndexError if the data is not long enough." ) @@ -178,8 +189,9 @@ void init_bnbt(py::module& m) { bool compressed, std::endian endianness, AmuletNBT::StringDecode string_decoder, + bool named, py::object read_offset_py - ){ + ) { if (count < -1){ throw std::invalid_argument("count must be -1 or higher"); } @@ -191,6 +203,7 @@ void init_bnbt(py::module& m) { buffer, endianness, string_decoder, + named, read_offset.offset ); } else { @@ -198,6 +211,7 @@ void init_bnbt(py::module& m) { buffer, endianness, string_decoder, + named, read_offset.offset, count ); @@ -209,6 +223,7 @@ void init_bnbt(py::module& m) { buffer, endianness, string_decoder, + named, offset ); } else { @@ -216,6 +231,7 @@ void init_bnbt(py::module& m) { buffer, endianness, string_decoder, + named, offset, count ); @@ -230,6 +246,7 @@ void init_bnbt(py::module& m) { py::object filepath_or_buffer, Py_ssize_t count, AmuletNBT::EncodingPreset preset, + bool named, py::object read_offset ){ return read_nbt_array( @@ -238,6 +255,7 @@ void init_bnbt(py::module& m) { preset.compressed, preset.endianness, preset.string_encoding.decode, + named, read_offset ); }, @@ -245,6 +263,7 @@ void init_bnbt(py::module& m) { py::kw_only(), py::arg("count") = 1, py::arg("preset") = java_encoding, + py::arg("named") = true, py::arg("read_offset") = py::none(), py::doc( "Load an array of binary NBT objects from a contiguous buffer.\n" @@ -252,6 +271,7 @@ void init_bnbt(py::module& m) { ":param filepath_or_buffer: A string path to a file on disk, a bytes or memory view object containing the binary NBT or a file-like object to read the binary data from.\n" ":param count: The number of binary NBT objects to read. Use -1 to exhaust the buffer.\n" ":param preset: The encoding preset. If this is defined little_endian and string_encoding have no effect.\n" + ":param named: If the tags to read are named, if not, return NamedTags with empty name.\n" ":param read_offset: Optional ReadOffset object to get read end offset.\n" ":raises: IndexError if the data is not long enough." ) @@ -265,6 +285,7 @@ void init_bnbt(py::module& m) { bool compressed, bool little_endian, AmuletNBT::StringEncoding string_encoding, + bool named, py::object read_offset ){ return read_nbt_array( @@ -273,6 +294,7 @@ void init_bnbt(py::module& m) { compressed, little_endian ? std::endian::little : std::endian::big, string_encoding.decode, + named, read_offset ); }, @@ -282,6 +304,7 @@ void init_bnbt(py::module& m) { py::arg("compressed") = true, py::arg("little_endian") = false, py::arg("string_encoding") = mutf8_encoding, + py::arg("named") = true, py::arg("read_offset") = py::none(), py::doc( "Load an array of binary NBT objects from a contiguous buffer.\n" @@ -291,6 +314,7 @@ void init_bnbt(py::module& m) { ":param compressed: Is the binary data gzip compressed. This only supports the whole buffer compressed as one.\n" ":param little_endian: Are the numerical values stored as little endian. True for Bedrock, False for Java.\n" ":param string_encoding: The bytes decoder function to parse strings. mutf8.decode_modified_utf8 for Java, amulet_nbt.utf8_escape_decoder for Bedrock.\n" + ":param named: If the tags to read are named, if not, return NamedTags with empty name.\n" ":param read_offset: Optional ReadOffset object to get read end offset.\n" ":raises: IndexError if the data is not long enough." ) diff --git a/src/amulet_nbt/pybind/tag/py_abc_tag.cpp b/src/amulet_nbt/pybind/tag/py_abc_tag.cpp index 070f512c..3d37f351 100644 --- a/src/amulet_nbt/pybind/tag/py_abc_tag.cpp +++ b/src/amulet_nbt/pybind/tag/py_abc_tag.cpp @@ -44,7 +44,7 @@ void init_abc(py::module& m) { []( const AmuletNBT::AbstractBaseTag& self, AmuletNBT::EncodingPreset preset, - std::string name + std::optional name ){ PyErr_SetString(PyExc_NotImplementedError, ""); throw py::error_already_set(); @@ -60,7 +60,7 @@ void init_abc(py::module& m) { bool compressed, bool little_endian, AmuletNBT::StringEncoding string_encoding, - std::string name + std::optional name ){ PyErr_SetString(PyExc_NotImplementedError, ""); throw py::error_already_set(); @@ -77,7 +77,7 @@ void init_abc(py::module& m) { const AmuletNBT::AbstractBaseTag& self, py::object filepath_or_writable, AmuletNBT::EncodingPreset preset, - std::string name + std::optional name ){ PyErr_SetString(PyExc_NotImplementedError, ""); throw py::error_already_set(); @@ -96,7 +96,7 @@ void init_abc(py::module& m) { bool compressed, bool little_endian, AmuletNBT::StringEncoding string_encoding, - std::string name + std::optional name ){ PyErr_SetString(PyExc_NotImplementedError, ""); throw py::error_already_set(); diff --git a/tests/test_nbt.py b/tests/test_nbt.py index 841cd77a..ef07d5d0 100644 --- a/tests/test_nbt.py +++ b/tests/test_nbt.py @@ -61,6 +61,34 @@ def test_write_little_endian(self) -> None: msg=str(data.named_tag), ) + def test_unnamed(self) -> None: + # Only one case is tested as the implementation of this is shared among all tag types and thus behaves the same + self.assertEqual( + amulet_nbt.read_nbt( + b"\x01\x05", named=False, compressed=False, little_endian=False + ), + amulet_nbt.NamedTag(amulet_nbt.ByteTag(5), ""), + "reading unnamed tag", + ) + self.assertEqual( + amulet_nbt.read_nbt_array( + b"\x01\x05\x01\x06\x01\x07", + named=False, + count=-1, + compressed=False, + little_endian=False, + ), + [amulet_nbt.NamedTag(amulet_nbt.ByteTag(i), "") for i in (5, 6, 7)], + "reading unnamed tag array", + ) + self.assertEqual( + amulet_nbt.ByteTag(5).to_nbt( + name=None, compressed=False, little_endian=False + ), + b"\x01\x05", + msg="writing unnamed tag", + ) + if __name__ == "__main__": unittest.main()