summaryrefslogtreecommitdiff
path: root/src/tag_read.c
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2023-12-14 19:38:55 -0500
committerFreya Murphy <freya@freyacat.org>2023-12-14 19:38:55 -0500
commit3d10d02620a0e587d765f6042ab05f530b201c39 (patch)
treeb28191352881a99286adfd798080b4325e259b55 /src/tag_read.c
parenttesting (diff)
downloadnbtvis-3d10d02620a0e587d765f6042ab05f530b201c39.tar.gz
nbtvis-3d10d02620a0e587d765f6042ab05f530b201c39.tar.bz2
nbtvis-3d10d02620a0e587d765f6042ab05f530b201c39.zip
initial stable
Diffstat (limited to 'src/tag_read.c')
-rw-r--r--src/tag_read.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/tag_read.c b/src/tag_read.c
new file mode 100644
index 0000000..5f43e7c
--- /dev/null
+++ b/src/tag_read.c
@@ -0,0 +1,202 @@
+#include "tag.h"
+#include "lib.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool tag_read_header(tag_t *tag, 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 tag_read_byte_array(tagdata_t *data, 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 tag_read_int_array(tagdata_t *data, 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 tag_read_long_array(tagdata_t *data, 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 tag_read_string(tagdata_t *data, 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 tag_read_list(tagdata_t *data, 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 (tag_read_data(&tag, stream) == false)
+ return false;
+ data->list.tags[i] = tag;
+ }
+ return true;
+}
+
+static bool tag_read_compound(tagdata_t *data, 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 (tag_read_header(&tag, stream, true) == false)
+ return false;
+
+ if (tag.type == TAG_END)
+ break;
+
+ if (tag_read_data(&tag, stream) == false)
+ 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;
+}
+bool tag_read_data(tag_t *tag, 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 = tag_read_byte_array(&tag->data, stream);
+ break;
+ case TAG_STRING:
+ ok = tag_read_string(&tag->data, stream);
+ break;
+ case TAG_LIST:
+ ok = tag_read_list(&tag->data, stream);
+ break;
+ case TAG_COMPOUND:
+ ok = tag_read_compound(&tag->data, stream);
+ break;
+ case TAG_INT_ARRAY:
+ ok = tag_read_int_array(&tag->data, stream);
+ break;
+ case TAG_LONG_ARRAY:
+ ok = tag_read_long_array(&tag->data, stream);
+ break;
+ break;
+ };
+ return ok;
+}
+
+bool tag_read(tag_t *tag, stream_t *stream, bool named) {
+ memset(tag, 0, sizeof(tag_t));
+ if (tag_read_header(tag, stream, named) == false)
+ return false;
+ if (tag_read_data(tag, stream) == false)
+ return false;
+ return true;
+}
+