summaryrefslogtreecommitdiff
path: root/lib/libjson/json.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libjson/json.c')
-rw-r--r--lib/libjson/json.c1607
1 files changed, 0 insertions, 1607 deletions
diff --git a/lib/libjson/json.c b/lib/libjson/json.c
deleted file mode 100644
index a50a6275..00000000
--- a/lib/libjson/json.c
+++ /dev/null
@@ -1,1607 +0,0 @@
-#include "json.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-inline struct json_value *json_array_get(struct json_value *array, int index)
-{
- return index < array->array.length ? array->array.items[index] : NULL;
-}
-
-/**
- * @brief Represents a JSON parser for decoding JSON strings.
- *
- * This structure is used internally by the JSON library to parse
- * JSON-encoded strings into structured `json_value` objects.
- *
- * @note This structure is private and should not be accessed directly
- * outside of the JSON library's internal implementation.
- */
-struct json_parser {
- /**
- * @brief The input JSON string to be parsed.
- *
- * This is a pointer to the null-terminated JSON string that the parser
- * operates on.
- */
- const char *input;
-
- /**
- * @brief The length of the input JSON string.
- *
- * This value represents the total number of characters in the input
- * JSON string, excluding the null terminator.
- */
- int length;
-
- /**
- * @brief The current position in the input JSON string.
- *
- * This value indicates the index of the character currently being
- * processed by the parser.
- */
- int position;
-
-#if defined(JSON_ERROR)
- /**
- * @brief Represents error information for the JSON parser.
- *
- * This structure is used to store details about any errors encountered
- * during the parsing process.
- */
- struct {
- /**
- * @brief Enum representing the type of error encountered.
- *
- * - `JSON_ERROR_NONE`: No error occurred.
- * - `JSON_ERROR_SYNTAX`: A syntax error was encountered.
- * - `JSON_ERROR_MEMORY`: A memory allocation error occurred.
- * - `JSON_ERROR_EOF`: Unexpected end of input was encountered.
- */
- enum {
- JSON_ERROR_NONE, /**< No error occurred. */
- JSON_ERROR_SYNTAX, /**< A syntax error was encountered.
- */
- JSON_ERROR_MEMORY, /**< A memory allocation error
- occurred. */
- JSON_ERROR_EOF, /**< Unexpected end of input was
- encountered. */
- JSON_ERROR_INVALID_NUMBER, /**< Failed to parse number
- */
- } code;
-
- /**
- * @brief The line number where the error occurred.
- *
- * This value is used for debugging purposes to identify the
- * location of the error in the source code.
- */
- int line;
-
- /**
- * @brief The name of the function where the error occurred.
- *
- * This is a pointer to a string containing the name of the
- * function in which the error was detected.
- */
- const char *func;
-
- /**
- * @brief A descriptive message about the error.
- *
- * This is a pointer to a string containing a human-readable
- * description of the error.
- */
- const char *message;
- } error;
-#endif
-};
-
-/**
- * Initializes a JSON object.
- *
- * This function is responsible for setting up the internal structure
- * of a JSON object, ensuring it is ready for use. It is invoked by
- * both json_object_new() and json_object_free() to manage the lifecycle
- * of JSON objects.
- *
- * @param object A pointer to the JSON object to be initialized.
- *
- * @note This function is marked as privative and should not be used
- * directly outside of the JSON library's internal implementation.
- */
-void json_object_init(struct json_value *object);
-
-#if defined(JSON_ERROR)
-/**
- * @brief Sets an error in the JSON parser.
- *
- * This macro assigns error details to the JSON parser's error structure.
- * It captures the error code, the line number, the function name, and
- * a descriptive error message.
- *
- * @param PARSER The JSON parser where the error occurred.
- * @param CODE The error code to set.
- * @param MESSAGE A descriptive message about the error.
- */
-#define JSON_PARSER_ERROR(PARSER, CODE, MESSAGE) \
- (PARSER)->error.code = (CODE); \
- (PARSER)->error.line = __LINE__; \
- (PARSER)->error.func = __func__; \
- (PARSER)->error.message = (MESSAGE)
-#else
-/**
- * @brief No-op macro for JSON parser errors.
- *
- * When JSON_ERROR is not defined, this macro does nothing.
- *
- * @param PARSER The JSON parser (unused).
- * @param CODE The error code (unused).
- * @param MESSAGE The error message (unused).
- */
-#define JSON_PARSER_ERROR(PARSER, CODE, MESSAGE)
-#endif
-
-static int json__decode_value(struct json_parser *parser,
- struct json_value *value);
-
-static int json__strlen(const char *str)
-{
- int len = 0;
- while (*str++)
- len++;
- return len;
-}
-
-static int json__streq(const char *s1, const char *s2)
-{
- if (json__strlen(s1) != json__strlen(s2))
- return 0;
-
- while (*s1 && *s1 == *s2) {
- s1++;
- s2++;
- }
-
- if (*s1 == 0 && *s2 == 0)
- return 1;
-
- return 0;
-}
-
-static int json__streqn(const char *s1, const char *s2, int limit)
-{
- while (*s1 && *s2 && *s1 == *s2 && limit-- > 1) {
- s1++;
- s2++;
- }
-
- return *s1 == *s2 ? 1 : 0;
-}
-
-static void json__parse_whitespace(struct json_parser *parser)
-{
- const char *ptr = parser->input;
- int pos = parser->position;
- int len = parser->length;
-
- while (pos < len && (ptr[pos] == ' ' || ptr[pos] == '\t' ||
- ptr[pos] == '\n' || ptr[pos] == '\r'))
- pos++;
-
- parser->position = pos;
-}
-
-static int json__decode_string(struct json_parser *parser,
- struct json_value *value)
-{
- int start = parser->position + 1;
- int end = start;
- int buffer_size = 16;
- int buffer_length = 0;
- char *buffer = malloc(buffer_size);
-
- if (buffer == NULL) {
- JSON_PARSER_ERROR(parser, JSON_ERROR_MEMORY,
- "Memory allocation failed");
- return -1;
- }
-
- while (end < parser->length && parser->input[end] != '"') {
- if (parser->input[end] == '\\') {
- end++;
- if (end >= parser->length) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser, JSON_ERROR_SYNTAX,
- "Unterminated escape sequence");
- return -1;
- }
-
- if (parser->input[end] == 'u') {
- // Handle \uXXXX Unicode escape sequences
- end++;
- if (end + 3 >= parser->length) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser, JSON_ERROR_SYNTAX,
- "Incomplete Unicode escape sequence");
- return -1;
- }
-
- // Parse 4 hex digits
- unsigned int code_point = 0;
- for (int i = 0; i < 4; i++) {
- char c = parser->input[end + i];
- code_point <<= 4;
-
- if (c >= '0' && c <= '9') {
- code_point |= (c - '0');
- } else if (c >= 'a' && c <= 'f') {
- code_point |= (c - 'a' + 10);
- } else if (c >= 'A' && c <= 'F') {
- code_point |= (c - 'A' + 10);
- } else {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_SYNTAX,
- "Invalid hex digit in Unicode escape");
- return -1;
- }
- }
-
- // Check for surrogate pair
- if (code_point >= 0xD800 &&
- code_point <= 0xDBFF) {
- // High surrogate - need to get the low
- // surrogate
- end += 4; // Move past the first \uXXXX
-
- // Check for the sequence \uYYYY where
- // YYYY is the low surrogate
- if (end + 1 >= parser->length ||
- parser->input[end] != '\\' ||
- parser->input[end + 1] != 'u') {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_SYNTAX,
- "Expected low surrogate after high surrogate");
- return -1;
- }
-
- end += 2; // Move past \u
- if (end + 3 >= parser->length) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_SYNTAX,
- "Incomplete Unicode escape sequence for low surrogate");
- return -1;
- }
-
- // Parse 4 hex digits for low surrogate
- unsigned int low_surrogate = 0;
- for (int i = 0; i < 4; i++) {
- char c = parser->input[end + i];
- low_surrogate <<= 4;
-
- if (c >= '0' && c <= '9') {
- low_surrogate |=
- (c - '0');
- } else if (c >= 'a' &&
- c <= 'f') {
- low_surrogate |=
- (c - 'a' + 10);
- } else if (c >= 'A' &&
- c <= 'F') {
- low_surrogate |=
- (c - 'A' + 10);
- } else {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_SYNTAX,
- "Invalid hex digit in low surrogate");
- return -1;
- }
- }
-
- // Validate low surrogate range
- if (low_surrogate < 0xDC00 ||
- low_surrogate > 0xDFFF) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_SYNTAX,
- "Invalid low surrogate value");
- return -1;
- }
-
- // Combine surrogate pair to get actual
- // code point
- code_point =
- 0x10000 +
- ((code_point - 0xD800) << 10) +
- (low_surrogate - 0xDC00);
- end += 4; // Move past the second \uXXXX
- } else {
- end += 4; // Move past \uXXXX for
- // non-surrogate case
- }
-
- // Encode code point as UTF-8
- if (code_point < 0x80) {
- // 1-byte character
- if (buffer_length + 1 >= buffer_size) {
- buffer_size *= 2;
- char *new_buffer = realloc(
- buffer, buffer_size);
- if (new_buffer == NULL) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_MEMORY,
- "Memory allocation failed");
- return -1;
- }
- buffer = new_buffer;
- }
- buffer[buffer_length++] =
- (char)code_point;
- } else if (code_point < 0x800) {
- // 2-byte character
- if (buffer_length + 2 >= buffer_size) {
- buffer_size *= 2;
- char *new_buffer = realloc(
- buffer, buffer_size);
- if (new_buffer == NULL) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_MEMORY,
- "Memory allocation failed");
- return -1;
- }
- buffer = new_buffer;
- }
- buffer[buffer_length++] =
- (char)(0xC0 |
- (code_point >> 6));
- buffer[buffer_length++] =
- (char)(0x80 |
- (code_point & 0x3F));
- } else if (code_point < 0x10000) {
- // 3-byte character
- if (buffer_length + 3 >= buffer_size) {
- buffer_size *= 2;
- char *new_buffer = realloc(
- buffer, buffer_size);
- if (new_buffer == NULL) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_MEMORY,
- "Memory allocation failed");
- return -1;
- }
- buffer = new_buffer;
- }
- buffer[buffer_length++] =
- (char)(0xE0 |
- (code_point >> 12));
- buffer[buffer_length++] =
- (char)(0x80 |
- ((code_point >> 6) &
- 0x3F));
- buffer[buffer_length++] =
- (char)(0x80 |
- (code_point & 0x3F));
- } else {
- // 4-byte character
- if (buffer_length + 4 >= buffer_size) {
- buffer_size *= 2;
- char *new_buffer = realloc(
- buffer, buffer_size);
- if (new_buffer == NULL) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_MEMORY,
- "Memory allocation failed");
- return -1;
- }
- buffer = new_buffer;
- }
- buffer[buffer_length++] =
- (char)(0xF0 |
- (code_point >> 18));
- buffer[buffer_length++] =
- (char)(0x80 |
- ((code_point >> 12) &
- 0x3F));
- buffer[buffer_length++] =
- (char)(0x80 |
- ((code_point >> 6) &
- 0x3F));
- buffer[buffer_length++] =
- (char)(0x80 |
- (code_point & 0x3F));
- }
-
- continue; // Skip the increment at the end of
- // the loop
- } else {
- // Handle standard escape sequences
- char escaped_char;
- switch (parser->input[end]) {
- case '"':
- escaped_char = '"';
- break;
- case '\\':
- escaped_char = '\\';
- break;
- case '/':
- escaped_char = '/';
- break;
- case 'b':
- escaped_char = '\b';
- break;
- case 'f':
- escaped_char = '\f';
- break;
- case 'n':
- escaped_char = '\n';
- break;
- case 'r':
- escaped_char = '\r';
- break;
- case 't':
- escaped_char = '\t';
- break;
- default:
- free(buffer);
- JSON_PARSER_ERROR(
- parser, JSON_ERROR_SYNTAX,
- "Invalid escape character");
- return -1;
- }
-
- if (buffer_length + 1 >= buffer_size) {
- buffer_size *= 2;
- char *new_buffer =
- realloc(buffer, buffer_size);
- if (new_buffer == NULL) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser,
- JSON_ERROR_MEMORY,
- "Memory allocation failed");
- return -1;
- }
- buffer = new_buffer;
- }
-
- buffer[buffer_length++] = escaped_char;
- }
- } else {
- if (buffer_length + 1 >= buffer_size) {
- buffer_size *= 2;
- char *new_buffer = realloc(buffer, buffer_size);
- if (new_buffer == NULL) {
- free(buffer);
- JSON_PARSER_ERROR(
- parser, JSON_ERROR_MEMORY,
- "Memory allocation failed");
- return -1;
- }
- buffer = new_buffer;
- }
-
- buffer[buffer_length++] = parser->input[end];
- }
- end++;
- }
-
- if (end == parser->length) {
- free(buffer);
- JSON_PARSER_ERROR(parser, JSON_ERROR_SYNTAX,
- "Unterminated string");
- return -1;
- }
-
- buffer[buffer_length] = 0;
-
- value->type = JSON_TYPE_STRING;
- value->string.value = buffer;
- value->string.length = buffer_length;
-
- parser->position = end + 1;
- return 0;
-}
-
-static void json__parser_consume_digits(struct json_parser *parser)
-{
- while (parser->position < parser->length &&
- parser->input[parser->position] >= '0' &&
- parser->input[parser->position] <= '9') {
- parser->position++;
- }
-}
-
-static int json__decode_number(struct json_parser *parser,
- struct json_value *value)
-{
- int start = parser->position;
- char *endptr;
-
- if (parser->position < parser->length &&
- parser->input[parser->position] == '-')
- parser->position++;
-
- if (parser->position < parser->length &&
- parser->input[parser->position] == '0') {
- parser->position++;
- } else if (parser->position < parser->length &&
- parser->input[parser->position] >= '1' &&
- parser->input[parser->position] <= '9') {
- json__parser_consume_digits(parser);
- } else {
- JSON_PARSER_ERROR(parser, JSON_ERROR_INVALID_NUMBER,
- "Invalid number");
- return -1;
- }
-
- if (parser->position < parser->length &&
- parser->input[parser->position] == '.') {
- parser->position++;
- if (parser->position < parser->length &&
- parser->input[parser->position] >= '0' &&
- parser->input[parser->position] <= '9') {
- json__parser_consume_digits(parser);
- } else {
- JSON_PARSER_ERROR(parser, JSON_ERROR_INVALID_NUMBER,
- "Invalid number");
- return -1;
- }
- }
-
- if (parser->position < parser->length &&
- (parser->input[parser->position] == 'e' ||
- parser->input[parser->position] == 'E')) {
- parser->position++;
- if (parser->position < parser->length &&
- (parser->input[parser->position] == '-' ||
- parser->input[parser->position] == '+')) {
- parser->position++;
- }
- if (parser->position < parser->length &&
- parser->input[parser->position] >= '0' &&
- parser->input[parser->position] <= '9') {
- json__parser_consume_digits(parser);
- } else {
- JSON_PARSER_ERROR(parser, JSON_ERROR_INVALID_NUMBER,
- "Invalid number");
- return -1;
- }
- }
-
- if (start == parser->position) {
- JSON_PARSER_ERROR(parser, JSON_ERROR_INVALID_NUMBER,
- "Invalid number");
- return -1;
- }
-
- value->type = JSON_TYPE_NUMBER;
- endptr = NULL;
- value->number = strtod(parser->input + start, &endptr);
-
- if (endptr != parser->input + parser->position) {
- JSON_PARSER_ERROR(parser, JSON_ERROR_INVALID_NUMBER,
- "Invalid number");
- return -1;
- }
-
- return 0;
-}
-
-static int json__decode_array(struct json_parser *parser,
- struct json_value *array)
-{
- if (parser->length - parser->position < 1) {
- JSON_PARSER_ERROR(parser, JSON_ERROR_EOF,
- "Unexpected end of input");
- return -1;
- }
-
- if (parser->input[parser->position] != '[') {
- JSON_PARSER_ERROR(parser, JSON_ERROR_SYNTAX, "Expected '['");
- return -1;
- }
-
- array->type = JSON_TYPE_ARRAY;
- json_array_init(array);
-
- if (parser->position + 1 < parser->length &&
- parser->input[parser->position + 1] == ']') {
- parser->position += 2;
- return 0;
- }
-
- parser->position += 1; // Skip '['
- while (parser->position < parser->length &&
- parser->input[parser->position] != ']') {
- json__parse_whitespace(parser);
-
- struct json_value *item;
- if ((item = malloc(sizeof(struct json_value))) == NULL) {
- JSON_PARSER_ERROR(parser, JSON_ERROR_MEMORY,
- "Memory allocation failed");
- json_array_free(array);
- return -1;
- }
-
- if (json__decode_value(parser, item) != 0) {
- free(item);
- json_array_free(array);
- return -1;
- }
-
- json_array_push(array, item);
- json__parse_whitespace(parser);
-
- if (parser->position < parser->length &&
- parser->input[parser->position] == ',') // Skip ','
- parser->position++;
- }
-
- if (parser->position >= parser->length ||
- parser->input[parser->position] != ']') {
- JSON_PARSER_ERROR(parser, JSON_ERROR_SYNTAX,
- "Expected closing ']' for array");
- json_array_free(array);
- return -1;
- }
-
- if (parser->position < parser->length) // Skip ']'
- parser->position++;
- return 0;
-}
-
-static int json__decode_object(struct json_parser *parser,
- struct json_value *object)
-{
- object->type = JSON_TYPE_OBJECT;
- json_object_init(object);
-
- parser->position++;
- json__parse_whitespace(parser);
-
- while (parser->position < parser->length &&
- parser->input[parser->position] != '}') {
- struct json_value key, *value;
- json__parse_whitespace(parser);
-
- if (parser->input[parser->position] != '"') {
- JSON_PARSER_ERROR(parser, JSON_ERROR_SYNTAX,
- "Expected string key");
- return -1;
- }
-
- if (json__decode_string(parser, &key) != 0) {
- JSON_PARSER_ERROR(parser, JSON_ERROR_SYNTAX,
- "Failed to parse string key");
- return -1;
- }
-
- json__parse_whitespace(parser);
- if (parser->position >= parser->length ||
- parser->input[parser->position] != ':') {
- free(key.string.value);
- JSON_PARSER_ERROR(parser, JSON_ERROR_SYNTAX,
- "Expected ':' after string key");
- return -1;
- }
- parser->position++; // Skip the colon
-
- value = malloc(sizeof(struct json_value));
- if (value == NULL) {
- free(key.string.value);
- JSON_PARSER_ERROR(
- parser, JSON_ERROR_MEMORY,
- "Failed to allocate memory for JSON item");
- return -1;
- }
-
- json__parse_whitespace(parser);
- if (json__decode_value(parser, value) != 0) {
- free(value);
- free(key.string.value);
- JSON_PARSER_ERROR(parser, JSON_ERROR_SYNTAX,
- "Failed to parse JSON value");
- return -1;
- }
-
- if (json_object_set(object, key.string.value, value) != 0) {
- free(value);
- free(key.string.value);
- JSON_PARSER_ERROR(
- parser, JSON_ERROR_MEMORY,
- "Failed to set key-value pair in object");
- return -1;
- }
-
- free(key.string.value);
- json__parse_whitespace(parser);
- if (parser->position < parser->length &&
- parser->input[parser->position] == ',')
- parser->position++; // Skip comma or closing brace
- }
-
- if (parser->position >= parser->length ||
- parser->input[parser->position] != '}') {
- JSON_PARSER_ERROR(parser, JSON_ERROR_SYNTAX,
- "Expected '}' after JSON object");
- return -1;
- }
-
- parser->position++; // Skip the closing brace
-
- return 0;
-}
-
-static int json__decode_value(struct json_parser *parser,
- struct json_value *value)
-{
- int rc;
- char c = parser->input[parser->position];
-
- if (c == '"') {
- rc = json__decode_string(parser, value);
- } else if (c == '[') {
- rc = json__decode_array(parser, value);
- } else if (c == '{') {
- rc = json__decode_object(parser, value);
- } else if (json__streqn(parser->input + parser->position, "true", 4)) {
- value->type = JSON_TYPE_BOOLEAN;
- value->number = 1;
- parser->position += 4;
- return 0;
- } else if (json__streqn(parser->input + parser->position, "false", 4)) {
- value->type = JSON_TYPE_BOOLEAN;
- value->number = 0;
- parser->position += 5;
- return 0;
- } else if (json__streqn(parser->input + parser->position, "null", 4)) {
- value->type = JSON_TYPE_NULL;
- parser->position += 4;
- return 0;
- } else {
- rc = json__decode_number(parser, value);
- }
-
-#if defined(JSON_ERROR)
- if (rc != 0 && parser->error.code == JSON_ERROR_NONE) {
- JSON_PARSER_ERROR(parser, JSON_ERROR_SYNTAX, "Expected value");
- }
-#endif
-
- return rc;
-}
-
-struct json_value *json_decode_with_length(const char *json, int length)
-{
- struct json_parser parser;
- struct json_value *value = NULL;
-
- parser.input = json;
- parser.length = length;
- parser.position = 0;
-
-#if defined(JSON_ERROR)
- parser.error.code = JSON_ERROR_NONE;
- parser.error.message = NULL;
-#endif
-
- if ((value = malloc(sizeof(struct json_value))) == NULL)
- return NULL;
-
- if (json__decode_value(&parser, value) != 0) {
-#if defined(JSON_ERROR) && !defined(JSON_ERROR_HANDLER)
- if (parser.error.code != JSON_ERROR_NONE) {
- fprintf(stderr,
- "JSON(\033[1merror\033[m): %s:%d %s at\n",
- parser.error.func, parser.error.line,
- parser.error.message);
- }
-#elif defined(JSON_ERROR) && defined(JSON_ERROR_HANDLER)
- if (parser.error.code != JSON_ERROR_NONE) {
- JSON_ERROR_HANDLER(parser.error.code,
- parser.error.message);
- }
-#endif
- free(value);
- return NULL;
- }
-
- return value;
-}
-
-struct json_value *json_decode(const char *json)
-{
- return json_decode_with_length(json, json__strlen(json));
-}
-
-static char *json__encode_array(struct json_value *value)
-{
- int length;
- int buffer_size;
- char *encoded_array;
- if (value == NULL) {
- return NULL;
- }
-
- buffer_size = 512;
- encoded_array = malloc(buffer_size);
- if (encoded_array == NULL) {
- return NULL;
- }
-
- length = 1;
- encoded_array[0] = '[';
-
- for (int i = 0; i < value->array.length; i++) {
- int needed;
- int encoded_item_len;
- char *encoded_item = json_encode(value->array.items[i]);
- if (encoded_item == NULL) {
- free(encoded_array);
- return NULL;
- }
-
- encoded_item_len = json__strlen(encoded_item);
- if (encoded_item_len < 0) {
- free(encoded_array);
- free(encoded_item);
- return NULL;
- }
-
- needed = length + encoded_item_len + (i > 0 ? 1 : 0) + 1;
- if (needed > buffer_size) {
- char *new_encoded_array = realloc(
- encoded_array, (buffer_size = needed * 2));
- if (new_encoded_array == NULL) {
- free(encoded_array);
- free(encoded_item);
- return NULL;
- }
- encoded_array = new_encoded_array;
- }
-
- if (i > 0) {
- encoded_array[length++] = ',';
- }
-
- for (int i = 0; i < encoded_item_len; i++) {
- if (encoded_item[i] == '\0')
- break;
- encoded_array[length + i] = encoded_item[i];
- }
-
- length += encoded_item_len;
-
- free(encoded_item);
- }
-
- encoded_array[length++] = ']';
- encoded_array[length] = '\0';
-
- return encoded_array;
-}
-
-static char *json__encode_object(struct json_value *object)
-{
- int length;
- int buffer_size = 256;
- char *encoded_object = malloc(buffer_size);
- if (encoded_object == NULL) {
- return NULL;
- }
-
- encoded_object[0] = '{';
- length = 1;
-
- for (int i = 0; i < object->object.n_items; i++) {
- char *new_buffer;
- char *key = object->object.items[i]->key;
- char *value = json_encode(object->object.items[i]->value);
- if (value == NULL) {
- free(encoded_object);
- return NULL;
- }
-
- int key_length = json__strlen(key);
- int value_length = json__strlen(value);
- if (value_length < 0) {
- free(encoded_object);
- free(value);
- return NULL;
- }
-
- int needed = length + key_length + value_length + 4 +
- (i < object->object.n_items - 1 ? 1 : 0);
-
- if (needed > buffer_size) {
- buffer_size = needed * 2;
- new_buffer = realloc(encoded_object, buffer_size);
- if (new_buffer == NULL) {
- free(encoded_object);
- free(value);
- return NULL;
- }
- encoded_object = new_buffer;
- }
-
- encoded_object[length++] = '"';
- for (int j = 0; j < key_length; j++)
- encoded_object[length++] = key[j];
-
- encoded_object[length++] = '"';
- encoded_object[length++] = ':';
- for (int j = 0; j < value_length; j++) {
- if (value[j] == '\0')
- break;
- encoded_object[length++] = value[j];
- }
-
- free(value);
-
- if (i < object->object.n_items - 1) {
- encoded_object[length++] = ',';
- }
- }
-
- encoded_object[length++] = '}';
- encoded_object[length] = '\0';
-
- return encoded_object;
-}
-
-static char *json__encode_string(struct json_value *value)
-{
- const char *str = value->string.value;
- int length = value->string.length;
- int buffer_size = length * 6 + 3; // Maximum possible size (all chars
- // escaped + quotes)
- char *buffer = malloc(buffer_size);
- int pos = 0;
-
- if (!buffer)
- return NULL;
-
- buffer[pos++] = '"';
-
- for (int i = 0; i < length; i++) {
- unsigned char c = (unsigned char)str[i];
-
- if (c == '"' || c == '\\' || c == '/') {
- buffer[pos++] = '\\';
- buffer[pos++] = c;
- } else if (c == '\b') {
- buffer[pos++] = '\\';
- buffer[pos++] = 'b';
- } else if (c == '\f') {
- buffer[pos++] = '\\';
- buffer[pos++] = 'f';
- } else if (c == '\n') {
- buffer[pos++] = '\\';
- buffer[pos++] = 'n';
- } else if (c == '\r') {
- buffer[pos++] = '\\';
- buffer[pos++] = 'r';
- } else if (c == '\t') {
- buffer[pos++] = '\\';
- buffer[pos++] = 't';
- } else if (c < 32) {
- // Control characters must be escaped as \uXXXX
- buffer[pos++] = '\\';
- buffer[pos++] = 'u';
- buffer[pos++] = '0';
- buffer[pos++] = '0';
- buffer[pos++] = "0123456789ABCDEF"[(c >> 4) & 0xF];
- buffer[pos++] = "0123456789ABCDEF"[c & 0xF];
- } else if (c < 128) {
- // ASCII characters
- buffer[pos++] = c;
- } else {
- // UTF-8 encoded characters
- // Check if this is a multi-byte sequence
- const unsigned char *bytes =
- (const unsigned char *)&str[i];
- if ((c & 0xE0) == 0xC0) {
- // Two-byte sequence
- if (i + 1 >= length ||
- (bytes[i + 1] & 0xC0) != 0x80) {
- // Invalid UTF-8 sequence, escape as
- // replacement character
- buffer[pos++] = '\\';
- buffer[pos++] = 'u';
- buffer[pos++] = 'F';
- buffer[pos++] = 'F';
- buffer[pos++] = 'F';
- buffer[pos++] = 'D';
- } else {
- // Valid two-byte sequence, keep as is
- buffer[pos++] = c;
- buffer[pos++] = str[++i];
- }
- } else if ((c & 0xF0) == 0xE0) {
- // Three-byte sequence
- if (i + 2 >= length ||
- (bytes[i + 1] & 0xC0) != 0x80 ||
- (bytes[i + 2] & 0xC0) != 0x80) {
- // Invalid UTF-8 sequence
- buffer[pos++] = '\\';
- buffer[pos++] = 'u';
- buffer[pos++] = 'F';
- buffer[pos++] = 'F';
- buffer[pos++] = 'F';
- buffer[pos++] = 'D';
- } else {
- // Valid three-byte sequence, keep as is
- buffer[pos++] = c;
- buffer[pos++] = str[++i];
- buffer[pos++] = str[++i];
- }
- } else if ((c & 0xF8) == 0xF0) {
- // Four-byte sequence
- if (i + 3 >= length ||
- (bytes[i + 1] & 0xC0) != 0x80 ||
- (bytes[i + 2] & 0xC0) != 0x80 ||
- (bytes[i + 3] & 0xC0) != 0x80) {
- // Invalid UTF-8 sequence
- buffer[pos++] = '\\';
- buffer[pos++] = 'u';
- buffer[pos++] = 'F';
- buffer[pos++] = 'F';
- buffer[pos++] = 'F';
- buffer[pos++] = 'D';
- } else {
- // Valid four-byte sequence, keep as is
- buffer[pos++] = c;
- buffer[pos++] = str[++i];
- buffer[pos++] = str[++i];
- buffer[pos++] = str[++i];
- }
- } else {
- // Invalid UTF-8 start byte
- buffer[pos++] = '\\';
- buffer[pos++] = 'u';
- buffer[pos++] = 'F';
- buffer[pos++] = 'F';
- buffer[pos++] = 'F';
- buffer[pos++] = 'D';
- }
- }
- }
-
- buffer[pos++] = '"';
- buffer[pos] = '\0';
-
- // Reallocate to actual size
- char *result = realloc(buffer, pos + 1);
- return result ? result : buffer;
-}
-
-char *json_encode(struct json_value *value)
-{
- switch (value->type) {
- case JSON_TYPE_STRING:
- return json__encode_string(value);
- case JSON_TYPE_NUMBER: {
- char *ptr;
- char buffer[32];
- int length = snprintf(buffer, sizeof(buffer), "%.17g",
- value->number);
-
- if ((ptr = malloc(length + 1)) == NULL)
- return NULL;
-
- for (int i = 0; i < length; i++)
- ptr[i] = buffer[i];
-
- ptr[length] = 0;
- return ptr;
- }
- case JSON_TYPE_BOOLEAN: {
- char *ptr;
- const char *boolean_str = value->number != 0.0 ? "true" :
- "false";
- int length = json__strlen(boolean_str);
-
- if ((ptr = malloc(length + 1)) == NULL)
- return NULL;
-
- for (int i = 0; i < length; i++)
- ptr[i] = boolean_str[i];
-
- ptr[length] = 0;
- return ptr;
- }
- case JSON_TYPE_NULL: {
- char *ptr;
- const char *null_str = "null";
- int length = json__strlen(null_str);
-
- if ((ptr = malloc(length + 1)) == NULL)
- return NULL;
-
- for (int i = 0; i < length; i++)
- ptr[i] = null_str[i];
-
- ptr[length] = 0;
- return ptr;
- }
- case JSON_TYPE_ARRAY:
- return json__encode_array(value);
- case JSON_TYPE_OBJECT:
- return json__encode_object(value);
- default:
- return NULL;
- }
-}
-
-void json_object_init(struct json_value *object)
-{
- object->object.n_items = 0;
- object->object.capacity = 0;
- object->object.items = NULL;
-}
-
-struct json_value *json_object_new(void)
-{
- struct json_value *object = malloc(sizeof(struct json_value));
- if (!object) {
- return NULL;
- }
-
- object->type = JSON_TYPE_OBJECT;
- json_object_init(object);
-
- return object;
-}
-
-void json_object_free(struct json_value *object)
-{
- for (int i = 0; i < object->object.n_items; i++) {
- json_free(object->object.items[i]->value);
- free(object->object.items[i]->key);
- free(object->object.items[i]);
- }
-
- free(object->object.items);
- free(object);
-}
-
-int json_object_set(struct json_value *object, const char *key,
- struct json_value *value)
-{
- if (object->object.n_items >=
- object->object.capacity * JSON_OBJECT_CAPACITY_THRESHOLD) {
- void *items;
- int capacity;
-
- if (object->object.capacity)
- capacity = object->object.capacity *
- JSON_OBJECT_CAPACITY_MULTIPLIER;
- else
- capacity = JSON_OBJECT_INITIAL_CAPACITY;
-
- if ((items = realloc(
- object->object.items,
- capacity * sizeof(*object->object.items))) == NULL)
- return -1;
-
- object->object.items = items;
- object->object.capacity = capacity;
- }
-
- for (int i = 0; i < object->object.n_items; i++) {
- if (json__streq(object->object.items[i]->key, key)) {
- json_free(object->object.items[i]->value);
- object->object.items[i]->value = value;
- return 0;
- }
- }
-
- int idx = object->object.n_items++;
- object->object.items[idx] = malloc(sizeof(*object->object.items[idx]));
-
- if (object->object.items[idx] == NULL)
- return -1;
-
- int key_len = json__strlen(key);
- object->object.items[idx]->key = malloc(key_len + 1);
- strncpy(object->object.items[idx]->key, key, key_len);
- object->object.items[idx]->key[key_len] = '\0';
- object->object.items[idx]->value = value;
-
- return 0;
-}
-
-int json_object_has(struct json_value *object, const char *key)
-{
- for (int i = 0; i < object->object.n_items; i++)
- if (json__streq(object->object.items[i]->key, key))
- return 1;
-
- return 0;
-}
-
-struct json_value *json_object_get(struct json_value *object, const char *key)
-{
- if (object == NULL || object->object.items == NULL)
- return NULL;
-
- for (int i = 0; i < object->object.n_items; i++)
- if (object->object.items[i] != NULL &&
- object->object.items[i]->key != NULL &&
- json__streq(object->object.items[i]->key, key))
- return object->object.items[i]->value;
-
- return NULL;
-}
-
-void json_object_remove(struct json_value *object, const char *key)
-{
- for (int i = 0; i < object->object.n_items; i++) {
- if (json__streq(object->object.items[i]->key, key)) {
- switch (object->object.items[i]->value->type) {
- case JSON_TYPE_ARRAY:
- json_array_free(object->object.items[i]->value);
- break;
- case JSON_TYPE_OBJECT:
- json_object_free(
- object->object.items[i]->value);
- break;
- case JSON_TYPE_STRING:
- json_string_free(
- object->object.items[i]->value);
- break;
- default:
- free(object->object.items[i]->value);
- break;
- }
-
- free(object->object.items[i]->key);
- free(object->object.items[i]);
-
- if (i < object->object.n_items - 1) {
- object->object.items[i] =
- object->object
- .items[object->object.n_items -
- 1];
- }
-
- object->object.n_items--;
- }
- }
-}
-
-int json_object_iter(const struct json_value *object, int *iter, char **key,
- struct json_value **value)
-{
- if (*iter >= object->object.n_items)
- return 0;
-
- *key = object->object.items[*iter]->key;
- *value = object->object.items[(*iter)++]->value;
-
- return 1;
-}
-
-void json_object_clear(struct json_value *object)
-{
- char *key;
- int iter = 0;
- struct json_value *value;
-
- while (json_object_iter(object, &iter, &key, &value)) {
- json_object_remove(object, key);
- iter--;
- }
-}
-
-void json_array_init(struct json_value *array)
-{
- array->array.length = 0;
- array->array.capacity = 0;
- array->array.items = NULL;
-}
-
-struct json_value *json_array_new(void)
-{
- struct json_value *value;
- if ((value = malloc(sizeof(struct json_value))) == NULL)
- return NULL;
-
- value->type = JSON_TYPE_ARRAY;
- json_array_init(value);
-
- return value;
-}
-
-void json_array_free(struct json_value *value)
-{
- for (int i = 0; i < value->array.length; i++) {
- switch (value->array.items[i]->type) {
- case JSON_TYPE_OBJECT:
- json_object_free(value->array.items[i]);
- break;
- case JSON_TYPE_ARRAY:
- json_array_free(value->array.items[i]);
- break;
- case JSON_TYPE_STRING:
- json_string_free(value->array.items[i]);
- break;
- default:
- free(value->array.items[i]);
- break;
- }
- }
- free(value->array.items);
- free(value);
-}
-
-void json_free(struct json_value *value)
-{
- switch (value->type) {
- case JSON_TYPE_OBJECT:
- json_object_free(value);
- break;
- case JSON_TYPE_ARRAY:
- json_array_free(value);
- break;
- case JSON_TYPE_STRING:
- json_string_free(value);
- break;
- default:
- free(value);
- }
-}
-
-struct json_value *json_deep_copy(struct json_value *value)
-{
- struct json_value *new_value;
- struct json_value *element;
- char *key;
- int iter;
-
- iter = 0;
-
- switch (value->type) {
- case JSON_TYPE_OBJECT:
- new_value = json_object_new();
- while (json_object_iter(value, &iter, &key, &element))
- json_object_set(new_value, key,
- json_deep_copy(element));
- return new_value;
-
- case JSON_TYPE_ARRAY:
- new_value = json_array_new();
- while (json_array_iter(value, &iter, &element))
- json_array_push(new_value, json_deep_copy(element));
- return new_value;
-
- case JSON_TYPE_STRING:
- return json_string_new(value->string.value);
-
- default:
- new_value = malloc(sizeof(struct json_value));
- memcpy(new_value, value, sizeof(*value));
- return new_value;
- }
-
- return NULL;
-}
-
-void json_array_remove(struct json_value *array, int index)
-{
- switch (array->array.items[index]->type) {
- case JSON_TYPE_OBJECT:
- json_object_free(array->array.items[index]);
- break;
- case JSON_TYPE_ARRAY:
- json_array_free(array->array.items[index]);
- break;
- case JSON_TYPE_STRING:
- json_string_free(array->array.items[index]);
- break;
- default:
- break;
- }
-
- for (int i = index; i < array->array.length - 1; i++)
- array->array.items[i] = array->array.items[i + 1];
- array->array.length--;
-}
-
-inline int json_array_length(struct json_value *array)
-{
- return array->array.length;
-}
-
-int json_array_push(struct json_value *array, struct json_value *value)
-{
- if (array == NULL) {
- return -1;
- }
-
- int index = array->array.length;
- int capacity = array->array.capacity;
- int capacity_threshold = capacity * JSON_ARRAY_CAPACITY_THRESHOLD;
-
- if (index >= capacity_threshold) {
- int capacity;
- if (array->array.capacity > 0)
- capacity = array->array.capacity *
- JSON_ARRAY_CAPACITY_MULTIPLIER;
- else
- capacity = JSON_ARRAY_INITIAL_CAPACITY;
-
- struct json_value **items;
- int size = capacity * sizeof(struct json_value *);
- if ((items = realloc(array->array.items, size)) == NULL)
- return -1;
-
- array->array.items = items;
- array->array.capacity = capacity;
- }
-
- array->array.items[array->array.length++] = value;
- return 0;
-}
-
-int json_array_iter(struct json_value *array, int *index,
- struct json_value **value)
-{
- if (*index >= array->array.length)
- return 0;
-
- *value = array->array.items[(*index)++];
- return 1;
-}
-
-void json_array_clear(struct json_value *array)
-{
- int iter = 0;
- struct json_value *value;
-
- while (json_array_iter(array, &iter, &value))
- json_array_remove(array, iter--);
-}
-
-struct json_value *json_string_new(const char *string)
-{
- struct json_value *value;
- if ((value = malloc(sizeof(struct json_value))) == NULL)
- return NULL;
-
- value->type = JSON_TYPE_STRING;
- value->string.length = json__strlen(string);
- if ((value->string.value = malloc(value->string.length + 1)) == NULL) {
- free(value);
- return NULL;
- }
-
- for (int i = 0; i < value->string.length; i++)
- value->string.value[i] = string[i];
-
- value->string.value[value->string.length] = 0;
- return value;
-}
-
-struct json_value *json_number_new(double value)
-{
- struct json_value *number;
- if ((number = malloc(sizeof(struct json_value))) == NULL)
- return NULL;
-
- number->type = JSON_TYPE_NUMBER;
- number->number = value;
-
- return number;
-}
-
-struct json_value *json_boolean_new(int value)
-{
- struct json_value *boolean;
- if ((boolean = malloc(sizeof(struct json_value))) == NULL)
- return NULL;
-
- boolean->type = JSON_TYPE_BOOLEAN;
- boolean->number = value;
-
- return boolean;
-}
-
-void json_string_free(struct json_value *string)
-{
- free(string->string.value);
- free(string);
-}
-
-static inline void json__print_indent(int indent)
-{
- for (int i = 0; i < indent; i++) {
- putchar(' ');
- }
-}
-
-static void json__print_internal(struct json_value *value, int indent)
-{
- if (value == NULL) {
- printf("null");
- return;
- }
-
- switch (value->type) {
- case JSON_TYPE_STRING:
- printf("\"%s\"", value->string.value);
- break;
- case JSON_TYPE_NUMBER:
- printf("%.17g", value->number);
- break;
- case JSON_TYPE_BOOLEAN:
- printf("%s", value->number == 0.0 ? "false" : "true");
- break;
- case JSON_TYPE_NULL:
- printf("null");
- break;
- case JSON_TYPE_ARRAY:
- printf("[\n");
- for (int i = 0; i < value->array.length; i++) {
- json__print_indent(indent + 2);
- json__print_internal(value->array.items[i], indent + 2);
- if (i < value->array.length - 1) {
- printf(",\n");
- } else {
- printf("\n");
- }
- }
- json__print_indent(indent);
- printf("]");
- break;
- case JSON_TYPE_OBJECT:
- printf("{\n");
- for (int i = 0; i < value->object.n_items; i++) {
- json__print_indent(indent + 2);
- printf("\"%s\": ", value->object.items[i]->key);
- json__print_internal(value->object.items[i]->value,
- indent + 2);
- if (i < value->object.n_items - 1) {
- printf(",\n");
- } else {
- printf("\n");
- }
- }
- json__print_indent(indent);
- printf("}");
- break;
- default:
- break;
- }
-}
-
-void json_print(struct json_value *value)
-{
- json__print_internal(value, 0);
-}
-
-void json_println(struct json_value *value)
-{
- json_print(value);
- putchar('\n');
-}