#include "NBT.h" #include "cNBT/nbt.h" #include #include #include #include namespace NBT { nbt_node* Internal::FindByName(nbt_node* tree, const char* name) { return nbt_find_by_name(tree, name); } nbt_node* Internal::ListItem(nbt_node* list, int32_t index) { return nbt_list_item(list, index); } list_head* Internal::GetFirstItem(nbt_node* list) { // The first node in nbt_list is the sentinel node, // so the first node is the one right after it. return GetNextItem(&(list->payload.tag_list->entry)); } list_head* Internal::GetNextItem(list_head* item) { return item->flink; } nbt_node* Internal::GetListEntry(list_head* item) { // In C, the type could have been 'const struct nbt_list' // but in C++ we have to use this monstrosity because of anonymous innter structs return list_entry(item, nbt_node::nbt_payload::nbt_list, entry)->data; } DataBuffer::~DataBuffer() { // equivalent to buffer_free in cNBT buffer.h // FIXME //free(data); } Tag Tag::CreateTag(nbt_node *node) { switch (node->type) { case TAG_BYTE: return DataTag(node); case TAG_SHORT: return DataTag(node); case TAG_INT: return DataTag(node); case TAG_LONG: return DataTag(node); case TAG_FLOAT: return DataTag(node); case TAG_DOUBLE: return DataTag(node); case TAG_BYTE_ARRAY: return ArrayTag(node); case TAG_STRING: return StringTag(node); case TAG_LIST: return CreateListTag(node); case TAG_COMPOUND: return CompoundTag(node); case TAG_INT_ARRAY: return ArrayTag(node); case TAG_LONG_ARRAY: return ArrayTag(node); case TAG_INVALID: default: return NULL; } } Tag Tag::CreateListTag(nbt_node* node) { nbt_type type = node->payload.tag_list->data->type; switch (type) { case TAG_BYTE: return ListTag(node); case TAG_SHORT: return ListTag(node); case TAG_INT: return ListTag(node); case TAG_LONG: return ListTag(node); case TAG_FLOAT: return ListTag(node); case TAG_DOUBLE: return ListTag(node); case TAG_BYTE_ARRAY: return ListTag>(node); case TAG_STRING: return ListTag(node); case TAG_LIST: return CreateListTag(node); case TAG_COMPOUND: return ListTag(node); case TAG_INT_ARRAY: return ListTag>(node); case TAG_LONG_ARRAY: return ListTag>(node); case TAG_INVALID: default: return NULL; } } const char *Tag::GetName() const { return m_node->name ? m_node->name : ""; } size_t Tag::GetLength() const { switch (m_node->type) { case TAG_BYTE_ARRAY: return m_node->payload.tag_byte_array.length; case TAG_INT_ARRAY: return m_node->payload.tag_int_array.length; case TAG_LONG_ARRAY: return m_node->payload.tag_long_array.length; case TAG_STRING: // cNBT does not store string length so compute here return strlen(m_node->payload.tag_string); case TAG_LIST: return list_length(&(m_node->payload.tag_list->entry)); case TAG_COMPOUND: return list_length(&(m_node->payload.tag_compound->entry)); // nbt_size(node) is only used for non-list types because // it gets the total number of nodes, rather than immediate children // and it treats arrays as consisting of one node default: // will return 1 for most types and 0 for invalid return nbt_size(m_node); } } const DataBuffer Tag::GetData() const { buffer buf = nbt_dump_binary(m_node); DataBuffer result { buf.data, buf.len }; return result; } const char *Tag::ToString() const { return nbt_dump_ascii(m_node); } Tag::operator bool() const { return m_node != NULL && m_node->type != TAG_INVALID; } std::ostream& operator<<(std::ostream& stream, const Tag& tag) { return stream << tag.ToString(); } //================================================== // TODO: still need this specialization? template <> Tag ListTag::Get(int32_t index) const { nbt_node* result = nbt_list_item(m_node, index); return Tag::CreateTag(result); } //================================================== CompoundTag::CompoundTag(const char *filename) : CompoundTag(nbt_parse_path(filename), true) // m_isRoot = true, this calls malloc { } CompoundTag::CompoundTag(const void* data, size_t length) : CompoundTag(nbt_parse_compressed(data, length), true) // m_isRoot = true, this calls malloc { } CompoundTag::~CompoundTag() { if (m_isRoot) nbt_free(m_node); } const Tag CompoundTag::operator[](const char *name) const { nbt_node *result = nbt_find_by_name(m_node, name); return Tag::CreateTag(result); } //================================================== // Byte template <> int8_t DataTag::GetValue() const { return m_node->payload.tag_byte; } // Short template <> int16_t DataTag::GetValue() const { return m_node->payload.tag_short; } // Int template <> int32_t DataTag::GetValue() const { return m_node->payload.tag_int; } // Long template <> int64_t DataTag::GetValue() const { return m_node->payload.tag_long; } // Float template <> float DataTag::GetValue() const { return m_node->payload.tag_float; } // Double template <> double DataTag::GetValue() const { return m_node->payload.tag_double; } // String template <> const char* DataTag::GetValue() const { return m_node->payload.tag_string; } //================================================== // Byte Array template <> const int8_t* ArrayTag::GetValue() const { return (const int8_t*)(m_node->payload.tag_byte_array.data); } // Int Array template <> const int32_t* ArrayTag::GetValue() const { return m_node->payload.tag_int_array.data; } // Long Array template <> const int64_t* ArrayTag::GetValue() const { return m_node->payload.tag_long_array.data; } // String template <> const char* StringTag::GetValue() const { return m_node->payload.tag_string; } }