FeatherMC/src/nbt/NBT.cpp

222 lines
7.1 KiB
C++

#include "NBT.h"
#include "cNBT/nbt.h"
#include <cstring>
#include <sstream>
#include <cstdio>
#include <cstdlib>
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<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 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<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), 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<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; }
}