From 6a286a418bff36284f5dada82bf0e186437233b5 Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Mon, 29 Apr 2024 10:52:05 +0200 Subject: [PATCH] json: move to libtrx --- meson.build | 5 - src/config.c | 4 +- src/game/gameflow.c | 3 +- src/game/savegame/savegame_bson.c | 4 +- src/json.h | 7 - src/json/bson_parse.c | 724 ------------ src/json/bson_parse.h | 27 - src/json/bson_write.c | 558 --------- src/json/bson_write.h | 11 - src/json/json_base.c | 540 --------- src/json/json_base.h | 173 --- src/json/json_parse.c | 1809 ----------------------------- src/json/json_parse.h | 120 -- src/json/json_write.c | 991 ---------------- src/json/json_write.h | 27 - subprojects/libtrx | 2 +- 16 files changed, 4 insertions(+), 5001 deletions(-) delete mode 100644 src/json.h delete mode 100644 src/json/bson_parse.c delete mode 100644 src/json/bson_parse.h delete mode 100644 src/json/bson_write.c delete mode 100644 src/json/bson_write.h delete mode 100644 src/json/json_base.c delete mode 100644 src/json/json_base.h delete mode 100644 src/json/json_parse.c delete mode 100644 src/json/json_parse.h delete mode 100644 src/json/json_write.c delete mode 100644 src/json/json_write.h diff --git a/meson.build b/meson.build index 6b722c9bd..043689233 100644 --- a/meson.build +++ b/meson.build @@ -262,11 +262,6 @@ sources = [ 'src/gfx/gl/vertex_array.c', 'src/gfx/screenshot.c', 'src/global/vars.c', - 'src/json/bson_parse.c', - 'src/json/bson_write.c', - 'src/json/json_base.c', - 'src/json/json_parse.c', - 'src/json/json_write.c', 'src/math/math.c', 'src/math/math_misc.c', 'src/math/matrix.c', diff --git a/src/config.c b/src/config.c index f0d01cd12..9111efb8b 100644 --- a/src/config.c +++ b/src/config.c @@ -7,10 +7,8 @@ #include "gfx/context.h" #include "global/const.h" #include "global/types.h" -#include "json/json_base.h" -#include "json/json_parse.h" -#include "json/json_write.h" #include "shared/filesystem.h" +#include "shared/json.h" #include "shared/log.h" #include "shared/memory.h" #include "util.h" diff --git a/src/game/gameflow.c b/src/game/gameflow.c index 1bcab3422..427d48887 100644 --- a/src/game/gameflow.c +++ b/src/game/gameflow.c @@ -15,9 +15,8 @@ #include "game/phase/phase_stats.h" #include "game/room.h" #include "global/vars.h" -#include "json/json_base.h" -#include "json/json_parse.h" #include "shared/filesystem.h" +#include "shared/json.h" #include "shared/log.h" #include "shared/memory.h" diff --git a/src/game/savegame/savegame_bson.c b/src/game/savegame/savegame_bson.c index 47b687f25..a17006dad 100644 --- a/src/game/savegame/savegame_bson.c +++ b/src/game/savegame/savegame_bson.c @@ -13,9 +13,7 @@ #include "game/shell.h" #include "global/const.h" #include "global/vars.h" -#include "json/bson_parse.h" -#include "json/bson_write.h" -#include "json/json_base.h" +#include "shared/json.h" #include "shared/log.h" #include "shared/memory.h" #include "util.h" diff --git a/src/json.h b/src/json.h deleted file mode 100644 index 296cacb93..000000000 --- a/src/json.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "json/bson_parse.h" -#include "json/bson_write.h" -#include "json/json_base.h" -#include "json/json_parse.h" -#include "json/json_write.h" diff --git a/src/json/bson_parse.c b/src/json/bson_parse.c deleted file mode 100644 index 6be1e0406..000000000 --- a/src/json/bson_parse.c +++ /dev/null @@ -1,724 +0,0 @@ -#include "json/bson_parse.h" - -#include "json/json_base.h" -#include "shared/log.h" -#include "shared/memory.h" - -#include -#include -#include -#include -#include - -struct bson_parse_state_s { - const char *src; - size_t size; - size_t offset; - - char *data; - char *dom; - size_t dom_size; - size_t data_size; - - size_t error; -}; - -static bool bson_parse_get_object_key_size(struct bson_parse_state_s *state); -static bool bson_parse_get_null_value_size(struct bson_parse_state_s *state); -static bool bson_parse_get_bool_value_size(struct bson_parse_state_s *state); -static bool bson_parse_get_int32_value_size(struct bson_parse_state_s *state); -static bool bson_parse_get_double_value_size(struct bson_parse_state_s *state); -static bool bson_parse_get_string_value_size(struct bson_parse_state_s *state); -static bool bson_parse_get_array_element_wrapped_size( - struct bson_parse_state_s *state); -static bool bson_parse_get_array_size(struct bson_parse_state_s *state); -static bool bson_parse_get_array_value_size(struct bson_parse_state_s *state); -static bool bson_parse_get_object_element_wrapped_size( - struct bson_parse_state_s *state); -static bool bson_parse_get_object_size(struct bson_parse_state_s *state); -static bool bson_parse_get_object_value_size(struct bson_parse_state_s *state); -static bool bson_parse_get_value_size( - struct bson_parse_state_s *state, uint8_t marker); -static bool bson_parse_get_root_size(struct bson_parse_state_s *state); - -static void bson_parse_object_key( - struct bson_parse_state_s *state, struct json_string_s *string); -static void bson_parse_null_value( - struct bson_parse_state_s *state, struct json_value_s *value); -static void bson_parse_bool_value( - struct bson_parse_state_s *state, struct json_value_s *value); -static void bson_parse_int32_value( - struct bson_parse_state_s *state, struct json_value_s *value); -static void bson_parse_double_value( - struct bson_parse_state_s *state, struct json_value_s *value); -static void bson_parse_string_value( - struct bson_parse_state_s *state, struct json_value_s *value); -static void bson_parse_array_element_wrapped( - struct bson_parse_state_s *state, struct json_array_element_s *element); -static void bson_parse_array( - struct bson_parse_state_s *state, struct json_array_s *array); -static void bson_parse_array_value( - struct bson_parse_state_s *state, struct json_value_s *value); -static void bson_parse_object_element_wrapped( - struct bson_parse_state_s *state, struct json_object_element_s *element); -static void bson_parse_object( - struct bson_parse_state_s *state, struct json_object_s *object); -static void bson_parse_object_value( - struct bson_parse_state_s *state, struct json_value_s *value); -static void bson_parse_value( - struct bson_parse_state_s *state, struct json_value_s *value, - uint8_t marker); - -static bool bson_parse_get_object_key_size(struct bson_parse_state_s *state) -{ - assert(state); - while (state->src[state->offset]) { - state->data_size++; - state->offset++; - } - state->data_size++; - state->offset++; - return true; -} - -static bool bson_parse_get_null_value_size(struct bson_parse_state_s *state) -{ - assert(state); - return true; -} - -static bool bson_parse_get_bool_value_size(struct bson_parse_state_s *state) -{ - assert(state); - if (state->offset + sizeof(uint8_t) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - - switch (state->src[state->offset]) { - case 0x00: - break; - case 0x01: - break; - default: - state->error = bson_parse_error_invalid_value; - return false; - } - - state->offset++; - return true; -} - -static bool bson_parse_get_int32_value_size(struct bson_parse_state_s *state) -{ - assert(state); - - if (state->offset + sizeof(int32_t) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - int32_t num = *(int32_t *)&state->src[state->offset]; - state->offset += sizeof(int32_t); - - state->dom_size += sizeof(struct json_number_s); - state->data_size += snprintf(NULL, 0, "%d", num) + 1; - return true; -} - -static bool bson_parse_get_double_value_size(struct bson_parse_state_s *state) -{ - assert(state); - - if (state->offset + sizeof(double) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - double num = *(double *)&state->src[state->offset]; - state->offset += sizeof(double); - - state->dom_size += sizeof(struct json_number_s); - state->data_size += snprintf(NULL, 0, "%f", num) + 1; - return true; -} - -static bool bson_parse_get_string_value_size(struct bson_parse_state_s *state) -{ - assert(state); - - if (state->offset + sizeof(int32_t) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - int32_t size = *(int32_t *)&state->src[state->offset]; - state->offset += sizeof(int32_t); - if (state->offset + size > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - if (state->src[state->offset + size - 1] != '\0') { - state->error = bson_parse_error_invalid_value; - return false; - } - state->offset += size; - state->dom_size += sizeof(struct json_string_s); - state->data_size += size; - return true; -} - -static bool bson_parse_get_array_element_wrapped_size( - struct bson_parse_state_s *state) -{ - assert(state); - - if (state->offset + sizeof(uint8_t) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - uint8_t marker = state->src[state->offset]; - state->offset++; - - // BSON arrays always use keys - state->dom_size += sizeof(struct json_string_s); - if (!bson_parse_get_object_key_size(state)) { - return false; - } - - state->dom_size += sizeof(struct json_value_s); - return bson_parse_get_value_size(state, marker); -} - -static bool bson_parse_get_array_size(struct bson_parse_state_s *state) -{ - assert(state); - - const size_t start_offset = state->offset; - if (state->offset + sizeof(int32_t) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - const int size = *(int32_t *)&state->src[state->offset]; - state->offset += sizeof(int32_t); - - while (state->offset < start_offset + size - 1) { - state->dom_size += sizeof(struct json_array_element_s); - if (!bson_parse_get_array_element_wrapped_size(state)) { - return false; - } - } - - if (state->offset + sizeof(char) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - if (state->src[state->offset] != '\0') { - state->error = bson_parse_error_invalid_value; - return false; - } - state->offset++; - return true; -} - -static bool bson_parse_get_array_value_size(struct bson_parse_state_s *state) -{ - assert(state); - state->dom_size += sizeof(struct json_array_s); - return bson_parse_get_array_size(state); -} - -static bool bson_parse_get_object_element_wrapped_size( - struct bson_parse_state_s *state) -{ - assert(state); - - if (state->offset + sizeof(uint8_t) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - uint8_t marker = state->src[state->offset]; - state->offset++; - - state->dom_size += sizeof(struct json_string_s); - if (!bson_parse_get_object_key_size(state)) { - return false; - } - - state->dom_size += sizeof(struct json_value_s); - return bson_parse_get_value_size(state, marker); -} - -static bool bson_parse_get_object_size(struct bson_parse_state_s *state) -{ - assert(state); - - const size_t start_offset = state->offset; - if (state->offset + sizeof(int32_t) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - const int size = *(int32_t *)&state->src[state->offset]; - state->offset += sizeof(int32_t); - - while (state->offset < start_offset + size - 1) { - state->dom_size += sizeof(struct json_object_element_s); - if (!bson_parse_get_object_element_wrapped_size(state)) { - return false; - } - } - - if (state->offset + sizeof(char) > state->size) { - state->error = bson_parse_error_premature_end_of_buffer; - return false; - } - if (state->src[state->offset] != '\0') { - state->error = bson_parse_error_invalid_value; - return false; - } - state->offset++; - return true; -} - -static bool bson_parse_get_object_value_size(struct bson_parse_state_s *state) -{ - assert(state); - state->dom_size += sizeof(struct json_object_s); - return bson_parse_get_object_size(state); -} - -static bool bson_parse_get_value_size( - struct bson_parse_state_s *state, uint8_t marker) -{ - assert(state); - switch (marker) { - case 0x01: - return bson_parse_get_double_value_size(state); - case 0x02: - return bson_parse_get_string_value_size(state); - case 0x03: - return bson_parse_get_object_value_size(state); - case 0x04: - return bson_parse_get_array_value_size(state); - case 0x0A: - return bson_parse_get_null_value_size(state); - case 0x08: - return bson_parse_get_bool_value_size(state); - case 0x10: - return bson_parse_get_int32_value_size(state); - default: - state->error = bson_parse_error_invalid_value; - return false; - } -} - -static bool bson_parse_get_root_size(struct bson_parse_state_s *state) -{ - // assume the root element to be an object - state->dom_size += sizeof(struct json_value_s); - return bson_parse_get_object_value_size(state); -} - -static void bson_parse_object_key( - struct bson_parse_state_s *state, struct json_string_s *string) -{ - assert(state); - assert(string); - size_t size = 0; - string->ref_count = 1; - string->string = state->data; - while (state->src[state->offset]) { - state->data[size++] = state->src[state->offset++]; - } - string->string_size = size; - state->data[size++] = state->src[state->offset++]; - state->data += size; -} - -static void bson_parse_null_value( - struct bson_parse_state_s *state, struct json_value_s *value) -{ - assert(state); - assert(value); - value->type = json_type_null; - value->payload = json_null; -} - -static void bson_parse_bool_value( - struct bson_parse_state_s *state, struct json_value_s *value) -{ - assert(state); - assert(value); - assert(state->offset + sizeof(char) <= state->size); - switch (state->src[state->offset]) { - case 0x00: - value->type = json_type_false; - value->payload = json_null; - break; - case 0x01: - value->type = json_type_true; - value->payload = json_null; - break; - default: - assert(0); - } - state->offset++; -} - -static void bson_parse_int32_value( - struct bson_parse_state_s *state, struct json_value_s *value) -{ - assert(state); - assert(value); - - assert(state->offset + sizeof(int32_t) <= state->size); - int32_t num = *(int32_t *)&state->src[state->offset]; - state->offset += sizeof(int32_t); - - struct json_number_s *number = (struct json_number_s *)state->dom; - number->ref_count = 1; - state->dom += sizeof(struct json_number_s); - - number->number = state->data; - sprintf(state->data, "%d", num); - number->number_size = strlen(number->number); - state->data += number->number_size + 1; - - value->type = json_type_number; - value->payload = number; -} - -static void bson_parse_double_value( - struct bson_parse_state_s *state, struct json_value_s *value) -{ - assert(state); - assert(value); - - assert(state->offset + sizeof(double) <= state->size); - double num = *(double *)&state->src[state->offset]; - state->offset += sizeof(double); - - struct json_number_s *number = (struct json_number_s *)state->dom; - number->ref_count = 1; - state->dom += sizeof(struct json_number_s); - - number->number = state->data; - sprintf(state->data, "%f", num); - number->number_size = strlen(number->number); - state->data += number->number_size + 1; - - // strip trailing zeroes after decimal point - if (strchr(number->number, '.')) { - while (number->number[number->number_size - 1] == '0' - && number->number_size > 1) { - number->number_size--; - } - number->number[number->number_size] = '\0'; - } - - value->type = json_type_number; - value->payload = number; -} - -static void bson_parse_string_value( - struct bson_parse_state_s *state, struct json_value_s *value) -{ - assert(state); - assert(value); - - assert(state->offset + sizeof(int32_t) <= state->size); - int32_t size = *(int32_t *)&state->src[state->offset]; - state->offset += sizeof(int32_t); - - struct json_string_s *string = (struct json_string_s *)state->dom; - string->ref_count = 1; - state->dom += sizeof(struct json_string_s); - - memcpy(state->data, state->src + state->offset, size); - state->offset += size; - - string->string = state->data; - string->string_size = size; - state->data += size; - - value->type = json_type_string; - value->payload = string; -} - -static void bson_parse_array_element_wrapped( - struct bson_parse_state_s *state, struct json_array_element_s *element) -{ - assert(state); - assert(element); - - assert(state->offset + sizeof(uint8_t) <= state->size); - uint8_t marker = state->src[state->offset]; - state->offset++; - - // BSON arrays always use keys - struct json_string_s *key = (struct json_string_s *)state->dom; - key->ref_count = 1; - state->dom += sizeof(struct json_string_s); - bson_parse_object_key(state, key); - - struct json_value_s *value = (struct json_value_s *)state->dom; - value->ref_count = 1; - state->dom += sizeof(struct json_value_s); - - element->value = value; - - bson_parse_value(state, value, marker); -} - -static void bson_parse_array( - struct bson_parse_state_s *state, struct json_array_s *array) -{ - assert(state); - assert(array); - - const size_t start_offset = state->offset; - assert(state->offset + sizeof(int32_t) <= state->size); - const int size = *(int32_t *)&state->src[state->offset]; - state->offset += sizeof(int32_t); - - struct json_array_element_s *previous = NULL; - int count = 0; - while (state->offset < start_offset + size - 1) { - struct json_array_element_s *element = - (struct json_array_element_s *)state->dom; - element->ref_count = 1; - state->dom += sizeof(struct json_array_element_s); - if (!previous) { - array->start = element; - } else { - previous->next = element; - } - previous = element; - bson_parse_array_element_wrapped(state, element); - count++; - } - if (previous) { - previous->next = NULL; - } - if (!count) { - array->start = NULL; - } - array->ref_count = 1; - array->length = count; - assert(state->offset + sizeof(char) <= state->size); - assert(!state->src[state->offset]); - state->offset++; -} - -static void bson_parse_array_value( - struct bson_parse_state_s *state, struct json_value_s *value) -{ - assert(state); - assert(value); - - struct json_array_s *array = (struct json_array_s *)state->dom; - array->ref_count = 1; - state->dom += sizeof(struct json_array_s); - - bson_parse_array(state, array); - - value->type = json_type_array; - value->payload = array; -} - -static void bson_parse_object_element_wrapped( - struct bson_parse_state_s *state, struct json_object_element_s *element) -{ - assert(state); - assert(element); - - assert(state->offset + sizeof(uint8_t) <= state->size); - uint8_t marker = state->src[state->offset]; - state->offset++; - - struct json_string_s *key = (struct json_string_s *)state->dom; - key->ref_count = 1; - state->dom += sizeof(struct json_string_s); - bson_parse_object_key(state, key); - - struct json_value_s *value = (struct json_value_s *)state->dom; - value->ref_count = 1; - state->dom += sizeof(struct json_value_s); - - element->name = key; - element->value = value; - - bson_parse_value(state, value, marker); -} - -static void bson_parse_object( - struct bson_parse_state_s *state, struct json_object_s *object) -{ - assert(state); - assert(object); - - const size_t start_offset = state->offset; - assert(state->offset + sizeof(int32_t) <= state->size); - const int size = *(int32_t *)&state->src[state->offset]; - state->offset += sizeof(int32_t); - - struct json_object_element_s *previous = NULL; - int count = 0; - while (state->offset < start_offset + size - 1) { - struct json_object_element_s *element = - (struct json_object_element_s *)state->dom; - element->ref_count = 1; - state->dom += sizeof(struct json_object_element_s); - if (!previous) { - object->start = element; - } else { - previous->next = element; - } - previous = element; - bson_parse_object_element_wrapped(state, element); - count++; - } - if (previous) { - previous->next = NULL; - } - if (!count) { - object->start = NULL; - } - object->ref_count = 1; - object->length = count; - assert(state->offset + sizeof(char) <= state->size); - assert(!state->src[state->offset]); - state->offset++; -} - -static void bson_parse_object_value( - struct bson_parse_state_s *state, struct json_value_s *value) -{ - assert(state); - assert(value); - - struct json_object_s *object = (struct json_object_s *)state->dom; - object->ref_count = 1; - state->dom += sizeof(struct json_object_s); - - bson_parse_object(state, object); - - value->type = json_type_object; - value->payload = object; -} - -static void bson_parse_value( - struct bson_parse_state_s *state, struct json_value_s *value, - uint8_t marker) -{ - assert(state); - assert(value); - switch (marker) { - case 0x01: - bson_parse_double_value(state, value); - break; - case 0x02: - bson_parse_string_value(state, value); - break; - case 0x03: - bson_parse_object_value(state, value); - break; - case 0x04: - bson_parse_array_value(state, value); - break; - case 0x0A: - bson_parse_null_value(state, value); - break; - case 0x08: - bson_parse_bool_value(state, value); - break; - case 0x10: - bson_parse_int32_value(state, value); - break; - default: - assert(0); - } -} - -struct json_value_s *bson_parse(const char *src, size_t src_size) -{ - return bson_parse_ex(src, src_size, NULL); -} - -struct json_value_s *bson_parse_ex( - const char *src, size_t src_size, struct bson_parse_result_s *result) -{ - struct bson_parse_state_s state; - void *allocation; - struct json_value_s *value; - size_t total_size; - - if (result) { - result->error = bson_parse_error_none; - result->error_offset = 0; - } - - if (!src) { - return NULL; - } - - state.src = src; - state.size = src_size; - state.offset = 0; - state.error = bson_parse_error_none; - state.dom_size = 0; - state.data_size = 0; - - if (bson_parse_get_root_size(&state)) { - if (state.offset != state.size) { - state.error = bson_parse_error_unexpected_trailing_bytes; - } - } - - if (state.error != bson_parse_error_none) { - if (result) { - result->error = state.error; - result->error_offset = state.offset; - } - LOG_ERROR( - "Error while reading BSON near offset %d: %s", state.offset, - bson_get_error_description(state.error)); - return NULL; - } - - total_size = state.dom_size + state.data_size; - - allocation = Memory_Alloc(total_size); - state.offset = 0; - state.dom = (char *)allocation; - state.data = state.dom + state.dom_size; - - // assume the root element to be an object - value = (struct json_value_s *)state.dom; - value->ref_count = 0; - state.dom += sizeof(struct json_value_s); - bson_parse_object_value(&state, value); - - assert(state.dom == allocation + state.dom_size); - assert(state.data == allocation + state.dom_size + state.data_size); - - return value; -} - -const char *bson_get_error_description(enum bson_parse_error_e error) -{ - switch (error) { - case bson_parse_error_none: - return "no error"; - - case bson_parse_error_invalid_value: - return "invalid value"; - - case bson_parse_error_premature_end_of_buffer: - return "premature end of buffer"; - - case bson_parse_error_unexpected_trailing_bytes: - return "unexpected trailing bytes"; - - case bson_parse_error_unknown: - default: - return "unknown"; - } -} diff --git a/src/json/bson_parse.h b/src/json/bson_parse.h deleted file mode 100644 index e4ba7a6cf..000000000 --- a/src/json/bson_parse.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "json/json_base.h" - -#include - -enum bson_parse_error_e { - bson_parse_error_none = 0, - bson_parse_error_invalid_value, - bson_parse_error_premature_end_of_buffer, - bson_parse_error_unexpected_trailing_bytes, - bson_parse_error_unknown, -}; - -struct bson_parse_result_s { - enum bson_parse_error_e error; - size_t error_offset; -}; - -// Parse a BSON file, returning a pointer to the root of the JSON structure. -// Returns NULL if an error occurred (malformed BSON input, or malloc failed). -struct json_value_s *bson_parse(const char *src, size_t src_size); - -struct json_value_s *bson_parse_ex( - const char *src, size_t src_size, struct bson_parse_result_s *result); - -const char *bson_get_error_description(enum bson_parse_error_e error); diff --git a/src/json/bson_write.c b/src/json/bson_write.c deleted file mode 100644 index 599921e31..000000000 --- a/src/json/bson_write.c +++ /dev/null @@ -1,558 +0,0 @@ -#include "json/bson_write.h" - -#include "json/json_base.h" -#include "shared/log.h" -#include "shared/memory.h" - -#include -#include -#include -#include -#include -#include -#include - -static bool bson_write_get_marker_size(size_t *size, const char *key); -static bool bson_write_get_null_wrapped(size_t *size, const char *key); -static bool bson_write_get_boolean_wrapped_size(size_t *size, const char *key); -static bool bson_write_get_int32_size(size_t *size); -static bool bson_write_get_int32_wrapped_size(size_t *size, const char *key); -static bool bson_write_get_double_size(size_t *size); -static bool bson_write_get_double_wrapped_size(size_t *size, const char *key); -static bool bson_write_get_number_wrapped_size( - size_t *size, const char *key, const struct json_number_s *number); -static bool bson_write_get_string_size( - size_t *size, const struct json_string_s *string); -static bool bson_write_get_string_wrapped_size( - size_t *size, const char *key, const struct json_string_s *string); -static bool bson_write_get_array_size( - size_t *size, const struct json_array_s *array); -static bool bson_write_get_array_wrapped_size( - size_t *size, const char *key, const struct json_array_s *array); -static bool bson_write_get_object_size( - size_t *size, const struct json_object_s *object); -static bool bson_write_get_object_wrapped_size( - size_t *size, const char *key, const struct json_object_s *object); -static bool bson_write_get_value_size( - size_t *size, const struct json_value_s *value); -static bool bson_write_get_value_wrapped_size( - size_t *size, const char *key, const struct json_value_s *value); - -static char *bson_write_marker( - char *data, const char *key, const uint8_t marker); -static char *bson_write_null_wrapped(char *data, const char *key); -static char *bson_write_boolean_wrapped( - char *data, const char *key, bool value); -static char *bson_write_int32(char *data, const int32_t value); -static char *bson_write_int32_wrapped( - char *data, const char *key, const int32_t value); -static char *bson_write_double(char *data, const double value); -static char *bson_write_double_wrapped( - char *data, const char *key, const double value); -static char *bson_write_number_wrapped( - char *data, const char *key, const struct json_number_s *number); -static char *bson_write_string(char *data, const struct json_string_s *string); -static char *bson_write_string_wrapped( - char *data, const char *key, const struct json_string_s *string); -static char *bson_write_array(char *data, const struct json_array_s *array); -static char *bson_write_array_wrapped( - char *data, const char *key, const struct json_array_s *array); -static char *bson_write_object(char *data, const struct json_object_s *object); -static char *bson_write_object_wrapped( - char *data, const char *key, const struct json_object_s *object); -static char *bson_write_value(char *data, const struct json_value_s *value); -static char *bson_write_value_wrapped( - char *data, const char *key, const struct json_value_s *value); - -static bool bson_write_get_marker_size(size_t *size, const char *key) -{ - assert(size); - assert(key); - *size += 1; // marker - *size += strlen(key); // key - *size += 1; // NULL terminator - return true; -} - -static bool bson_write_get_null_wrapped_size(size_t *size, const char *key) -{ - assert(size); - assert(key); - return bson_write_get_marker_size(size, key); -} - -static bool bson_write_get_boolean_wrapped_size(size_t *size, const char *key) -{ - assert(size); - assert(key); - if (!bson_write_get_marker_size(size, key)) { - return false; - } - *size += 1; - return true; -} - -static bool bson_write_get_int32_size(size_t *size) -{ - assert(size); - *size += sizeof(int32_t); - return true; -} - -static bool bson_write_get_int32_wrapped_size(size_t *size, const char *key) -{ - assert(size); - assert(key); - if (!bson_write_get_marker_size(size, key)) { - return false; - } - if (!bson_write_get_int32_size(size)) { - return false; - } - return true; -} - -static bool bson_write_get_double_size(size_t *size) -{ - assert(size); - *size += sizeof(double); - return true; -} - -static bool bson_write_get_double_wrapped_size(size_t *size, const char *key) -{ - assert(size); - assert(key); - if (!bson_write_get_marker_size(size, key)) { - return false; - } - if (!bson_write_get_double_size(size)) { - return false; - } - return true; -} - -static bool bson_write_get_number_wrapped_size( - size_t *size, const char *key, const struct json_number_s *number) -{ - assert(size); - assert(key); - - char *str = number->number; - assert(str); - - // hexadecimal numbers - if (number->number_size >= 2 && (str[1] == 'x' || str[1] == 'X')) { - return bson_write_get_int32_wrapped_size(size, key); - } - - // skip leading sign - if (str[0] == '+' || str[0] == '-') { - str += 1; - } - assert(str[0]); - - if (!strcmp(str, "Infinity")) { - // BSON does not support Infinity. - return bson_write_get_double_wrapped_size(size, key); - } else if (!strcmp(str, "NaN")) { - // BSON does not support NaN. - return bson_write_get_int32_wrapped_size(size, key); - } else if (strchr(str, '.')) { - return bson_write_get_double_wrapped_size(size, key); - } else { - return bson_write_get_int32_wrapped_size(size, key); - } - - return false; -} - -static bool bson_write_get_string_size( - size_t *size, const struct json_string_s *string) -{ - assert(size); - assert(string); - *size += sizeof(uint32_t); // size - *size += string->string_size; // string - *size += 1; // NULL terminator - return true; -} - -static bool bson_write_get_string_wrapped_size( - size_t *size, const char *key, const struct json_string_s *string) -{ - assert(size); - assert(key); - assert(string); - if (!bson_write_get_marker_size(size, key)) { - return false; - } - if (!bson_write_get_string_size(size, string)) { - return false; - } - return true; -} - -static bool bson_write_get_array_size( - size_t *size, const struct json_array_s *array) -{ - assert(size); - assert(array); - char key[12]; - int idx = 0; - *size += sizeof(int32_t); // object size - for (struct json_array_element_s *element = array->start; - element != json_null; element = element->next) { - sprintf(key, "%d", idx); - idx++; - if (!bson_write_get_value_wrapped_size(size, key, element->value)) { - return false; - } - } - *size += 1; // NULL terminator - return true; -} - -static bool bson_write_get_array_wrapped_size( - size_t *size, const char *key, const struct json_array_s *array) -{ - assert(size); - assert(key); - assert(array); - if (!bson_write_get_marker_size(size, key)) { - return false; - } - if (!bson_write_get_array_size(size, array)) { - return false; - } - return true; -} - -static bool bson_write_get_object_size( - size_t *size, const struct json_object_s *object) -{ - assert(size); - assert(object); - *size += sizeof(int32_t); // object size - for (struct json_object_element_s *element = object->start; - element != json_null; element = element->next) { - if (!bson_write_get_value_wrapped_size( - size, element->name->string, element->value)) { - return false; - } - } - *size += 1; // NULL terminator - return true; -} - -static bool bson_write_get_object_wrapped_size( - size_t *size, const char *key, const struct json_object_s *object) -{ - assert(size); - assert(key); - assert(object); - if (!bson_write_get_marker_size(size, key)) { - return false; - } - if (!bson_write_get_object_size(size, object)) { - return false; - } - return true; -} - -static bool bson_write_get_value_size( - size_t *size, const struct json_value_s *value) -{ - assert(size); - assert(value); - switch (value->type) { - case json_type_array: - return bson_write_get_array_size( - size, (struct json_array_s *)value->payload); - case json_type_object: - return bson_write_get_object_size( - size, (struct json_object_s *)value->payload); - default: - LOG_ERROR("Bad BSON root element: %d", value->type); - } - return false; -} - -static bool bson_write_get_value_wrapped_size( - size_t *size, const char *key, const struct json_value_s *value) -{ - assert(size); - assert(key); - assert(value); - switch (value->type) { - case json_type_null: - return bson_write_get_null_wrapped_size(size, key); - case json_type_true: - return bson_write_get_boolean_wrapped_size(size, key); - case json_type_false: - return bson_write_get_boolean_wrapped_size(size, key); - case json_type_number: - return bson_write_get_number_wrapped_size( - size, key, (struct json_number_s *)value->payload); - case json_type_string: - return bson_write_get_string_wrapped_size( - size, key, (struct json_string_s *)value->payload); - case json_type_array: - return bson_write_get_array_wrapped_size( - size, key, (struct json_array_s *)value->payload); - case json_type_object: - return bson_write_get_object_wrapped_size( - size, key, (struct json_object_s *)value->payload); - default: - LOG_ERROR("Unknown JSON element: %d", value->type); - return false; - } -} - -static char *bson_write_marker( - char *data, const char *key, const uint8_t marker) -{ - assert(data); - assert(key); - *data++ = marker; - strcpy(data, key); - data += strlen(key); - *data++ = '\0'; - return data; -} - -static char *bson_write_null_wrapped(char *data, const char *key) -{ - assert(data); - assert(key); - return bson_write_marker(data, key, '\x0A'); -} - -static char *bson_write_boolean_wrapped(char *data, const char *key, bool value) -{ - assert(data); - assert(key); - data = bson_write_marker(data, key, '\x08'); - *(int8_t *)data++ = (int8_t)value; - return data; -} - -static char *bson_write_int32(char *data, const int32_t value) -{ - assert(data); - *(int32_t *)data = value; - data += sizeof(int32_t); - return data; -} - -static char *bson_write_int32_wrapped( - char *data, const char *key, const int32_t value) -{ - assert(data); - assert(key); - data = bson_write_marker(data, key, '\x10'); - return bson_write_int32(data, value); -} - -static char *bson_write_double(char *data, const double value) -{ - assert(data); - *(double *)data = value; - data += sizeof(double); - return data; -} - -static char *bson_write_double_wrapped( - char *data, const char *key, const double value) -{ - assert(data); - assert(key); - data = bson_write_marker(data, key, '\x01'); - return bson_write_double(data, value); -} - -static char *bson_write_number_wrapped( - char *data, const char *key, const struct json_number_s *number) -{ - assert(data); - assert(key); - assert(number); - char *str = number->number; - - // hexadecimal numbers - if (number->number_size >= 2 && (str[1] == 'x' || str[1] == 'X')) { - return bson_write_int32_wrapped( - data, key, json_strtoumax(number->number, json_null, 0)); - } - - // skip leading sign - if (str[0] == '+' || str[0] == '-') { - str++; - } - assert(str[0]); - - if (!strcmp(str, "Infinity")) { - // BSON does not support Infinity. - return bson_write_double_wrapped(data, key, DBL_MAX); - } else if (!strcmp(str, "NaN")) { - // BSON does not support NaN. - return bson_write_int32_wrapped(data, key, 0); - } else if (strchr(str, '.')) { - return bson_write_double_wrapped(data, key, atof(number->number)); - } else { - return bson_write_int32_wrapped(data, key, atoi(number->number)); - } - - return data; -} - -static char *bson_write_string(char *data, const struct json_string_s *string) -{ - assert(data); - assert(string); - *(uint32_t *)data = string->string_size + 1; - data += sizeof(uint32_t); - memcpy(data, string->string, string->string_size); - data += string->string_size; - *data++ = '\0'; - return data; -} - -static char *bson_write_string_wrapped( - char *data, const char *key, const struct json_string_s *string) -{ - assert(data); - assert(key); - assert(string); - data = bson_write_marker(data, key, '\x02'); - data = bson_write_string(data, string); - return data; -} - -static char *bson_write_array(char *data, const struct json_array_s *array) -{ - assert(data); - assert(array); - char key[12]; - int idx = 0; - char *old = data; - data += sizeof(int32_t); - for (struct json_array_element_s *element = array->start; - element != json_null; element = element->next) { - sprintf(key, "%d", idx); - idx++; - data = bson_write_value_wrapped(data, key, element->value); - } - *data++ = '\0'; - *(int32_t *)old = data - old; - return data; -} - -static char *bson_write_array_wrapped( - char *data, const char *key, const struct json_array_s *array) -{ - assert(data); - assert(key); - assert(array); - data = bson_write_marker(data, key, '\x04'); - data = bson_write_array(data, array); - return data; -} - -static char *bson_write_object(char *data, const struct json_object_s *object) -{ - assert(data); - assert(object); - char *old = data; - data += sizeof(int32_t); - for (struct json_object_element_s *element = object->start; - element != json_null; element = element->next) { - data = bson_write_value_wrapped( - data, element->name->string, element->value); - } - *data++ = '\0'; - *(int32_t *)old = data - old; - return data; -} - -static char *bson_write_object_wrapped( - char *data, const char *key, const struct json_object_s *object) -{ - assert(data); - assert(key); - assert(object); - data = bson_write_marker(data, key, '\x03'); - data = bson_write_object(data, object); - return data; -} - -static char *bson_write_value(char *data, const struct json_value_s *value) -{ - assert(data); - assert(value); - switch (value->type) { - case json_type_array: - data = bson_write_array(data, (struct json_array_s *)value->payload); - break; - case json_type_object: - data = bson_write_object(data, (struct json_object_s *)value->payload); - break; - default: - assert(0); - } - return data; -} - -static char *bson_write_value_wrapped( - char *data, const char *key, const struct json_value_s *value) -{ - assert(data); - assert(key); - assert(value); - switch (value->type) { - case json_type_null: - return bson_write_null_wrapped(data, key); - case json_type_true: - return bson_write_boolean_wrapped(data, key, true); - case json_type_false: - return bson_write_boolean_wrapped(data, key, false); - case json_type_number: - return bson_write_number_wrapped( - data, key, (struct json_number_s *)value->payload); - case json_type_string: - return bson_write_string_wrapped( - data, key, (struct json_string_s *)value->payload); - case json_type_array: - return bson_write_array_wrapped( - data, key, (struct json_array_s *)value->payload); - case json_type_object: - return bson_write_object_wrapped( - data, key, (struct json_object_s *)value->payload); - default: - return json_null; - } -} - -void *bson_write(const struct json_value_s *value, size_t *out_size) -{ - assert(value); - *out_size = -1; - if (value == json_null) { - return json_null; - } - - size_t size = 0; - if (!bson_write_get_value_size(&size, value)) { - return json_null; - } - - char *data = Memory_Alloc(size); - char *data_end = bson_write_value(data, value); - assert((size_t)(data_end - data) == size); - - if (out_size != json_null) { - *out_size = size; - } - - return data; -} diff --git a/src/json/bson_write.h b/src/json/bson_write.h deleted file mode 100644 index 6eb97567b..000000000 --- a/src/json/bson_write.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "json/json_base.h" - -#include - -struct json_value_s; - -/* Write out a BSON binary string. Return 0 if an error occurred (malformed - * JSON input, or malloc failed). The out_size parameter is optional. */ -void *bson_write(const struct json_value_s *value, size_t *out_size); diff --git a/src/json/json_base.c b/src/json/json_base.c deleted file mode 100644 index db248fd08..000000000 --- a/src/json/json_base.c +++ /dev/null @@ -1,540 +0,0 @@ -#include "json/json_base.h" - -#include "shared/memory.h" - -#include -#include -#include -#include - -struct json_string_s *json_value_as_string(struct json_value_s *const value) -{ - if (!value || value->type != json_type_string) { - return json_null; - } - - return (struct json_string_s *)value->payload; -} - -struct json_number_s *json_value_as_number(struct json_value_s *const value) -{ - if (!value || value->type != json_type_number) { - return json_null; - } - - return (struct json_number_s *)value->payload; -} - -struct json_object_s *json_value_as_object(struct json_value_s *const value) -{ - if (!value || value->type != json_type_object) { - return json_null; - } - - return (struct json_object_s *)value->payload; -} - -struct json_array_s *json_value_as_array(struct json_value_s *const value) -{ - if (!value || value->type != json_type_array) { - return json_null; - } - - return (struct json_array_s *)value->payload; -} - -int json_value_is_true(const struct json_value_s *const value) -{ - return value && value->type == json_type_true; -} - -int json_value_is_false(const struct json_value_s *const value) -{ - return value && value->type == json_type_false; -} - -int json_value_is_null(const struct json_value_s *const value) -{ - return value && value->type == json_type_null; -} - -struct json_number_s *json_number_new_int(int number) -{ - size_t size = snprintf(NULL, 0, "%d", number) + 1; - char *buf = Memory_Alloc(size); - sprintf(buf, "%d", number); - struct json_number_s *elem = Memory_Alloc(sizeof(struct json_number_s)); - elem->number = buf; - elem->number_size = strlen(buf); - return elem; -} - -struct json_number_s *json_number_new_int64(int64_t number) -{ - size_t size = snprintf(NULL, 0, "%" PRId64, number) + 1; - char *buf = Memory_Alloc(size); - sprintf(buf, "%" PRId64, number); - struct json_number_s *elem = Memory_Alloc(sizeof(struct json_number_s)); - elem->number = buf; - elem->number_size = strlen(buf); - return elem; -} - -struct json_number_s *json_number_new_double(double number) -{ - size_t size = snprintf(NULL, 0, "%f", number) + 1; - char *buf = Memory_Alloc(size); - sprintf(buf, "%f", number); - struct json_number_s *elem = Memory_Alloc(sizeof(struct json_number_s)); - elem->number = buf; - elem->number_size = strlen(buf); - return elem; -} - -void json_number_free(struct json_number_s *num) -{ - if (!num->ref_count) { - Memory_Free(num->number); - Memory_Free(num); - } -} - -struct json_string_s *json_string_new(const char *string) -{ - struct json_string_s *str = Memory_Alloc(sizeof(struct json_string_s)); - str->string = Memory_DupStr(string); - str->string_size = strlen(string); - return str; -} - -void json_string_free(struct json_string_s *str) -{ - if (!str->ref_count) { - Memory_Free(str->string); - Memory_Free(str); - } -} - -struct json_array_s *json_array_new(void) -{ - struct json_array_s *arr = Memory_Alloc(sizeof(struct json_array_s)); - arr->start = NULL; - arr->length = 0; - return arr; -} - -void json_array_free(struct json_array_s *arr) -{ - struct json_array_element_s *elem = arr->start; - while (elem) { - struct json_array_element_s *next = elem->next; - json_value_free(elem->value); - json_array_element_free(elem); - elem = next; - } - if (!arr->ref_count) { - Memory_Free(arr); - } -} - -void json_array_element_free(struct json_array_element_s *element) -{ - if (!element->ref_count) { - Memory_FreePointer(&element); - } -} - -void json_array_append(struct json_array_s *arr, struct json_value_s *value) -{ - struct json_array_element_s *elem = - Memory_Alloc(sizeof(struct json_array_element_s)); - elem->value = value; - elem->next = NULL; - if (arr->start) { - struct json_array_element_s *target = arr->start; - while (target->next) { - target = target->next; - } - target->next = elem; - } else { - arr->start = elem; - } - arr->length++; -} - -void json_array_append_bool(struct json_array_s *arr, int b) -{ - json_array_append(arr, json_value_from_bool(b)); -} - -void json_array_append_int(struct json_array_s *arr, int number) -{ - json_array_append(arr, json_value_from_number(json_number_new_int(number))); -} - -void json_array_append_double(struct json_array_s *arr, double number) -{ - json_array_append( - arr, json_value_from_number(json_number_new_double(number))); -} - -void json_array_append_string(struct json_array_s *arr, const char *string) -{ - json_array_append(arr, json_value_from_string(json_string_new(string))); -} - -void json_array_append_array( - struct json_array_s *arr, struct json_array_s *arr2) -{ - json_array_append(arr, json_value_from_array(arr2)); -} - -void json_array_append_object( - struct json_array_s *arr, struct json_object_s *obj) -{ - json_array_append(arr, json_value_from_object(obj)); -} - -struct json_value_s *json_array_get_value( - struct json_array_s *arr, const size_t idx) -{ - if (!arr || idx >= arr->length) { - return json_null; - } - struct json_array_element_s *elem = arr->start; - for (size_t i = 0; i < idx; i++) { - elem = elem->next; - } - return elem->value; -} - -int json_array_get_bool(struct json_array_s *arr, const size_t idx, int d) -{ - struct json_value_s *value = json_array_get_value(arr, idx); - if (json_value_is_true(value)) { - return 1; - } else if (json_value_is_false(value)) { - return 0; - } - return d; -} - -int json_array_get_int(struct json_array_s *arr, const size_t idx, int d) -{ - struct json_value_s *value = json_array_get_value(arr, idx); - struct json_number_s *num = json_value_as_number(value); - if (num) { - return atoi(num->number); - } - return d; -} - -double json_array_get_double( - struct json_array_s *arr, const size_t idx, double d) -{ - struct json_value_s *value = json_array_get_value(arr, idx); - struct json_number_s *num = json_value_as_number(value); - if (num) { - return atof(num->number); - } - return d; -} - -const char *json_array_get_string( - struct json_array_s *arr, const size_t idx, const char *d) -{ - struct json_value_s *value = json_array_get_value(arr, idx); - struct json_string_s *str = json_value_as_string(value); - if (str) { - return str->string; - } - return d; -} - -struct json_array_s *json_array_get_array( - struct json_array_s *arr, const size_t idx) -{ - struct json_value_s *value = json_array_get_value(arr, idx); - struct json_array_s *arr2 = json_value_as_array(value); - return arr2; -} - -struct json_object_s *json_array_get_object( - struct json_array_s *arr, const size_t idx) -{ - struct json_value_s *value = json_array_get_value(arr, idx); - struct json_object_s *obj = json_value_as_object(value); - return obj; -} - -struct json_object_s *json_object_new(void) -{ - struct json_object_s *obj = Memory_Alloc(sizeof(struct json_object_s)); - obj->start = NULL; - obj->length = 0; - return obj; -} - -void json_object_free(struct json_object_s *obj) -{ - struct json_object_element_s *elem = obj->start; - while (elem) { - struct json_object_element_s *next = elem->next; - json_string_free(elem->name); - json_value_free(elem->value); - json_object_element_free(elem); - elem = next; - } - if (!obj->ref_count) { - Memory_Free(obj); - } -} - -void json_object_element_free(struct json_object_element_s *element) -{ - if (!element->ref_count) { - Memory_FreePointer(&element); - } -} - -void json_object_append( - struct json_object_s *obj, const char *key, struct json_value_s *value) -{ - struct json_object_element_s *elem = - Memory_Alloc(sizeof(struct json_object_element_s)); - elem->name = json_string_new(key); - elem->value = value; - elem->next = NULL; - if (obj->start) { - struct json_object_element_s *target = obj->start; - while (target->next) { - target = target->next; - } - target->next = elem; - } else { - obj->start = elem; - } - obj->length++; -} - -void json_object_append_bool(struct json_object_s *obj, const char *key, int b) -{ - json_object_append(obj, key, json_value_from_bool(b)); -} - -void json_object_append_int( - struct json_object_s *obj, const char *key, int number) -{ - json_object_append( - obj, key, json_value_from_number(json_number_new_int(number))); -} - -void json_object_append_int64( - struct json_object_s *obj, const char *key, int64_t number) -{ - json_object_append( - obj, key, json_value_from_number(json_number_new_int64(number))); -} - -void json_object_append_double( - struct json_object_s *obj, const char *key, double number) -{ - json_object_append( - obj, key, json_value_from_number(json_number_new_double(number))); -} - -void json_object_append_string( - struct json_object_s *obj, const char *key, const char *string) -{ - json_object_append( - obj, key, json_value_from_string(json_string_new(string))); -} - -void json_object_append_array( - struct json_object_s *obj, const char *key, struct json_array_s *arr) -{ - json_object_append(obj, key, json_value_from_array(arr)); -} - -void json_object_append_object( - struct json_object_s *obj, const char *key, struct json_object_s *obj2) -{ - json_object_append(obj, key, json_value_from_object(obj2)); -} - -void json_object_evict_key(struct json_object_s *obj, const char *key) -{ - if (!obj) { - return; - } - struct json_object_element_s *elem = obj->start; - struct json_object_element_s *prev = json_null; - while (elem) { - if (!strcmp(elem->name->string, key)) { - if (!prev) { - obj->start = elem->next; - } else { - prev->next = elem->next; - } - json_object_element_free(elem); - return; - } - prev = elem; - elem = elem->next; - } -} - -struct json_value_s *json_object_get_value( - struct json_object_s *obj, const char *key) -{ - if (!obj) { - return json_null; - } - struct json_object_element_s *elem = obj->start; - while (elem) { - if (!strcmp(elem->name->string, key)) { - return elem->value; - } - elem = elem->next; - } - return json_null; -} - -int json_object_get_bool(struct json_object_s *obj, const char *key, int d) -{ - struct json_value_s *value = json_object_get_value(obj, key); - if (json_value_is_true(value)) { - return 1; - } else if (json_value_is_false(value)) { - return 0; - } - return d; -} - -int json_object_get_int(struct json_object_s *obj, const char *key, int d) -{ - struct json_value_s *value = json_object_get_value(obj, key); - struct json_number_s *num = json_value_as_number(value); - if (num) { - return atoi(num->number); - } - return d; -} - -int64_t json_object_get_int64( - struct json_object_s *obj, const char *key, int64_t d) -{ - struct json_value_s *value = json_object_get_value(obj, key); - struct json_number_s *num = json_value_as_number(value); - if (num) { - return strtoll(num->number, NULL, 10); - } - return d; -} - -double json_object_get_double( - struct json_object_s *obj, const char *key, double d) -{ - struct json_value_s *value = json_object_get_value(obj, key); - struct json_number_s *num = json_value_as_number(value); - if (num) { - return atof(num->number); - } - return d; -} - -const char *json_object_get_string( - struct json_object_s *obj, const char *key, const char *d) -{ - struct json_value_s *value = json_object_get_value(obj, key); - struct json_string_s *str = json_value_as_string(value); - if (str) { - return str->string; - } - return d; -} - -struct json_array_s *json_object_get_array( - struct json_object_s *obj, const char *key) -{ - struct json_value_s *value = json_object_get_value(obj, key); - struct json_array_s *arr = json_value_as_array(value); - return arr; -} - -struct json_object_s *json_object_get_object( - struct json_object_s *obj, const char *key) -{ - struct json_value_s *value = json_object_get_value(obj, key); - struct json_object_s *obj2 = json_value_as_object(value); - return obj2; -} - -struct json_value_s *json_value_from_bool(int b) -{ - struct json_value_s *value = Memory_Alloc(sizeof(struct json_value_s)); - value->type = b ? json_type_true : json_type_false; - value->payload = NULL; - return value; -} - -struct json_value_s *json_value_from_number(struct json_number_s *num) -{ - struct json_value_s *value = Memory_Alloc(sizeof(struct json_value_s)); - value->type = json_type_number; - value->payload = num; - return value; -} - -struct json_value_s *json_value_from_string(struct json_string_s *str) -{ - struct json_value_s *value = Memory_Alloc(sizeof(struct json_value_s)); - value->type = json_type_string; - value->payload = str; - return value; -} - -struct json_value_s *json_value_from_array(struct json_array_s *arr) -{ - struct json_value_s *value = Memory_Alloc(sizeof(struct json_value_s)); - value->type = json_type_array; - value->payload = arr; - return value; -} - -struct json_value_s *json_value_from_object(struct json_object_s *obj) -{ - struct json_value_s *value = Memory_Alloc(sizeof(struct json_value_s)); - value->type = json_type_object; - value->payload = obj; - return value; -} - -void json_value_free(struct json_value_s *value) -{ - if (!value) { - return; - } - if (!value->ref_count) { - switch (value->type) { - case json_type_number: - json_number_free((struct json_number_s *)value->payload); - break; - case json_type_string: - json_string_free((struct json_string_s *)value->payload); - break; - case json_type_array: - json_array_free((struct json_array_s *)value->payload); - break; - case json_type_object: - json_object_free((struct json_object_s *)value->payload); - break; - case json_type_true: - case json_type_null: - case json_type_false: - break; - } - - Memory_Free(value); - } -} diff --git a/src/json/json_base.h b/src/json/json_base.h deleted file mode 100644 index 82573ad59..000000000 --- a/src/json/json_base.h +++ /dev/null @@ -1,173 +0,0 @@ -#pragma once - -#define JSON_INVALID_BOOL -1 -#define JSON_INVALID_STRING NULL -#define JSON_INVALID_NUMBER 0x7FFFFFFF - -#include -#include -#include - -#define json_null NULL -#define json_uintmax_t uintmax_t -#define json_strtoumax strtoumax - -enum json_type_e { - json_type_string, - json_type_number, - json_type_object, - json_type_array, - json_type_true, - json_type_false, - json_type_null -}; - -struct json_string_s { - char *string; - size_t string_size; - size_t ref_count; -}; - -struct json_string_ex_s { - struct json_string_s string; - size_t offset; - size_t line_no; - size_t row_no; -}; - -struct json_number_s { - char *number; - size_t number_size; - size_t ref_count; -}; - -struct json_object_element_s { - struct json_string_s *name; - struct json_value_s *value; - struct json_object_element_s *next; - size_t ref_count; -}; - -struct json_object_s { - struct json_object_element_s *start; - size_t length; - size_t ref_count; -}; - -struct json_array_element_s { - struct json_value_s *value; - struct json_array_element_s *next; - size_t ref_count; -}; - -struct json_array_s { - struct json_array_element_s *start; - size_t length; - size_t ref_count; -}; - -struct json_value_s { - void *payload; - size_t type; - size_t ref_count; -}; - -struct json_value_ex_s { - struct json_value_s value; - size_t offset; - size_t line_no; - size_t row_no; -}; - -// numbers -struct json_number_s *json_number_new_int(int number); -struct json_number_s *json_number_new_int64(int64_t number); -struct json_number_s *json_number_new_double(double number); -void json_number_free(struct json_number_s *num); - -// strings -struct json_string_s *json_string_new(const char *string); -void json_string_free(struct json_string_s *str); - -// arrays -struct json_array_s *json_array_new(void); -void json_array_free(struct json_array_s *arr); -void json_array_element_free(struct json_array_element_s *element); - -void json_array_append(struct json_array_s *arr, struct json_value_s *value); -void json_array_append_bool(struct json_array_s *arr, int b); -void json_array_append_int(struct json_array_s *arr, int number); -void json_array_append_double(struct json_array_s *arr, double number); -void json_array_append_string(struct json_array_s *arr, const char *string); -void json_array_append_array( - struct json_array_s *arr, struct json_array_s *arr2); -void json_array_append_object( - struct json_array_s *arr, struct json_object_s *obj); - -struct json_value_s *json_array_get_value( - struct json_array_s *arr, const size_t idx); -int json_array_get_bool(struct json_array_s *arr, const size_t idx, int d); -int json_array_get_int(struct json_array_s *arr, const size_t idx, int d); -double json_array_get_double( - struct json_array_s *arr, const size_t idx, double d); -const char *json_array_get_string( - struct json_array_s *arr, const size_t idx, const char *d); -struct json_array_s *json_array_get_array( - struct json_array_s *arr, const size_t idx); -struct json_object_s *json_array_get_object( - struct json_array_s *arr, const size_t idx); - -// objects -struct json_object_s *json_object_new(void); -void json_object_free(struct json_object_s *obj); -void json_object_element_free(struct json_object_element_s *element); - -void json_object_append( - struct json_object_s *obj, const char *key, struct json_value_s *value); -void json_object_append_bool(struct json_object_s *obj, const char *key, int b); -void json_object_append_int( - struct json_object_s *obj, const char *key, int number); -void json_object_append_int64( - struct json_object_s *obj, const char *key, int64_t number); -void json_object_append_double( - struct json_object_s *obj, const char *key, double number); -void json_object_append_string( - struct json_object_s *obj, const char *key, const char *string); -void json_object_append_array( - struct json_object_s *obj, const char *key, struct json_array_s *arr); -void json_object_append_object( - struct json_object_s *obj, const char *key, struct json_object_s *obj2); - -void json_object_evict_key(struct json_object_s *obj, const char *key); - -struct json_value_s *json_object_get_value( - struct json_object_s *obj, const char *key); -int json_object_get_bool(struct json_object_s *obj, const char *key, int d); -int json_object_get_int(struct json_object_s *obj, const char *key, int d); -int64_t json_object_get_int64( - struct json_object_s *obj, const char *key, int64_t d); -double json_object_get_double( - struct json_object_s *obj, const char *key, double d); -const char *json_object_get_string( - struct json_object_s *obj, const char *key, const char *d); -struct json_array_s *json_object_get_array( - struct json_object_s *obj, const char *key); -struct json_object_s *json_object_get_object( - struct json_object_s *obj, const char *key); - -// values -struct json_string_s *json_value_as_string(struct json_value_s *const value); -struct json_number_s *json_value_as_number(struct json_value_s *const value); -struct json_object_s *json_value_as_object(struct json_value_s *const value); -struct json_array_s *json_value_as_array(struct json_value_s *const value); -int json_value_is_true(const struct json_value_s *const value); -int json_value_is_false(const struct json_value_s *const value); -int json_value_is_null(const struct json_value_s *const value); - -struct json_value_s *json_value_from_bool(int b); -struct json_value_s *json_value_from_number(struct json_number_s *num); -struct json_value_s *json_value_from_string(struct json_string_s *str); -struct json_value_s *json_value_from_array(struct json_array_s *arr); -struct json_value_s *json_value_from_object(struct json_object_s *obj); - -void json_value_free(struct json_value_s *value); diff --git a/src/json/json_parse.c b/src/json/json_parse.c deleted file mode 100644 index 859297111..000000000 --- a/src/json/json_parse.c +++ /dev/null @@ -1,1809 +0,0 @@ -#include "json/json_parse.h" - -#include "json/json_base.h" -#include "shared/memory.h" - -struct json_parse_state_s { - const char *src; - size_t size; - size_t offset; - size_t flags_bitset; - char *data; - char *dom; - size_t dom_size; - size_t data_size; - size_t line_no; - size_t line_offset; - size_t error; -}; - -static int json_hexadecimal_digit(const char c); -static int json_hexadecimal_value( - const char *c, const unsigned long size, unsigned long *result); - -static int json_skip_whitespace(struct json_parse_state_s *state); -static int json_skip_c_style_comments(struct json_parse_state_s *state); -static int json_skip_all_skippables(struct json_parse_state_s *state); - -static int json_get_value_size( - struct json_parse_state_s *state, int is_global_object); -static int json_get_string_size( - struct json_parse_state_s *state, size_t is_key); -static int is_valid_unquoted_key_char(const char c); -static int json_get_key_size(struct json_parse_state_s *state); -static int json_get_object_size( - struct json_parse_state_s *state, int is_global_object); -static int json_get_array_size(struct json_parse_state_s *state); -static int json_get_number_size(struct json_parse_state_s *state); - -static void json_parse_value( - struct json_parse_state_s *state, int is_global_object, - struct json_value_s *value); -static void json_parse_string( - struct json_parse_state_s *state, struct json_string_s *string); -static void json_parse_key( - struct json_parse_state_s *state, struct json_string_s *string); -static void json_parse_object( - struct json_parse_state_s *state, int is_global_object, - struct json_object_s *object); -static void json_parse_array( - struct json_parse_state_s *state, struct json_array_s *array); -static void json_parse_number( - struct json_parse_state_s *state, struct json_number_s *number); - -static int json_hexadecimal_digit(const char c) -{ - if ('0' <= c && c <= '9') { - return c - '0'; - } - if ('a' <= c && c <= 'f') { - return c - 'a' + 10; - } - if ('A' <= c && c <= 'F') { - return c - 'A' + 10; - } - return -1; -} - -static int json_hexadecimal_value( - const char *c, const unsigned long size, unsigned long *result) -{ - const char *p; - int digit; - - if (size > sizeof(unsigned long) * 2) { - return 0; - } - - *result = 0; - for (p = c; (unsigned long)(p - c) < size; ++p) { - *result <<= 4; - digit = json_hexadecimal_digit(*p); - if (digit < 0 || digit > 15) { - return 0; - } - *result |= (unsigned char)digit; - } - return 1; -} - -static int json_skip_whitespace(struct json_parse_state_s *state) -{ - size_t offset = state->offset; - const size_t size = state->size; - const char *const src = state->src; - - /* the only valid whitespace according to ECMA-404 is ' ', '\n', '\r' and - * '\t'. */ - switch (src[offset]) { - default: - return 0; - case ' ': - case '\r': - case '\t': - case '\n': - break; - } - - do { - switch (src[offset]) { - default: - /* Update offset. */ - state->offset = offset; - return 1; - case ' ': - case '\r': - case '\t': - break; - case '\n': - state->line_no++; - state->line_offset = offset; - break; - } - - offset++; - } while (offset < size); - - /* Update offset. */ - state->offset = offset; - return 1; -} - -static int json_skip_c_style_comments(struct json_parse_state_s *state) -{ - /* do we have a comment?. */ - if ('/' == state->src[state->offset]) { - /* skip '/'. */ - state->offset++; - - if ('/' == state->src[state->offset]) { - /* we had a comment of the form //. */ - - /* skip second '/'. */ - state->offset++; - - while (state->offset < state->size) { - switch (state->src[state->offset]) { - default: - /* skip the character in the comment. */ - state->offset++; - break; - case '\n': - /* if we have a newline, our comment has ended! Skip the - * newline. */ - state->offset++; - - /* we entered a newline, so move our line info forward. */ - state->line_no++; - state->line_offset = state->offset; - return 1; - } - } - - /* we reached the end of the JSON file! */ - return 1; - } else if ('*' == state->src[state->offset]) { - /* we had a comment in the C-style long form. */ - - /* skip '*'. */ - state->offset++; - - while (state->offset + 1 < state->size) { - if (('*' == state->src[state->offset]) - && ('/' == state->src[state->offset + 1])) { - /* we reached the end of our comment! */ - state->offset += 2; - return 1; - } else if ('\n' == state->src[state->offset]) { - /* we entered a newline, so move our line info forward. */ - state->line_no++; - state->line_offset = state->offset; - } - - /* skip character within comment. */ - state->offset++; - } - - /* Comment wasn't ended correctly which is a failure. */ - return 1; - } - } - - /* we didn't have any comment, which is ok too! */ - return 0; -} - -static int json_skip_all_skippables(struct json_parse_state_s *state) -{ - /* skip all whitespace and other skippables until there are none left. note - * that the previous version suffered from read past errors should. the - * stream end on json_skip_c_style_comments eg. '{"a" ' with comments flag. - */ - - int did_consume = 0; - const size_t size = state->size; - - if (json_parse_flags_allow_c_style_comments & state->flags_bitset) { - do { - if (state->offset == size) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - did_consume = json_skip_whitespace(state); - - /* This should really be checked on access, not in front of every - * call. - */ - if (state->offset == size) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - did_consume |= json_skip_c_style_comments(state); - } while (0 != did_consume); - } else { - do { - if (state->offset == size) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - did_consume = json_skip_whitespace(state); - } while (0 != did_consume); - } - - if (state->offset == size) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - return 0; -} - -static int json_get_string_size(struct json_parse_state_s *state, size_t is_key) -{ - size_t offset = state->offset; - const size_t size = state->size; - size_t data_size = 0; - const char *const src = state->src; - const int is_single_quote = '\'' == src[offset]; - const char quote_to_use = is_single_quote ? '\'' : '"'; - const size_t flags_bitset = state->flags_bitset; - unsigned long codepoint; - unsigned long high_surrogate = 0; - - if ((json_parse_flags_allow_location_information & flags_bitset) != 0 - && is_key != 0) { - state->dom_size += sizeof(struct json_string_ex_s); - } else { - state->dom_size += sizeof(struct json_string_s); - } - - if ('"' != src[offset]) { - /* if we are allowed single quoted strings check for that too. */ - if (!((json_parse_flags_allow_single_quoted_strings & flags_bitset) - && is_single_quote)) { - state->error = json_parse_error_expected_opening_quote; - state->offset = offset; - return 1; - } - } - - /* skip leading '"' or '\''. */ - offset++; - - while ((offset < size) && (quote_to_use != src[offset])) { - /* add space for the character. */ - data_size++; - - switch (src[offset]) { - case '\0': - case '\t': - state->error = json_parse_error_invalid_string; - state->offset = offset; - return 1; - } - - if ('\\' == src[offset]) { - /* skip reverse solidus character. */ - offset++; - - if (offset == size) { - state->error = json_parse_error_premature_end_of_buffer; - state->offset = offset; - return 1; - } - - switch (src[offset]) { - default: - state->error = json_parse_error_invalid_string_escape_sequence; - state->offset = offset; - return 1; - case '"': - case '\\': - case '/': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - /* all valid characters! */ - offset++; - break; - case 'u': - if (!(offset + 5 < size)) { - /* invalid escaped unicode sequence! */ - state->error = - json_parse_error_invalid_string_escape_sequence; - state->offset = offset; - return 1; - } - - codepoint = 0; - if (!json_hexadecimal_value(&src[offset + 1], 4, &codepoint)) { - /* escaped unicode sequences must contain 4 hexadecimal - * digits! */ - state->error = - json_parse_error_invalid_string_escape_sequence; - state->offset = offset; - return 1; - } - - /* Valid sequence! - * see: https://en.wikipedia.org/wiki/UTF-8#Invalid_code_points. - * 1 7 U + 0000 U + 007F 0xxxxxxx. 2 11 - * U + 0080 U + 07FF 110xxxxx 10xxxxxx. 3 16 - * U + 0800 U + FFFF 1110xxxx 10xxxxxx 10xxxxxx. - * 4 21 U + 10000 U + 10FFFF 11110xxx - * 10xxxxxx 10xxxxxx 10xxxxxx. - * Note: the high and low surrogate halves used by UTF-16 - * (U+D800 through U+DFFF) and code points not encodable by - * UTF-16 (those after U+10FFFF) are not legal Unicode values, - * and their UTF-8 encoding must be treated as an invalid byte - * sequence. */ - - if (high_surrogate != 0) { - /* we previously read the high half of the \uxxxx\uxxxx - * pair, so now we expect the low half. */ - if (codepoint >= 0xdc00 - && codepoint <= 0xdfff) { /* low surrogate range. */ - data_size += 3; - high_surrogate = 0; - } else { - state->error = - json_parse_error_invalid_string_escape_sequence; - state->offset = offset; - return 1; - } - } else if (codepoint <= 0x7f) { - data_size += 0; - } else if (codepoint <= 0x7ff) { - data_size += 1; - } else if ( - codepoint >= 0xd800 && codepoint <= 0xdbff) { /* high - surrogate - range. - */ - /* The codepoint is the first half of a "utf-16 surrogate - * pair". so we need the other half for it to be valid: - * \uHHHH\uLLLL. */ - if (offset + 11 > size || '\\' != src[offset + 5] - || 'u' != src[offset + 6]) { - state->error = - json_parse_error_invalid_string_escape_sequence; - state->offset = offset; - return 1; - } - high_surrogate = codepoint; - } else if ( - codepoint >= 0xd800 && codepoint <= 0xdfff) { /* low - surrogate - range. - */ - /* we did not read the other half before. */ - state->error = - json_parse_error_invalid_string_escape_sequence; - state->offset = offset; - return 1; - } else { - data_size += 2; - } - /* escaped codepoints after 0xffff are supported in json through - * utf-16 surrogate pairs: \uD83D\uDD25 for U+1F525. */ - - offset += 5; - break; - } - } else if (('\r' == src[offset]) || ('\n' == src[offset])) { - if (!(json_parse_flags_allow_multi_line_strings & flags_bitset)) { - /* invalid escaped unicode sequence! */ - state->error = json_parse_error_invalid_string_escape_sequence; - state->offset = offset; - return 1; - } - - offset++; - } else { - /* skip character (valid part of sequence). */ - offset++; - } - } - - /* If the offset is equal to the size, we had a non-terminated string! */ - if (offset == size) { - state->error = json_parse_error_premature_end_of_buffer; - state->offset = offset - 1; - return 1; - } - - /* skip trailing '"' or '\''. */ - offset++; - - /* add enough space to store the string. */ - state->data_size += data_size; - - /* one more byte for null terminator ending the string! */ - state->data_size++; - - /* update offset. */ - state->offset = offset; - - return 0; -} - -static int is_valid_unquoted_key_char(const char c) -{ - return ( - ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') || ('_' == c)); -} - -static int json_get_key_size(struct json_parse_state_s *state) -{ - const size_t flags_bitset = state->flags_bitset; - - if (json_parse_flags_allow_unquoted_keys & flags_bitset) { - size_t offset = state->offset; - const size_t size = state->size; - const char *const src = state->src; - size_t data_size = state->data_size; - - /* if we are allowing unquoted keys, first grok for a quote... */ - if ('"' == src[offset]) { - /* ... if we got a comma, just parse the key as a string as normal. - */ - return json_get_string_size(state, 1); - } else if ( - (json_parse_flags_allow_single_quoted_strings & flags_bitset) - && ('\'' == src[offset])) { - /* ... if we got a comma, just parse the key as a string as normal. - */ - return json_get_string_size(state, 1); - } else { - while ((offset < size) && is_valid_unquoted_key_char(src[offset])) { - offset++; - data_size++; - } - - /* one more byte for null terminator ending the string! */ - data_size++; - - if (json_parse_flags_allow_location_information & flags_bitset) { - state->dom_size += sizeof(struct json_string_ex_s); - } else { - state->dom_size += sizeof(struct json_string_s); - } - - /* update offset. */ - state->offset = offset; - - /* update data_size. */ - state->data_size = data_size; - - return 0; - } - } else { - /* we are only allowed to have quoted keys, so just parse a string! */ - return json_get_string_size(state, 1); - } -} - -static int json_get_object_size( - struct json_parse_state_s *state, int is_global_object) -{ - const size_t flags_bitset = state->flags_bitset; - const char *const src = state->src; - const size_t size = state->size; - size_t elements = 0; - int allow_comma = 0; - int found_closing_brace = 0; - - if (is_global_object) { - /* if we found an opening '{' of an object, we actually have a normal - * JSON object at the root of the DOM... */ - if (!json_skip_all_skippables(state) - && '{' == state->src[state->offset]) { - /* . and we don't actually have a global object after all! */ - is_global_object = 0; - } - } - - if (!is_global_object) { - if ('{' != src[state->offset]) { - state->error = json_parse_error_unknown; - return 1; - } - - /* skip leading '{'. */ - state->offset++; - } - - state->dom_size += sizeof(struct json_object_s); - - if ((state->offset == size) && !is_global_object) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - do { - if (!is_global_object) { - if (json_skip_all_skippables(state)) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - if ('}' == src[state->offset]) { - /* skip trailing '}'. */ - state->offset++; - - found_closing_brace = 1; - - /* finished the object! */ - break; - } - } else { - /* we don't require brackets, so that means the object ends when the - * input stream ends! */ - if (json_skip_all_skippables(state)) { - break; - } - } - - /* if we parsed at least once element previously, grok for a comma. */ - if (allow_comma) { - if (',' == src[state->offset]) { - /* skip comma. */ - state->offset++; - allow_comma = 0; - } else if (json_parse_flags_allow_no_commas & flags_bitset) { - /* we don't require a comma, and we didn't find one, which is - * ok! */ - allow_comma = 0; - } else { - /* otherwise we are required to have a comma, and we found none. - */ - state->error = - json_parse_error_expected_comma_or_closing_bracket; - return 1; - } - - if (json_parse_flags_allow_trailing_comma & flags_bitset) { - continue; - } else { - if (json_skip_all_skippables(state)) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - } - } - - if (json_get_key_size(state)) { - /* key parsing failed! */ - state->error = json_parse_error_invalid_string; - return 1; - } - - if (json_skip_all_skippables(state)) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - if (json_parse_flags_allow_equals_in_object & flags_bitset) { - const char current = src[state->offset]; - if ((':' != current) && ('=' != current)) { - state->error = json_parse_error_expected_colon; - return 1; - } - } else { - if (':' != src[state->offset]) { - state->error = json_parse_error_expected_colon; - return 1; - } - } - - /* skip colon. */ - state->offset++; - - if (json_skip_all_skippables(state)) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - if (json_get_value_size(state, /* is_global_object = */ 0)) { - /* value parsing failed! */ - return 1; - } - - /* successfully parsed a name/value pair! */ - elements++; - allow_comma = 1; - } while (state->offset < size); - - if ((state->offset == size) && !is_global_object && !found_closing_brace) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - state->dom_size += sizeof(struct json_object_element_s) * elements; - - return 0; -} - -static int json_get_array_size(struct json_parse_state_s *state) -{ - const size_t flags_bitset = state->flags_bitset; - size_t elements = 0; - int allow_comma = 0; - const char *const src = state->src; - const size_t size = state->size; - - if ('[' != src[state->offset]) { - /* expected array to begin with leading '['. */ - state->error = json_parse_error_unknown; - return 1; - } - - /* skip leading '['. */ - state->offset++; - - state->dom_size += sizeof(struct json_array_s); - - while (state->offset < size) { - if (json_skip_all_skippables(state)) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - if (']' == src[state->offset]) { - /* skip trailing ']'. */ - state->offset++; - - state->dom_size += sizeof(struct json_array_element_s) * elements; - - /* finished the object! */ - return 0; - } - - /* if we parsed at least once element previously, grok for a comma. */ - if (allow_comma) { - if (',' == src[state->offset]) { - /* skip comma. */ - state->offset++; - allow_comma = 0; - } else if (!(json_parse_flags_allow_no_commas & flags_bitset)) { - state->error = - json_parse_error_expected_comma_or_closing_bracket; - return 1; - } - - if (json_parse_flags_allow_trailing_comma & flags_bitset) { - allow_comma = 0; - continue; - } else { - if (json_skip_all_skippables(state)) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - } - } - - if (json_get_value_size(state, /* is_global_object = */ 0)) { - /* value parsing failed! */ - return 1; - } - - /* successfully parsed an array element! */ - elements++; - allow_comma = 1; - } - - /* we consumed the entire input before finding the closing ']' of the array! - */ - state->error = json_parse_error_premature_end_of_buffer; - return 1; -} - -static int json_get_number_size(struct json_parse_state_s *state) -{ - const size_t flags_bitset = state->flags_bitset; - size_t offset = state->offset; - const size_t size = state->size; - int had_leading_digits = 0; - const char *const src = state->src; - - state->dom_size += sizeof(struct json_number_s); - - if ((json_parse_flags_allow_hexadecimal_numbers & flags_bitset) - && (offset + 1 < size) && ('0' == src[offset]) - && (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) { - /* skip the leading 0x that identifies a hexadecimal number. */ - offset += 2; - - /* consume hexadecimal digits. */ - while ((offset < size) - && (('0' <= src[offset] && src[offset] <= '9') - || ('a' <= src[offset] && src[offset] <= 'f') - || ('A' <= src[offset] && src[offset] <= 'F'))) { - offset++; - } - } else { - int found_sign = 0; - int inf_or_nan = 0; - - if ((offset < size) - && (('-' == src[offset]) - || ((json_parse_flags_allow_leading_plus_sign & flags_bitset) - && ('+' == src[offset])))) { - /* skip valid leading '-' or '+'. */ - offset++; - - found_sign = 1; - } - - if (json_parse_flags_allow_inf_and_nan & flags_bitset) { - const char inf[9] = "Infinity"; - const size_t inf_strlen = sizeof(inf) - 1; - const char nan[4] = "NaN"; - const size_t nan_strlen = sizeof(nan) - 1; - - if (offset + inf_strlen < size) { - int found = 1; - size_t i; - for (i = 0; i < inf_strlen; i++) { - if (inf[i] != src[offset + i]) { - found = 0; - break; - } - } - - if (found) { - /* We found our special 'Infinity' keyword! */ - offset += inf_strlen; - - inf_or_nan = 1; - } - } - - if (offset + nan_strlen < size) { - int found = 1; - size_t i; - for (i = 0; i < nan_strlen; i++) { - if (nan[i] != src[offset + i]) { - found = 0; - break; - } - } - - if (found) { - /* We found our special 'NaN' keyword! */ - offset += nan_strlen; - - inf_or_nan = 1; - } - } - } - - if (found_sign && !inf_or_nan && (offset < size) - && !('0' <= src[offset] && src[offset] <= '9')) { - /* check if we are allowing leading '.'. */ - if (!(json_parse_flags_allow_leading_or_trailing_decimal_point - & flags_bitset) - || ('.' != src[offset])) { - /* a leading '-' must be immediately followed by any digit! */ - state->error = json_parse_error_invalid_number_format; - state->offset = offset; - return 1; - } - } - - if ((offset < size) && ('0' == src[offset])) { - /* skip valid '0'. */ - offset++; - - /* we need to record whether we had any leading digits for checks - * later. - */ - had_leading_digits = 1; - - if ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) { - /* a leading '0' must not be immediately followed by any digit! - */ - state->error = json_parse_error_invalid_number_format; - state->offset = offset; - return 1; - } - } - - /* the main digits of our number next. */ - while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) { - offset++; - - /* we need to record whether we had any leading digits for checks - * later. - */ - had_leading_digits = 1; - } - - if ((offset < size) && ('.' == src[offset])) { - offset++; - - if (!('0' <= src[offset] && src[offset] <= '9')) { - if (!(json_parse_flags_allow_leading_or_trailing_decimal_point - & flags_bitset) - || !had_leading_digits) { - /* a decimal point must be followed by at least one digit. - */ - state->error = json_parse_error_invalid_number_format; - state->offset = offset; - return 1; - } - } - - /* a decimal point can be followed by more digits of course! */ - while ((offset < size) - && ('0' <= src[offset] && src[offset] <= '9')) { - offset++; - } - } - - if ((offset < size) && ('e' == src[offset] || 'E' == src[offset])) { - /* our number has an exponent! Skip 'e' or 'E'. */ - offset++; - - if ((offset < size) && ('-' == src[offset] || '+' == src[offset])) { - /* skip optional '-' or '+'. */ - offset++; - } - - if ((offset < size) - && !('0' <= src[offset] && src[offset] <= '9')) { - /* an exponent must have at least one digit! */ - state->error = json_parse_error_invalid_number_format; - state->offset = offset; - return 1; - } - - /* consume exponent digits. */ - do { - offset++; - } while ((offset < size) - && ('0' <= src[offset] && src[offset] <= '9')); - } - } - - if (offset < size) { - switch (src[offset]) { - case ' ': - case '\t': - case '\r': - case '\n': - case '}': - case ',': - case ']': - /* all of the above are ok. */ - break; - case '=': - if (json_parse_flags_allow_equals_in_object & flags_bitset) { - break; - } - - state->error = json_parse_error_invalid_number_format; - state->offset = offset; - return 1; - default: - state->error = json_parse_error_invalid_number_format; - state->offset = offset; - return 1; - } - } - - state->data_size += offset - state->offset; - - /* one more byte for null terminator ending the number string! */ - state->data_size++; - - /* update offset. */ - state->offset = offset; - - return 0; -} - -static int json_get_value_size( - struct json_parse_state_s *state, int is_global_object) -{ - const size_t flags_bitset = state->flags_bitset; - const char *const src = state->src; - size_t offset; - const size_t size = state->size; - - if (json_parse_flags_allow_location_information & flags_bitset) { - state->dom_size += sizeof(struct json_value_ex_s); - } else { - state->dom_size += sizeof(struct json_value_s); - } - - if (is_global_object) { - return json_get_object_size(state, /* is_global_object = */ 1); - } else { - if (json_skip_all_skippables(state)) { - state->error = json_parse_error_premature_end_of_buffer; - return 1; - } - - /* can cache offset now. */ - offset = state->offset; - - switch (src[offset]) { - case '"': - return json_get_string_size(state, 0); - case '\'': - if (json_parse_flags_allow_single_quoted_strings & flags_bitset) { - return json_get_string_size(state, 0); - } else { - /* invalid value! */ - state->error = json_parse_error_invalid_value; - return 1; - } - case '{': - return json_get_object_size(state, /* is_global_object = */ 0); - case '[': - return json_get_array_size(state); - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return json_get_number_size(state); - case '+': - if (json_parse_flags_allow_leading_plus_sign & flags_bitset) { - return json_get_number_size(state); - } else { - /* invalid value! */ - state->error = json_parse_error_invalid_number_format; - return 1; - } - case '.': - if (json_parse_flags_allow_leading_or_trailing_decimal_point - & flags_bitset) { - return json_get_number_size(state); - } else { - /* invalid value! */ - state->error = json_parse_error_invalid_number_format; - return 1; - } - default: - if ((offset + 4) <= size && 't' == src[offset + 0] - && 'r' == src[offset + 1] && 'u' == src[offset + 2] - && 'e' == src[offset + 3]) { - state->offset += 4; - return 0; - } else if ( - (offset + 5) <= size && 'f' == src[offset + 0] - && 'a' == src[offset + 1] && 'l' == src[offset + 2] - && 's' == src[offset + 3] && 'e' == src[offset + 4]) { - state->offset += 5; - return 0; - } else if ( - (offset + 4) <= size && 'n' == state->src[offset + 0] - && 'u' == state->src[offset + 1] - && 'l' == state->src[offset + 2] - && 'l' == state->src[offset + 3]) { - state->offset += 4; - return 0; - } else if ( - (json_parse_flags_allow_inf_and_nan & flags_bitset) - && (offset + 3) <= size && 'N' == src[offset + 0] - && 'a' == src[offset + 1] && 'N' == src[offset + 2]) { - return json_get_number_size(state); - } else if ( - (json_parse_flags_allow_inf_and_nan & flags_bitset) - && (offset + 8) <= size && 'I' == src[offset + 0] - && 'n' == src[offset + 1] && 'f' == src[offset + 2] - && 'i' == src[offset + 3] && 'n' == src[offset + 4] - && 'i' == src[offset + 5] && 't' == src[offset + 6] - && 'y' == src[offset + 7]) { - return json_get_number_size(state); - } - - /* invalid value! */ - state->error = json_parse_error_invalid_value; - return 1; - } - } -} - -static void json_parse_string( - struct json_parse_state_s *state, struct json_string_s *string) -{ - size_t offset = state->offset; - size_t bytes_written = 0; - const char *const src = state->src; - const char quote_to_use = '\'' == src[offset] ? '\'' : '"'; - char *data = state->data; - unsigned long high_surrogate = 0; - unsigned long codepoint; - - string->ref_count = 1; - string->string = data; - - /* skip leading '"' or '\''. */ - offset++; - - while (quote_to_use != src[offset]) { - if ('\\' == src[offset]) { - /* skip the reverse solidus. */ - offset++; - - switch (src[offset++]) { - default: - return; /* we cannot ever reach here. */ - case 'u': { - codepoint = 0; - if (!json_hexadecimal_value(&src[offset], 4, &codepoint)) { - return; /* this shouldn't happen as the value was already - * validated. - */ - } - - offset += 4; - - if (codepoint <= 0x7fu) { - data[bytes_written++] = (char)codepoint; /* 0xxxxxxx. */ - } else if (codepoint <= 0x7ffu) { - data[bytes_written++] = - (char)(0xc0u | (codepoint >> 6)); /* 110xxxxx. */ - data[bytes_written++] = - (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */ - } else if ( - codepoint >= 0xd800 && codepoint <= 0xdbff) { /* high - surrogate. - */ - high_surrogate = codepoint; - continue; /* we need the low half to form a complete - codepoint. */ - } else if ( - codepoint >= 0xdc00 && codepoint <= 0xdfff) { /* low - surrogate. - */ - /* combine with the previously read half to obtain the - * complete codepoint. */ - const unsigned long surrogate_offset = - 0x10000u - (0xD800u << 10) - 0xDC00u; - codepoint = - (high_surrogate << 10) + codepoint + surrogate_offset; - high_surrogate = 0; - data[bytes_written++] = - (char)(0xF0u | (codepoint >> 18)); /* 11110xxx. */ - data[bytes_written++] = - (char)(0x80u - | ((codepoint >> 12) & 0x3fu)); /* 10xxxxxx. - */ - data[bytes_written++] = - (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. - */ - data[bytes_written++] = - (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */ - } else { - /* we assume the value was validated and thus is within the - * valid range. */ - data[bytes_written++] = - (char)(0xe0u | (codepoint >> 12)); /* 1110xxxx. */ - data[bytes_written++] = - (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. - */ - data[bytes_written++] = - (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */ - } - } break; - case '"': - data[bytes_written++] = '"'; - break; - case '\\': - data[bytes_written++] = '\\'; - break; - case '/': - data[bytes_written++] = '/'; - break; - case 'b': - data[bytes_written++] = '\b'; - break; - case 'f': - data[bytes_written++] = '\f'; - break; - case 'n': - data[bytes_written++] = '\n'; - break; - case 'r': - data[bytes_written++] = '\r'; - break; - case 't': - data[bytes_written++] = '\t'; - break; - case '\r': - data[bytes_written++] = '\r'; - - /* check if we have a "\r\n" sequence. */ - if ('\n' == src[offset]) { - data[bytes_written++] = '\n'; - offset++; - } - - break; - case '\n': - data[bytes_written++] = '\n'; - break; - } - } else { - /* copy the character. */ - data[bytes_written++] = src[offset++]; - } - } - - /* skip trailing '"' or '\''. */ - offset++; - - /* record the size of the string. */ - string->string_size = bytes_written; - - /* add null terminator to string. */ - data[bytes_written++] = '\0'; - - /* move data along. */ - state->data += bytes_written; - - /* update offset. */ - state->offset = offset; -} - -static void json_parse_key( - struct json_parse_state_s *state, struct json_string_s *string) -{ - if (json_parse_flags_allow_unquoted_keys & state->flags_bitset) { - const char *const src = state->src; - char *const data = state->data; - size_t offset = state->offset; - - /* if we are allowing unquoted keys, check for quoted anyway... */ - if (('"' == src[offset]) || ('\'' == src[offset])) { - /* ... if we got a quote, just parse the key as a string as normal. - */ - json_parse_string(state, string); - } else { - size_t size = 0; - - string->ref_count = 1; - string->string = state->data; - - while (is_valid_unquoted_key_char(src[offset])) { - data[size++] = src[offset++]; - } - - /* add null terminator to string. */ - data[size] = '\0'; - - /* record the size of the string. */ - string->string_size = size++; - - /* move data along. */ - state->data += size; - - /* update offset. */ - state->offset = offset; - } - } else { - /* we are only allowed to have quoted keys, so just parse a string! */ - json_parse_string(state, string); - } -} - -static void json_parse_object( - struct json_parse_state_s *state, int is_global_object, - struct json_object_s *object) -{ - const size_t flags_bitset = state->flags_bitset; - const size_t size = state->size; - const char *const src = state->src; - size_t elements = 0; - int allow_comma = 0; - struct json_object_element_s *previous = json_null; - - if (is_global_object) { - /* if we skipped some whitespace, and then found an opening '{' of an. - */ - /* object, we actually have a normal JSON object at the root of the - * DOM... - */ - if ('{' == src[state->offset]) { - /* . and we don't actually have a global object after all! */ - is_global_object = 0; - } - } - - if (!is_global_object) { - /* skip leading '{'. */ - state->offset++; - } - - (void)json_skip_all_skippables(state); - - /* reset elements. */ - elements = 0; - - while (state->offset < size) { - struct json_object_element_s *element = json_null; - struct json_string_s *string = json_null; - struct json_value_s *value = json_null; - - if (!is_global_object) { - (void)json_skip_all_skippables(state); - - if ('}' == src[state->offset]) { - /* skip trailing '}'. */ - state->offset++; - - /* finished the object! */ - break; - } - } else { - if (json_skip_all_skippables(state)) { - /* global object ends when the file ends! */ - break; - } - } - - /* if we parsed at least one element previously, grok for a comma. */ - if (allow_comma) { - if (',' == src[state->offset]) { - /* skip comma. */ - state->offset++; - allow_comma = 0; - continue; - } - } - - element = (struct json_object_element_s *)state->dom; - element->ref_count = 1; - - state->dom += sizeof(struct json_object_element_s); - - if (json_null == previous) { - /* this is our first element, so record it in our object. */ - object->start = element; - } else { - previous->next = element; - } - - previous = element; - - if (json_parse_flags_allow_location_information & flags_bitset) { - struct json_string_ex_s *string_ex = - (struct json_string_ex_s *)state->dom; - state->dom += sizeof(struct json_string_ex_s); - - string_ex->offset = state->offset; - string_ex->line_no = state->line_no; - string_ex->row_no = state->offset - state->line_offset; - - string = &(string_ex->string); - } else { - string = (struct json_string_s *)state->dom; - state->dom += sizeof(struct json_string_s); - } - - element->name = string; - - (void)json_parse_key(state, string); - - (void)json_skip_all_skippables(state); - - /* skip colon or equals. */ - state->offset++; - - (void)json_skip_all_skippables(state); - - if (json_parse_flags_allow_location_information & flags_bitset) { - struct json_value_ex_s *value_ex = - (struct json_value_ex_s *)state->dom; - state->dom += sizeof(struct json_value_ex_s); - - value_ex->offset = state->offset; - value_ex->line_no = state->line_no; - value_ex->row_no = state->offset - state->line_offset; - - value = &(value_ex->value); - } else { - value = (struct json_value_s *)state->dom; - state->dom += sizeof(struct json_value_s); - } - - element->value = value; - - json_parse_value(state, /* is_global_object = */ 0, value); - - /* successfully parsed a name/value pair! */ - elements++; - allow_comma = 1; - } - - /* if we had at least one element, end the linked list. */ - if (previous) { - previous->next = json_null; - } - - if (0 == elements) { - object->start = json_null; - } - - object->ref_count = 1; - object->length = elements; -} - -static void json_parse_array( - struct json_parse_state_s *state, struct json_array_s *array) -{ - const char *const src = state->src; - const size_t size = state->size; - size_t elements = 0; - int allow_comma = 0; - struct json_array_element_s *previous = json_null; - - /* skip leading '['. */ - state->offset++; - - (void)json_skip_all_skippables(state); - - /* reset elements. */ - elements = 0; - - do { - struct json_array_element_s *element = json_null; - struct json_value_s *value = json_null; - - (void)json_skip_all_skippables(state); - - if (']' == src[state->offset]) { - /* skip trailing ']'. */ - state->offset++; - - /* finished the array! */ - break; - } - - /* if we parsed at least one element previously, grok for a comma. */ - if (allow_comma) { - if (',' == src[state->offset]) { - /* skip comma. */ - state->offset++; - allow_comma = 0; - continue; - } - } - - element = (struct json_array_element_s *)state->dom; - element->ref_count = 1; - - state->dom += sizeof(struct json_array_element_s); - - if (json_null == previous) { - /* this is our first element, so record it in our array. */ - array->start = element; - } else { - previous->next = element; - } - - previous = element; - - if (json_parse_flags_allow_location_information & state->flags_bitset) { - struct json_value_ex_s *value_ex = - (struct json_value_ex_s *)state->dom; - state->dom += sizeof(struct json_value_ex_s); - - value_ex->offset = state->offset; - value_ex->line_no = state->line_no; - value_ex->row_no = state->offset - state->line_offset; - - value = &(value_ex->value); - } else { - value = (struct json_value_s *)state->dom; - state->dom += sizeof(struct json_value_s); - } - - element->value = value; - - json_parse_value(state, /* is_global_object = */ 0, value); - - /* successfully parsed an array element! */ - elements++; - allow_comma = 1; - } while (state->offset < size); - - /* end the linked list. */ - if (previous) { - previous->next = json_null; - } - - if (0 == elements) { - array->start = json_null; - } - - array->ref_count = 1; - array->length = elements; -} - -static void json_parse_number( - struct json_parse_state_s *state, struct json_number_s *number) -{ - const size_t flags_bitset = state->flags_bitset; - size_t offset = state->offset; - const size_t size = state->size; - size_t bytes_written = 0; - const char *const src = state->src; - char *data = state->data; - - number->ref_count = 1; - number->number = data; - - if (json_parse_flags_allow_hexadecimal_numbers & flags_bitset) { - if (('0' == src[offset]) - && (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) { - /* consume hexadecimal digits. */ - while ((offset < size) - && (('0' <= src[offset] && src[offset] <= '9') - || ('a' <= src[offset] && src[offset] <= 'f') - || ('A' <= src[offset] && src[offset] <= 'F') - || ('x' == src[offset]) || ('X' == src[offset]))) { - data[bytes_written++] = src[offset++]; - } - } - } - - while (offset < size) { - int end = 0; - - switch (src[offset]) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '.': - case 'e': - case 'E': - case '+': - case '-': - data[bytes_written++] = src[offset++]; - break; - default: - end = 1; - break; - } - - if (0 != end) { - break; - } - } - - if (json_parse_flags_allow_inf_and_nan & flags_bitset) { - const size_t inf_strlen = 8; /* = strlen("Infinity");. */ - const size_t nan_strlen = 3; /* = strlen("NaN");. */ - - if (offset + inf_strlen < size) { - if ('I' == src[offset]) { - size_t i; - /* We found our special 'Infinity' keyword! */ - for (i = 0; i < inf_strlen; i++) { - data[bytes_written++] = src[offset++]; - } - } - } - - if (offset + nan_strlen < size) { - if ('N' == src[offset]) { - size_t i; - /* We found our special 'NaN' keyword! */ - for (i = 0; i < nan_strlen; i++) { - data[bytes_written++] = src[offset++]; - } - } - } - } - - /* record the size of the number. */ - number->number_size = bytes_written; - /* add null terminator to number string. */ - data[bytes_written++] = '\0'; - /* move data along. */ - state->data += bytes_written; - /* update offset. */ - state->offset = offset; -} - -static void json_parse_value( - struct json_parse_state_s *state, int is_global_object, - struct json_value_s *value) -{ - const size_t flags_bitset = state->flags_bitset; - const char *const src = state->src; - const size_t size = state->size; - size_t offset; - - (void)json_skip_all_skippables(state); - - /* cache offset now. */ - offset = state->offset; - - if (is_global_object) { - value->type = json_type_object; - value->payload = state->dom; - state->dom += sizeof(struct json_object_s); - json_parse_object( - state, /* is_global_object = */ 1, - (struct json_object_s *)value->payload); - } else { - value->ref_count = 1; - switch (src[offset]) { - case '"': - case '\'': - value->type = json_type_string; - value->payload = state->dom; - state->dom += sizeof(struct json_string_s); - json_parse_string(state, (struct json_string_s *)value->payload); - break; - case '{': - value->type = json_type_object; - value->payload = state->dom; - state->dom += sizeof(struct json_object_s); - json_parse_object( - state, /* is_global_object = */ 0, - (struct json_object_s *)value->payload); - break; - case '[': - value->type = json_type_array; - value->payload = state->dom; - state->dom += sizeof(struct json_array_s); - json_parse_array(state, (struct json_array_s *)value->payload); - break; - case '-': - case '+': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '.': - value->type = json_type_number; - value->payload = state->dom; - state->dom += sizeof(struct json_number_s); - json_parse_number(state, (struct json_number_s *)value->payload); - break; - default: - if ((offset + 4) <= size && 't' == src[offset + 0] - && 'r' == src[offset + 1] && 'u' == src[offset + 2] - && 'e' == src[offset + 3]) { - value->type = json_type_true; - value->payload = json_null; - state->offset += 4; - } else if ( - (offset + 5) <= size && 'f' == src[offset + 0] - && 'a' == src[offset + 1] && 'l' == src[offset + 2] - && 's' == src[offset + 3] && 'e' == src[offset + 4]) { - value->type = json_type_false; - value->payload = json_null; - state->offset += 5; - } else if ( - (offset + 4) <= size && 'n' == src[offset + 0] - && 'u' == src[offset + 1] && 'l' == src[offset + 2] - && 'l' == src[offset + 3]) { - value->type = json_type_null; - value->payload = json_null; - state->offset += 4; - } else if ( - (json_parse_flags_allow_inf_and_nan & flags_bitset) - && (offset + 3) <= size && 'N' == src[offset + 0] - && 'a' == src[offset + 1] && 'N' == src[offset + 2]) { - value->type = json_type_number; - value->payload = state->dom; - state->dom += sizeof(struct json_number_s); - json_parse_number( - state, (struct json_number_s *)value->payload); - } else if ( - (json_parse_flags_allow_inf_and_nan & flags_bitset) - && (offset + 8) <= size && 'I' == src[offset + 0] - && 'n' == src[offset + 1] && 'f' == src[offset + 2] - && 'i' == src[offset + 3] && 'n' == src[offset + 4] - && 'i' == src[offset + 5] && 't' == src[offset + 6] - && 'y' == src[offset + 7]) { - value->type = json_type_number; - value->payload = state->dom; - state->dom += sizeof(struct json_number_s); - json_parse_number( - state, (struct json_number_s *)value->payload); - } - break; - } - } -} - -struct json_value_s *json_parse(const void *src, size_t src_size) -{ - return json_parse_ex( - src, src_size, json_parse_flags_default, json_null, json_null, - json_null); -} - -struct json_value_s *json_parse_ex( - const void *src, size_t src_size, size_t flags_bitset, - void *(*alloc_func_ptr)(void *user_data, size_t size), void *user_data, - struct json_parse_result_s *result) -{ - struct json_parse_state_s state; - void *allocation; - struct json_value_s *value; - size_t total_size; - int input_error; - - if (result) { - result->error = json_parse_error_none; - result->error_offset = 0; - result->error_line_no = 0; - result->error_row_no = 0; - } - - if (json_null == src) { - /* invalid src pointer was null! */ - return json_null; - } - - state.src = (const char *)src; - state.size = src_size; - state.offset = 0; - state.line_no = 1; - state.line_offset = 0; - state.error = json_parse_error_none; - state.dom_size = 0; - state.data_size = 0; - state.flags_bitset = flags_bitset; - - input_error = json_get_value_size( - &state, - (int)(json_parse_flags_allow_global_object & state.flags_bitset)); - - if (0 == input_error) { - json_skip_all_skippables(&state); - - if (state.offset != state.size) { - /* our parsing didn't have an error, but there are characters - * remaining in the input that weren't part of the JSON! */ - - state.error = json_parse_error_unexpected_trailing_characters; - input_error = 1; - } - } - - if (input_error) { - /* parsing value's size failed (most likely an invalid JSON DOM!). */ - if (result) { - result->error = state.error; - result->error_offset = state.offset; - result->error_line_no = state.line_no; - result->error_row_no = state.offset - state.line_offset; - } - return json_null; - } - - /* our total allocation is the combination of the dom and data sizes (we. */ - /* first encode the structure of the JSON, and then the data referenced by. - */ - /* the JSON values). */ - total_size = state.dom_size + state.data_size; - - if (json_null == alloc_func_ptr) { - allocation = Memory_Alloc(total_size); - } else { - allocation = alloc_func_ptr(user_data, total_size); - } - - if (json_null == allocation) { - /* malloc failed! */ - if (result) { - result->error = json_parse_error_allocator_failed; - result->error_offset = 0; - result->error_line_no = 0; - result->error_row_no = 0; - } - - return json_null; - } - - /* reset offset so we can reuse it. */ - state.offset = 0; - - /* reset the line information so we can reuse it. */ - state.line_no = 1; - state.line_offset = 0; - - state.dom = (char *)allocation; - state.data = state.dom + state.dom_size; - - if (json_parse_flags_allow_location_information & state.flags_bitset) { - struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state.dom; - state.dom += sizeof(struct json_value_ex_s); - - value_ex->offset = state.offset; - value_ex->line_no = state.line_no; - value_ex->row_no = state.offset - state.line_offset; - - value = &(value_ex->value); - } else { - value = (struct json_value_s *)state.dom; - state.dom += sizeof(struct json_value_s); - } - - json_parse_value( - &state, - (int)(json_parse_flags_allow_global_object & state.flags_bitset), - value); - - ((struct json_value_s *)allocation)->ref_count = 0; - - return (struct json_value_s *)allocation; -} - -const char *json_get_error_description(enum json_parse_error_e error) -{ - switch (error) { - case json_parse_error_none: - return "no error"; - - case json_parse_error_expected_comma_or_closing_bracket: - return "expected comma or closing bracket"; - - case json_parse_error_expected_colon: - return "expected colon"; - - case json_parse_error_expected_opening_quote: - return "expected opening quote"; - - case json_parse_error_invalid_string_escape_sequence: - return "invalid string escape sequence"; - - case json_parse_error_invalid_number_format: - return "invalid number format"; - - case json_parse_error_invalid_value: - return "invalid value"; - - case json_parse_error_premature_end_of_buffer: - return "premature end of buffer"; - - case json_parse_error_invalid_string: - return "allocator failed"; - - case json_parse_error_allocator_failed: - return "allocator failed"; - - case json_parse_error_unexpected_trailing_characters: - return "unexpected trailing characters"; - - case json_parse_error_unknown: - default: - return "unknown"; - } -} diff --git a/src/json/json_parse.h b/src/json/json_parse.h deleted file mode 100644 index 547935857..000000000 --- a/src/json/json_parse.h +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once - -#include "json/json_base.h" - -#include - -enum json_parse_error_e { - json_parse_error_none = 0, - json_parse_error_expected_comma_or_closing_bracket, - json_parse_error_expected_colon, - json_parse_error_expected_opening_quote, - json_parse_error_invalid_string_escape_sequence, - json_parse_error_invalid_number_format, - json_parse_error_invalid_value, - json_parse_error_premature_end_of_buffer, - json_parse_error_invalid_string, - json_parse_error_allocator_failed, - json_parse_error_unexpected_trailing_characters, - json_parse_error_unknown -}; - -struct json_parse_result_s { - size_t error; - size_t error_offset; - size_t error_line_no; - size_t error_row_no; -}; - -enum json_parse_flags_e { - json_parse_flags_default = 0, - - /* allow trailing commas in objects and arrays. For example, both [true,] - and - {"a" : null,} would be allowed with this option on. */ - json_parse_flags_allow_trailing_comma = 0x1, - - /* allow unquoted keys for objects. For example, {a : null} would be allowed - with this option on. */ - json_parse_flags_allow_unquoted_keys = 0x2, - - /* allow a global unbracketed object. For example, a : null, b : true, c : - {} would be allowed with this option on. */ - json_parse_flags_allow_global_object = 0x4, - - /* allow objects to use '=' instead of ':' between key/value pairs. For - example, a = null, b : true would be allowed with this option on. */ - json_parse_flags_allow_equals_in_object = 0x8, - - /* allow that objects don't have to have comma separators between key/value - pairs. */ - json_parse_flags_allow_no_commas = 0x10, - - /* allow c-style comments (either variants) to be ignored in the input JSON - file. */ - json_parse_flags_allow_c_style_comments = 0x20, - - /* deprecated flag, unused. */ - json_parse_flags_deprecated = 0x40, - - /* record location information for each value. */ - json_parse_flags_allow_location_information = 0x80, - - /* allow strings to be 'single quoted'. */ - json_parse_flags_allow_single_quoted_strings = 0x100, - - /* allow numbers to be hexadecimal. */ - json_parse_flags_allow_hexadecimal_numbers = 0x200, - - /* allow numbers like +123 to be parsed. */ - json_parse_flags_allow_leading_plus_sign = 0x400, - - /* allow numbers like .0123 or 123. to be parsed. */ - json_parse_flags_allow_leading_or_trailing_decimal_point = 0x800, - - /* allow Infinity, -Infinity, NaN, -NaN. */ - json_parse_flags_allow_inf_and_nan = 0x1000, - - /* allow multi line string values. */ - json_parse_flags_allow_multi_line_strings = 0x2000, - - /* allow simplified JSON to be parsed. Simplified JSON is an enabling of a - set of other parsing options. */ - json_parse_flags_allow_simplified_json = - (json_parse_flags_allow_trailing_comma - | json_parse_flags_allow_unquoted_keys - | json_parse_flags_allow_global_object - | json_parse_flags_allow_equals_in_object - | json_parse_flags_allow_no_commas), - - /* allow JSON5 to be parsed. JSON5 is an enabling of a set of other parsing - options. */ - json_parse_flags_allow_json5 = - (json_parse_flags_allow_trailing_comma - | json_parse_flags_allow_unquoted_keys - | json_parse_flags_allow_c_style_comments - | json_parse_flags_allow_single_quoted_strings - | json_parse_flags_allow_hexadecimal_numbers - | json_parse_flags_allow_leading_plus_sign - | json_parse_flags_allow_leading_or_trailing_decimal_point - | json_parse_flags_allow_inf_and_nan - | json_parse_flags_allow_multi_line_strings) -}; - -/* Parse a JSON text file, returning a pointer to the root of the JSON - * structure. json_parse performs 1 call to malloc for the entire encoding. - * Returns 0 if an error occurred (malformed JSON input, or malloc failed). */ -struct json_value_s *json_parse(const void *src, size_t src_size); - -/* Parse a JSON text file, returning a pointer to the root of the JSON - * structure. json_parse performs 1 call to alloc_func_ptr for the entire - * encoding. Returns 0 if an error occurred (malformed JSON input, or malloc - * failed). If an error occurred, the result struct (if not NULL) will explain - * the type of error, and the location in the input it occurred. If - * alloc_func_ptr is null then malloc is used. */ -struct json_value_s *json_parse_ex( - const void *src, size_t src_size, size_t flags_bitset, - void *(*alloc_func_ptr)(void *, size_t), void *user_data, - struct json_parse_result_s *result); - -const char *json_get_error_description(enum json_parse_error_e error); diff --git a/src/json/json_write.c b/src/json/json_write.c deleted file mode 100644 index 00358b923..000000000 --- a/src/json/json_write.c +++ /dev/null @@ -1,991 +0,0 @@ -#include "json/json_write.h" - -#include "json/json_base.h" -#include "shared/memory.h" - -static int json_write_minified_get_value_size( - const struct json_value_s *value, size_t *size); -static int json_write_get_number_size( - const struct json_number_s *number, size_t *size); -static int json_write_get_string_size( - const struct json_string_s *string, size_t *size); -static int json_write_minified_get_array_size( - const struct json_array_s *array, size_t *size); -static int json_write_minified_get_object_size( - const struct json_object_s *object, size_t *size); -static char *json_write_minified_value( - const struct json_value_s *value, char *data); -static char *json_write_number(const struct json_number_s *number, char *data); -static char *json_write_string(const struct json_string_s *string, char *data); -static char *json_write_minified_array( - const struct json_array_s *array, char *data); -static char *json_write_minified_object( - const struct json_object_s *object, char *data); -static int json_write_pretty_get_value_size( - const struct json_value_s *value, size_t depth, size_t indent_size, - size_t newline_size, size_t *size); -static int json_write_pretty_get_array_size( - const struct json_array_s *array, size_t depth, size_t indent_size, - size_t newline_size, size_t *size); -static int json_write_pretty_get_object_size( - const struct json_object_s *object, size_t depth, size_t indent_size, - size_t newline_size, size_t *size); -static char *json_write_pretty_value( - const struct json_value_s *value, size_t depth, const char *indent, - const char *newline, char *data); -static char *json_write_pretty_array( - const struct json_array_s *array, size_t depth, const char *indent, - const char *newline, char *data); -static char *json_write_pretty_object( - const struct json_object_s *object, size_t depth, const char *indent, - const char *newline, char *data); - -static int json_write_get_number_size( - const struct json_number_s *number, size_t *size) -{ - json_uintmax_t parsed_number; - size_t i; - - if (number->number_size >= 2) { - switch (number->number[1]) { - case 'x': - case 'X': - /* the number is a json_parse_flags_allow_hexadecimal_numbers - * hexadecimal so we have to do extra work to convert it to a - * non-hexadecimal for JSON output. */ - parsed_number = json_strtoumax(number->number, json_null, 0); - - i = 0; - - while (0 != parsed_number) { - parsed_number /= 10; - i++; - } - - *size += i; - return 0; - } - } - - /* check to see if the number has leading/trailing decimal point. */ - i = 0; - - /* skip any leading '+' or '-'. */ - if ((i < number->number_size) - && (('+' == number->number[i]) || ('-' == number->number[i]))) { - i++; - } - - /* check if we have infinity. */ - if ((i < number->number_size) && ('I' == number->number[i])) { - const char *inf = "Infinity"; - size_t k; - - for (k = i; k < number->number_size; k++) { - const char c = *inf++; - - /* Check if we found the Infinity string! */ - if ('\0' == c) { - break; - } else if (c != number->number[k]) { - break; - } - } - - if ('\0' == *inf) { - /* Inf becomes 1.7976931348623158e308 because JSON can't support it. - */ - *size += 22; - - /* if we had a leading '-' we need to record it in the JSON output. - */ - if ('-' == number->number[0]) { - *size += 1; - } - } - - return 0; - } - - /* check if we have nan. */ - if ((i < number->number_size) && ('N' == number->number[i])) { - const char *nan = "NaN"; - size_t k; - - for (k = i; k < number->number_size; k++) { - const char c = *nan++; - - /* Check if we found the NaN string! */ - if ('\0' == c) { - break; - } else if (c != number->number[k]) { - break; - } - } - - if ('\0' == *nan) { - /* NaN becomes 1 because JSON can't support it. */ - *size += 1; - - return 0; - } - } - - /* if we had a leading decimal point. */ - if ((i < number->number_size) && ('.' == number->number[i])) { - /* 1 + because we had a leading decimal point. */ - *size += 1; - goto cleanup; - } - - for (; i < number->number_size; i++) { - const char c = number->number[i]; - if (!('0' <= c && c <= '9')) { - break; - } - } - - /* if we had a trailing decimal point. */ - if ((i + 1 == number->number_size) && ('.' == number->number[i])) { - /* 1 + because we had a trailing decimal point. */ - *size += 1; - goto cleanup; - } - -cleanup: - *size += number->number_size; /* the actual string of the number. */ - - /* if we had a leading '+' we don't record it in the JSON output. */ - if ('+' == number->number[0]) { - *size -= 1; - } - - return 0; -} - -static int json_write_get_string_size( - const struct json_string_s *string, size_t *size) -{ - size_t i; - for (i = 0; i < string->string_size; i++) { - switch (string->string[i]) { - case '"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - *size += 2; - break; - default: - *size += 1; - break; - } - } - - *size += 2; /* need to encode the surrounding '"' characters. */ - - return 0; -} - -static int json_write_minified_get_array_size( - const struct json_array_s *array, size_t *size) -{ - struct json_array_element_s *element; - - *size += 2; /* '[' and ']'. */ - - if (1 < array->length) { - *size += array->length - 1; /* ','s seperate each element. */ - } - - for (element = array->start; json_null != element; - element = element->next) { - if (json_write_minified_get_value_size(element->value, size)) { - /* value was malformed! */ - return 1; - } - } - - return 0; -} - -static int json_write_minified_get_object_size( - const struct json_object_s *object, size_t *size) -{ - struct json_object_element_s *element; - - *size += 2; /* '{' and '}'. */ - - *size += object->length; /* ':'s seperate each name/value pair. */ - - if (1 < object->length) { - *size += object->length - 1; /* ','s seperate each element. */ - } - - for (element = object->start; json_null != element; - element = element->next) { - if (json_write_get_string_size(element->name, size)) { - /* string was malformed! */ - return 1; - } - - if (json_write_minified_get_value_size(element->value, size)) { - /* value was malformed! */ - return 1; - } - } - - return 0; -} - -static int json_write_minified_get_value_size( - const struct json_value_s *value, size_t *size) -{ - switch (value->type) { - default: - /* unknown value type found! */ - return 1; - case json_type_number: - return json_write_get_number_size( - (struct json_number_s *)value->payload, size); - case json_type_string: - return json_write_get_string_size( - (struct json_string_s *)value->payload, size); - case json_type_array: - return json_write_minified_get_array_size( - (struct json_array_s *)value->payload, size); - case json_type_object: - return json_write_minified_get_object_size( - (struct json_object_s *)value->payload, size); - case json_type_true: - *size += 4; /* the string "true". */ - return 0; - case json_type_false: - *size += 5; /* the string "false". */ - return 0; - case json_type_null: - *size += 4; /* the string "null". */ - return 0; - } -} - -static char *json_write_number(const struct json_number_s *number, char *data) -{ - json_uintmax_t parsed_number, backup; - size_t i; - - if (number->number_size >= 2) { - switch (number->number[1]) { - case 'x': - case 'X': - /* The number is a json_parse_flags_allow_hexadecimal_numbers - * hexadecimal so we have to do extra work to convert it to a - * non-hexadecimal for JSON output. */ - parsed_number = json_strtoumax(number->number, json_null, 0); - - /* We need a copy of parsed number twice, so take a backup of it. */ - backup = parsed_number; - - i = 0; - - while (0 != parsed_number) { - parsed_number /= 10; - i++; - } - - /* Restore parsed_number to its original value stored in the backup. - */ - parsed_number = backup; - - /* Now use backup to take a copy of i, or the length of the string. - */ - backup = i; - - do { - *(data + i - 1) = '0' + (char)(parsed_number % 10); - parsed_number /= 10; - i--; - } while (0 != parsed_number); - - data += backup; - - return data; - } - } - - /* check to see if the number has leading/trailing decimal point. */ - i = 0; - - /* skip any leading '-'. */ - if ((i < number->number_size) - && (('+' == number->number[i]) || ('-' == number->number[i]))) { - i++; - } - - /* check if we have infinity. */ - if ((i < number->number_size) && ('I' == number->number[i])) { - const char *inf = "Infinity"; - size_t k; - - for (k = i; k < number->number_size; k++) { - const char c = *inf++; - - /* Check if we found the Infinity string! */ - if ('\0' == c) { - break; - } else if (c != number->number[k]) { - break; - } - } - - if ('\0' == *inf++) { - const char *dbl_max; - - /* if we had a leading '-' we need to record it in the JSON output. - */ - if ('-' == number->number[0]) { - *data++ = '-'; - } - - /* Inf becomes 1.7976931348623158e308 because JSON can't support it. - */ - for (dbl_max = "1.7976931348623158e308"; '\0' != *dbl_max; - dbl_max++) { - *data++ = *dbl_max; - } - - return data; - } - } - - /* check if we have nan. */ - if ((i < number->number_size) && ('N' == number->number[i])) { - const char *nan = "NaN"; - size_t k; - - for (k = i; k < number->number_size; k++) { - const char c = *nan++; - - /* Check if we found the NaN string! */ - if ('\0' == c) { - break; - } else if (c != number->number[k]) { - break; - } - } - - if ('\0' == *nan++) { - /* NaN becomes 0 because JSON can't support it. */ - *data++ = '0'; - return data; - } - } - - /* if we had a leading decimal point. */ - if ((i < number->number_size) && ('.' == number->number[i])) { - i = 0; - - /* skip any leading '+'. */ - if ('+' == number->number[i]) { - i++; - } - - /* output the leading '-' if we had one. */ - if ('-' == number->number[i]) { - *data++ = '-'; - i++; - } - - /* insert a '0' to fix the leading decimal point for JSON output. */ - *data++ = '0'; - - /* and output the rest of the number as normal. */ - for (; i < number->number_size; i++) { - *data++ = number->number[i]; - } - - return data; - } - - for (; i < number->number_size; i++) { - const char c = number->number[i]; - if (!('0' <= c && c <= '9')) { - break; - } - } - - /* if we had a trailing decimal point. */ - if ((i + 1 == number->number_size) && ('.' == number->number[i])) { - i = 0; - - /* skip any leading '+'. */ - if ('+' == number->number[i]) { - i++; - } - - /* output the leading '-' if we had one. */ - if ('-' == number->number[i]) { - *data++ = '-'; - i++; - } - - /* and output the rest of the number as normal. */ - for (; i < number->number_size; i++) { - *data++ = number->number[i]; - } - - /* insert a '0' to fix the trailing decimal point for JSON output. */ - *data++ = '0'; - - return data; - } - - i = 0; - - /* skip any leading '+'. */ - if ('+' == number->number[i]) { - i++; - } - - for (; i < number->number_size; i++) { - *data++ = number->number[i]; - } - - return data; -} - -static char *json_write_string(const struct json_string_s *string, char *data) -{ - size_t i; - - *data++ = '"'; /* open the string. */ - - for (i = 0; i < string->string_size; i++) { - switch (string->string[i]) { - case '"': - *data++ = '\\'; /* escape the control character. */ - *data++ = '"'; - break; - case '\\': - *data++ = '\\'; /* escape the control character. */ - *data++ = '\\'; - break; - case '\b': - *data++ = '\\'; /* escape the control character. */ - *data++ = 'b'; - break; - case '\f': - *data++ = '\\'; /* escape the control character. */ - *data++ = 'f'; - break; - case '\n': - *data++ = '\\'; /* escape the control character. */ - *data++ = 'n'; - break; - case '\r': - *data++ = '\\'; /* escape the control character. */ - *data++ = 'r'; - break; - case '\t': - *data++ = '\\'; /* escape the control character. */ - *data++ = 't'; - break; - default: - *data++ = string->string[i]; - break; - } - } - - *data++ = '"'; /* close the string. */ - - return data; -} - -static char *json_write_minified_array( - const struct json_array_s *array, char *data) -{ - struct json_array_element_s *element = json_null; - - *data++ = '['; /* open the array. */ - - for (element = array->start; json_null != element; - element = element->next) { - if (element != array->start) { - *data++ = ','; /* ','s seperate each element. */ - } - - data = json_write_minified_value(element->value, data); - - if (json_null == data) { - /* value was malformed! */ - return json_null; - } - } - - *data++ = ']'; /* close the array. */ - - return data; -} - -static char *json_write_minified_object( - const struct json_object_s *object, char *data) -{ - struct json_object_element_s *element = json_null; - - *data++ = '{'; /* open the object. */ - - for (element = object->start; json_null != element; - element = element->next) { - if (element != object->start) { - *data++ = ','; /* ','s seperate each element. */ - } - - data = json_write_string(element->name, data); - - if (json_null == data) { - /* string was malformed! */ - return json_null; - } - - *data++ = ':'; /* ':'s seperate each name/value pair. */ - - data = json_write_minified_value(element->value, data); - - if (json_null == data) { - /* value was malformed! */ - return json_null; - } - } - - *data++ = '}'; /* close the object. */ - - return data; -} - -static char *json_write_minified_value( - const struct json_value_s *value, char *data) -{ - switch (value->type) { - default: - /* unknown value type found! */ - return json_null; - case json_type_number: - return json_write_number((struct json_number_s *)value->payload, data); - case json_type_string: - return json_write_string((struct json_string_s *)value->payload, data); - case json_type_array: - return json_write_minified_array( - (struct json_array_s *)value->payload, data); - case json_type_object: - return json_write_minified_object( - (struct json_object_s *)value->payload, data); - case json_type_true: - data[0] = 't'; - data[1] = 'r'; - data[2] = 'u'; - data[3] = 'e'; - return data + 4; - case json_type_false: - data[0] = 'f'; - data[1] = 'a'; - data[2] = 'l'; - data[3] = 's'; - data[4] = 'e'; - return data + 5; - case json_type_null: - data[0] = 'n'; - data[1] = 'u'; - data[2] = 'l'; - data[3] = 'l'; - return data + 4; - } -} - -void *json_write_minified(const struct json_value_s *value, size_t *out_size) -{ - size_t size = 0; - char *data = json_null; - char *data_end = json_null; - - if (json_null == value) { - return json_null; - } - - if (json_write_minified_get_value_size(value, &size)) { - /* value was malformed! */ - return json_null; - } - - size += 1; /* for the '\0' null terminating character. */ - - data = (char *)Memory_Alloc(size); - - if (json_null == data) { - /* malloc failed! */ - return json_null; - } - - data_end = json_write_minified_value(value, data); - - if (json_null == data_end) { - /* bad chi occurred! */ - Memory_Free(data); - return json_null; - } - - /* null terminated the string. */ - *data_end = '\0'; - - if (json_null != out_size) { - *out_size = size; - } - - return data; -} - -static int json_write_pretty_get_array_size( - const struct json_array_s *array, size_t depth, size_t indent_size, - size_t newline_size, size_t *size) -{ - struct json_array_element_s *element; - - *size += 1; /* '['. */ - - if (0 < array->length) { - /* if we have any elements we need to add a newline after our '['. */ - *size += newline_size; - - *size += array->length - 1; /* ','s seperate each element. */ - - for (element = array->start; json_null != element; - element = element->next) { - /* each element gets an indent. */ - *size += (depth + 1) * indent_size; - - if (json_write_pretty_get_value_size( - element->value, depth + 1, indent_size, newline_size, - size)) { - /* value was malformed! */ - return 1; - } - - /* each element gets a newline too. */ - *size += newline_size; - } - - /* since we wrote out some elements, need to add a newline and - * indentation. - */ - /* to the trailing ']'. */ - *size += depth * indent_size; - } - - *size += 1; /* ']'. */ - - return 0; -} - -static int json_write_pretty_get_object_size( - const struct json_object_s *object, size_t depth, size_t indent_size, - size_t newline_size, size_t *size) -{ - struct json_object_element_s *element; - - *size += 1; /* '{'. */ - - if (0 < object->length) { - *size += newline_size; /* need a newline next. */ - - *size += object->length - 1; /* ','s seperate each element. */ - - for (element = object->start; json_null != element; - element = element->next) { - /* each element gets an indent and newline. */ - *size += (depth + 1) * indent_size; - *size += newline_size; - - if (json_write_get_string_size(element->name, size)) { - /* string was malformed! */ - return 1; - } - - *size += 3; /* seperate each name/value pair with " : ". */ - - if (json_write_pretty_get_value_size( - element->value, depth + 1, indent_size, newline_size, - size)) { - /* value was malformed! */ - return 1; - } - } - - *size += depth * indent_size; - } - - *size += 1; /* '}'. */ - - return 0; -} - -static int json_write_pretty_get_value_size( - const struct json_value_s *value, size_t depth, size_t indent_size, - size_t newline_size, size_t *size) -{ - switch (value->type) { - default: - /* unknown value type found! */ - return 1; - case json_type_number: - return json_write_get_number_size( - (struct json_number_s *)value->payload, size); - case json_type_string: - return json_write_get_string_size( - (struct json_string_s *)value->payload, size); - case json_type_array: - return json_write_pretty_get_array_size( - (struct json_array_s *)value->payload, depth, indent_size, - newline_size, size); - case json_type_object: - return json_write_pretty_get_object_size( - (struct json_object_s *)value->payload, depth, indent_size, - newline_size, size); - case json_type_true: - *size += 4; /* the string "true". */ - return 0; - case json_type_false: - *size += 5; /* the string "false". */ - return 0; - case json_type_null: - *size += 4; /* the string "null". */ - return 0; - } -} - -static char *json_write_pretty_array( - const struct json_array_s *array, size_t depth, const char *indent, - const char *newline, char *data) -{ - size_t k, m; - struct json_array_element_s *element; - - *data++ = '['; /* open the array. */ - - if (0 < array->length) { - for (k = 0; '\0' != newline[k]; k++) { - *data++ = newline[k]; - } - - for (element = array->start; json_null != element; - element = element->next) { - if (element != array->start) { - *data++ = ','; /* ','s seperate each element. */ - - for (k = 0; '\0' != newline[k]; k++) { - *data++ = newline[k]; - } - } - - for (k = 0; k < depth + 1; k++) { - for (m = 0; '\0' != indent[m]; m++) { - *data++ = indent[m]; - } - } - - data = json_write_pretty_value( - element->value, depth + 1, indent, newline, data); - - if (json_null == data) { - /* value was malformed! */ - return json_null; - } - } - - for (k = 0; '\0' != newline[k]; k++) { - *data++ = newline[k]; - } - - for (k = 0; k < depth; k++) { - for (m = 0; '\0' != indent[m]; m++) { - *data++ = indent[m]; - } - } - } - - *data++ = ']'; /* close the array. */ - - return data; -} - -static char *json_write_pretty_object( - const struct json_object_s *object, size_t depth, const char *indent, - const char *newline, char *data) -{ - size_t k, m; - struct json_object_element_s *element; - - *data++ = '{'; /* open the object. */ - - if (0 < object->length) { - for (k = 0; '\0' != newline[k]; k++) { - *data++ = newline[k]; - } - - for (element = object->start; json_null != element; - element = element->next) { - if (element != object->start) { - *data++ = ','; /* ','s seperate each element. */ - - for (k = 0; '\0' != newline[k]; k++) { - *data++ = newline[k]; - } - } - - for (k = 0; k < depth + 1; k++) { - for (m = 0; '\0' != indent[m]; m++) { - *data++ = indent[m]; - } - } - - data = json_write_string(element->name, data); - - if (json_null == data) { - /* string was malformed! */ - return json_null; - } - - /* " : "s seperate each name/value pair. */ - *data++ = ' '; - *data++ = ':'; - *data++ = ' '; - - data = json_write_pretty_value( - element->value, depth + 1, indent, newline, data); - - if (json_null == data) { - /* value was malformed! */ - return json_null; - } - } - - for (k = 0; '\0' != newline[k]; k++) { - *data++ = newline[k]; - } - - for (k = 0; k < depth; k++) { - for (m = 0; '\0' != indent[m]; m++) { - *data++ = indent[m]; - } - } - } - - *data++ = '}'; /* close the object. */ - - return data; -} - -static char *json_write_pretty_value( - const struct json_value_s *value, size_t depth, const char *indent, - const char *newline, char *data) -{ - switch (value->type) { - default: - /* unknown value type found! */ - return json_null; - case json_type_number: - return json_write_number((struct json_number_s *)value->payload, data); - case json_type_string: - return json_write_string((struct json_string_s *)value->payload, data); - case json_type_array: - return json_write_pretty_array( - (struct json_array_s *)value->payload, depth, indent, newline, - data); - case json_type_object: - return json_write_pretty_object( - (struct json_object_s *)value->payload, depth, indent, newline, - data); - case json_type_true: - data[0] = 't'; - data[1] = 'r'; - data[2] = 'u'; - data[3] = 'e'; - return data + 4; - case json_type_false: - data[0] = 'f'; - data[1] = 'a'; - data[2] = 'l'; - data[3] = 's'; - data[4] = 'e'; - return data + 5; - case json_type_null: - data[0] = 'n'; - data[1] = 'u'; - data[2] = 'l'; - data[3] = 'l'; - return data + 4; - } -} - -void *json_write_pretty( - const struct json_value_s *value, const char *indent, const char *newline, - size_t *out_size) -{ - size_t size = 0; - size_t indent_size = 0; - size_t newline_size = 0; - char *data = json_null; - char *data_end = json_null; - - if (json_null == value) { - return json_null; - } - - if (json_null == indent) { - indent = " "; /* default to two spaces. */ - } - - if (json_null == newline) { - newline = "\n"; /* default to linux newlines. */ - } - - while ('\0' != indent[indent_size]) { - ++indent_size; /* skip non-null terminating characters. */ - } - - while ('\0' != newline[newline_size]) { - ++newline_size; /* skip non-null terminating characters. */ - } - - if (json_write_pretty_get_value_size( - value, 0, indent_size, newline_size, &size)) { - /* value was malformed! */ - return json_null; - } - - size += 1; /* for the '\0' null terminating character. */ - - data = (char *)Memory_Alloc(size); - - if (json_null == data) { - /* malloc failed! */ - return json_null; - } - - data_end = json_write_pretty_value(value, 0, indent, newline, data); - - if (json_null == data_end) { - /* bad chi occurred! */ - Memory_Free(data); - return json_null; - } - - /* null terminated the string. */ - *data_end = '\0'; - - if (json_null != out_size) { - *out_size = size; - } - - return data; -} diff --git a/src/json/json_write.h b/src/json/json_write.h deleted file mode 100644 index bbbd3c856..000000000 --- a/src/json/json_write.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "json/json_base.h" - -#include - -struct json_value_s; - -/* Write out a minified JSON utf-8 string. This string is an encoding of the - * minimal string characters required to still encode the same data. - * json_write_minified performs 1 call to malloc for the entire encoding. Return - * 0 if an error occurred (malformed JSON input, or malloc failed). The out_size - * parameter is optional as the utf-8 string is null terminated. */ -void *json_write_minified(const struct json_value_s *value, size_t *out_size); - -/* Write out a pretty JSON utf-8 string. This string is encoded such that the - * resultant JSON is pretty in that it is easily human readable. The indent and - * newline parameters allow a user to specify what kind of indentation and - * newline they want (two spaces / three spaces / tabs? \r, \n, \r\n ?). Both - * indent and newline can be NULL, indent defaults to two spaces (" "), and - * newline defaults to linux newlines ('\n' as the newline character). - * json_write_pretty performs 1 call to malloc for the entire encoding. Return 0 - * if an error occurred (malformed JSON input, or malloc failed). The out_size - * parameter is optional as the utf-8 string is null terminated. */ -void *json_write_pretty( - const struct json_value_s *value, const char *indent, const char *newline, - size_t *out_size); diff --git a/subprojects/libtrx b/subprojects/libtrx index e2d100485..c60e20846 160000 --- a/subprojects/libtrx +++ b/subprojects/libtrx @@ -1 +1 @@ -Subproject commit e2d10048599eeb39dd56a6d8dcfe51afd87cd9e7 +Subproject commit c60e2084607d69c5a9c337afb6e9f33e2ce6bbd0