diff options
author | Freya Murphy <freya@freyacat.org> | 2023-12-17 11:10:04 -0500 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2023-12-17 11:10:04 -0500 |
commit | e0eacfa9773c83850ed5169d1e889ff845180581 (patch) | |
tree | 9f8bb433404ce7e4dda1b86ca4dd5d5a2fba10e9 /nbt/json/print.c | |
parent | snbt (diff) | |
download | nbtvis-e0eacfa9773c83850ed5169d1e889ff845180581.tar.gz nbtvis-e0eacfa9773c83850ed5169d1e889ff845180581.tar.bz2 nbtvis-e0eacfa9773c83850ed5169d1e889ff845180581.zip |
Diffstat (limited to 'nbt/json/print.c')
-rw-r--r-- | nbt/json/print.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/nbt/json/print.c b/nbt/json/print.c new file mode 100644 index 0000000..3b7cdb3 --- /dev/null +++ b/nbt/json/print.c @@ -0,0 +1,177 @@ +#include <stdarg.h> +#include <stdio.h> + +#include "nbt.h" + +static char buf[1024]; + +__attribute__((format(printf, 3, 4))) +static bool printi(const stream_t *stream, int depth, const char *format, ...) { + for (int i = 0; i < depth; i++) + if (stream_write(stream, "\t", 1) == false) + return false; + va_list list; + va_start(list, format); + int len; + if ((len = vsnprintf(buf, 1024, format, list)) < 0) + return false; + if (stream_write(stream, buf, len) == false) + return false; + return true; +} + +static bool json_print_impl(const tag_t *tag, const stream_t *stream, int depth); + +static bool json_print_byte_array(const tagdata_t *data, const stream_t *stream) { + if (printi(stream, 0, "[") == false) + return false; + for (int32_t i = 0; i < data->b_arr.size; i++) { + if (i != 0) + if (printi(stream, 0, ",") == false) + return false; + if (printi(stream, 0, "%hhd", data->b_arr.data[i]) == false) + return false; + } + if (printi(stream, 0, "]") == false) + return false; + return true; +} + +static bool json_print_int_array(const tagdata_t *data, const stream_t *stream) { + if (printi(stream, 0, "[") == false) + return false; + for (int32_t i = 0; i < data->i_arr.size; i++) { + if (i != 0) + if (printi(stream, 0, ",") == false) + return false; + if (printi(stream, 0, "%d", data->i_arr.data[i]) == false) + return false; + } + if (printi(stream, 0, "]") == false) + return false; + return true; +} + +static bool json_print_long_array(const tagdata_t *data, const stream_t *stream) { + if (printi(stream, 0, "[") == false) + return false; + for (int32_t i = 0; i < data->l_arr.size; i++) { + if (i != 0) + if (printi(stream, 0, ",") == false) + return false; + if (printi(stream, 0, "%ld", data->l_arr.data[i]) == false) + return false; + } + if (printi(stream, 0, "]") == false) + return false; + return true; +} + +static bool json_print_string(const tagdata_t *data, const stream_t *stream) { + if (data->string.size > 0) { + if (printi(stream, 0, "\"%.*s\"", data->string.size, data->string.data) == false) + return false; + } else { + if (printi(stream, 0, "\"\"") == false) + return false; + } + return true; +} + +static bool json_print_compound(const tagdata_t *data, const stream_t *stream, int depth) { + if (printi(stream, 0, "{\n") == false) + return false; + bool first = true; + for (uint32_t i = 0; i < data->compound.capacity; i++) { + if (data->compound.entries[i].name == NULL) + continue; + if (!first && printi(stream, 0, ",\n") == false) + return false; + first = false; + if (json_print_impl(&data->compound.entries[i], stream, depth + 1) == false) + return false; + } + if (printi(stream, 0, "\n") == false || printi(stream, depth, "}") == false) + return false; + return true; +} + +static bool json_print_list(const tagdata_t *data, const stream_t *stream, int depth) { + if (printi(stream, 0, "[\n") == false) + return false; + for (int32_t i = 0; i < data->list.size; i++) { + if (i != 0 && printi(stream, 0, ",\n") == false) + return false; + if (json_print_impl(&data->list.tags[i], stream, depth + 1) == false) + return false; + } + if (printi(stream, 0, "\n") == false || printi(stream, depth, "]") == false) + return false; + return true; +} + +static bool json_print_data(const tag_t *tag, const stream_t *stream, int depth) { + + bool ok = true; + + switch (tag->type) { + case TAG_BYTE: + ok = printi(stream, 0, "%hhd", tag->data.b); + break; + case TAG_SHORT: + ok = printi(stream, 0, "%hd", tag->data.s); + break; + case TAG_INT: + ok = printi(stream, 0, "%d", tag->data.i); + break; + case TAG_LONG: + ok = printi(stream, 0, "%ld", tag->data.l); + break; + case TAG_FLOAT: + ok = printi(stream, 0, "%.9g", tag->data.f); + break; + case TAG_DOUBLE: + ok = printi(stream, 0, "%.17g", tag->data.d); + break; + case TAG_BYTE_ARRAY: + ok = json_print_byte_array(&tag->data, stream); + break; + case TAG_STRING: + ok = json_print_string(&tag->data, stream); + break; + case TAG_LIST: + ok = json_print_list(&tag->data, stream, depth); + break; + case TAG_COMPOUND: + ok = json_print_compound(&tag->data, stream, depth); + break; + case TAG_INT_ARRAY: + ok = json_print_int_array(&tag->data, stream); + break; + case TAG_LONG_ARRAY: + ok = json_print_long_array(&tag->data, stream); + break; + case TAG_END: + break; + } + + return ok; +} + +static bool json_print_impl(const tag_t *tag, const stream_t *stream, int depth) { + if (tag->name_len > 0) { + printi(stream, depth, "\"%.*s\": ", tag->name_len, tag->name); + } else { + for (int i = 0; i < depth; i++) + printi(stream, 0, "\t"); + } + return json_print_data(tag, stream, depth); +} + +bool json_print(const tag_t *tag, const stream_t *stream) { + if (json_print_impl(tag, stream, 0) == false) + return false; + if (stream_write(stream, "\n", 1) == false) + return false; + return true; +} |