diff options
Diffstat (limited to 'src/nbt/nbt.c')
| -rw-r--r-- | src/nbt/nbt.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/src/nbt/nbt.c b/src/nbt/nbt.c new file mode 100644 index 0000000..5948bce --- /dev/null +++ b/src/nbt/nbt.c @@ -0,0 +1,207 @@ +#include "../nbt.internal.h"
+#include "nbt.h"
+#include "src/nbt.internal.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+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;
+ if (!cap) cap = 16;
+
+ tag->value.nbt_list.len = 0;
+ tag->value.nbt_list.cap = cap;
+
+ 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);
+}
|
