diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/flags.c | 1 | ||||
-rw-r--r-- | src/flags.h | 2 | ||||
-rw-r--r-- | src/json/json.h | 7 | ||||
-rw-r--r-- | src/json/print.c | 177 | ||||
-rw-r--r-- | src/json/read.c | 632 | ||||
-rw-r--r-- | src/lib.c | 51 | ||||
-rw-r--r-- | src/lib.h | 13 | ||||
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/map.c | 86 | ||||
-rw-r--r-- | src/map.h | 15 | ||||
-rw-r--r-- | src/nbt/nbt.h | 7 | ||||
-rw-r--r-- | src/nbt/print.c | 127 | ||||
-rw-r--r-- | src/nbt/read.c | 207 | ||||
-rw-r--r-- | src/snbt/print.c | 210 | ||||
-rw-r--r-- | src/snbt/read.c | 740 | ||||
-rw-r--r-- | src/snbt/snbt.h | 9 | ||||
-rw-r--r-- | src/stream.c | 144 | ||||
-rw-r--r-- | src/stream.h | 29 | ||||
-rw-r--r-- | src/tag.c | 68 | ||||
-rw-r--r-- | src/tag.h | 77 |
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); @@ -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); - |