summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/flags.c1
-rw-r--r--src/flags.h2
-rw-r--r--src/json/json.h7
-rw-r--r--src/json/print.c177
-rw-r--r--src/json/read.c632
-rw-r--r--src/lib.c51
-rw-r--r--src/lib.h13
-rw-r--r--src/main.c5
-rw-r--r--src/map.c86
-rw-r--r--src/map.h15
-rw-r--r--src/nbt/nbt.h7
-rw-r--r--src/nbt/print.c127
-rw-r--r--src/nbt/read.c207
-rw-r--r--src/snbt/print.c210
-rw-r--r--src/snbt/read.c740
-rw-r--r--src/snbt/snbt.h9
-rw-r--r--src/stream.c144
-rw-r--r--src/stream.h29
-rw-r--r--src/tag.c68
-rw-r--r--src/tag.h77
20 files changed, 4 insertions, 2603 deletions
diff --git a/src/flags.c b/src/flags.c
index 9abe76c..55740e4 100644
--- a/src/flags.c
+++ b/src/flags.c
@@ -2,6 +2,7 @@
#include "lib.h"
#include "stream.h"
+#include <string.h>
#include <strings.h>
static format_t get_file_extension(char *path) {
diff --git a/src/flags.h b/src/flags.h
index a14580b..95bb039 100644
--- a/src/flags.h
+++ b/src/flags.h
@@ -1,6 +1,6 @@
#pragma once
-#include "tag.h"
+#include "nbt.h"
#include "stream.h"
typedef struct {
diff --git a/src/json/json.h b/src/json/json.h
deleted file mode 100644
index 73b4f52..0000000
--- a/src/json/json.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-#include "../tag.h"
-#include "../stream.h"
-
-bool json_read(tag_t *tag, const stream_t *stream);
-bool json_print(const tag_t *tag, const stream_t *stream);
diff --git a/src/json/print.c b/src/json/print.c
deleted file mode 100644
index ab154b9..0000000
--- a/src/json/print.c
+++ /dev/null
@@ -1,177 +0,0 @@
-#include "json.h"
-
-#include <stdarg.h>
-#include <stdio.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;
-}
diff --git a/src/json/read.c b/src/json/read.c
deleted file mode 100644
index dbb246a..0000000
--- a/src/json/read.c
+++ /dev/null
@@ -1,632 +0,0 @@
-#include "json.h"
-#include "../lib.h"
-
-#include <ctype.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static char ret = '\0';
-
-typedef enum {
- TOK_LBRACE,
- TOK_RBRACE,
- TOK_LBRACK,
- TOK_RBRACK,
- TOK_COLON,
- TOK_COMMA,
- TOK_STRING,
- TOK_NUMBER,
- TOK_DOUBLE,
- TOK_BOOL,
- TOK_NULL
-} tokentype_t ;
-
-typedef union {
- bool b;
- int64_t number;
- double decimal;
- struct {
- uint16_t len;
- char *data;
- } string;
-} tokendata_t;
-
-typedef struct {
- tokentype_t type;
- tokendata_t data;
-} token_t;
-
-static void json_token_free(token_t *token) {
- if (token->type == TOK_STRING)
- free(token->data.string.data);
-}
-
-static bool json_parse_unicode(char buf[4], int *read, const stream_t *stream) {
- char temp[5];
- temp[4] = '\0';
-
- if (stream_read(stream, temp, 4) == false)
- return false;
-
- uint16_t code_point;
- char *end = NULL;
-
- code_point = strtol(temp, &end, 16);
-
- if (end != NULL)
- return false;
-
- int lead1 = 0b00000000;
- int lead2 = 0b11000000;
- int lead3 = 0b11100000;
- int cont = 0b10000000;
- int contmask = 0b00111111;
-
- if (code_point < 0x0080) {
- buf[0] = ((code_point >> 0)) | lead1;
- *read = 1;
- } else if (code_point < 0x0800) {
- buf[0] = ((code_point >> 6)) | lead2;
- buf[1] = ((code_point >> 0) & contmask) | cont;
- *read = 2;
- } else {
- buf[0] = ((code_point >> 12)) | lead3;
- buf[1] = ((code_point >> 6) & contmask) | cont;
- buf[2] = ((code_point >> 0) & contmask) | cont;
- *read = 3;
- }
-
- return true;
-}
-
-static bool json_parse_escape(char buf[4], int *read, const stream_t *stream) {
- char n;
-
- char *c = &buf[0];
- *read = 1;
-
- if (stream_read(stream, &n, 1) == false)
- return false;
-
- switch (n) {
- case '"':
- case '\\':
- case '/':
- *c = n;
- return true;
- case 'b':
- *c = '\b';
- return true;
- case 'f':
- *c = '\f';
- return true;
- case 'n':
- *c = '\n';
- return true;
- case 'r':
- *c = '\r';
- return true;
- case 't':
- *c = '\t';
- return true;
- case 'u': {
- return json_parse_unicode(buf, read, stream);
- default:
- // invalid escape
- return false;
- };
- }
-}
-
-static bool json_parse_string(tokendata_t *token, const stream_t *stream) {
-
- int capacity = 8;
- int len = 0;
- char *buf = xalloc(capacity * sizeof(char));
-
- while (1) {
-
- char tmp[4];
- int read = 1;
-
- if (stream_read(stream, tmp, 1) == false) {
- free(buf);
- return false;
- }
-
- uint8_t c = tmp[0];
-
- if (c == '"')
- break;
-
- // non printable ascii character
- if (c < 32 || c > 127) {
- free(buf);
- return false;
- }
- // an escape, dont push to buffer, get next char
- if (c == '\\' && json_parse_escape(tmp, &read, stream) == false) {
- free(buf);
- return false;
- }
-
- if (len + read >= capacity) {
- capacity *= 2;
- buf = xrealloc(buf, capacity);
- }
-
- memcpy(buf + len, tmp, read);
- len += read;
-
- }
-
- token->string.data = xalloc(len * sizeof(char));
- token->string.len = len;
- memcpy(token->string.data, buf, len);
- free(buf);
-
- return true;
-}
-
-static bool json_ident_assert(const stream_t *stream, const char *rest) {
- char c;
- if (stream_read(stream, &c, 1) == false)
- return false;
- if (c != *rest)
- return false;
- rest += 1;
- if (*rest == '\0')
- return true;
- else
- return json_ident_assert(stream, rest);
-}
-
-static bool json_parse_ident(token_t *token, const stream_t *stream, char first) {
- if (first == 't' && json_ident_assert(stream, "true")) {
- token->type = TOK_BOOL;
- token->data.b = true;
- } else if (first == 'f' && json_ident_assert(stream, "alse")) {
- token->type = TOK_BOOL;
- token->data.b = false;
- } else if (first == 'n' && json_ident_assert(stream, "ull")) {
- token->type = TOK_NULL;
- } else {
- return false;
- }
- return true;
-}
-
-static void push_char(char **buf, int *len, int *cap, char c) {
- if (*len == *cap) {
- *cap *= *cap * 2;
- *buf = xrealloc(*buf, *cap * sizeof(char));
- }
- (*buf)[(*len)++] = c;
-}
-
-static bool json_parse_number(token_t *token, const stream_t *stream, char first) {
-
- int capacity = 8;
- int len = 0;
- char *buf = xalloc(capacity * sizeof(char));
- bool isdec = false;
- bool isneg = false;
-
- char c = first;
-
- // PARSE DIGITS AND NEGATIVITY
-
- while (1) {
- if (c == '\0' && stream_read(stream, &c, 1) == false) {
- free(buf);
- return false;
- }
-
- if (c == '-' && isneg) {
- // cannot negate twice
- free(buf);
- return false;
- } else if (c == '-') {
- isneg = true;
- c = '\0';
- } else if (c == '0' && len == 0) {
- // string starting with 0 cannot not have other digits
- push_char(&buf, &len, &capacity, c);
- c = '\0';
- break;
- } else if (c >= '0' && c <= '9') {
- push_char(&buf, &len, &capacity, c);
- c = '\0';
- } else if (len == 0) {
- // invalid start of digits
- free(buf);
- return false;
- } else {
- // end of starting digits
- break;
- }
- }
-
- // SET NEXT CHAR C IF NOT READ YET
-
- if (c == '\0' && stream_read(stream, &c, 1) == false) {
- free(buf);
- return false;
- }
-
- // THERE IS A DECIMAL
- // READ STREAM OF DIGITS
-
- if (c == '.') {
- isdec = true;
- push_char(&buf, &len, &capacity, c);
- int declen = 0;
- while (1) {
- if (stream_read(stream, &c, 1) == false) {
- free(buf);
- return false;
- }
- if (c >= '0' && c <= '9') {
- push_char(&buf, &len, &capacity, c);
- declen++;
- } else if (declen == 0) {
- // invalid decimal
- free(buf);
- return false;
- } else {
- // end of decimal
- break;
- }
- }
- }
-
- // PARSE EXPONENT
- if (c == 'e' || c == 'E') {
- isdec = true;
- push_char(&buf, &len, &capacity, 'E');
-
- int explen = 0; // the exponent len
-
- if (stream_read(stream, &c, 1) == false) {
- free(buf);
- return false;
- }
-
- if (c == '+' || c == '-') {
- push_char(&buf, &len, &capacity, c);
- c = '\0';
- }
-
- while (1) {
- if (c == '\0' && stream_read(stream, &c, 1) == false) {
- free(buf);
- return false;
- }
-
- if (c >= '0' && c <= '9') {
- push_char(&buf, &len, &capacity, c);
- explen++;
- c = '\0';
- } else if (explen == 0) {
- // invalid exponent
- free(buf);
- return false;
- } else {
- break;
- }
- }
-
- }
-
- char *end = NULL;
- push_char(&buf, &len, &capacity, '\0');
-
- if (isdec) {
- token->type = TOK_DOUBLE;
- token->data.decimal = strtod(buf, &end);
- } else {
- token->type = TOK_NUMBER;
- token->data.number = strtol(buf, &end, 10);
- }
-
- if (end != NULL && *end != 0)
- return false;
-
- free(buf);
-
- ret = c;
- return true;
-}
-
-static bool json_next_token(token_t *token, const stream_t *stream) {
-
- memset(token, 0, sizeof(token_t));
-
- char c;
-
-retry:
-
- if (ret != '\0') {
- c = ret;
- ret = '\0';
- } else if (stream_read(stream, &c, 1) == false) {
- return false;
- }
-
- bool ok = true;
-
- switch (c) {
- case '{':
- token->type = TOK_LBRACE;
- break;
- case '}':
- token->type = TOK_RBRACE;
- break;
- case '[':
- token->type = TOK_LBRACK;
- break;
- case ']':
- token->type = TOK_RBRACK;
- break;
- case ':':
- token->type = TOK_COLON;
- break;
- case ',':
- token->type = TOK_COMMA;
- break;
- case '"':
- token->type = TOK_STRING;
- ok = json_parse_string(&token->data, stream);
- break;
- case 't':
- case 'f':
- case 'n':
- // parse null or bool
- ok = json_parse_ident(token, stream, c);
- break;
- case ' ':
- case '\n':
- case '\t':
- case '\r':
- goto retry;
- default:
- if (isdigit(c) || c == '-') {
- // parse number
- ok = json_parse_number(token, stream, c);
- } else {
- // disallowed symbol
- ok = false;
- }
- break;
- }
-
- return ok;
-}
-
-static bool json_get_list_type(tagtype_t *type, const tag_t *tags, int len) {
- if (len < 1) {
- *type = TAG_END;
- return true;
- }
-
- *type = tags[0].type;
-
- for (int i = 0; i < len; i++)
- if (tags[i].type != *type)
- return false;
-
- return true;
-}
-
-static bool json_read_value(tag_t *tag, const stream_t *stream, token_t *first);
-
-static bool json_read_list(tagdata_t *data, const stream_t *stream) {
-
- token_t next = {0};
- if (json_next_token(&next, stream) == false) {
- json_token_free(&next);
- return false;
- }
-
- token_t *ret = &next;
-
- if (next.type == TOK_RBRACK) {
- data->list.tags = NULL;
- data->list.size = 0;
- data->list.type = TAG_END;
- return true;
- }
-
- int capacity = 8;
- int len = 0;
- tag_t *tags = xalloc(capacity * sizeof(tag_t));
-
- while (1) {
-
- tag_t value;
- value.name = "";
- value.name_len = 0;
-
- if (json_read_value(&value, stream, ret) == false) {
- free(tags);
- return false;
- }
-
- ret = NULL;
-
- if (len == capacity) {
- capacity *= 2;
- tags = xrealloc(tags, capacity * sizeof(tag_t));
- }
-
- tags[len++] = value;
-
- if (json_next_token(&next, stream) == false) {
- free(tags);
- json_token_free(&next);
- return false;
- }
-
- if (next.type == TOK_COMMA) {
- continue;
- } else if (next.type == TOK_RBRACK) {
- break;
- } else {
- free(tags);
- json_token_free(&next);
- return false;
- }
-
- }
-
- tagtype_t type;
- if (json_get_list_type(&type, tags, len) == false) {
- free(tags);
- return false;
- }
-
- data->list.type = type;
- data->list.size = len;
- data->list.tags = xalloc(len * sizeof(tag_t));
- memcpy(data->list.tags, tags, len * sizeof(tag_t));
- free(tags);
-
- return true;
-
-}
-
-static bool json_read_compound(tagdata_t *data, const stream_t *stream) {
-
- map_t map;
- map_init(&map);
-
- token_t next = {0};
- if (json_next_token(&next, stream) == false) {
- json_token_free(&next);
- return false;
- }
-
- if (next.type == TOK_RBRACE) {
- data->compound = map;
- return true;
- }
-
- while (1) {
-
- if (next.type != TOK_STRING) {
- map_free(&map);
- json_token_free(&next);
- return false;
- }
-
- char *name = next.data.string.data;
- int name_len = next.data.string.len;
-
- if (name_len < 1) {
- map_free(&map);
- free(name);
- return false;
- }
-
- if (json_next_token(&next, stream) == false || next.type != TOK_COLON) {
- map_free(&map);
- free(name);
- return false;
- }
-
- tag_t value;
- if (json_read_value(&value, stream, NULL) == false) {
- map_free(&map);
- free(name);
- return false;
- }
-
- value.name = name;
- value.name_len = name_len;
-
- map_put(&map, &value);
-
- if (json_next_token(&next, stream) == false) {
- map_free(&map);
- json_token_free(&next);
- return false;
- }
-
- if (next.type == TOK_COMMA) {
- if (json_next_token(&next, stream) == false) {
- map_free(&map);
- return false;
- }
- continue;
- } else if (next.type == TOK_RBRACE) {
- break;
- } else {
- map_free(&map);
- json_token_free(&next);
- return false;
- }
-
- }
-
- data->compound = map;
-
- return true;
-}
-
-static bool json_read_value(tag_t *tag, const stream_t *stream, token_t *first) {
-
- token_t token;
-
- if (first != NULL)
- token = *first;
- else if (json_next_token(&token, stream) == false)
- return false;
-
- tag->name = "";
- tag->name_len = 0;
-
- bool ok = true;
-
- switch (token.type) {
- case TOK_RBRACK:
- case TOK_RBRACE:
- case TOK_COLON:
- case TOK_COMMA:
- case TOK_NULL:
- ok = false;
- break;
- case TOK_LBRACK:
- tag->type = TAG_LIST;
- ok = json_read_list(&tag->data, stream);
- break;
- case TOK_LBRACE:
- tag->type = TAG_COMPOUND;
- ok = json_read_compound(&tag->data, stream);
- break;
- case TOK_STRING:
- tag->type = TAG_STRING;
- tag->data.string.data = token.data.string.data;
- tag->data.string.size = token.data.string.len;
- break;
- case TOK_NUMBER:
- tag->type = TAG_LONG;
- tag->data.l = token.data.number;
- break;
- case TOK_DOUBLE:
- tag->type = TAG_DOUBLE;
- tag->data.d = token.data.decimal;
- break;
- case TOK_BOOL:
- tag->type = TAG_BYTE;
- tag->data.b = token.data.b ? 1 : 0;
- break;
- }
-
- return ok;
-}
-
-bool json_read(tag_t *tag, const stream_t *stream) {
- return json_read_value(tag, stream, NULL);
-}
diff --git a/src/lib.c b/src/lib.c
deleted file mode 100644
index e6e691a..0000000
--- a/src/lib.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "lib.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-__attribute__((__noreturn__))
-static void die() {
- exit(1);
-}
-
-void error_and_die(char *format, ...) {
- va_list list;
- va_start(list, format);
-
- vfprintf(stderr, format, list);
-
- die();
-}
-
-__attribute__((__noreturn__, format(printf, 1, 2)))
-void perror_and_die(char *format, ...) {
- va_list list;
- va_start(list, format);
-
- vfprintf(stderr, format, list);
- perror(": ");
-
- die();
-}
-
-void *xalloc(size_t amount) {
- void *res = malloc(amount);
- if (res == NULL)
- error_and_die("failed to allocate memory");
- return res;
-}
-
-void *xzalloc(size_t amount) {
- void *res = xalloc(amount);
- memset(res, 0, sizeof(amount));
- return res;
-}
-
-void *xrealloc(void *ptr, size_t amount) {
- void *res = realloc(ptr, amount);
- if (res == NULL)
- error_and_die("failed to allocate memory");
- return res;
-}
diff --git a/src/lib.h b/src/lib.h
deleted file mode 100644
index 35cbc3c..0000000
--- a/src/lib.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-#include <stddef.h>
-
-__attribute__((__noreturn__, format(printf, 1, 2)))
-void error_and_die(char *format, ...);
-
-__attribute__((__noreturn__, format(printf, 1, 2)))
-void perror_and_die(char *format, ...);
-
-void *xalloc(size_t amount);
-void *xzalloc(size_t amount);
-void *xrealloc(void *ptr, size_t amount);
diff --git a/src/main.c b/src/main.c
index d49e5b6..010a262 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,20 +1,19 @@
#include "lib.h"
#include "stream.h"
-#include "tag.h"
#include "flags.h"
#include <stdio.h>
#include <stdlib.h>
__attribute__((__noreturn__))
-void version() {
+void version(void) {
fprintf(stderr, "nbtvis v0.0.1\n");
fprintf(stderr, "Copyright (C) 2023 Freya Murphy\n");
exit(0);
}
__attribute__((__noreturn__))
-void help() {
+void help(void) {
fprintf(stderr, "Usage: nbtvis [OPTION]... [INFILE] [OUTFILE]\n\n");
fprintf(stderr, "\t-j\tinput data is JSON\n");
fprintf(stderr, "\t-s\tinput data is SNBT\n");
diff --git a/src/map.c b/src/map.c
deleted file mode 100644
index 0c6d4f2..0000000
--- a/src/map.c
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "map.h"
-#include "lib.h"
-#include "tag.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-void map_init(map_t *map) {
- map->len = 0;
- map->capacity = 0;
- map->entries = NULL;
-}
-
-void map_free(map_t *map) {
- if (map->entries == NULL)
- return;
- for (uint32_t i = 0; i < map->capacity; i++) {
- if (map->entries[i].name != NULL)
- tag_free(&map->entries[i]);
- }
- free(map->entries);
-}
-
-static uint32_t hash(const char *name, uint16_t len) {
- uint32_t hash = 2166136261u;
- while(len > 0) {
- hash ^= (uint8_t)(*name);
- hash *= 16777619;
- name++;
- len--;
- }
- return hash;
-}
-
-static tag_t *map_find(tag_t *entries, uint32_t capacity, tag_t *tag) {
- uint32_t index = hash(tag->name, tag->name_len) % capacity;
- while(true) {
- tag_t *entry = &entries[index];
- if (entry->name == NULL) {
- return entry;
- } else if (
- entry->name_len == tag->name_len &&
- memcmp(entry->name, tag->name, tag->name_len) == 0
- ) {
- return entry;
- }
- index += 1;
- index %= capacity;
- }
-}
-
-static void map_grow(map_t *map, uint32_t capacity) {
- tag_t *entries = xzalloc(capacity * sizeof(tag_t));
- for (uint32_t i = 0; i < capacity; i++) {
- entries[i].name = NULL;
- entries[i].name_len = 0;
- }
- map->len = 0;
- for (uint32_t i = 0; i < map->capacity; i++) {
- tag_t *tag = &map->entries[i];
- if (tag->name == NULL) continue;
-
- tag_t *dest = map_find(entries, capacity, tag);
- *dest = *tag;
- map->len++;
- }
- free(map->entries);
-
- map->entries = entries;
- map->capacity = capacity;
-}
-
-void map_put(map_t *map, tag_t *tag) {
- if (map->len + 1 > map->capacity * 0.75) {
- int capacity = (map->capacity == 0 ? 8 : (2 * map->capacity));
- map_grow(map, capacity);
- }
- tag_t *dest = map_find(map->entries, map->capacity, tag);
- if (dest->name == NULL) {
- map->len++;
- } else {
- tag_free(dest);
- }
- *dest = *tag;
-}
diff --git a/src/map.h b/src/map.h
deleted file mode 100644
index 6672323..0000000
--- a/src/map.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-
-typedef struct tag_t tag_t;
-
-typedef struct {
- uint32_t len;
- uint32_t capacity;
- tag_t *entries;
-} map_t;
-
-void map_init(map_t *map);
-void map_free(map_t *map);
-void map_put(map_t *map, tag_t *tag);
diff --git a/src/nbt/nbt.h b/src/nbt/nbt.h
deleted file mode 100644
index 13c0606..0000000
--- a/src/nbt/nbt.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#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
deleted file mode 100644
index 3f687dc..0000000
--- a/src/nbt/print.c
+++ /dev/null
@@ -1,127 +0,0 @@
-#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 (uint32_t i = 0; i < data->compound.capacity; i++) {
- if (data->compound.entries[i].name == NULL) continue;
- if (nbt_print(&data->compound.entries[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
deleted file mode 100644
index 38f8b14..0000000
--- a/src/nbt/read.c
+++ /dev/null
@@ -1,207 +0,0 @@
-#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) {
-
- map_t map;
- map_init(&map);
-
- while (1) {
-
- tag_t tag;
-
- if (nbt_read_header(&tag, stream, true) == false) {
- map_free(&map);
- return false;
- }
-
- if (tag.type == TAG_END)
- break;
-
- if (tag.name_len < 1) {
- map_free(&map);
- return false;
- }
-
- if (nbt_read_data(&tag, stream) == false) {
- map_free(&map);
- return false;
- }
-
- map_put(&map, &tag);
- }
-
- data->compound = map;
-
- 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;
-}
-
diff --git a/src/snbt/print.c b/src/snbt/print.c
deleted file mode 100644
index 9dec75c..0000000
--- a/src/snbt/print.c
+++ /dev/null
@@ -1,210 +0,0 @@
-#include "snbt.h"
-#include <stdarg.h>
-#include <stdio.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 snbt_print_impl(const tag_t *tag, const stream_t *stream, int depth);
-
-static bool snbt_print_byte_array(const tagdata_t *data, const stream_t *stream) {
- if (printi(stream, 0, "[B;") == 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, "%hhdb", data->b_arr.data[i]) == false)
- return false;
- }
- if (printi(stream, 0, "]") == false)
- return false;
- return true;
-}
-
-static bool snbt_print_int_array(const tagdata_t *data, const stream_t *stream) {
- if (printi(stream, 0, "[I;") == 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 snbt_print_long_array(const tagdata_t *data, const stream_t *stream) {
- if (printi(stream, 0, "[L;") == 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, "%ldL", data->l_arr.data[i]) == false)
- return false;
- }
- if (printi(stream, 0, "]") == false)
- return false;
- return true;
-}
-
-static bool snbt_string_unquoted(const char *text, uint16_t len) {
- for (uint16_t i = 0; i < len; i++) {
- char c = text[i];
- if (snbt_allowed_ident(c))
- continue;
- return false;
- }
- return true;
-}
-
-static bool snbt_print_string_impl(const stream_t *stream, int depth, char *text, uint16_t len) {
- if (len > 0 && snbt_string_unquoted(text, len)) {
- if (printi(stream, depth, "%.*s", len, text) == false)
- return false;
- } else if (len > 0) {
- if (printi(stream, depth, "\"") == false)
- return false;
- for (uint16_t i = 0; i < len; i++) {
- char c = text[i];
- if (c == '\\' || c == '"') {
- if (printi(stream, 0, "\\%c", c) == false)
- return false;
- } else {
- if (printi(stream, 0, "%c", c) == false)
- return false;
- }
- }
- if (printi(stream, 0, "\"") == false)
- return false;
- } else {
- if (printi(stream, depth, "''") == false)
- return false;
- }
- return true;
-}
-
-static bool snbt_print_string(const tagdata_t *data, const stream_t *stream) {
- char *text = data->string.data;
- uint16_t len = data->string.size;
- return snbt_print_string_impl(stream, 0, text, len);
-}
-
-static bool snbt_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 (snbt_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 snbt_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 (snbt_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 snbt_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, "%hhdb", tag->data.b);
- break;
- case TAG_SHORT:
- ok = printi(stream, 0, "%hds", tag->data.s);
- break;
- case TAG_INT:
- ok = printi(stream, 0, "%d", tag->data.i);
- break;
- case TAG_LONG:
- ok = printi(stream, 0, "%ldL", tag->data.l);
- break;
- case TAG_FLOAT:
- ok = printi(stream, 0, "%.9gf", tag->data.f);
- break;
- case TAG_DOUBLE:
- ok = printi(stream, 0, "%.17g", tag->data.d);
- break;
- case TAG_BYTE_ARRAY:
- ok = snbt_print_byte_array(&tag->data, stream);
- break;
- case TAG_STRING:
- ok = snbt_print_string(&tag->data, stream);
- break;
- case TAG_LIST:
- ok = snbt_print_list(&tag->data, stream, depth);
- break;
- case TAG_COMPOUND:
- ok = snbt_print_compound(&tag->data, stream, depth);
- break;
- case TAG_INT_ARRAY:
- ok = snbt_print_int_array(&tag->data, stream);
- break;
- case TAG_LONG_ARRAY:
- ok = snbt_print_long_array(&tag->data, stream);
- break;
- case TAG_END:
- break;
- }
-
- return ok;
-}
-
-static bool snbt_print_impl(const tag_t *tag, const stream_t *stream, int depth) {
- if (tag->name_len > 0) {
- if (snbt_print_string_impl(stream, depth, tag->name, tag->name_len) == false)
- return false;
- if (printi(stream, 0, ": ") == false)
- return false;
- } else {
- for (int i = 0; i < depth; i++)
- printi(stream, 0, "\t");
- }
- return snbt_print_data(tag, stream, depth);
-}
-
-bool snbt_print(const tag_t *tag, const stream_t *stream) {
- if (snbt_print_impl(tag, stream, 0) == false)
- return false;
- if (stream_write(stream, "\n", 1) == false)
- return false;
- return true;
-}
diff --git a/src/snbt/read.c b/src/snbt/read.c
deleted file mode 100644
index 231404a..0000000
--- a/src/snbt/read.c
+++ /dev/null
@@ -1,740 +0,0 @@
-#include "snbt.h"
-#include "../lib.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-typedef enum {
- TOK_RBRACE,
- TOK_LBRACE,
- TOK_RBRACK,
- TOK_LBRACK,
- TOK_COMMA,
- TOK_COLON,
- TOK_SEMI_COLON,
- TOK_STRING,
- TOK_IDENT,
-} tokentype_t;
-
-typedef union {
- struct {
- char *data;
- uint16_t len;
- } text;
- double d;
- int64_t l;
-} tokendata_t;
-
-typedef struct {
- tokentype_t type;
- tokendata_t data;
-} token_t;
-
-static char ret = '\0';
-
-static void snbt_free_token(token_t *token) {
- if (token->type == TOK_IDENT || token->type == TOK_STRING) {
- free(token->data.text.data);
- }
-}
-
-static bool snbt_parse_string(token_t *token, const stream_t *stream, char delimiter) {
- int len = 0;
- int capacity = 8;
- char *buf = xalloc(capacity * sizeof(char));
-
- while (1) {
- char c;
- if (stream_read(stream, &c, 1) == false) {
- free(buf);
- return false;
- }
-
- if (c == delimiter)
- break;
-
- if (c == '\\') {
- if (stream_read(stream, &c, 1) == false) {
- free(buf);
- return false;
- }
-
- if (c != '\\' && c != delimiter) {
- free(buf);
- return false;
- }
- }
-
- if (len == capacity) {
- capacity *= 2;
- buf = xrealloc(buf, capacity);
- }
-
- buf[len++] = c;
- }
-
- token->data.text.data = xalloc(len * sizeof(char));
- token->data.text.len = len;
- memcpy(token->data.text.data, buf, len * sizeof(char));
- free(buf);
-
- return true;
-}
-
-bool snbt_allowed_ident(char c) {
- if (c >= '0' && c <= '9')
- return true;
- if (c >= 'a' && c <= 'z')
- return true;
- if (c >= 'A' && c <= 'Z')
- return true;
- if (c == '_' || c == '-' || c == '.' || c == '+')
- return true;
- return false;
-}
-
-static bool snbt_parse_ident(token_t *token, const stream_t *stream, char first) {
- int len = 0;
- int capacity = 8;
- char *buf = xalloc(capacity * sizeof(char));
-
- buf[len++] = first;
-
- while (1) {
- char c;
- if (stream_read(stream, &c, 1) == false) {
- free(buf);
- return false;
- }
-
- if (snbt_allowed_ident(c) == false) {
- if (len == 0) {
- free(buf);
- return false;
- } else {
- ret = c;
- break;
- }
- }
-
- if (len == capacity) {
- capacity *= 2;
- buf = xrealloc(buf, capacity);
- }
-
- buf[len++] = c;
- }
-
- token->data.text.data = xalloc(len * sizeof(char));
- token->data.text.len = len;
- memcpy(token->data.text.data, buf, len * sizeof(char));
- free(buf);
-
- return true;
-}
-
-static bool snbt_next_token(token_t *token, const stream_t *stream) {
-
- memset(token, 0, sizeof(token_t));
-
- char c;
- bool ok = true;
-
-retry:
-
- c = ret;
- ret = '\0';
-
- if (c == '\0' && stream_read(stream, &c, 1) == false)
- return false;
-
- switch (c) {
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- goto retry;
- case '{':
- token->type = TOK_LBRACE;
- break;
- case '}':
- token->type = TOK_RBRACE;
- break;
- case '[':
- token->type = TOK_LBRACK;
- break;
- case ']':
- token->type = TOK_RBRACK;
- break;
- case ':':
- token->type = TOK_COLON;
- break;
- case ';':
- token->type = TOK_SEMI_COLON;
- break;
- case ',':
- token->type = TOK_COMMA;
- break;
- case '"':
- case '\'':
- token->type = TOK_STRING;
- ok = snbt_parse_string(token, stream, c);
- break;
- default:
- token->type = TOK_IDENT;
- ok = snbt_parse_ident(token, stream, c);
- break;
- }
-
- return ok;
-}
-
-static bool snbt_read_value(tag_t *tag, const stream_t *stream, token_t *first);
-static bool snbt_convert_ident(tag_t *tag, token_t token);
-
-static bool snbt_read_byte_array(tag_t *tag, const stream_t *stream) {
- int capacity = 8;
- int len = 0;
- int8_t *buf = xalloc(capacity * sizeof(int8_t));
-
- while(1) {
- tag_t value;
- if (snbt_read_value(&value, stream, NULL) == false) {
- free(buf);
- return false;
- }
-
- if (value.type != TAG_BYTE) {
- tag_free(&value);
- free(buf);
- return false;
- }
- if (len == capacity) {
- capacity *= 2;
- buf = xrealloc(buf, capacity * sizeof(int8_t));
- }
- buf[len++] = value.data.b;
- token_t token;
- if (snbt_next_token(&token, stream) == false) {
- free(buf);
- return false;
- }
- if (token.type == TOK_COMMA)
- continue;
- if (token.type == TOK_RBRACK)
- break;
- free(buf);
- return false;
- }
- tag->type = TAG_BYTE_ARRAY;
- tag->data.b_arr.data = xalloc(len * sizeof(int8_t));
- tag->data.b_arr.size = len;
- memcpy(tag->data.b_arr.data, buf, len * sizeof(int8_t));
- free(buf);
-
- return true;
-}
-
-static bool snbt_read_int_array(tag_t *tag, const stream_t *stream) {
- int capacity = 8;
- int len = 0;
- int32_t *buf = xalloc(capacity * sizeof(int32_t));
-
- while(1) {
- tag_t value;
- if (snbt_read_value(&value, stream, NULL) == false) {
- free(buf);
- return false;
- }
- if (value.type != TAG_INT) {
- tag_free(&value);
- free(buf);
- return false;
- }
- if (len == capacity) {
- capacity *= 2;
- buf = xrealloc(buf, capacity * sizeof(int32_t));
- }
- buf[len++] = value.data.i;
- token_t token;
- if (snbt_next_token(&token, stream) == false) {
- free(buf);
- return false;
- }
- if (token.type == TOK_COMMA)
- continue;
- if (token.type == TOK_RBRACK)
- break;
- free(buf);
- return false;
- }
- tag->type = TAG_INT_ARRAY;
- tag->data.i_arr.data = xalloc(len * sizeof(int32_t));
- tag->data.i_arr.size = len;
- memcpy(tag->data.i_arr.data, buf, len * sizeof(int32_t));
- free(buf);
-
- return true;
-}
-
-static bool snbt_read_long_array(tag_t *tag, const stream_t *stream) {
- int capacity = 8;
- int len = 0;
- int64_t *buf = xalloc(capacity * sizeof(int64_t));
-
- while(1) {
- tag_t value;
- if (snbt_read_value(&value, stream, NULL) == false) {
- free(buf);
- return false;
- }
- if (value.type != TAG_LONG) {
- tag_free(&value);
- free(buf);
- return false;
- }
- if (len == capacity) {
- capacity *= 2;
- buf = xrealloc(buf, capacity * sizeof(int64_t));
- }
- buf[len++] = value.data.l;
- token_t token;
- if (snbt_next_token(&token, stream) == false) {
- free(buf);
- return false;
- }
- if (token.type == TOK_COMMA)
- continue;
- if (token.type == TOK_RBRACK)
- break;
- free(buf);
- return false;
- }
- tag->type = TAG_LONG_ARRAY;
- tag->data.l_arr.data = xalloc(len * sizeof(int64_t));
- tag->data.l_arr.size = len;
- memcpy(tag->data.l_arr.data, buf, len * sizeof(int64_t));
- free(buf);
-
- return true;
-}
-
-static bool snbt_read_array(tag_t *tag, tagtype_t type, const stream_t *stream) {
- switch(type) {
- case TAG_BYTE:
- return snbt_read_byte_array(tag, stream);
- case TAG_INT:
- return snbt_read_int_array(tag, stream);
- case TAG_LONG:
- return snbt_read_long_array(tag, stream);
- default:
- return false;
- }
-}
-
-static bool snbt_read_list(tag_t *tag, tag_t *first, token_t *tok_sav, const stream_t *stream) {
- int capacity = 8;
- int len = 0;
- tag_t *tags = xalloc(sizeof(tag_t) * capacity);
- tagtype_t type = TAG_END;
-
- if (first != NULL) {
- first->name_len = 0;
- first->name = "";
- tags[len++] = *first;
- type = first->type;
- goto endcheck;
- }
-
- if (tok_sav == NULL) {
- if (snbt_next_token(tok_sav, stream) == false) {
- free(tags);
- return false;
- }
- if (tok_sav->type == TOK_RBRACK) {
- goto end;
- }
- }
-
- while(1) {
-
- tag_t value;
- token_t check;
-
- if (snbt_read_value(&value, stream, tok_sav) == false) {
- snbt_free_token(tok_sav);
- free(tags);
- return false;
- }
-
- tok_sav = NULL;
-
- if (type != TAG_END && value.type != type) {
- free(tags);
- return false;
- }
-
- if (len == capacity) {
- capacity *= 2;
- tags = xrealloc(tags, capacity * sizeof(tag_t));
- }
-
- tags[len++] = value;
-
-endcheck:
-
- if (snbt_next_token(&check, stream) == false) {
- free(tags);
- return false;
- }
-
- if (check.type == TOK_COMMA)
- continue;
-
- if (check.type == TOK_RBRACK)
- break;
-
- free(tags);
- return false;
- }
-end:
- tag->type = TAG_LIST;
- tag->data.list.type = type;
- tag->data.list.size = len;
- tag->data.list.tags = xalloc(len * sizeof(tag_t));
- memcpy(tag->data.list.tags, tags, len *sizeof(tag_t));
- free(tags);
-
- return true;
-}
-
-static bool snbt_read_collection(tag_t *tag, const stream_t *stream) {
-
- token_t first;
-
- if (snbt_next_token(&first, stream) == false)
- return false;
-
- if (first.type == TOK_RBRACK) {
- tag->type = TAG_LIST;
- tag->data.list.type = TAG_END;
- tag->data.list.size = 0;
- tag->data.list.tags = NULL;
- return true;
- }
-
- if (first.type == TOK_IDENT && first.data.text.len == 1) {
- tagtype_t type;
- char c = first.data.text.data[0];
- switch (c) {
- case 'B':
- type = TAG_BYTE;
- break;
- case 'I':
- type = TAG_INT;
- break;
- case 'L':
- type = TAG_LONG;
- break;
- default: {
- tag_t new;
- if (snbt_convert_ident(&new, first) == false) {
- snbt_free_token(&first);
- return false;
- }
- return snbt_read_list(tag, &new, NULL, stream);
- }
- }
-
- token_t second;
- if (snbt_next_token(&second, stream) == false) {
- snbt_free_token(&first);
- return false;
- }
-
- if (second.type == TOK_COMMA) {
- tag_t new;
- new.type = TAG_STRING;
- new.data.string.data = first.data.text.data;
- new.data.string.size = first.data.text.len;
- return snbt_read_list(tag, &new, NULL, stream);
- }
-
- snbt_free_token(&first);
-
- if (second.type == TOK_SEMI_COLON) {
- return snbt_read_array(tag, type, stream);
- }
-
- snbt_free_token(&second);
- return false;
-
- }
-
- return snbt_read_list(tag, NULL, &first, stream);
-}
-
-static bool snbt_read_compound(tagdata_t *data, const stream_t *stream) {
- map_t map;
- map_init(&map);
-
- token_t next = {0};
- if (snbt_next_token(&next, stream) == false) {
- snbt_free_token(&next);
- return false;
- }
-
- if (next.type == TOK_RBRACE) {
- data->compound = map;
- return true;
- }
-
- while (1) {
-
- if (next.type != TOK_STRING && next.type != TOK_IDENT) {
- map_free(&map);
- snbt_free_token(&next);
- return false;
- }
-
- char *name = next.data.text.data;
- int name_len = next.data.text.len;
-
- if (name_len < 1) {
- map_free(&map);
- free(name);
- return false;
- }
-
- if (snbt_next_token(&next, stream) == false || next.type != TOK_COLON) {
- map_free(&map);
- free(name);
- return false;
- }
-
- tag_t value;
- if (snbt_read_value(&value, stream, NULL) == false) {
- map_free(&map);
- free(name);
- return false;
- }
-
- value.name = name;
- value.name_len = name_len;
-
- map_put(&map, &value);
-
- if (snbt_next_token(&next, stream) == false) {
- map_free(&map);
- snbt_free_token(&next);
- return false;
- }
-
- if (next.type == TOK_COMMA) {
- if (snbt_next_token(&next, stream) == false) {
- map_free(&map);
- return false;
- }
- continue;
- } else if (next.type == TOK_RBRACE) {
- break;
- } else {
- map_free(&map);
- snbt_free_token(&next);
- return false;
- }
-
- }
-
- data->compound = map;
-
- return true;
-}
-
-static bool snbt_convert_decimal(tag_t *tag, char *text) {
- uint16_t len = strlen(text);
-
- char *end = NULL;
-
- double d = strtod(text, &end);
-
- char c = *end;
- bool check1 = end == &text[len - 1] && (
- c == 'f' ||
- c == 'F' ||
- c == 'd' ||
- c == 'D'
- );
- bool check2 = end == &text[len] && c == '\0';
- if (!check1 && !check2) {
- return false;
- }
-
- if (tag->type == TAG_FLOAT) {
- tag->data.f = (float)d;
- } else {
- tag->data.d = d;
- }
-
- return true;
-}
-
-static bool snbt_convert_int(tag_t *tag, char *text) {
- uint16_t len = strlen(text);
-
- char *end = NULL;
-
- uint64_t i = strtol(text, &end, 10);
-
- char c = *end;
- bool check1 = end == &text[len - 1] && (
- c == 'b' ||
- c == 'B' ||
- c == 's' ||
- c == 'S' ||
- c == 'l' ||
- c == 'L'
- );
- bool check2 = end == &text[len] && c == '\0';
- if (!check1 && !check2) {
- return false;
- }
-
- if (tag->type == TAG_BYTE) {
- tag->data.b = (uint8_t)i;
- } else if (tag->type == TAG_SHORT) {
- tag->data.s = (uint16_t)i;
- } else if (tag->type == TAG_INT) {
- tag->data.i = (uint32_t)i;
- } else {
- tag->data.l = i;
- }
-
- return true;
-}
-
-static bool snbt_convert_ident(tag_t *tag, token_t token) {
- uint16_t len = token.data.text.len + 1;
- char *text = xalloc(len * sizeof(char));
- memcpy(text, token.data.text.data, len - 1);
- text[len - 1] = '\0';
-
- if (len == 4 && memcmp(text, "true", 4) == 0) {
- tag->type = TAG_BYTE;
- tag->data.b = 1;
- } else if (len == 5 && memcmp(text, "false", 5) == 0) {
- tag->type = TAG_BYTE;
- tag->data.b = 0;
- }
-
- // try to parse as a number lol he he ha ha
- char end = text[len - 2];
-
- bool ok = false;
-
- switch (end) {
- case 'f':
- case 'F':
- tag->type = TAG_FLOAT;
- ok = snbt_convert_decimal(tag, text);
- break;
- case 'd':
- case 'D':
- tag->type = TAG_DOUBLE;
- ok = snbt_convert_decimal(tag, text);
- break;
- case 'b':
- case 'B':
- tag->type = TAG_BYTE;
- ok = snbt_convert_int(tag, text);
- break;
- case 's':
- case 'S':
- tag->type = TAG_SHORT;
- ok = snbt_convert_int(tag, text);
- break;
- case 'l':
- case 'L':
- tag->type = TAG_LONG;
- ok = snbt_convert_int(tag, text);
- break;
- default:
- break;
- }
-
- if (ok) {
- free(text);
- snbt_free_token(&token);
- return true;
- }
-
- // unkown type try long >> double >> string (fallback)
-
- tag->type = TAG_INT;
- if (snbt_convert_int(tag, text) == true) {
- free(text);
- snbt_free_token(&token);
- return true;
- }
-
- tag->type = TAG_DOUBLE;
- if (snbt_convert_decimal(tag, text) == true) {
- free(text);
- snbt_free_token(&token);
- return true;
- }
-
- tag->type = TAG_STRING;
- tag->data.string.data = token.data.text.data;
- tag->data.string.size = token.data.text.len;
- free(text);
- return true;
-}
-
-static bool snbt_read_value(tag_t *tag, const stream_t *stream, token_t *first) {
-
- token_t token;
-
- if (first != NULL)
- token = *first;
- else if (snbt_next_token(&token, stream) == false)
- return false;
-
- tag->name = "";
- tag->name_len = 0;
-
- bool ok = true;
-
- switch (token.type) {
- case TOK_RBRACK:
- case TOK_RBRACE:
- case TOK_COLON:
- case TOK_SEMI_COLON:
- case TOK_COMMA:
- ok = false;
- break;
- case TOK_LBRACK:
- tag->type = TAG_LIST;
- ok = snbt_read_collection(tag, stream);
- break;
- case TOK_LBRACE:
- tag->type = TAG_COMPOUND;
- ok = snbt_read_compound(&tag->data, stream);
- break;
- case TOK_STRING:
- tag->type = TAG_STRING;
- tag->data.string.data = token.data.text.data;
- tag->data.string.size = token.data.text.len;
- break;
- case TOK_IDENT:
- ok = snbt_convert_ident(tag, token);
- break;
- }
-
- return ok;
-}
-
-bool snbt_read(tag_t *tag, const stream_t *stream) {
- return snbt_read_value(tag, stream, NULL);
-}
diff --git a/src/snbt/snbt.h b/src/snbt/snbt.h
deleted file mode 100644
index 4b367bc..0000000
--- a/src/snbt/snbt.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "../tag.h"
-#include "../stream.h"
-
-bool snbt_read(tag_t *tag, const stream_t *stream);
-bool snbt_print(const tag_t *tag, const stream_t *stream);
-
-bool snbt_allowed_ident(char c);
diff --git a/src/stream.c b/src/stream.c
deleted file mode 100644
index 6780d02..0000000
--- a/src/stream.c
+++ /dev/null
@@ -1,144 +0,0 @@
-#include "stream.h"
-#include "lib.h"
-
-#include <errno.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static uint64_t longswap(uint64_t ll) {
- if (htons(20) == 20)
- return ll;
-
- union { uint64_t ll; uint8_t c[8]; } out = {0};
- union { uint64_t ll; uint8_t c[8]; } in = {ll};
-
- for (int i = 0; i < 8; i++)
- out.c[7-i] = in.c[i];
-
- return out.ll;
-}
-
-
-stream_t stream_open(const char *path, const char* mode) {
- stream_t stream;
-
- if (strcmp("-", path) == 0) {
- if (*mode == 'r')
- stream.__file = stdin;
- else
- stream.__file = stdout;
- stream.__alloc = false;
- return stream;
- }
-
- stream.__file = fopen(path, mode);
- stream.__alloc = true;
-
- if (stream.__file == NULL) {
- perror_and_die("cannot open '%s'", path);
- };
-
- return stream;
-}
-
-void stream_close(stream_t *stream) {
- if (stream->__alloc)
- fclose(stream->__file);
-}
-
-bool stream_read(const stream_t *stream, void *res, size_t amount) {
- size_t read;
- read = fread(res, 1, amount, stream->__file);
-
- if (read == 0) {
- if (feof(stream->__file) || errno == 0)
- return false;
- else
- perror_and_die("cannot read from stream");
- }
-
- return true;
-}
-
-bool stream_read_i8(const stream_t *stream, int8_t *res) {
- if (stream_read(stream, res, 1) == false)
- return false;
- return true;
-}
-
-bool stream_read_i16(const stream_t *stream, int16_t *res) {
- if (stream_read(stream, res, 2) == false)
- return false;
- *res = ntohs(*res);
- return true;
-}
-
-bool stream_read_i32(const stream_t *stream, int32_t *res) {
- if (stream_read(stream, res, 4) == false)
- return false;
- *res = ntohl(*res);
- return true;
-}
-
-bool stream_read_i64(const stream_t *stream, int64_t *res) {
- if (stream_read(stream, res, 8) == false)
- return false;
- *res = longswap(*res);
- return true;
-}
-
-bool stream_read_u16(const stream_t *stream, uint16_t *res) {
- if (stream_read(stream, res, 2) == false)
- return false;
- *res = ntohs(*res);
- return true;
-}
-
-bool stream_write(const stream_t *stream, const void *buf, size_t amount) {
- size_t wrote;
- wrote = fwrite(buf, 1, amount, stream->__file);
-
- if (wrote == 0)
- perror_and_die("cannot write to stream");
-
- if (wrote < amount)
- return false;
-
- return true;
-}
-
-bool stream_write_i8(const stream_t *stream, int8_t b) {
- if (stream_write(stream, &b, 1) == false)
- return false;
- return true;
-}
-
-bool stream_write_i16(const stream_t *stream, int16_t s) {
- s = htons(s);
- if (stream_write(stream, &s, 2) == false)
- return false;
- return true;
-}
-
-bool stream_write_i32(const stream_t *stream, int32_t i) {
- i = htonl(i);
- if (stream_write(stream, &i, 4) == false)
- return false;
- return true;
-}
-
-bool stream_write_i64(const stream_t *stream, int64_t l) {
- l = longswap(l);
- if (stream_write(stream, &l, 8) == false)
- return false;
- return true;
-}
-
-bool stream_write_u16(const stream_t *stream, uint16_t s) {
- s = htons(s);
- if (stream_write(stream, &s, 2) == false)
- return false;
- return true;
-}
diff --git a/src/stream.h b/src/stream.h
deleted file mode 100644
index 7dc5407..0000000
--- a/src/stream.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdbool.h>
-
-typedef struct {
- FILE *__file;
- bool __alloc;
- char peakbuf[16];
- int peakamt;
-} stream_t;
-
-stream_t stream_open(const char *path, const char* mode);
-void stream_close(stream_t *stream);
-
-bool stream_read(const stream_t *stream, void *res, size_t amount);
-bool stream_read_i8(const stream_t *stream, int8_t *res);
-bool stream_read_i16(const stream_t *stream, int16_t *res);
-bool stream_read_i32(const stream_t *stream, int32_t *res);
-bool stream_read_i64(const stream_t *stream, int64_t *res);
-bool stream_read_u16(const stream_t *stream, uint16_t *res);
-
-bool stream_write(const stream_t *stream, const void *buf, size_t amount);
-bool stream_write_i8(const stream_t *stream, int8_t b);
-bool stream_write_i16(const stream_t *stream, int16_t s);
-bool stream_write_i32(const stream_t *stream, int32_t i);
-bool stream_write_i64(const stream_t *stream, int64_t l);
-bool stream_write_u16(const stream_t *stream, uint16_t s);
diff --git a/src/tag.c b/src/tag.c
deleted file mode 100644
index 8f1502c..0000000
--- a/src/tag.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include "tag.h"
-#include "map.h"
-#include "nbt/nbt.h"
-#include "snbt/snbt.h"
-#include "json/json.h"
-
-#include <stdlib.h>
-
-void tag_free(tag_t *tag) {
- if (tag->name_len > 0 && tag->name != NULL)
- free(tag->name);
- switch(tag->type) {
- case TAG_END:
- case TAG_BYTE:
- case TAG_SHORT:
- case TAG_INT:
- case TAG_LONG:
- case TAG_FLOAT:
- case TAG_DOUBLE:
- break;
- case TAG_BYTE_ARRAY:
- free(tag->data.b_arr.data);
- break;
- case TAG_STRING:
- free(tag->data.string.data);
- break;
- case TAG_LIST:
- for (int32_t i = 0; i < tag->data.list.size; i++)
- tag_free(&tag->data.list.tags[i]);
- free(tag->data.list.tags);
- break;
- case TAG_COMPOUND:
- map_free(&tag->data.compound);
- break;
- case TAG_INT_ARRAY:
- free(tag->data.i_arr.data);
- break;
- case TAG_LONG_ARRAY:
- free(tag->data.l_arr.data);
- break;
- }
-}
-
-bool tag_read(tag_t *tag, const stream_t *stream, format_t format) {
- switch (format) {
- case JSON:
- return json_read(tag, stream);
- case NBT:
- return nbt_read(tag, stream);
- case SNBT:
- return snbt_read(tag, stream);
- default:
- return false;
- }
-}
-
-bool tag_print(tag_t *tag, const stream_t *stream, format_t format) {
- switch (format) {
- case JSON:
- return json_print(tag, stream);
- case NBT:
- return nbt_print(tag, stream);
- case SNBT:
- return snbt_print(tag, stream);
- default:
- return false;
- }
-}
diff --git a/src/tag.h b/src/tag.h
deleted file mode 100644
index 81d1950..0000000
--- a/src/tag.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#pragma once
-
-#include "stream.h"
-#include "map.h"
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <unistd.h>
-
-typedef enum: int8_t {
- TAG_END = 0,
- TAG_BYTE = 1,
- TAG_SHORT = 2,
- TAG_INT = 3,
- TAG_LONG = 4,
- TAG_FLOAT = 5,
- TAG_DOUBLE = 6,
- TAG_BYTE_ARRAY = 7,
- TAG_STRING = 8,
- TAG_LIST = 9,
- TAG_COMPOUND = 10,
- TAG_INT_ARRAY = 11,
- TAG_LONG_ARRAY = 12
-} tagtype_t ;
-
-struct tag_t;
-
-typedef union {
- int8_t b;
- int16_t s;
- int32_t i;
- int64_t l;
- float f;
- double d;
- struct {
- int32_t size;
- int8_t *data;
- } b_arr;
- struct {
- uint16_t size;
- char *data;
- } string;
- struct {
- tagtype_t type;
- int32_t size;
- struct tag_t *tags;
- } list;
- map_t compound;
- struct {
- int32_t size;
- int32_t *data;
- } i_arr;
- struct {
- int32_t size;
- int64_t *data;
- } l_arr;
-} tagdata_t;
-
-typedef struct tag_t {
- tagtype_t type;
- tagdata_t data;
- uint16_t name_len;
- char *name;
-} tag_t;
-
-typedef enum {
- JSON,
- NBT,
- SNBT
-} format_t;
-
-void tag_free(tag_t *tag);
-bool tag_read(tag_t *tag, const stream_t *stream, format_t format);
-bool tag_print(tag_t *tag, const stream_t *stream, format_t format);
-