diff options
Diffstat (limited to 'src/nbt')
-rw-r--r-- | src/nbt/nbt.h | 7 | ||||
-rw-r--r-- | src/nbt/print.c | 125 | ||||
-rw-r--r-- | src/nbt/read.c | 210 |
3 files changed, 342 insertions, 0 deletions
diff --git a/src/nbt/nbt.h b/src/nbt/nbt.h new file mode 100644 index 0000000..13c0606 --- /dev/null +++ b/src/nbt/nbt.h @@ -0,0 +1,7 @@ +#pragma once + +#include "../tag.h" +#include "../stream.h" + +bool nbt_read(tag_t *tag, const stream_t *stream); +bool nbt_print(const tag_t *tag, const stream_t *stream); diff --git a/src/nbt/print.c b/src/nbt/print.c new file mode 100644 index 0000000..4eac31f --- /dev/null +++ b/src/nbt/print.c @@ -0,0 +1,125 @@ +#include "nbt.h" + +static bool nbt_print_header(const tag_t *tag, const stream_t *stream, bool named) { + if (stream_write_i8(stream, tag->type) == false) + return false; + if (!named) + return true; + if (stream_write_u16(stream, tag->name_len) == false) + return false; + if (tag->name_len > 0) + if (stream_write(stream, tag->name, tag->name_len) == false) + return false; + return true; +} + +static bool nbt_print_byte_array(const tagdata_t *data, const stream_t *stream) { + if (stream_write_i32(stream, data->b_arr.size) == false) + return false; + for (int32_t i = 0; i < data->b_arr.size; i++) + if (stream_write_i8(stream, data->b_arr.data[i]) == false) + return false; + return true; +} + +static bool nbt_print_int_array(const tagdata_t *data, const stream_t *stream) { + if (stream_write_i32(stream, data->i_arr.size) == false) + return false; + for (int32_t i = 0; i < data->i_arr.size; i++) + if (stream_write_i32(stream, data->i_arr.data[i]) == false) + return false; + return true; +} + +static bool nbt_print_long_array(const tagdata_t *data, const stream_t *stream) { + if (stream_write_i32(stream, data->l_arr.size) == false) + return false; + for (int32_t i = 0; i < data->l_arr.size; i++) + if (stream_write_i64(stream, data->l_arr.data[i]) == false) + return false; + return true; +} + +static bool nbt_print_string(const tagdata_t *data, const stream_t *stream) { + if (stream_write_u16(stream, data->string.size) == false) + return false; + if (data->string.size < 1) + return true; + if (stream_write(stream, data->string.data, data->string.size) == false) + return false; + return true; +} + +static bool nbt_print_data(const tag_t *tag, const stream_t *stream); + +static bool nbt_print_list(const tagdata_t *data, const stream_t *stream) { + if (stream_write_i8(stream, data->list.type) == false) + return false; + if (stream_write_i32(stream, data->list.size) == false) + return false; + for (int32_t i = 0; i < data->list.size; i++) + if (nbt_print_data(&data->list.tags[i], stream) == false) + return false; + return true; +} + +static bool nbt_print_compound(const tagdata_t *data, const stream_t *stream) { + for (int32_t i = 0; i < data->compound.size; i++) + if (nbt_print(&data->compound.tags[i], stream) == false) + return false; + if (stream_write_i8(stream, TAG_END) == false) + return false; + return true; +} + +static bool nbt_print_data(const tag_t *tag, const stream_t *stream) { + bool ok = true; + + switch (tag->type) { + case TAG_END: + // tag end has no data + break; + case TAG_BYTE: + ok = stream_write_i8(stream, tag->data.b); + break; + case TAG_SHORT: + ok = stream_write_i16(stream, tag->data.s); + break; + case TAG_INT: + case TAG_FLOAT: + ok = stream_write_i32(stream, tag->data.i); + break; + case TAG_LONG: + case TAG_DOUBLE: + ok = stream_write_i64(stream, tag->data.l); + break; + case TAG_BYTE_ARRAY: + ok = nbt_print_byte_array(&tag->data, stream); + break; + case TAG_STRING: + ok = nbt_print_string(&tag->data, stream); + break; + case TAG_LIST: + ok = nbt_print_list(&tag->data, stream); + break; + case TAG_COMPOUND: + ok = nbt_print_compound(&tag->data, stream); + break; + case TAG_INT_ARRAY: + ok = nbt_print_int_array(&tag->data, stream); + break; + case TAG_LONG_ARRAY: + ok = nbt_print_long_array(&tag->data, stream); + break; + } + + return ok; +} + +bool nbt_print(const tag_t *tag, const stream_t *stream) { + if (nbt_print_header(tag, stream, true) == false) + return false; + if (nbt_print_data(tag, stream) == false) + return false; + return true; +} 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; +} + |