/* This software is licensed by the MIT License, see LICENSE file */ /* Copyright © 2022 Gregory Lirent */ #include #include #include #include #include "buffer.h" #include "../modules/libcdsb/include/list.h" #include "../modules/libcdsb/include/map.h" #include "../modules/libcdsb/include/string.h" typedef struct { FILE* stream; char cur; } reader_t; #define next libcjsonp_builtin_read_next #define next_sign libcjsonp_builtin_read_next_sign static bool libcjsonp_builtin_parse(value_t* x, reader_t* s); static inline char libcjsonp_builtin_read_next(reader_t *x) { int cur = fgetc(x->stream); return x->cur = (cur == EOF) ? 0 : cur; } static inline char libcjsonp_builtin_read_next_sign(reader_t *x) { for (int cur;;) { switch (cur = fgetc(x->stream)) { default: return x->cur = cur; case EOF: return x->cur = 0; case '\n': case ' ': case '\r': case '\t': case '\v': break; } } } static bool libcjsonp_builtin_parse_number(value_t* x, reader_t* s) { char b[64], *p = b; bool is_float = false; for (;;) { switch (*p++ = s->cur) { case '.': case 'E': case 'e': if (p > b+1) { is_float = true; break; } case 0: return false; case '\n': case ' ': case '\r': case '\t': case '\v': next_sign(s); default: p[-1] = 0; goto break_; case '-': case '+': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; } next(s); } break_: return (bool)libcjsonp_builtin_fetch_number(x, b, is_float); } static bool libcjsonp_builtin_parse_string(vtype_string* x, reader_t* s) { char *mem, *ptr; size_t nmemb, size; vtype_uint8 esc; mem = 0; nmemb = 0; size = 0; esc = 0; while (next(s)) { if (s->cur == '"' && !esc) { if (!nmemb) { mem = realloc(mem, size + 1); mem[size] = 0; } else *ptr = 0; x->buffer = mem; libcjsonp_string_unescape(x); return true; } else if (s->cur == '\\') { esc ^= 1; } else esc = 0; if (nmemb--) { *ptr++ = s->cur; } else { mem = realloc(mem, size += nmemb = buffer_block); ptr = mem + (size - buffer_block); } } libcdsb_free(mem); return false; } static bool libcjsonp_builtin_parse_map(vtype_map* x, reader_t* s) { vtype_string name; value_t value; map_init(x, VTYPE_STRING); if (next_sign(s) == '}') return true; for (;;) { if (!libcjsonp_builtin_parse_string(&name, s)) return false; if (next_sign(s) != ':') { goto bad_; } else next_sign(s); if (!libcjsonp_builtin_parse(&value, s)) goto bad_; switch (s->cur) { case ',': libcdsb_map_inject(x, &name, VTYPE_STRING, value.value, value.type); next_sign(s); break; case '}': return true; default: if (value.type == VTYPE_MAP) map_free ((void*)value.value); else if (value.type == VTYPE_LIST) list_free ((void*)value.value); else if (value.type == VTYPE_STRING) string_free((void*)value.value); bad_: string_free(&name); return false; } } } static bool libcjsonp_builtin_parse_list(vtype_list* x, reader_t* s) { value_t value; list_init(x); if (next_sign(s) == ']') return true; for (;;) { if (!libcjsonp_builtin_parse(&value, s)) return false; switch (s->cur) { case ',': libcdsb_list_attach(x, -1, value.value, value.type, 1); next_sign(s); break; case ']': return true; default: if (value.type == VTYPE_MAP) map_free ((void*)value.value); else if (value.type == VTYPE_LIST) list_free ((void*)value.value); else if (value.type == VTYPE_STRING) string_free((void*)value.value); return false; } } } static bool libcjsonp_builtin_parse(value_t* x, reader_t* s) { bool ret = true; switch (s->cur) { case '{': if (!(ret = libcjsonp_builtin_parse_map((void*)x->value, s))) { map_free((void*)x->value); } else x->type = VTYPE_MAP; break; case '[': if (!(ret = libcjsonp_builtin_parse_list((void*)x->value, s))) { list_free((void*)x->value); } else x->type = VTYPE_LIST; break; case '"': if (!(ret = libcjsonp_builtin_parse_string((void*)x->value, s))) { string_free((void*)x->value); } else x->type = VTYPE_STRING; break; case 't': if (next(s) == 'r' && next(s) == 'u' && next(s) == 'e') { x->value->b = true; x->type = VTYPE_BOOLEAN; } else ret = false; break; case 'f': if (next(s) == 'a' && next(s) == 'l' && next(s) == 's' && next(s) == 'e') { x->value->b = false; x->type = VTYPE_BOOLEAN; } else ret = false; break; case 'n': if (next(s) == 'u' && next(s) == 'l' && next(s) == 'l') { x->value->ptr = 0; x->type = VTYPE_POINTER; } else ret = false; break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return libcjsonp_builtin_parse_number(x, s); } if (ret) next_sign(s); return ret; } /*#####################################################################################################################*/ bool json_load(json_t* x, FILE* s) { reader_t reader; value_t value; reader.stream = s; next_sign(&reader); if (libcjsonp_builtin_parse(&value, &reader)) { switch (x->type = value.type) { default: #ifndef NDEBUG abort(); #endif case VTYPE_BOOLEAN: case VTYPE_INT8: case VTYPE_UINT8: x->data = libcdsb_memndup(value.value, sizeof(vtype_uint8)); break; case VTYPE_INT16: case VTYPE_UINT16: x->data = libcdsb_memndup(value.value, sizeof(vtype_uint16)); break; case VTYPE_INT32: case VTYPE_UINT32: x86_: x->data = libcdsb_memndup(value.value, sizeof(vtype_uint32)); break; case VTYPE_POINTER: if (sizeof(void*) == sizeof(vtype_uint32)) goto x86_; case VTYPE_INT64: case VTYPE_UINT64: x->data = libcdsb_memndup(value.value, sizeof(vtype_uint64)); break; case VTYPE_LDOUBLE: x->data = libcdsb_memndup(value.value, sizeof(vtype_ldouble)); break; case VTYPE_MAP: x->data = libcdsb_memndup(value.value, sizeof(vtype_map)); break; case VTYPE_LIST: x->data = libcdsb_memndup(value.value, sizeof(vtype_list)); break; case VTYPE_STRING: x->data = libcdsb_memndup(value.value, sizeof(vtype_string)); break; } } else { memset(x, 0, sizeof(*x)); return false; } return true; }