diff options
author | Freya Murphy <freya@freyacat.org> | 2023-12-17 11:10:04 -0500 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2023-12-17 11:10:04 -0500 |
commit | e0eacfa9773c83850ed5169d1e889ff845180581 (patch) | |
tree | 9f8bb433404ce7e4dda1b86ca4dd5d5a2fba10e9 /src/snbt/read.c | |
parent | snbt (diff) | |
download | nbtvis-main.tar.gz nbtvis-main.tar.bz2 nbtvis-main.zip |
Diffstat (limited to 'src/snbt/read.c')
-rw-r--r-- | src/snbt/read.c | 740 |
1 files changed, 0 insertions, 740 deletions
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); -} |