diff options
author | Freya Murphy <freya@freyacat.org> | 2023-12-15 23:02:45 -0500 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2023-12-15 23:02:45 -0500 |
commit | 42d1c82a0bfa615b832f5ecc2652edc290bf6e9c (patch) | |
tree | 09223f3ca9b54fc3cd5a7cb45180542cc3a8a1ba /src/nbt/read.c | |
parent | fix printing arrays (diff) | |
download | nbtvis-42d1c82a0bfa615b832f5ecc2652edc290bf6e9c.tar.gz nbtvis-42d1c82a0bfa615b832f5ecc2652edc290bf6e9c.tar.bz2 nbtvis-42d1c82a0bfa615b832f5ecc2652edc290bf6e9c.zip |
add json support and other things
Diffstat (limited to 'src/nbt/read.c')
-rw-r--r-- | src/nbt/read.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/src/nbt/read.c b/src/nbt/read.c new file mode 100644 index 0000000..d5dd827 --- /dev/null +++ b/src/nbt/read.c @@ -0,0 +1,210 @@ +#include "nbt.h" +#include "../lib.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static bool nbt_read_data(tag_t *tag, const stream_t *stream); + +static bool nbt_read_header(tag_t *tag, const stream_t *stream, bool named) { + bool ok = true; + + if (stream_read_i8(stream, &tag->type) == false) + return false; + + if (tag->type == TAG_END) + named = false; + + if (named) { + if (stream_read_u16(stream, &tag->name_len) == false) + return false; + } else { + tag->name_len = 0; + } + + if (tag->name_len < 1) { + tag->name = ""; + } else { + tag->name = xalloc(tag->name_len); + ok = stream_read(stream, tag->name, tag->name_len); + } + + if (!ok) + return false; + + return true; +} + + +static bool nbt_read_byte_array(tagdata_t *data, const stream_t *stream) { + if (stream_read_i32(stream, &data->b_arr.size) == false) + return false; + if (data->b_arr.size == 0) { + data->b_arr.data = NULL; + return true; + } + data->b_arr.data = xalloc(data->b_arr.size * sizeof(int8_t)); + for (int32_t i = 0; i < data->b_arr.size; i++) + if (stream_read_i8(stream, &data->b_arr.data[i]) == false) + return false; + return true; +} + +static bool nbt_read_int_array(tagdata_t *data, const stream_t *stream) { + if (stream_read_i32(stream, &data->i_arr.size) == false) + return false; + if (data->i_arr.size == 0) { + data->i_arr.data = NULL; + return true; + } + data->i_arr.data = xalloc(data->i_arr.size * sizeof(int32_t)); + for (int32_t i = 0; i < data->i_arr.size; i++) + if (stream_read_i32(stream, &data->i_arr.data[i]) == false) + return false; + return true; +} + +static bool nbt_read_long_array(tagdata_t *data, const stream_t *stream) { + if (stream_read_i32(stream, &data->l_arr.size) == false) + return false; + if (data->l_arr.size == 0) { + data->l_arr.data = NULL; + return true; + } + data->l_arr.data = xalloc(data->l_arr.size * sizeof(int64_t)); + for (int32_t i = 0; i < data->l_arr.size; i++) + if (stream_read_i64(stream, &data->l_arr.data[i]) == false) + return false; + return true; +} + +static bool nbt_read_string(tagdata_t *data, const stream_t *stream) { + if (stream_read_u16(stream, &data->string.size) == false) + return false; + if (data->string.size < 1) { + data->string.data = NULL; + return true; + } + data->string.data = xalloc(data->string.size); + if (stream_read(stream, data->string.data, data->string.size) == false) + return false; + return true; +} + +static bool nbt_read_list(tagdata_t *data, const stream_t *stream) { + if (stream_read_i8(stream, &data->list.type) == false) + return false; + if (stream_read_i32(stream, &data->list.size) == false) + return false; + if (data->list.size <= 0) { + data->list.tags = NULL; + return true; + } else if (data->list.type == 0) { + // tag end is not allowed to be used with non empty list + return false; + } + data->list.tags = xalloc(data->list.size * sizeof(tag_t)); + for (int32_t i = 0; i < data->list.size; i++) { + tag_t tag; + tag.type = data->list.type; + tag.name = ""; + tag.name_len = 0; + if (nbt_read_data(&tag, stream) == false) + return false; + data->list.tags[i] = tag; + } + return true; +} + +static bool nbt_read_compound(tagdata_t *data, const stream_t *stream) { + int32_t size = 0; + int32_t capacity = 8; + tag_t *tags = xalloc(capacity * sizeof(tag_t)); + + while (1) { + + tag_t tag; + + if (nbt_read_header(&tag, stream, true) == false) { + free(tags); + return false; + } + + if (tag.type == TAG_END) + break; + + if (nbt_read_data(&tag, stream) == false) { + free(tags); + return false; + } + + if (size == capacity) { + capacity *= 2; + tags = xrealloc(tags, capacity * sizeof(tag_t)); + } + + tags[size++] = tag; + } + + data->compound.size = size; + data->compound.tags = xalloc(size * sizeof(tag_t)); + memcpy(data->compound.tags, tags, size * sizeof(tag_t)); + free(tags); + + return true; +} + +static bool nbt_read_data(tag_t *tag, const stream_t *stream) { + bool ok = true; + + switch (tag->type) { + case TAG_END: + // tag has no data + break; + case TAG_BYTE: + ok = stream_read_i8(stream, &tag->data.b); + break; + case TAG_SHORT: + ok = stream_read_i16(stream, &tag->data.s); + break; + case TAG_FLOAT: + case TAG_INT: + ok = stream_read_i32(stream, &tag->data.i); + break; + case TAG_DOUBLE: + case TAG_LONG: + ok = stream_read_i64(stream, &tag->data.l); + break; + case TAG_BYTE_ARRAY: + ok = nbt_read_byte_array(&tag->data, stream); + break; + case TAG_STRING: + ok = nbt_read_string(&tag->data, stream); + break; + case TAG_LIST: + ok = nbt_read_list(&tag->data, stream); + break; + case TAG_COMPOUND: + ok = nbt_read_compound(&tag->data, stream); + break; + case TAG_INT_ARRAY: + ok = nbt_read_int_array(&tag->data, stream); + break; + case TAG_LONG_ARRAY: + ok = nbt_read_long_array(&tag->data, stream); + break; + break; + }; + return ok; +} + +bool nbt_read(tag_t *tag, const stream_t *stream) { + memset(tag, 0, sizeof(tag_t)); + if (nbt_read_header(tag, stream, true) == false) + return false; + if (nbt_read_data(tag, stream) == false) + return false; + return true; +} + |