diff options
author | Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> | 2023-08-18 01:55:49 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-18 01:55:49 +0900 |
commit | 524df1f621321e892099d00df2174ca19a5b2a98 (patch) | |
tree | 408cf63a852141771fcce3f1464fe00bc3ea2656 | |
parent | fff5d792978837061d47225925a2832f1b638f00 (diff) | |
parent | 036b88c6be9a096e682a3f350bdcb45b8e2f27a9 (diff) |
Merge pull request #320 from AkihiroSuda/dev
parson: update to v1.5.2
-rwxr-xr-x | vendor.sh | 4 | ||||
-rw-r--r-- | vendor/README.md | 2 | ||||
-rw-r--r-- | vendor/parson/LICENSE | 2 | ||||
-rw-r--r-- | vendor/parson/README.md | 1 | ||||
-rw-r--r-- | vendor/parson/parson.c | 914 | ||||
-rw-r--r-- | vendor/parson/parson.h | 28 |
6 files changed, 630 insertions, 321 deletions
@@ -1,8 +1,8 @@ #!/bin/bash set -eux -o pipefail -# v1.1.3 (May 26, 2021) -PARSON_COMMIT=2d7b3ddf1280bf7f5ad82d26e09252240e7c4557 +# v1.5.2 (May 21, 2023) +PARSON_COMMIT=60c37844d7a1c97547812cac3423d458c73e60f9 PARSON_REPO=https://github.com/kgabis/parson.git # prepare diff --git a/vendor/README.md b/vendor/README.md index ab0c908..27b1024 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -1,7 +1,7 @@ # DO NOT EDIT MANUALLY Vendored components: -* parson: https://github.com/kgabis/parson.git (`2d7b3ddf1280bf7f5ad82d26e09252240e7c4557`) +* parson: https://github.com/kgabis/parson.git (`60c37844d7a1c97547812cac3423d458c73e60f9`) Please do not edit the contents under this directory manually. diff --git a/vendor/parson/LICENSE b/vendor/parson/LICENSE index 64a1f04..4431a61 100644 --- a/vendor/parson/LICENSE +++ b/vendor/parson/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2012 - 2021 Krzysztof Gabis +Copyright (c) 2012 - 2022 Krzysztof Gabis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/parson/README.md b/vendor/parson/README.md index f398071..011e051 100644 --- a/vendor/parson/README.md +++ b/vendor/parson/README.md @@ -2,7 +2,6 @@ Parson is a lightweight [json](http://json.org) library written in C. ## Features -* Full JSON support * Lightweight (only 2 files) * Simple API * Addressing json values with dot notation (similar to C structs or objects in most OO languages, e.g. "objectA.objectB.value") diff --git a/vendor/parson/parson.c b/vendor/parson/parson.c index 65a0e8b..4a18fe9 100644 --- a/vendor/parson/parson.c +++ b/vendor/parson/parson.c @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: MIT - Parson 1.1.3 ( http://kgabis.github.com/parson/ ) - Copyright (c) 2012 - 2021 Krzysztof Gabis + Parson 1.5.2 (https://github.com/kgabis/parson) + Copyright (c) 2012 - 2023 Krzysztof Gabis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,16 @@ #include "parson.h" +#define PARSON_IMPL_VERSION_MAJOR 1 +#define PARSON_IMPL_VERSION_MINOR 5 +#define PARSON_IMPL_VERSION_PATCH 2 + +#if (PARSON_VERSION_MAJOR != PARSON_IMPL_VERSION_MAJOR)\ +|| (PARSON_VERSION_MINOR != PARSON_IMPL_VERSION_MINOR)\ +|| (PARSON_VERSION_PATCH != PARSON_IMPL_VERSION_PATCH) +#error "parson version mismatch between parson.c and parson.h" +#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -39,13 +49,31 @@ /* Apparently sscanf is not implemented in some "standard" libraries, so don't use it, if you * don't have to. */ +#ifdef sscanf +#undef sscanf #define sscanf THINK_TWICE_ABOUT_USING_SSCANF +#endif + +/* strcpy is unsafe */ +#ifdef strcpy +#undef strcpy +#endif +#define strcpy USE_MEMCPY_INSTEAD_OF_STRCPY #define STARTING_CAPACITY 16 #define MAX_NESTING 2048 -#define FLOAT_FORMAT "%1.17g" /* do not increase precision without incresing NUM_BUF_SIZE */ -#define NUM_BUF_SIZE 64 /* double printed with "%1.17g" shouldn't be longer than 25 bytes so let's be paranoid and use 64 */ +#ifndef PARSON_DEFAULT_FLOAT_FORMAT +#define PARSON_DEFAULT_FLOAT_FORMAT "%1.17g" /* do not increase precision without incresing NUM_BUF_SIZE */ +#endif + +#ifndef PARSON_NUM_BUF_SIZE +#define PARSON_NUM_BUF_SIZE 64 /* double printed with "%1.17g" shouldn't be longer than 25 bytes so let's be paranoid and use 64 */ +#endif + +#ifndef PARSON_INDENT_STR +#define PARSON_INDENT_STR " " +#endif #define SIZEOF_TOKEN(a) (sizeof(a) - 1) #define SKIP_CHAR(str) ((*str)++) @@ -61,13 +89,24 @@ #define IS_NUMBER_INVALID(x) (((x) * 0.0) != 0.0) #endif +#define OBJECT_INVALID_IX ((size_t)-1) + static JSON_Malloc_Function parson_malloc = malloc; static JSON_Free_Function parson_free = free; static int parson_escape_slashes = 1; +static char *parson_float_format = NULL; + +static JSON_Number_Serialization_Function parson_number_serialization_function = NULL; + #define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */ +typedef int parson_bool_t; + +#define PARSON_TRUE 1 +#define PARSON_FALSE 0 + typedef struct json_string { char *chars; size_t length; @@ -90,11 +129,15 @@ struct json_value_t { }; struct json_object_t { - JSON_Value *wrapping_value; - char **names; - JSON_Value **values; - size_t count; - size_t capacity; + JSON_Value *wrapping_value; + size_t *cells; + unsigned long *hashes; + char **names; + JSON_Value **values; + size_t *cell_ixs; + size_t count; + size_t item_capacity; + size_t cell_capacity; }; struct json_array_t { @@ -110,24 +153,27 @@ static void remove_comments(char *string, const char *start_token, const char static char * parson_strndup(const char *string, size_t n); static char * parson_strdup(const char *string); static int hex_char_to_int(char c); -static int parse_utf16_hex(const char *string, unsigned int *result); -static int num_bytes_in_utf8_sequence(unsigned char c); -static int verify_utf8_sequence(const unsigned char *string, int *len); -static int is_valid_utf8(const char *string, size_t string_len); -static int is_decimal(const char *string, size_t length); +static JSON_Status parse_utf16_hex(const char *string, unsigned int *result); +static int num_bytes_in_utf8_sequence(unsigned char c); +static JSON_Status verify_utf8_sequence(const unsigned char *string, int *len); +static parson_bool_t is_valid_utf8(const char *string, size_t string_len); +static parson_bool_t is_decimal(const char *string, size_t length); +static unsigned long hash_string(const char *string, size_t n); /* JSON Object */ -static JSON_Object * json_object_init(JSON_Value *wrapping_value); -static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value); -static JSON_Status json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value); -static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity); +static JSON_Object * json_object_make(JSON_Value *wrapping_value); +static JSON_Status json_object_init(JSON_Object *object, size_t capacity); +static void json_object_deinit(JSON_Object *object, parson_bool_t free_keys, parson_bool_t free_values); +static JSON_Status json_object_grow_and_rehash(JSON_Object *object); +static size_t json_object_get_cell_ix(const JSON_Object *object, const char *key, size_t key_len, unsigned long hash, parson_bool_t *out_found); +static JSON_Status json_object_add(JSON_Object *object, char *name, JSON_Value *value); static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len); -static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, int free_value); -static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value); +static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, parson_bool_t free_value); +static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, parson_bool_t free_value); static void json_object_free(JSON_Object *object); /* JSON Array */ -static JSON_Array * json_array_init(JSON_Value *wrapping_value); +static JSON_Array * json_array_make(JSON_Value *wrapping_value); static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value); static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity); static void json_array_free(JSON_Array *array); @@ -137,25 +183,91 @@ static JSON_Value * json_value_init_string_no_copy(char *string, size_t length); static const JSON_String * json_value_get_string_desc(const JSON_Value *value); /* Parser */ -static JSON_Status skip_quotes(const char **string); -static int parse_utf16(const char **unprocessed, char **processed); -static char * process_string(const char *input, size_t input_len, size_t *output_len); -static char * get_quoted_string(const char **string, size_t *output_string_len); -static JSON_Value * parse_object_value(const char **string, size_t nesting); -static JSON_Value * parse_array_value(const char **string, size_t nesting); -static JSON_Value * parse_string_value(const char **string); -static JSON_Value * parse_boolean_value(const char **string); -static JSON_Value * parse_number_value(const char **string); -static JSON_Value * parse_null_value(const char **string); -static JSON_Value * parse_value(const char **string, size_t nesting); +static JSON_Status skip_quotes(const char **string); +static JSON_Status parse_utf16(const char **unprocessed, char **processed); +static char * process_string(const char *input, size_t input_len, size_t *output_len); +static char * get_quoted_string(const char **string, size_t *output_string_len); +static JSON_Value * parse_object_value(const char **string, size_t nesting); +static JSON_Value * parse_array_value(const char **string, size_t nesting); +static JSON_Value * parse_string_value(const char **string); +static JSON_Value * parse_boolean_value(const char **string); +static JSON_Value * parse_number_value(const char **string); +static JSON_Value * parse_null_value(const char **string); +static JSON_Value * parse_value(const char **string, size_t nesting); /* Serialization */ -static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf); -static int json_serialize_string(const char *string, size_t len, char *buf); -static int append_indent(char *buf, int level); -static int append_string(char *buf, const char *string); +static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf); +static int json_serialize_string(const char *string, size_t len, char *buf); /* Various */ +static char * read_file(const char * filename) { + FILE *fp = fopen(filename, "r"); + size_t size_to_read = 0; + size_t size_read = 0; + long pos; + char *file_contents; + if (!fp) { + return NULL; + } + fseek(fp, 0L, SEEK_END); + pos = ftell(fp); + if (pos < 0) { + fclose(fp); + return NULL; + } + size_to_read = pos; + rewind(fp); + file_contents = (char*)parson_malloc(sizeof(char) * (size_to_read + 1)); + if (!file_contents) { + fclose(fp); + return NULL; + } + size_read = fread(file_contents, 1, size_to_read, fp); + if (size_read == 0 || ferror(fp)) { + fclose(fp); + parson_free(file_contents); + return NULL; + } + fclose(fp); + file_contents[size_read] = '\0'; + return file_contents; +} + +static void remove_comments(char *string, const char *start_token, const char *end_token) { + parson_bool_t in_string = PARSON_FALSE, escaped = PARSON_FALSE; + size_t i; + char *ptr = NULL, current_char; + size_t start_token_len = strlen(start_token); + size_t end_token_len = strlen(end_token); + if (start_token_len == 0 || end_token_len == 0) { + return; + } + while ((current_char = *string) != '\0') { + if (current_char == '\\' && !escaped) { + escaped = PARSON_TRUE; + string++; + continue; + } else if (current_char == '\"' && !escaped) { + in_string = !in_string; + } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) { + for(i = 0; i < start_token_len; i++) { + string[i] = ' '; + } + string = string + start_token_len; + ptr = strstr(string, end_token); + if (!ptr) { + return; + } + for (i = 0; i < (ptr - string) + end_token_len; i++) { + string[i] = ' '; + } + string = ptr + end_token_len - 1; + } + escaped = PARSON_FALSE; + string++; + } +} + static char * parson_strndup(const char *string, size_t n) { /* We expect the caller has validated that 'n' fits within the input buffer. */ char *output_string = (char*)parson_malloc(n + 1); @@ -182,20 +294,20 @@ static int hex_char_to_int(char c) { return -1; } -static int parse_utf16_hex(const char *s, unsigned int *result) { +static JSON_Status parse_utf16_hex(const char *s, unsigned int *result) { int x1, x2, x3, x4; if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0' || s[3] == '\0') { - return 0; + return JSONFailure; } x1 = hex_char_to_int(s[0]); x2 = hex_char_to_int(s[1]); x3 = hex_char_to_int(s[2]); x4 = hex_char_to_int(s[3]); if (x1 == -1 || x2 == -1 || x3 == -1 || x4 == -1) { - return 0; + return JSONFailure; } *result = (unsigned int)((x1 << 12) | (x2 << 8) | (x3 << 4) | x4); - return 1; + return JSONSuccess; } static int num_bytes_in_utf8_sequence(unsigned char c) { @@ -213,7 +325,7 @@ static int num_bytes_in_utf8_sequence(unsigned char c) { return 0; /* won't happen */ } -static int verify_utf8_sequence(const unsigned char *string, int *len) { +static JSON_Status verify_utf8_sequence(const unsigned char *string, int *len) { unsigned int cp = 0; *len = num_bytes_in_utf8_sequence(string[0]); @@ -232,242 +344,342 @@ static int verify_utf8_sequence(const unsigned char *string, int *len) { cp = (cp << 6) | (string[2] & 0x3F); cp = (cp << 6) | (string[3] & 0x3F); } else { - return 0; + return JSONFailure; } /* overlong encodings */ if ((cp < 0x80 && *len > 1) || (cp < 0x800 && *len > 2) || (cp < 0x10000 && *len > 3)) { - return 0; + return JSONFailure; } /* invalid unicode */ if (cp > 0x10FFFF) { - return 0; + return JSONFailure; } /* surrogate halves */ if (cp >= 0xD800 && cp <= 0xDFFF) { - return 0; + return JSONFailure; } - return 1; + return JSONSuccess; } static int is_valid_utf8(const char *string, size_t string_len) { int len = 0; const char *string_end = string + string_len; while (string < string_end) { - if (!verify_utf8_sequence((const unsigned char*)string, &len)) { - return 0; + if (verify_utf8_sequence((const unsigned char*)string, &len) != JSONSuccess) { + return PARSON_FALSE; } string += len; } - return 1; + return PARSON_TRUE; } -static int is_decimal(const char *string, size_t length) { +static parson_bool_t is_decimal(const char *string, size_t length) { if (length > 1 && string[0] == '0' && string[1] != '.') { - return 0; + return PARSON_FALSE; } if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') { - return 0; + return PARSON_FALSE; } while (length--) { if (strchr("xX", string[length])) { - return 0; + return PARSON_FALSE; } } - return 1; -} - -static char * read_file(const char * filename) { - FILE *fp = fopen(filename, "r"); - size_t size_to_read = 0; - size_t size_read = 0; - long pos; - char *file_contents; - if (!fp) { - return NULL; - } - fseek(fp, 0L, SEEK_END); - pos = ftell(fp); - if (pos < 0) { - fclose(fp); - return NULL; - } - size_to_read = pos; - rewind(fp); - file_contents = (char*)parson_malloc(sizeof(char) * (size_to_read + 1)); - if (!file_contents) { - fclose(fp); - return NULL; - } - size_read = fread(file_contents, 1, size_to_read, fp); - if (size_read == 0 || ferror(fp)) { - fclose(fp); - parson_free(file_contents); - return NULL; - } - fclose(fp); - file_contents[size_read] = '\0'; - return file_contents; + return PARSON_TRUE; } -static void remove_comments(char *string, const char *start_token, const char *end_token) { - int in_string = 0, escaped = 0; - size_t i; - char *ptr = NULL, current_char; - size_t start_token_len = strlen(start_token); - size_t end_token_len = strlen(end_token); - if (start_token_len == 0 || end_token_len == 0) { - return; - } - while ((current_char = *string) != '\0') { - if (current_char == '\\' && !escaped) { - escaped = 1; - string++; - continue; - } else if (current_char == '\"' && !escaped) { - in_string = !in_string; - } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) { - for(i = 0; i < start_token_len; i++) { - string[i] = ' '; - } - string = string + start_token_len; - ptr = strstr(string, end_token); - if (!ptr) { - return; - } - for (i = 0; i < (ptr - string) + end_token_len; i++) { - string[i] = ' '; - } - string = ptr + end_token_len - 1; +static unsigned long hash_string(const char *string, size_t n) { +#ifdef PARSON_FORCE_HASH_COLLISIONS + (void)string; + (void)n; + return 0; +#else + unsigned long hash = 5381; + unsigned char c; + size_t i = 0; + for (i = 0; i < n; i++) { + c = string[i]; + if (c == '\0') { + break; } - escaped = 0; - string++; + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ } + return hash; +#endif } /* JSON Object */ -static JSON_Object * json_object_init(JSON_Value *wrapping_value) { +static JSON_Object * json_object_make(JSON_Value *wrapping_value) { + JSON_Status res = JSONFailure; JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object)); if (new_obj == NULL) { return NULL; } new_obj->wrapping_value = wrapping_value; - new_obj->names = (char**)NULL; - new_obj->values = (JSON_Value**)NULL; - new_obj->capacity = 0; - new_obj->count = 0; + res = json_object_init(new_obj, 0); + if (res != JSONSuccess) { + parson_free(new_obj); + return NULL; + } return new_obj; } -static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value) { - if (name == NULL) { - return JSONFailure; +static JSON_Status json_object_init(JSON_Object *object, size_t capacity) { + unsigned int i = 0; + + object->cells = NULL; + object->names = NULL; + object->values = NULL; + object->cell_ixs = NULL; + object->hashes = NULL; + + object->count = 0; + object->cell_capacity = capacity; + object->item_capacity = (unsigned int)(capacity * 7/10); + + if (capacity == 0) { + return JSONSuccess; + } + + object->cells = (size_t*)parson_malloc(object->cell_capacity * sizeof(*object->cells)); + object->names = (char**)parson_malloc(object->item_capacity * sizeof(*object->names)); + object->values = (JSON_Value**)parson_malloc(object->item_capacity * sizeof(*object->values)); + object->cell_ixs = (size_t*)parson_malloc(object->item_capacity * sizeof(*object->cell_ixs)); + object->hashes = (unsigned long*)parson_malloc(object->item_capacity * sizeof(*object->hashes)); + if (object->cells == NULL + || object->names == NULL + || object->values == NULL + || object->cell_ixs == NULL + || object->hashes == NULL) { + goto error; } - return json_object_addn(object, name, strlen(name), value); + for (i = 0; i < object->cell_capacity; i++) { + object->cells[i] = OBJECT_INVALID_IX; + } + return JSONSuccess; +error: + parson_free(object->cells); + parson_free(object->names); + parson_free(object->values); + parson_free(object->cell_ixs); + parson_free(object->hashes); + return JSONFailure; } -static JSON_Status json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value) { - size_t index = 0; - if (object == NULL || name == NULL || value == NULL) { - return JSONFailure; +static void json_object_deinit(JSON_Object *object, parson_bool_t free_keys, parson_bool_t free_values) { + unsigned int i = 0; + for (i = 0; i < object->count; i++) { + if (free_keys) { + parson_free(object->names[i]); + } + if (free_values) { + json_value_free(object->values[i]); + } } - if (json_object_getn_value(object, name, name_len) != NULL) { + + object->count = 0; + object->item_capacity = 0; + object->cell_capacity = 0; + + parson_free(object->cells); + parson_free(object->names); + parson_free(object->values); + parson_free(object->cell_ixs); + parson_free(object->hashes); + + object->cells = NULL; + object->names = NULL; + object->values = NULL; + object->cell_ixs = NULL; + object->hashes = NULL; +} + +static JSON_Status json_object_grow_and_rehash(JSON_Object *object) { + JSON_Value *wrapping_value = NULL; + JSON_Object new_object; + char *key = NULL; + JSON_Value *value = NULL; + unsigned int i = 0; + size_t new_capacity = MAX(object->cell_capacity * 2, STARTING_CAPACITY); + JSON_Status res = json_object_init(&new_object, new_capacity); + if (res != JSONSuccess) { return JSONFailure; } - if (object->count >= object->capacity) { - size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY); - if (json_object_resize(object, new_capacity) == JSONFailure) { + + wrapping_value = json_object_get_wrapping_value(object); + new_object.wrapping_value = wrapping_value; + + for (i = 0; i < object->count; i++) { + key = object->names[i]; + value = object->values[i]; + res = json_object_add(&new_object, key, value); + if (res != JSONSuccess) { + json_object_deinit(&new_object, PARSON_FALSE, PARSON_FALSE); return JSONFailure; } + value->parent = wrapping_value; } - index = object->count; - object->names[index] = parson_strndup(name, name_len); - if (object->names[index] == NULL) { - return JSONFailure; - } - value->parent = json_object_get_wrapping_value(object); - object->values[index] = value; - object->count++; + json_object_deinit(object, PARSON_FALSE, PARSON_FALSE); + *object = new_object; return JSONSuccess; } -static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity) { - char **temp_names = NULL; - JSON_Value **temp_values = NULL; +static size_t json_object_get_cell_ix(const JSON_Object *object, const char *key, size_t key_len, unsigned long hash, parson_bool_t *out_found) { + size_t cell_ix = hash & (object->cell_capacity - 1); + size_t cell = 0; + size_t ix = 0; + unsigned int i = 0; + unsigned long hash_to_check = 0; + const char *key_to_check = NULL; + size_t key_to_check_len = 0; - if ((object->names == NULL && object->values != NULL) || - (object->names != NULL && object->values == NULL) || - new_capacity == 0) { - return JSONFailure; /* Shouldn't happen */ + *out_found = PARSON_FALSE; + + for (i = 0; i < object->cell_capacity; i++) { + ix = (cell_ix + i) & (object->cell_capacity - 1); + cell = object->cells[ix]; + if (cell == OBJECT_INVALID_IX) { + return ix; + } + hash_to_check = object->hashes[cell]; + if (hash != hash_to_check) { + continue; + } + key_to_check = object->names[cell]; + key_to_check_len = strlen(key_to_check); + if (key_to_check_len == key_len && strncmp(key, key_to_check, key_len) == 0) { + *out_found = PARSON_TRUE; + return ix; + } } - temp_names = (char**)parson_malloc(new_capacity * sizeof(char*)); - if (temp_names == NULL) { + return OBJECT_INVALID_IX; +} + +static JSON_Status json_object_add(JSON_Object *object, char *name, JSON_Value *value) { + unsigned long hash = 0; + parson_bool_t found = PARSON_FALSE; + size_t cell_ix = 0; + JSON_Status res = JSONFailure; + + if (!object || !name || !value) { return JSONFailure; } - temp_values = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*)); - if (temp_values == NULL) { - parson_free(temp_names); + + hash = hash_string(name, strlen(name)); + found = PARSON_FALSE; + cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); + if (found) { return JSONFailure; } - if (object->names != NULL && object->values != NULL && object->count > 0) { - memcpy(temp_names, object->names, object->count * sizeof(char*)); - memcpy(temp_values, object->values, object->count * sizeof(JSON_Value*)); + + if (object->count >= object->item_capacity) { + res = json_object_grow_and_rehash(object); + if (res != JSONSuccess) { + return JSONFailure; + } + cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); } - parson_free(object->names); - parson_free(object->values); - object->names = temp_names; - object->values = temp_values; - object->capacity = new_capacity; + + object->names[object->count] = name; + object->cells[cell_ix] = object->count; + object->values[object->count] = value; + object->cell_ixs[object->count] = cell_ix; + object->hashes[object->count] = hash; + object->count++; + value->parent = json_object_get_wrapping_value(object); + return JSONSuccess; } static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len) { - size_t i, name_length; - for (i = 0; i < json_object_get_count(object); i++) { - name_length = strlen(object->names[i]); - if (name_length != name_len) { - continue; - } - if (strncmp(object->names[i], name, name_len) == 0) { - return object->values[i]; - } + unsigned long hash = 0; + parson_bool_t found = PARSON_FALSE; + size_t cell_ix = 0; + size_t item_ix = 0; + if (!object || !name) { + return NULL; } - return NULL; + hash = hash_string(name, name_len); + found = PARSON_FALSE; + cell_ix = json_object_get_cell_ix(object, name, name_len, hash, &found); + if (!found) { + return NULL; + } + item_ix = object->cells[cell_ix]; + return object->values[item_ix]; } -static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, int free_value) { - size_t i = 0, last_item_index = 0; - if (object == NULL || json_object_get_value(object, name) == NULL) { +static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, parson_bool_t free_value) { + unsigned long hash = 0; + parson_bool_t found = PARSON_FALSE; + size_t cell = 0; + size_t item_ix = 0; + size_t last_item_ix = 0; + size_t i = 0; + size_t j = 0; + size_t x = 0; + size_t k = 0; + JSON_Value *val = NULL; + + if (object == NULL) { return JSONFailure; } - last_item_index = json_object_get_count(object) - 1; - for (i = 0; i < json_object_get_count(object); i++) { - if (strcmp(object->names[i], name) == 0) { - parson_free(object->names[i]); - if (free_value) { - json_value_free(object->values[i]); - } - if (i != last_item_index) { /* Replace key value pair with one from the end */ - object->names[i] = object->names[last_item_index]; - object->values[i] = object->values[last_item_index]; - } - object->count -= 1; - return JSONSuccess; + + hash = hash_string(name, strlen(name)); + found = PARSON_FALSE; + cell = json_object_get_cell_ix(object, name, strlen(name), hash, &found); + if (!found) { + return JSONFailure; + } + + item_ix = object->cells[cell]; + if (free_value) { + val = object->values[item_ix]; + json_value_free(val); + val = NULL; + } + + parson_free(object->names[item_ix]); + last_item_ix = object->count - 1; + if (item_ix < last_item_ix) { + object->names[item_ix] = object->names[last_item_ix]; + object->values[item_ix] = object->values[last_item_ix]; + object->cell_ixs[item_ix] = object->cell_ixs[last_item_ix]; + object->hashes[item_ix] = object->hashes[last_item_ix]; + object->cells[object->cell_ixs[item_ix]] = item_ix; + } + object->count--; + + i = cell; + j = i; + for (x = 0; x < (object->cell_capacity - 1); x++) { + j = (j + 1) & (object->cell_capacity - 1); + if (object->cells[j] == OBJECT_INVALID_IX) { + break; + } + k = object->hashes[object->cells[j]] & (object->cell_capacity - 1); + if ((j > i && (k <= i || k > j)) + || (j < i && (k <= i && k > j))) { + object->cell_ixs[object->cells[j]] = i; + object->cells[i] = object->cells[j]; + i = j; } } - return JSONFailure; /* No execution path should end here */ + object->cells[i] = OBJECT_INVALID_IX; + return JSONSuccess; } -static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value) { +static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, parson_bool_t free_value) { JSON_Value *temp_value = NULL; JSON_Object *temp_object = NULL; const char *dot_pos = strchr(name, '.'); - if (dot_pos == NULL) { + if (!dot_pos) { return json_object_remove_internal(object, name, free_value); } temp_value = json_object_getn_value(object, name, dot_pos - name); @@ -479,18 +691,12 @@ static JSON_Status json_object_dotremove_internal(JSON_Object *object, const cha } static void json_object_free(JSON_Object *object) { - size_t i; - for (i = 0; i < object->count; i++) { - parson_free(object->names[i]); - json_value_free(object->values[i]); - } - parson_free(object->names); - parson_free(object->values); + json_object_deinit(object, PARSON_TRUE, PARSON_TRUE); parson_free(object); } /* JSON Array */ -static JSON_Array * json_array_init(JSON_Value *wrapping_value) { +static JSON_Array * json_array_make(JSON_Value *wrapping_value) { JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array)); if (new_array == NULL) { return NULL; @@ -505,7 +711,7 @@ static JSON_Array * json_array_init(JSON_Value *wrapping_value) { static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value) { if (array->count >= array->capacity) { size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY); - if (json_array_resize(array, new_capacity) == JSONFailure) { + if (json_array_resize(array, new_capacity) != JSONSuccess) { return JSONFailure; } } @@ -576,14 +782,14 @@ static JSON_Status skip_quotes(const char **string) { return JSONSuccess; } -static int parse_utf16(const char **unprocessed, char **processed) { +static JSON_Status parse_utf16(const char **unprocessed, char **processed) { unsigned int cp, lead, trail; - int parse_succeeded = 0; char *processed_ptr = *processed; const char *unprocessed_ptr = *unprocessed; + JSON_Status status = JSONFailure; unprocessed_ptr++; /* skips u */ - parse_succeeded = parse_utf16_hex(unprocessed_ptr, &cp); - if (!parse_succeeded) { + status = parse_utf16_hex(unprocessed_ptr, &cp); + if (status != JSONSuccess) { return JSONFailure; } if (cp < 0x80) { @@ -603,8 +809,8 @@ static int parse_utf16(const char **unprocessed, char **processed) { if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u') { return JSONFailure; } - parse_succeeded = parse_utf16_hex(unprocessed_ptr, &trail); - if (!parse_succeeded || trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */ + status = parse_utf16_hex(unprocessed_ptr, &trail); + if (status != JSONSuccess || trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */ return JSONFailure; } cp = ((((lead - 0xD800) & 0x3FF) << 10) | ((trail - 0xDC00) & 0x3FF)) + 0x010000; @@ -648,7 +854,7 @@ static char* process_string(const char *input, size_t input_len, size_t *output_ case 'r': *output_ptr = '\r'; break; case 't': *output_ptr = '\t'; break; case 'u': - if (parse_utf16(&input_ptr, &output_ptr) == JSONFailure) { + if (parse_utf16(&input_ptr, &output_ptr) != JSONSuccess) { goto error; } break; @@ -719,9 +925,11 @@ static JSON_Value * parse_value(const char **string, size_t nesting) { } static JSON_Value * parse_object_value(const char **string, size_t nesting) { + JSON_Status status = JSONFailure; JSON_Value *output_value = NULL, *new_value = NULL; JSON_Object *output_object = NULL; char *new_key = NULL; + output_value = json_value_init_object(); if (output_value == NULL) { return NULL; @@ -741,10 +949,12 @@ static JSON_Value * parse_object_value(const char **string, size_t nesting) { size_t key_len = 0; new_key = get_quoted_string(string, &key_len); /* We do not support key names with embedded \0 chars */ - if (new_key == NULL || key_len != strlen(new_key)) { - if (new_key) { - parson_free(new_key); - } + if (!new_key) { + json_value_free(output_value); + return NULL; + } + if (key_len != strlen(new_key)) { + parson_free(new_key); json_value_free(output_value); return NULL; } @@ -761,25 +971,27 @@ static JSON_Value * parse_object_value(const char **string, size_t nesting) { json_value_free(output_value); return NULL; } - if (json_object_add(output_object, new_key, new_value) == JSONFailure) { + status = json_object_add(output_object, new_key, new_value); + if (status != JSONSuccess) { parson_free(new_key); json_value_free(new_value); json_value_free(output_value); return NULL; } - parson_free(new_key); SKIP_WHITESPACES(string); if (**string != ',') { break; } SKIP_CHAR(string); SKIP_WHITESPACES(string); + if (**string == '}') { + break; + } } SKIP_WHITESPACES(string); - if (**string != '}' || /* Trim object after parsing is over */ - json_object_resize(output_object, json_object_get_count(output_object)) == JSONFailure) { - json_value_free(output_value); - return NULL; + if (**string != '}') { + json_value_free(output_value); + return NULL; } SKIP_CHAR(string); return output_value; @@ -809,7 +1021,7 @@ static JSON_Value * parse_array_value(const char **string, size_t nesting) { json_value_free(output_value); return NULL; } - if (json_array_add(output_array, new_array_value) == JSONFailure) { + if (json_array_add(output_array, new_array_value) != JSONSuccess) { json_value_free(new_array_value); json_value_free(output_value); return NULL; @@ -820,10 +1032,13 @@ static JSON_Value * parse_array_value(const char **string, size_t nesting) { } SKIP_CHAR(string); SKIP_WHITESPACES(string); + if (**string == ']') { + break; + } } SKIP_WHITESPACES(string); if (**string != ']' || /* Trim array after parsing is over */ - json_array_resize(output_array, json_array_get_count(output_array)) == JSONFailure) { + json_array_resize(output_array, json_array_get_count(output_array)) != JSONSuccess) { json_value_free(output_value); return NULL; } @@ -864,7 +1079,7 @@ static JSON_Value * parse_number_value(const char **string) { double number = 0; errno = 0; number = strtod(*string, &end); - if (errno == ERANGE && (number == -HUGE_VAL || number == HUGE_VAL)) { + if (errno == ERANGE && (number <= -HUGE_VAL || number >= HUGE_VAL)) { return NULL; } if ((errno && errno != ERANGE) || !is_decimal(*string, end - *string)) { @@ -884,17 +1099,29 @@ static JSON_Value * parse_null_value(const char **string) { } /* Serialization */ -#define APPEND_STRING(str) do { written = append_string(buf, (str));\ - if (written < 0) { return -1; }\ - if (buf != NULL) { buf += written; }\ - written_total += written; } while(0) -#define APPEND_INDENT(level) do { written = append_indent(buf, (level));\ - if (written < 0) { return -1; }\ - if (buf != NULL) { buf += written; }\ - written_total += written; } while(0) - -static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf) +/* APPEND_STRING() is only called on string literals. + It's a bit hacky because it makes plenty of assumptions about the external state + and should eventually be tidied up into a function (same goes for APPEND_INDENT) + */ +#define APPEND_STRING(str) do {\ + written = SIZEOF_TOKEN((str));\ + if (buf != NULL) {\ + memcpy(buf, (str), written);\ + buf[written] = '\0';\ + buf += written;\ + }\ + written_total += written;\ + } while (0) + +#define APPEND_INDENT(level) do {\ + int level_i = 0;\ + for (level_i = 0; level_i < (level); level_i++) {\ + APPEND_STRING(PARSON_INDENT_STR);\ + }\ + } while (0) + +static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf) { const char *key = NULL, *string = NULL; JSON_Value *temp_value = NULL; @@ -1014,7 +1241,13 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le if (buf != NULL) { num_buf = buf; } - written = sprintf(num_buf, FLOAT_FORMAT, num); + if (parson_number_serialization_function) { + written = parson_number_serialization_function(num, num_buf); + } else if (parson_float_format) { + written = sprintf(num_buf, parson_float_format, num); + } else { + written = sprintf(num_buf, PARSON_DEFAULT_FLOAT_FORMAT, num); + } if (written < 0) { return -1; } @@ -1100,22 +1333,6 @@ static int json_serialize_string(const char *string, size_t len, char *buf) { return written_total; } -static int append_indent(char *buf, int level) { - int i; - int written = -1, written_total = 0; - for (i = 0; i < level; i++) { - APPEND_STRING(" "); - } - return written_total; -} - -static int append_string(char *buf, const char *string) { - if (buf == NULL) { - return (int)strlen(string); - } - return sprintf(buf, "%s", string); -} - #undef APPEND_STRING #undef APPEND_INDENT @@ -1252,6 +1469,9 @@ JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index) { } JSON_Value *json_object_get_wrapping_value(const JSON_Object *object) { + if (!object) { + return NULL; + } return object->wrapping_value; } @@ -1310,6 +1530,9 @@ size_t json_array_get_count(const JSON_Array *array) { } JSON_Value * json_array_get_wrapping_value(const JSON_Array *array) { + if (!array) { + return NULL; + } return array->wrapping_value; } @@ -1376,7 +1599,7 @@ JSON_Value * json_value_init_object(void) { } new_value->parent = NULL; new_value->type = JSONObject; - new_value->value.object = json_object_init(new_value); + new_value->value.object = json_object_make(new_value); if (!new_value->value.object) { parson_free(new_value); return NULL; @@ -1391,7 +1614,7 @@ JSON_Value * json_value_init_array(void) { } new_value->parent = NULL; new_value->type = JSONArray; - new_value->value.array = json_array_init(new_value); + new_value->value.array = json_array_make(new_value); if (!new_value->value.array) { parson_free(new_value); return NULL; @@ -1470,6 +1693,8 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { char *temp_string_copy = NULL; JSON_Array *temp_array = NULL, *temp_array_copy = NULL; JSON_Object *temp_object = NULL, *temp_object_copy = NULL; + JSON_Status res = JSONFailure; + char *key_copy = NULL; switch (json_value_get_type(value)) { case JSONArray: @@ -1486,7 +1711,7 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { json_value_free(return_value); return NULL; } - if (json_array_add(temp_array_copy, temp_value_copy) == JSONFailure) { + if (json_array_add(temp_array_copy, temp_value_copy) != JSONSuccess) { json_value_free(return_value); json_value_free(temp_value_copy); return NULL; @@ -1496,7 +1721,7 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { case JSONObject: temp_object = json_value_get_object(value); return_value = json_value_init_object(); - if (return_value == NULL) { + if (!return_value) { return NULL; } temp_object_copy = json_value_get_object(return_value); @@ -1504,13 +1729,21 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { temp_key = json_object_get_name(temp_object, i); temp_value = json_object_get_value(temp_object, temp_key); temp_value_copy = json_value_deep_copy(temp_value); - if (temp_value_copy == NULL) { + if (!temp_value_copy) { json_value_free(return_value); return NULL; } - if (json_object_add(temp_object_copy, temp_key, temp_value_copy) == JSONFailure) { + key_copy = parson_strdup(temp_key); + if (!key_copy) { + json_value_free(temp_value_copy); json_value_free(return_value); + return NULL; + } + res = json_object_add(temp_object_copy, key_copy, temp_value_copy); + if (res != JSONSuccess) { + parson_free(key_copy); json_value_free(temp_value_copy); + json_value_free(return_value); return NULL; } } @@ -1543,8 +1776,8 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { } size_t json_serialization_size(const JSON_Value *value) { - char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ - int res = json_serialize_to_buffer_r(value, NULL, 0, 0, num_buf); + char num_buf[PARSON_NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ + int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_FALSE, num_buf); return res < 0 ? 0 : (size_t)(res) + 1; } @@ -1554,7 +1787,7 @@ JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) { return JSONFailure; } - written = json_serialize_to_buffer_r(value, buf, 0, 0, NULL); + written = json_serialize_to_buffer_r(value, buf, 0, PARSON_FALSE, NULL); if (written < 0) { return JSONFailure; } @@ -1595,7 +1828,7 @@ char * json_serialize_to_string(const JSON_Value *value) { return NULL; } serialization_result = json_serialize_to_buffer(value, buf, buf_size_bytes); - if (serialization_result == JSONFailure) { + if (serialization_result != JSONSuccess) { json_free_serialized_string(buf); return NULL; } @@ -1603,8 +1836,8 @@ char * json_serialize_to_string(const JSON_Value *value) { } size_t json_serialization_size_pretty(const JSON_Value *value) { - char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ - int res = json_serialize_to_buffer_r(value, NULL, 0, 1, num_buf); + char num_buf[PARSON_NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ + int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_TRUE, num_buf); return res < 0 ? 0 : (size_t)(res) + 1; } @@ -1614,7 +1847,7 @@ JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) { return JSONFailure; } - written = json_serialize_to_buffer_r(value, buf, 0, 1, NULL); + written = json_serialize_to_buffer_r(value, buf, 0, PARSON_TRUE, NULL); if (written < 0) { return JSONFailure; } @@ -1655,7 +1888,7 @@ char * json_serialize_to_string_pretty(const JSON_Value *value) { return NULL; } serialization_result = json_serialize_to_buffer_pretty(value, buf, buf_size_bytes); - if (serialization_result == JSONFailure) { + if (serialization_result != JSONSuccess) { json_free_serialized_string(buf); return NULL; } @@ -1693,7 +1926,7 @@ JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* s if (value == NULL) { return JSONFailure; } - if (json_array_replace_value(array, i, value) == JSONFailure) { + if (json_array_replace_value(array, i, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1705,7 +1938,7 @@ JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, cons if (value == NULL) { return JSONFailure; } - if (json_array_replace_value(array, i, value) == JSONFailure) { + if (json_array_replace_value(array, i, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1717,7 +1950,7 @@ JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number if (value == NULL) { return JSONFailure; } - if (json_array_replace_value(array, i, value) == JSONFailure) { + if (json_array_replace_value(array, i, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1729,7 +1962,7 @@ JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean) if (value == NULL) { return JSONFailure; } - if (json_array_replace_value(array, i, value) == JSONFailure) { + if (json_array_replace_value(array, i, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1741,7 +1974,7 @@ JSON_Status json_array_replace_null(JSON_Array *array, size_t i) { if (value == NULL) { return JSONFailure; } - if (json_array_replace_value(array, i, value) == JSONFailure) { + if (json_array_replace_value(array, i, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1772,7 +2005,7 @@ JSON_Status json_array_append_string(JSON_Array *array, const char *string) { if (value == NULL) { return JSONFailure; } - if (json_array_append_value(array, value) == JSONFailure) { + if (json_array_append_value(array, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1784,7 +2017,7 @@ JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *str if (value == NULL) { return JSONFailure; } - if (json_array_append_value(array, value) == JSONFailure) { + if (json_array_append_value(array, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1796,7 +2029,7 @@ JSON_Status json_array_append_number(JSON_Array *array, double number) { if (value == NULL) { return JSONFailure; } - if (json_array_append_value(array, value) == JSONFailure) { + if (json_array_append_value(array, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1808,7 +2041,7 @@ JSON_Status json_array_append_boolean(JSON_Array *array, int boolean) { if (value == NULL) { return JSONFailure; } - if (json_array_append_value(array, value) == JSONFailure) { + if (json_array_append_value(array, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1820,7 +2053,7 @@ JSON_Status json_array_append_null(JSON_Array *array) { if (value == NULL) { return JSONFailure; } - if (json_array_append_value(array, value) == JSONFailure) { + if (json_array_append_value(array, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1828,30 +2061,52 @@ JSON_Status json_array_append_null(JSON_Array *array) { } JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) { - size_t i = 0; - JSON_Value *old_value; - if (object == NULL || name == NULL || value == NULL || value->parent != NULL) { + unsigned long hash = 0; + parson_bool_t found = PARSON_FALSE; + size_t cell_ix = 0; + size_t item_ix = 0; + JSON_Value *old_value = NULL; + char *key_copy = NULL; + + if (!object || !name || !value || value->parent) { return JSONFailure; } - old_value = json_object_get_value(object, name); - if (old_value != NULL) { /* free and overwrite old value */ + hash = hash_string(name, strlen(name)); + found = PARSON_FALSE; + cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); + if (found) { + item_ix = object->cells[cell_ix]; + old_value = object->values[item_ix]; json_value_free(old_value); - for (i = 0; i < json_object_get_count(object); i++) { - if (strcmp(object->names[i], name) == 0) { - value->parent = json_object_get_wrapping_value(object); - object->values[i] = value; - return JSONSuccess; - } + object->values[item_ix] = value; + value->parent = json_object_get_wrapping_value(object); + return JSONSuccess; + } + if (object->count >= object->item_capacity) { + JSON_Status res = json_object_grow_and_rehash(object); + if (res != JSONSuccess) { + return JSONFailure; } + cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); + } + key_copy = parson_strdup(name); + if (!key_copy) { + return JSONFailure; } - /* add new key value pair */ - return json_object_add(object, name, value); + object->names[object->count] = key_copy; + object->cells[cell_ix] = object->count; + object->values[object->count] = value; + object->cell_ixs[object->count] = cell_ix; + object->hashes[object->count] = hash; + object->count++; + value->parent = json_object_get_wrapping_value(object); + return JSONSuccess; } JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string) { JSON_Value *value = json_value_init_string(string); JSON_Status status = json_object_set_value(object, name, value); - if (status == JSONFailure) { + if (status != JSONSuccess) { json_value_free(value); } return status; @@ -1860,7 +2115,7 @@ JSON_Status json_object_set_string(JSON_Object *object, const char *name, const JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len) { JSON_Value *value = json_value_init_string_with_len(string, len); JSON_Status status = json_object_set_value(object, name, value); - if (status == JSONFailure) { + if (status != JSONSuccess) { json_value_free(value); } return status; @@ -1869,7 +2124,7 @@ JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *nam JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) { JSON_Value *value = json_value_init_number(number); JSON_Status status = json_object_set_value(object, name, value); - if (status == JSONFailure) { + if (status != JSONSuccess) { json_value_free(value); } return status; @@ -1878,7 +2133,7 @@ JSON_Status json_object_set_number(JSON_Object *object, const char *name, double JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) { JSON_Value *value = json_value_init_boolean(boolean); JSON_Status status = json_object_set_value(object, name, value); - if (status == JSONFailure) { + if (status != JSONSuccess) { json_value_free(value); } return status; @@ -1887,7 +2142,7 @@ JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int b JSON_Status json_object_set_null(JSON_Object *object, const char *name) { JSON_Value *value = json_value_init_null(); JSON_Status status = json_object_set_value(object, name, value); - if (status == JSONFailure) { + if (status != JSONSuccess) { json_value_free(value); } return status; @@ -1899,6 +2154,8 @@ JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON JSON_Object *temp_object = NULL, *new_object = NULL; JSON_Status status = JSONFailure; size_t name_len = 0; + char *name_copy = NULL; + if (object == NULL || name == NULL || value == NULL) { return JSONFailure; } @@ -1926,8 +2183,15 @@ JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON json_value_free(new_value); return JSONFailure; } - status = json_object_addn(object, name, name_len, new_value); + name_copy = parson_strndup(name, name_len); + if (!name_copy) { + json_object_dotremove_internal(new_object, dot_pos + 1, 0); + json_value_free(new_value); + return JSONFailure; + } + status = json_object_add(object, name_copy, new_value); if (status != JSONSuccess) { + parson_free(name_copy); json_object_dotremove_internal(new_object, dot_pos + 1, 0); json_value_free(new_value); return JSONFailure; @@ -1940,7 +2204,7 @@ JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, con if (value == NULL) { return JSONFailure; } - if (json_object_dotset_value(object, name, value) == JSONFailure) { + if (json_object_dotset_value(object, name, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1952,7 +2216,7 @@ JSON_Status json_object_dotset_string_with_len(JSON_Object *object, const char * if (value == NULL) { return JSONFailure; } - if (json_object_dotset_value(object, name, value) == JSONFailure) { + if (json_object_dotset_value(object, name, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1964,7 +2228,7 @@ JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, dou if (value == NULL) { return JSONFailure; } - if (json_object_dotset_value(object, name, value) == JSONFailure) { + if (json_object_dotset_value(object, name, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1976,7 +2240,7 @@ JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, in if (value == NULL) { return JSONFailure; } - if (json_object_dotset_value(object, name, value) == JSONFailure) { + if (json_object_dotset_value(object, name, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1988,7 +2252,7 @@ JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) { if (value == NULL) { return JSONFailure; } - if (json_object_dotset_value(object, name, value) == JSONFailure) { + if (json_object_dotset_value(object, name, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1996,11 +2260,11 @@ JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) { } JSON_Status json_object_remove(JSON_Object *object, const char *name) { - return json_object_remove_internal(object, name, 1); + return json_object_remove_internal(object, name, PARSON_TRUE); } JSON_Status json_object_dotremove(JSON_Object *object, const char *name) { - return json_object_dotremove_internal(object, name, 1); + return json_object_dotremove_internal(object, name, PARSON_TRUE); } JSON_Status json_object_clear(JSON_Object *object) { @@ -2010,9 +2274,15 @@ JSON_Status json_object_clear(JSON_Object *object) { } for (i = 0; i < json_object_get_count(object); i++) { parson_free(object->names[i]); + object->names[i] = NULL; + json_value_free(object->values[i]); + object->values[i] = NULL; } object->count = 0; + for (i = 0; i < object->cell_capacity; i++) { + object->cells[i] = OBJECT_INVALID_IX; + } return JSONSuccess; } @@ -2043,7 +2313,7 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) { temp_schema_value = json_array_get_value(schema_array, 0); for (i = 0; i < json_array_get_count(value_array); i++) { temp_value = json_array_get_value(value_array, i); - if (json_validate(temp_schema_value, temp_value) == JSONFailure) { + if (json_validate(temp_schema_value, temp_value) != JSONSuccess) { return JSONFailure; } } @@ -2064,7 +2334,7 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) { if (temp_value == NULL) { return JSONFailure; } - if (json_validate(temp_schema_value, temp_value) == JSONFailure) { + if (json_validate(temp_schema_value, temp_value) != JSONSuccess) { return JSONFailure; } } @@ -2086,7 +2356,7 @@ int json_value_equals(const JSON_Value *a, const JSON_Value *b) { a_type = json_value_get_type(a); b_type = json_value_get_type(b); if (a_type != b_type) { - return 0; + return PARSON_FALSE; } switch (a_type) { case JSONArray: @@ -2095,36 +2365,36 @@ int json_value_equals(const JSON_Value *a, const JSON_Value *b) { a_count = json_array_get_count(a_array); b_count = json_array_get_count(b_array); if (a_count != b_count) { - return 0; + return PARSON_FALSE; } for (i = 0; i < a_count; i++) { if (!json_value_equals(json_array_get_value(a_array, i), json_array_get_value(b_array, i))) { - return 0; + return PARSON_FALSE; } } - return 1; + return PARSON_TRUE; case JSONObject: a_object = json_value_get_object(a); b_object = json_value_get_object(b); a_count = json_object_get_count(a_object); b_count = json_object_get_count(b_object); if (a_count != b_count) { - return 0; + return PARSON_FALSE; } for (i = 0; i < a_count; i++) { key = json_object_get_name(a_object, i); if (!json_value_equals(json_object_get_value(a_object, key), json_object_get_value(b_object, key))) { - return 0; + return PARSON_FALSE; } } - return 1; + return PARSON_TRUE; case JSONString: a_string = json_value_get_string_desc(a); b_string = json_value_get_string_desc(b); if (a_string == NULL || b_string == NULL) { - return 0; /* shouldn't happen */ + return PARSON_FALSE; /* shouldn't happen */ } return a_string->length == b_string->length && memcmp(a_string->chars, b_string->chars, a_string->length) == 0; @@ -2133,11 +2403,11 @@ int json_value_equals(const JSON_Value *a, const JSON_Value *b) { case JSONNumber: return fabs(json_value_get_number(a) - json_value_get_number(b)) < 0.000001; /* EPSILON */ case JSONError: - return 1; + return PARSON_TRUE; case JSONNull: - return 1; + return PARSON_TRUE; default: - return 1; + return PARSON_TRUE; } } @@ -2149,11 +2419,11 @@ JSON_Object * json_object (const JSON_Value *value) { return json_value_get_object(value); } -JSON_Array * json_array (const JSON_Value *value) { +JSON_Array * json_array(const JSON_Value *value) { return json_value_get_array(value); } -const char * json_string (const JSON_Value *value) { +const char * json_string(const JSON_Value *value) { return json_value_get_string(value); } @@ -2161,7 +2431,7 @@ size_t json_string_len(const JSON_Value *value) { return json_value_get_string_len(value); } -double json_number (const JSON_Value *value) { +double json_number(const JSON_Value *value) { return json_value_get_number(value); } @@ -2177,3 +2447,19 @@ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Fu void json_set_escape_slashes(int escape_slashes) { parson_escape_slashes = escape_slashes; } + +void json_set_float_serialization_format(const char *format) { + if (parson_float_format) { + parson_free(parson_float_format); + parson_float_format = NULL; + } + if (!format) { + parson_float_format = NULL; + return; + } + parson_float_format = parson_strdup(format); +} + +void json_set_number_serialization_function(JSON_Number_Serialization_Function func) { + parson_number_serialization_function = func; +} diff --git a/vendor/parson/parson.h b/vendor/parson/parson.h index 2caac18..77b451e 100644 --- a/vendor/parson/parson.h +++ b/vendor/parson/parson.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: MIT - Parson 1.1.3 ( http://kgabis.github.com/parson/ ) - Copyright (c) 2012 - 2021 Krzysztof Gabis + Parson 1.5.2 (https://github.com/kgabis/parson) + Copyright (c) 2012 - 2023 Krzysztof Gabis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,15 @@ extern "C" { #endif +#if 0 +} /* unconfuse xcode */ +#endif + +#define PARSON_VERSION_MAJOR 1 +#define PARSON_VERSION_MINOR 5 +#define PARSON_VERSION_PATCH 2 + +#define PARSON_VERSION_STRING "1.5.2" #include <stddef.h> /* size_t */ @@ -58,6 +67,12 @@ typedef int JSON_Status; typedef void * (*JSON_Malloc_Function)(size_t); typedef void (*JSON_Free_Function)(void *); +/* A function used for serializing numbers (see json_set_number_serialization_function). + If 'buf' is null then it should return number of bytes that would've been written + (but not more than PARSON_NUM_BUF_SIZE). +*/ +typedef int (*JSON_Number_Serialization_Function)(double num, char *buf); + /* Call only once, before calling any other function from parson API. If not called, malloc and free from stdlib will be used for all allocations */ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun); @@ -66,6 +81,15 @@ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Fu This function sets a global setting and is not thread safe. */ void json_set_escape_slashes(int escape_slashes); +/* Sets float format used for serialization of numbers. + Make sure it can't serialize to a string longer than PARSON_NUM_BUF_SIZE. + If format is null then the default format is used. */ +void json_set_float_serialization_format(const char *format); + +/* Sets a function that will be used for serialization of numbers. + If function is null then the default serialization function is used. */ +void json_set_number_serialization_function(JSON_Number_Serialization_Function fun); + /* Parses first JSON value in a file, returns NULL in case of error */ JSON_Value * json_parse_file(const char *filename); |