197 lines
6.4 KiB
C++
197 lines
6.4 KiB
C++
#include "NBT.h"
|
|
|
|
#include "cNBT/nbt.h"
|
|
#include "cNBT/list.h"
|
|
|
|
#include <cstring>
|
|
#include <sstream>
|
|
#include <cstdio>
|
|
|
|
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, const decltype(nbt_node::payload)::nbt_list, entry)->data;
|
|
}
|
|
|
|
Tag Tag::CreateTag(nbt_node *node)
|
|
{
|
|
switch (node->type)
|
|
{
|
|
case TAG_BYTE: return DataTag<int8_t>(node);
|
|
case TAG_SHORT: return DataTag<int16_t>(node);
|
|
case TAG_INT: return DataTag<int32_t>(node);
|
|
case TAG_LONG: return DataTag<int64_t>(node);
|
|
case TAG_FLOAT: return DataTag<float>(node);
|
|
case TAG_DOUBLE: return DataTag<double>(node);
|
|
case TAG_BYTE_ARRAY: return ArrayTag<int8_t>(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<int32_t>(node);
|
|
case TAG_LONG_ARRAY: return ArrayTag<int64_t>(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<int8_t>(node);
|
|
case TAG_SHORT: return ListTag<int16_t>(node);
|
|
case TAG_INT: return ListTag<int32_t>(node);
|
|
case TAG_LONG: return ListTag<int64_t>(node);
|
|
case TAG_FLOAT: return ListTag<float>(node);
|
|
case TAG_DOUBLE: return ListTag<double>(node);
|
|
case TAG_BYTE_ARRAY: return ListTag<ArrayTag<int8_t>>(node);
|
|
case TAG_STRING: return ListTag<StringTag>(node);
|
|
case TAG_LIST: return CreateListTag(node);
|
|
case TAG_COMPOUND: return ListTag<CompoundTag>(node);
|
|
case TAG_INT_ARRAY: return ListTag<ArrayTag<int32_t>>(node);
|
|
case TAG_LONG_ARRAY: return ListTag<ArrayTag<int64_t>>(node);
|
|
|
|
case TAG_INVALID:
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
const char *Tag::GetName() const
|
|
{
|
|
return m_node->name ? m_node->name : "<null>";
|
|
}
|
|
|
|
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 char *Tag::ToString() const
|
|
{
|
|
return nbt_dump_ascii(m_node);
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& stream, const Tag& tag)
|
|
{
|
|
return stream << tag.ToString();
|
|
}
|
|
|
|
//==================================================
|
|
|
|
// TODO: still need this specialization?
|
|
template <>
|
|
Tag ListTag<Tag>::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))
|
|
{
|
|
}
|
|
|
|
CompoundTag::~CompoundTag()
|
|
{
|
|
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<int8_t>::GetValue() const { return m_node->payload.tag_byte; }
|
|
|
|
// Short
|
|
template <> int16_t DataTag<int16_t>::GetValue() const { return m_node->payload.tag_short; }
|
|
|
|
// Int
|
|
template <> int32_t DataTag<int32_t>::GetValue() const { return m_node->payload.tag_int; }
|
|
|
|
// Long
|
|
template <> int64_t DataTag<int64_t>::GetValue() const { return m_node->payload.tag_long; }
|
|
|
|
// Float
|
|
template <> float DataTag<float>::GetValue() const { return m_node->payload.tag_float; }
|
|
|
|
// Double
|
|
template <> double DataTag<double>::GetValue() const { return m_node->payload.tag_double; }
|
|
|
|
// String
|
|
template <> const char* DataTag<const char*>::GetValue() const { return m_node->payload.tag_string; }
|
|
|
|
//==================================================
|
|
|
|
// Byte Array
|
|
template <> const int8_t* ArrayTag<int8_t>::GetValue() const { return (const int8_t*)(m_node->payload.tag_byte_array.data); }
|
|
|
|
// Int Array
|
|
template <> const int32_t* ArrayTag<int32_t>::GetValue() const { return m_node->payload.tag_int_array.data; }
|
|
|
|
// Long Array
|
|
template <> const int64_t* ArrayTag<int64_t>::GetValue() const { return m_node->payload.tag_long_array.data; }
|
|
|
|
// String
|
|
template <> const char* StringTag::GetValue() const { return m_node->payload.tag_string; }
|
|
} |