#include "../nbt.internal.h" #include "nbt.h" #include "src/nbt.internal.h" #include #include #include const char *const nbt__type_names[] = { "TAG_End", "TAG_Byte", "TAG_Short", "TAG_Int", "TAG_Long", "TAG_Float", "TAG_Double", "TAG_Byte_Array", "TAG_String", "TAG_List", "TAG_Compound", "TAG_Int_Array", "TAG_Long_Array", NULL }; nbt_type_t nbt_tag_type(nbt_tag_t *tag) { if (!tag) return NBT_TAG_END; return tag->type; } nbt_tag_t *nbt__new_val(nbt_type_t type) { nbt_tag_t *tag = calloc(1, sizeof(nbt_tag_t)); if (!tag) return NULL; tag->ref = 1; tag->type = type; return tag; } nbt_tag_t *nbt_byte(nbt_byte_t b) { nbt_tag_t *tag = nbt__new_val(NBT_TAG_BYTE); if (!tag) return NULL; tag->value.nbt_byte = b; return tag; } nbt_tag_t *nbt_short(nbt_short_t s) { nbt_tag_t *tag = nbt__new_val(NBT_TAG_SHORT); if (!tag) return NULL; tag->value.nbt_short = s; return tag; } nbt_tag_t *nbt_int(nbt_int_t i) { nbt_tag_t *tag = nbt__new_val(NBT_TAG_INT); if (!tag) return NULL; tag->value.nbt_int = i; return tag; } nbt_tag_t *nbt_long(nbt_long_t l) { nbt_tag_t *tag = nbt__new_val(NBT_TAG_LONG); if (!tag) return NULL; tag->value.nbt_long = l; return tag; } nbt_tag_t *nbt_float(nbt_float_t f) { nbt_tag_t *tag = nbt__new_val(NBT_TAG_FLOAT); if (!tag) return NULL; tag->value.nbt_float = f; return tag; } nbt_tag_t *nbt_double(nbt_double_t d) { nbt_tag_t *tag = nbt__new_val(NBT_TAG_DOUBLE); if (!tag) return NULL; tag->value.nbt_byte = d; return tag; } #define NBT__BUFCOPY_BODY(_tl, _tu, _te, _inbuf, _inlen) \ { \ static nbt_tag_t nbt__single_empty_ ## _tl = { \ .ref = SIZE_MAX, \ .type = NBT_TAG_ ## _tu, \ .value = { .nbt_ ## _tl = { .len = 0, .data = NULL } } \ }; \ \ if (!(_inlen)) return &nbt__single_empty_ ## _tl; \ \ nbt_tag_t *tag = nbt__new_val(NBT_TAG_ ## _tu); \ if (!tag) return NULL; \ \ _te *buf = calloc(_inlen, sizeof(_te)); \ if (!buf) goto cleanup; \ \ memcpy(buf, _inbuf, (_inlen) * sizeof(_te)); \ tag->value.nbt_ ## _tl.len = _inlen; \ tag->value.nbt_ ## _tl.data = buf; \ \ return tag; \ \ cleanup: \ free(tag); \ return NULL; \ } nbt_tag_t *nbt_byte_array(const nbt_byte_t *bytes, nbt_size_t length) NBT__BUFCOPY_BODY(byte_array, BYTE_ARRAY, nbt_byte_t, bytes, length) nbt_tag_t *nbt_string(const char *c_str) { return nbt_stringn(c_str, strlen(c_str)); } nbt_tag_t *nbt_stringn(const char *c_str, nbt_size_t length) NBT__BUFCOPY_BODY(string, STRING, char, c_str, length) nbt_tag_t *nbt_list(void) { return nbt_listn(0); } nbt_tag_t *nbt_listn(nbt_size_t cap) { nbt_tag_t *tag = nbt__new_val(NBT_TAG_LIST); if (!tag) return NULL; tag->value.nbt_list.len = 0; tag->value.nbt_list.cap = cap; if (!cap) { tag->value.nbt_list.ptags = NULL; return tag; } nbt_tag_t **tags = calloc(cap, sizeof(nbt_tag_t *)); if (!tags) goto cleanup; tag->value.nbt_list.ptags = tags; return tag; cleanup: free(tag); return NULL; } nbt_tag_t *nbt_compound(void) { return nbt_compoundn(0); } nbt_tag_t *nbt_compoundn(nbt_size_t cap) { nbt_tag_t *tag = nbt__new_val(NBT_TAG_COMPOUND); if (!tag) return NULL; tag->value.nbt_compound.hash = nbt__ht_create(cap); if (!tag->value.nbt_compound.hash) goto cleanup; return tag; cleanup: free(tag); return NULL; } nbt_tag_t *nbt_int_array(const nbt_int_t *ints, nbt_size_t length) NBT__BUFCOPY_BODY(int_array, INT_ARRAY, nbt_int_t, ints, length) nbt_tag_t *nbt_long_array(const nbt_long_t *longs, nbt_size_t length) NBT__BUFCOPY_BODY(long_array, LONG_ARRAY, nbt_long_t, longs, length); void nbt_decref(nbt_tag_t *tag) { if (!tag) return; if (tag->ref == SIZE_MAX) return; --tag->ref; if (!tag->ref) nbt__tag_free(tag); } nbt_tag_t *nbt_incref(nbt_tag_t *tag) { if (tag->ref != SIZE_MAX) ++tag->ref; return tag; } void nbt__tag_free(nbt_tag_t *tag) { if (!tag) return; switch (tag->type) { case NBT_TAG_BYTE_ARRAY: free(tag->value.nbt_byte_array.data); break; case NBT_TAG_STRING: free(tag->value.nbt_string.data); break; case NBT_TAG_INT_ARRAY: free(tag->value.nbt_int_array.data); break; case NBT_TAG_LONG_ARRAY: free(tag->value.nbt_long_array.data); break; case NBT_TAG_LIST: nbt_list_clear(tag); free(tag->value.nbt_list.ptags); break; case NBT_TAG_COMPOUND: nbt_compound_clear(tag); nbt__ht_free(tag->value.nbt_compound.hash); break; default: break; } free(tag); } const char *nbt_typestr(nbt_type_t type) { if (type < 0 || type >= NBT_TAG_MAX) return NULL; return nbt__type_names[type]; }