From 3d10d02620a0e587d765f6042ab05f530b201c39 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Thu, 14 Dec 2023 19:38:55 -0500 Subject: initial stable --- src/main.c | 13 +++- src/stream.c | 3 +- src/tag.c | 195 ------------------------------------------------------ src/tag.h | 2 +- src/tag_print.c | 95 ++++++++++++++++++++++++++ src/tag_read.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 311 insertions(+), 199 deletions(-) delete mode 100644 src/tag.c create mode 100644 src/tag_print.c create mode 100644 src/tag_read.c (limited to 'src') diff --git a/src/main.c b/src/main.c index 077085c..fec6d06 100644 --- a/src/main.c +++ b/src/main.c @@ -1,15 +1,24 @@ #include "tag.h" #include "lib.h" +#include int main (int argc, char** argv) { + if (argc != 2) { + printf("usage: nbtvis file.nbt\n"); + return 0; + } + stream_t stream = stream_open(argv[1], "rb"); tag_t tag; - tag_read(&tag, &stream, true); + if (tag_read(&tag, &stream, true) == false) + error_and_die("failed to read tag\n"); if (tag.type != TAG_COMPOUND) - error_and_die("root tag is not of type compound"); + error_and_die("root tag is not of type compound\n"); + + tag_print(&tag); stream_close(&stream); } diff --git a/src/stream.c b/src/stream.c index 1993df6..622fafa 100644 --- a/src/stream.c +++ b/src/stream.c @@ -1,6 +1,7 @@ #include "stream.h" #include "lib.h" +#include #include #include #include @@ -34,7 +35,7 @@ bool stream_read(stream_t *stream, void *res, size_t amount) { read = fread(res, 1, amount, stream->__file); if (read == 0) { - if (feof(stream->__file)) + if (feof(stream->__file) || errno == 0) return false; else perror_and_die("cannot read open stream"); diff --git a/src/tag.c b/src/tag.c deleted file mode 100644 index ded1c07..0000000 --- a/src/tag.c +++ /dev/null @@ -1,195 +0,0 @@ -#include "tag.h" -#include "lib.h" -#include -#include -#include - -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; - 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; - 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; - 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; - 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) { - printf("entering tag read compound\n"); - 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); - - printf("returning from tag read compound\n"); - return true; -} - -bool tag_read_data(tag_t *tag, stream_t *stream) { - printf("READING THE FUCKING DATA!!!!\n"); - void *p = NULL; - printf("%p\n", (void*)&p); - 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: - printf("TAG OWO TAG OWO\n"); - ok = tag_read_compound(&tag->data, stream); - printf("TAG OWO TAG OWO PART 2\n"); - 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; - }; - printf("read tag: %d\n", tag->type); - 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; -} - diff --git a/src/tag.h b/src/tag.h index 7fd0b4e..93eff64 100644 --- a/src/tag.h +++ b/src/tag.h @@ -70,4 +70,4 @@ typedef struct tag_t { bool tag_read_header(tag_t *tag, stream_t *stream, bool named); bool tag_read_data(tag_t *tag, stream_t *stream); bool tag_read(tag_t *tag, stream_t *stream, bool named); - +void tag_print(const tag_t *tag); diff --git a/src/tag_print.c b/src/tag_print.c new file mode 100644 index 0000000..9612698 --- /dev/null +++ b/src/tag_print.c @@ -0,0 +1,95 @@ +#include "tag.h" +#include +#include + +__attribute__((format(printf, 2, 3))) +static void printi(int depth, const char *format, ...) { + for (int i = 0; i < depth; i++) + printf("\t"); + va_list list; + va_start(list, format); + vprintf(format, list); +} + +static void tag_print_impl(const tag_t *tag, int depth); + +static void tag_print_data(const tag_t *tag, int depth) { + switch (tag->type) { + case TAG_BYTE: + printf("%hhd", tag->data.b); + break; + case TAG_SHORT: + printf("%hd", tag->data.s); + break; + case TAG_INT: + printf("%d", tag->data.i); + break; + case TAG_LONG: + printf("%ld", tag->data.l); + break; + case TAG_FLOAT: + printf("%f", tag->data.f); + break; + case TAG_DOUBLE: + printf("%lf", tag->data.d); + break; + case TAG_BYTE_ARRAY: + printf("["); + for (int32_t i = 0; i < tag->data.b_arr.size; i++) + printf("%hhd,", tag->data.b_arr.data[i]); + printf("\b]"); + break; + case TAG_STRING: + if (tag->data.string.size > 1) + printf("\"%.*s\"", tag->data.string.size, tag->data.string.data); + else + printf("\"\""); + break; + case TAG_LIST: + printf("[\n"); + for (int32_t i = 0; i < tag->data.list.size; i++) { + if (i != 0) printf(",\n"); + tag_print_impl(&tag->data.list.tags[i], depth + 1); + } + printf("\n"); + printi(depth, "]"); + break; + case TAG_COMPOUND: + printf("{\n"); + for (int32_t i = 0; i < tag->data.compound.size; i++) { + if (i != 0) printf(",\n"); + tag_print_impl(&tag->data.compound.tags[i], depth + 1); + } + printf("\n"); + printi(depth, "}"); + break; + case TAG_INT_ARRAY: + printi(depth, "["); + for (int32_t i = 0; i < tag->data.i_arr.size; i++) + printf("%d,", tag->data.i_arr.data[i]); + printf("\b]"); + break; + case TAG_LONG_ARRAY: + printf("["); + for (int32_t i = 0; i < tag->data.l_arr.size; i++) + printf("%ld,", tag->data.l_arr.data[i]); + printf("\b]"); + break; + case TAG_END: + break; + } +} + +static void tag_print_impl(const tag_t *tag, int depth) { + if (tag->name_len > 0) { + printi(depth, "\"%.*s\":\t", tag->name_len, tag->name); + } else { + for (int i = 0; i < depth; i++) printf("\t"); + } + tag_print_data(tag, depth); +} + +void tag_print(const tag_t *tag) { + tag_print_impl(tag, 0); + printf("\n"); +} 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 +#include +#include + +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; +} + -- cgit v1.2.3-freya