Add support for string values with embedded '\0' characters (#137)

* Add support for strings with \0 chars

* address feedback

* Increments minor version, adds comments, changes license year

Co-authored-by: Krzysztof Gabis <kgabis@gmail.com>
This commit is contained in:
reuben olinsky 2020-04-16 12:55:56 -07:00 committed by GitHub
parent 8d8850d9d5
commit 102a4467e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 164 additions and 47 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
.DS_Store .DS_Store
test test
*.o *.o
testcpp
tests/test_2_serialized.txt
tests/test_2_serialized_pretty.txt

View File

@ -3,7 +3,7 @@ project(parson C)
include (GNUInstallDirs) include (GNUInstallDirs)
set(PARSON_VERSION 1.0.2) set(PARSON_VERSION 1.1.0)
add_library(parson parson.c) add_library(parson parson.c)
target_include_directories(parson PUBLIC $<INSTALL_INTERFACE:include>) target_include_directories(parson PUBLIC $<INSTALL_INTERFACE:include>)

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2012 - 2019 Krzysztof Gabis Copyright (c) 2012 - 2020 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,6 +1,6 @@
{ {
"name": "parson", "name": "parson",
"version": "1.0.2", "version": "1.1.0",
"repo": "kgabis/parson", "repo": "kgabis/parson",
"description": "Small json parser and reader", "description": "Small json parser and reader",
"keywords": [ "json", "parser" ], "keywords": [ "json", "parser" ],

175
parson.c
View File

@ -1,8 +1,8 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Parson 1.0.2 ( http://kgabis.github.com/parson/ ) Parson 1.1.0 ( http://kgabis.github.com/parson/ )
Copyright (c) 2012 - 2019 Krzysztof Gabis Copyright (c) 2012 - 2020 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -68,9 +68,14 @@ static int parson_escape_slashes = 1;
#define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */ #define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
typedef struct json_string {
char *chars;
size_t length;
} JSON_String;
/* Type definitions */ /* Type definitions */
typedef union json_value_value { typedef union json_value_value {
char *string; JSON_String string;
double number; double number;
JSON_Object *object; JSON_Object *object;
JSON_Array *array; JSON_Array *array;
@ -128,13 +133,14 @@ static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity);
static void json_array_free(JSON_Array *array); static void json_array_free(JSON_Array *array);
/* JSON Value */ /* JSON Value */
static JSON_Value * json_value_init_string_no_copy(char *string); 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 */ /* Parser */
static JSON_Status skip_quotes(const char **string); static JSON_Status skip_quotes(const char **string);
static int parse_utf16(const char **unprocessed, char **processed); static int parse_utf16(const char **unprocessed, char **processed);
static char * process_string(const char *input, size_t len); static char * process_string(const char *input, size_t input_len, size_t *output_len);
static char * get_quoted_string(const char **string); 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_object_value(const char **string, size_t nesting);
static JSON_Value * parse_array_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_string_value(const char **string);
@ -145,12 +151,13 @@ static JSON_Value * parse_value(const char **string, size_t nesting);
/* Serialization */ /* 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_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, char *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_indent(char *buf, int level);
static int append_string(char *buf, const char *string); static int append_string(char *buf, const char *string);
/* Various */ /* Various */
static char * parson_strndup(const char *string, size_t n) { 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); char *output_string = (char*)parson_malloc(n + 1);
if (!output_string) { if (!output_string) {
return NULL; return NULL;
@ -536,14 +543,15 @@ static void json_array_free(JSON_Array *array) {
} }
/* JSON Value */ /* JSON Value */
static JSON_Value * json_value_init_string_no_copy(char *string) { static JSON_Value * json_value_init_string_no_copy(char *string, size_t length) {
JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
if (!new_value) { if (!new_value) {
return NULL; return NULL;
} }
new_value->parent = NULL; new_value->parent = NULL;
new_value->type = JSONString; new_value->type = JSONString;
new_value->value.string = string; new_value->value.string.chars = string;
new_value->value.string.length = length;
return new_value; return new_value;
} }
@ -617,9 +625,9 @@ static int parse_utf16(const char **unprocessed, char **processed) {
/* Copies and processes passed string up to supplied length. /* Copies and processes passed string up to supplied length.
Example: "\u006Corem ipsum" -> lorem ipsum */ Example: "\u006Corem ipsum" -> lorem ipsum */
static char* process_string(const char *input, size_t len) { static char* process_string(const char *input, size_t input_len, size_t *output_len) {
const char *input_ptr = input; const char *input_ptr = input;
size_t initial_size = (len + 1) * sizeof(char); size_t initial_size = (input_len + 1) * sizeof(char);
size_t final_size = 0; size_t final_size = 0;
char *output = NULL, *output_ptr = NULL, *resized_output = NULL; char *output = NULL, *output_ptr = NULL, *resized_output = NULL;
output = (char*)parson_malloc(initial_size); output = (char*)parson_malloc(initial_size);
@ -627,7 +635,7 @@ static char* process_string(const char *input, size_t len) {
goto error; goto error;
} }
output_ptr = output; output_ptr = output;
while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < len) { while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < input_len) {
if (*input_ptr == '\\') { if (*input_ptr == '\\') {
input_ptr++; input_ptr++;
switch (*input_ptr) { switch (*input_ptr) {
@ -664,6 +672,7 @@ static char* process_string(const char *input, size_t len) {
goto error; goto error;
} }
memcpy(resized_output, output, final_size); memcpy(resized_output, output, final_size);
*output_len = final_size - 1;
parson_free(output); parson_free(output);
return resized_output; return resized_output;
error: error:
@ -673,15 +682,15 @@ error:
/* Return processed contents of a string between quotes and /* Return processed contents of a string between quotes and
skips passed argument to a matching quote. */ skips passed argument to a matching quote. */
static char * get_quoted_string(const char **string) { static char * get_quoted_string(const char **string, size_t *output_string_len) {
const char *string_start = *string; const char *string_start = *string;
size_t string_len = 0; size_t input_string_len = 0;
JSON_Status status = skip_quotes(string); JSON_Status status = skip_quotes(string);
if (status != JSONSuccess) { if (status != JSONSuccess) {
return NULL; return NULL;
} }
string_len = *string - string_start - 2; /* length without quotes */ input_string_len = *string - string_start - 2; /* length without quotes */
return process_string(string_start + 1, string_len); return process_string(string_start + 1, input_string_len, output_string_len);
} }
static JSON_Value * parse_value(const char **string, size_t nesting) { static JSON_Value * parse_value(const char **string, size_t nesting) {
@ -729,8 +738,10 @@ static JSON_Value * parse_object_value(const char **string, size_t nesting) {
return output_value; return output_value;
} }
while (**string != '\0') { while (**string != '\0') {
new_key = get_quoted_string(string); size_t key_len = 0;
if (new_key == NULL) { 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)) {
json_value_free(output_value); json_value_free(output_value);
return NULL; return NULL;
} }
@ -819,11 +830,12 @@ 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_string_value(const char **string) {
JSON_Value *value = NULL; JSON_Value *value = NULL;
char *new_string = get_quoted_string(string); size_t new_string_len = 0;
char *new_string = get_quoted_string(string, &new_string_len);
if (new_string == NULL) { if (new_string == NULL) {
return NULL; return NULL;
} }
value = json_value_init_string_no_copy(new_string); value = json_value_init_string_no_copy(new_string, new_string_len);
if (value == NULL) { if (value == NULL) {
parson_free(new_string); parson_free(new_string);
return NULL; return NULL;
@ -885,6 +897,7 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le
size_t i = 0, count = 0; size_t i = 0, count = 0;
double num = 0.0; double num = 0.0;
int written = -1, written_total = 0; int written = -1, written_total = 0;
size_t len = 0;
switch (json_value_get_type(value)) { switch (json_value_get_type(value)) {
case JSONArray: case JSONArray:
@ -934,7 +947,8 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le
if (is_pretty) { if (is_pretty) {
APPEND_INDENT(level+1); APPEND_INDENT(level+1);
} }
written = json_serialize_string(key, buf); /* We do not support key names with embedded \0 chars */
written = json_serialize_string(key, strlen(key), buf);
if (written < 0) { if (written < 0) {
return -1; return -1;
} }
@ -972,7 +986,8 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le
if (string == NULL) { if (string == NULL) {
return -1; return -1;
} }
written = json_serialize_string(string, buf); len = json_value_get_string_len(value);
written = json_serialize_string(string, len, buf);
if (written < 0) { if (written < 0) {
return -1; return -1;
} }
@ -1012,8 +1027,8 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le
} }
} }
static int json_serialize_string(const char *string, char *buf) { static int json_serialize_string(const char *string, size_t len, char *buf) {
size_t i = 0, len = strlen(string); size_t i = 0;
char c = '\0'; char c = '\0';
int written = -1, written_total = 0; int written = -1, written_total = 0;
APPEND_STRING("\""); APPEND_STRING("\"");
@ -1159,6 +1174,10 @@ const char * json_object_get_string(const JSON_Object *object, const char *name)
return json_value_get_string(json_object_get_value(object, name)); return json_value_get_string(json_object_get_value(object, name));
} }
size_t json_object_get_string_len(const JSON_Object *object, const char *name) {
return json_value_get_string_len(json_object_get_value(object, name));
}
double json_object_get_number(const JSON_Object *object, const char *name) { double json_object_get_number(const JSON_Object *object, const char *name) {
return json_value_get_number(json_object_get_value(object, name)); return json_value_get_number(json_object_get_value(object, name));
} }
@ -1188,6 +1207,10 @@ const char * json_object_dotget_string(const JSON_Object *object, const char *na
return json_value_get_string(json_object_dotget_value(object, name)); return json_value_get_string(json_object_dotget_value(object, name));
} }
size_t json_object_dotget_string_len(const JSON_Object *object, const char *name) {
return json_value_get_string_len(json_object_dotget_value(object, name));
}
double json_object_dotget_number(const JSON_Object *object, const char *name) { double json_object_dotget_number(const JSON_Object *object, const char *name) {
return json_value_get_number(json_object_dotget_value(object, name)); return json_value_get_number(json_object_dotget_value(object, name));
} }
@ -1256,6 +1279,10 @@ const char * json_array_get_string(const JSON_Array *array, size_t index) {
return json_value_get_string(json_array_get_value(array, index)); return json_value_get_string(json_array_get_value(array, index));
} }
size_t json_array_get_string_len(const JSON_Array *array, size_t index) {
return json_value_get_string_len(json_array_get_value(array, index));
}
double json_array_get_number(const JSON_Array *array, size_t index) { double json_array_get_number(const JSON_Array *array, size_t index) {
return json_value_get_number(json_array_get_value(array, index)); return json_value_get_number(json_array_get_value(array, index));
} }
@ -1293,8 +1320,18 @@ JSON_Array * json_value_get_array(const JSON_Value *value) {
return json_value_get_type(value) == JSONArray ? value->value.array : NULL; return json_value_get_type(value) == JSONArray ? value->value.array : NULL;
} }
static const JSON_String * json_value_get_string_desc(const JSON_Value *value) {
return json_value_get_type(value) == JSONString ? &value->value.string : NULL;
}
const char * json_value_get_string(const JSON_Value *value) { const char * json_value_get_string(const JSON_Value *value) {
return json_value_get_type(value) == JSONString ? value->value.string : NULL; const JSON_String *str = json_value_get_string_desc(value);
return str ? str->chars : NULL;
}
size_t json_value_get_string_len(const JSON_Value *value) {
const JSON_String *str = json_value_get_string_desc(value);
return str ? str->length : 0;
} }
double json_value_get_number(const JSON_Value *value) { double json_value_get_number(const JSON_Value *value) {
@ -1315,7 +1352,7 @@ void json_value_free(JSON_Value *value) {
json_object_free(value->value.object); json_object_free(value->value.object);
break; break;
case JSONString: case JSONString:
parson_free(value->value.string); parson_free(value->value.string.chars);
break; break;
case JSONArray: case JSONArray:
json_array_free(value->value.array); json_array_free(value->value.array);
@ -1357,21 +1394,26 @@ JSON_Value * json_value_init_array(void) {
} }
JSON_Value * json_value_init_string(const char *string) { JSON_Value * json_value_init_string(const char *string) {
char *copy = NULL;
JSON_Value *value;
size_t string_len = 0;
if (string == NULL) { if (string == NULL) {
return NULL; return NULL;
} }
string_len = strlen(string); return json_value_init_string_with_len(string, strlen(string));
if (!is_valid_utf8(string, string_len)) { }
JSON_Value * json_value_init_string_with_len(const char *string, size_t length) {
char *copy = NULL;
JSON_Value *value;
if (string == NULL) {
return NULL; return NULL;
} }
copy = parson_strndup(string, string_len); if (!is_valid_utf8(string, length)) {
return NULL;
}
copy = parson_strndup(string, length);
if (copy == NULL) { if (copy == NULL) {
return NULL; return NULL;
} }
value = json_value_init_string_no_copy(copy); value = json_value_init_string_no_copy(copy, length);
if (value == NULL) { if (value == NULL) {
parson_free(copy); parson_free(copy);
} }
@ -1417,7 +1459,8 @@ JSON_Value * json_value_init_null(void) {
JSON_Value * json_value_deep_copy(const JSON_Value *value) { JSON_Value * json_value_deep_copy(const JSON_Value *value) {
size_t i = 0; size_t i = 0;
JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL; JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL;
const char *temp_string = NULL, *temp_key = NULL; const JSON_String *temp_string = NULL;
const char *temp_key = NULL;
char *temp_string_copy = NULL; char *temp_string_copy = NULL;
JSON_Array *temp_array = NULL, *temp_array_copy = NULL; JSON_Array *temp_array = NULL, *temp_array_copy = NULL;
JSON_Object *temp_object = NULL, *temp_object_copy = NULL; JSON_Object *temp_object = NULL, *temp_object_copy = NULL;
@ -1471,15 +1514,15 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) {
case JSONNumber: case JSONNumber:
return json_value_init_number(json_value_get_number(value)); return json_value_init_number(json_value_get_number(value));
case JSONString: case JSONString:
temp_string = json_value_get_string(value); temp_string = json_value_get_string_desc(value);
if (temp_string == NULL) { if (temp_string == NULL) {
return NULL; return NULL;
} }
temp_string_copy = parson_strdup(temp_string); temp_string_copy = parson_strndup(temp_string->chars, temp_string->length);
if (temp_string_copy == NULL) { if (temp_string_copy == NULL) {
return NULL; return NULL;
} }
return_value = json_value_init_string_no_copy(temp_string_copy); return_value = json_value_init_string_no_copy(temp_string_copy, temp_string->length);
if (return_value == NULL) { if (return_value == NULL) {
parson_free(temp_string_copy); parson_free(temp_string_copy);
} }
@ -1651,6 +1694,18 @@ JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* s
return JSONSuccess; return JSONSuccess;
} }
JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len) {
JSON_Value *value = json_value_init_string_with_len(string, len);
if (value == NULL) {
return JSONFailure;
}
if (json_array_replace_value(array, i, value) == JSONFailure) {
json_value_free(value);
return JSONFailure;
}
return JSONSuccess;
}
JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number) { JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number) {
JSON_Value *value = json_value_init_number(number); JSON_Value *value = json_value_init_number(number);
if (value == NULL) { if (value == NULL) {
@ -1718,6 +1773,18 @@ JSON_Status json_array_append_string(JSON_Array *array, const char *string) {
return JSONSuccess; return JSONSuccess;
} }
JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *string, size_t len) {
JSON_Value *value = json_value_init_string_with_len(string, len);
if (value == NULL) {
return JSONFailure;
}
if (json_array_append_value(array, value) == JSONFailure) {
json_value_free(value);
return JSONFailure;
}
return JSONSuccess;
}
JSON_Status json_array_append_number(JSON_Array *array, double number) { JSON_Status json_array_append_number(JSON_Array *array, double number) {
JSON_Value *value = json_value_init_number(number); JSON_Value *value = json_value_init_number(number);
if (value == NULL) { if (value == NULL) {
@ -1784,6 +1851,15 @@ JSON_Status json_object_set_string(JSON_Object *object, const char *name, const
return status; return status;
} }
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) {
json_value_free(value);
}
return status;
}
JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) { JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) {
JSON_Value *value = json_value_init_number(number); JSON_Value *value = json_value_init_number(number);
JSON_Status status = json_object_set_value(object, name, value); JSON_Status status = json_object_set_value(object, name, value);
@ -1865,6 +1941,18 @@ JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, con
return JSONSuccess; return JSONSuccess;
} }
JSON_Status json_object_dotset_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);
if (value == NULL) {
return JSONFailure;
}
if (json_object_dotset_value(object, name, value) == JSONFailure) {
json_value_free(value);
return JSONFailure;
}
return JSONSuccess;
}
JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number) { JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number) {
JSON_Value *value = json_value_init_number(number); JSON_Value *value = json_value_init_number(number);
if (value == NULL) { if (value == NULL) {
@ -1985,7 +2073,7 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) {
int json_value_equals(const JSON_Value *a, const JSON_Value *b) { int json_value_equals(const JSON_Value *a, const JSON_Value *b) {
JSON_Object *a_object = NULL, *b_object = NULL; JSON_Object *a_object = NULL, *b_object = NULL;
JSON_Array *a_array = NULL, *b_array = NULL; JSON_Array *a_array = NULL, *b_array = NULL;
const char *a_string = NULL, *b_string = NULL; const JSON_String *a_string = NULL, *b_string = NULL;
const char *key = NULL; const char *key = NULL;
size_t a_count = 0, b_count = 0, i = 0; size_t a_count = 0, b_count = 0, i = 0;
JSON_Value_Type a_type, b_type; JSON_Value_Type a_type, b_type;
@ -2027,12 +2115,13 @@ int json_value_equals(const JSON_Value *a, const JSON_Value *b) {
} }
return 1; return 1;
case JSONString: case JSONString:
a_string = json_value_get_string(a); a_string = json_value_get_string_desc(a);
b_string = json_value_get_string(b); b_string = json_value_get_string_desc(b);
if (a_string == NULL || b_string == NULL) { if (a_string == NULL || b_string == NULL) {
return 0; /* shouldn't happen */ return 0; /* shouldn't happen */
} }
return strcmp(a_string, b_string) == 0; return a_string->length == b_string->length &&
memcmp(a_string->chars, b_string->chars, a_string->length) == 0;
case JSONBoolean: case JSONBoolean:
return json_value_get_boolean(a) == json_value_get_boolean(b); return json_value_get_boolean(a) == json_value_get_boolean(b);
case JSONNumber: case JSONNumber:
@ -2062,6 +2151,10 @@ const char * json_string (const JSON_Value *value) {
return json_value_get_string(value); return json_value_get_string(value);
} }
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); return json_value_get_number(value);
} }

View File

@ -1,8 +1,8 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Parson 1.0.2 ( http://kgabis.github.com/parson/ ) Parson 1.1.0 ( http://kgabis.github.com/parson/ )
Copyright (c) 2012 - 2019 Krzysztof Gabis Copyright (c) 2012 - 2020 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -114,6 +114,7 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value);
*/ */
JSON_Value * json_object_get_value (const JSON_Object *object, const char *name); JSON_Value * json_object_get_value (const JSON_Object *object, const char *name);
const char * json_object_get_string (const JSON_Object *object, const char *name); const char * json_object_get_string (const JSON_Object *object, const char *name);
size_t json_object_get_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
JSON_Object * json_object_get_object (const JSON_Object *object, const char *name); JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
JSON_Array * json_object_get_array (const JSON_Object *object, const char *name); JSON_Array * json_object_get_array (const JSON_Object *object, const char *name);
double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
@ -125,6 +126,7 @@ int json_object_get_boolean(const JSON_Object *object, const char *nam
this way. */ this way. */
JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name); JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name);
const char * json_object_dotget_string (const JSON_Object *object, const char *name); const char * json_object_dotget_string (const JSON_Object *object, const char *name);
size_t json_object_dotget_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name); JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name); JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name);
double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
@ -148,6 +150,7 @@ int json_object_dothas_value_of_type(const JSON_Object *object, const char *name
* json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */ * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value); JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string); JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number); JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean); JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
JSON_Status json_object_set_null(JSON_Object *object, const char *name); JSON_Status json_object_set_null(JSON_Object *object, const char *name);
@ -156,6 +159,7 @@ JSON_Status json_object_set_null(JSON_Object *object, const char *name);
* json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */ * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value); JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value);
JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string); JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string);
JSON_Status json_object_dotset_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number); JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number);
JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean); JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean);
JSON_Status json_object_dotset_null(JSON_Object *object, const char *name); JSON_Status json_object_dotset_null(JSON_Object *object, const char *name);
@ -174,6 +178,7 @@ JSON_Status json_object_clear(JSON_Object *object);
*/ */
JSON_Value * json_array_get_value (const JSON_Array *array, size_t index); JSON_Value * json_array_get_value (const JSON_Array *array, size_t index);
const char * json_array_get_string (const JSON_Array *array, size_t index); const char * json_array_get_string (const JSON_Array *array, size_t index);
size_t json_array_get_string_len(const JSON_Array *array, size_t index); /* doesn't account for last null character */
JSON_Object * json_array_get_object (const JSON_Array *array, size_t index); JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
JSON_Array * json_array_get_array (const JSON_Array *array, size_t index); JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */ double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
@ -190,6 +195,7 @@ JSON_Status json_array_remove(JSON_Array *array, size_t i);
* json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */ * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value); JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string); JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string);
JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number); JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean); JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
JSON_Status json_array_replace_null(JSON_Array *array, size_t i); JSON_Status json_array_replace_null(JSON_Array *array, size_t i);
@ -201,6 +207,7 @@ JSON_Status json_array_clear(JSON_Array *array);
* json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */ * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value); JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value);
JSON_Status json_array_append_string(JSON_Array *array, const char *string); JSON_Status json_array_append_string(JSON_Array *array, const char *string);
JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_array_append_number(JSON_Array *array, double number); JSON_Status json_array_append_number(JSON_Array *array, double number);
JSON_Status json_array_append_boolean(JSON_Array *array, int boolean); JSON_Status json_array_append_boolean(JSON_Array *array, int boolean);
JSON_Status json_array_append_null(JSON_Array *array); JSON_Status json_array_append_null(JSON_Array *array);
@ -211,6 +218,7 @@ JSON_Status json_array_append_null(JSON_Array *array);
JSON_Value * json_value_init_object (void); JSON_Value * json_value_init_object (void);
JSON_Value * json_value_init_array (void); JSON_Value * json_value_init_array (void);
JSON_Value * json_value_init_string (const char *string); /* copies passed string */ JSON_Value * json_value_init_string (const char *string); /* copies passed string */
JSON_Value * json_value_init_string_with_len(const char *string, size_t length); /* copies passed string, length shouldn't include last null character */
JSON_Value * json_value_init_number (double number); JSON_Value * json_value_init_number (double number);
JSON_Value * json_value_init_boolean(int boolean); JSON_Value * json_value_init_boolean(int boolean);
JSON_Value * json_value_init_null (void); JSON_Value * json_value_init_null (void);
@ -221,6 +229,7 @@ JSON_Value_Type json_value_get_type (const JSON_Value *value);
JSON_Object * json_value_get_object (const JSON_Value *value); JSON_Object * json_value_get_object (const JSON_Value *value);
JSON_Array * json_value_get_array (const JSON_Value *value); JSON_Array * json_value_get_array (const JSON_Value *value);
const char * json_value_get_string (const JSON_Value *value); const char * json_value_get_string (const JSON_Value *value);
size_t json_value_get_string_len(const JSON_Value *value); /* doesn't account for last null character */
double json_value_get_number (const JSON_Value *value); double json_value_get_number (const JSON_Value *value);
int json_value_get_boolean(const JSON_Value *value); int json_value_get_boolean(const JSON_Value *value);
JSON_Value * json_value_get_parent (const JSON_Value *value); JSON_Value * json_value_get_parent (const JSON_Value *value);
@ -230,6 +239,7 @@ JSON_Value_Type json_type (const JSON_Value *value);
JSON_Object * json_object (const JSON_Value *value); JSON_Object * json_object (const JSON_Value *value);
JSON_Array * json_array (const JSON_Value *value); JSON_Array * json_array (const JSON_Value *value);
const char * json_string (const JSON_Value *value); const char * json_string (const JSON_Value *value);
size_t json_string_len(const JSON_Value *value); /* doesn't account for last null character */
double json_number (const JSON_Value *value); double json_number (const JSON_Value *value);
int json_boolean(const JSON_Value *value); int json_boolean(const JSON_Value *value);

View File

@ -2,7 +2,7 @@
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Parson ( http://kgabis.github.com/parson/ ) Parson ( http://kgabis.github.com/parson/ )
Copyright (c) 2012 - 2019 Krzysztof Gabis Copyright (c) 2012 - 2020 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -136,6 +136,7 @@ void test_suite_2(JSON_Value *root_value) {
JSON_Object *root_object; JSON_Object *root_object;
JSON_Array *array; JSON_Array *array;
JSON_Value *array_value; JSON_Value *array_value;
size_t len;
size_t i; size_t i;
TEST(root_value); TEST(root_value);
TEST(json_value_get_type(root_value) == JSONObject); TEST(json_value_get_type(root_value) == JSONObject);
@ -176,6 +177,10 @@ void test_suite_2(JSON_Value *root_value) {
TEST(STREQ(json_object_get_string(root_object, "utf-8 string"), "あいうえお")); TEST(STREQ(json_object_get_string(root_object, "utf-8 string"), "あいうえお"));
TEST(STREQ(json_object_get_string(root_object, "surrogate string"), "lorem𝄞ipsum𝍧lorem")); TEST(STREQ(json_object_get_string(root_object, "surrogate string"), "lorem𝄞ipsum𝍧lorem"));
len = json_object_get_string_len(root_object, "string with null");
TEST(len == 7);
TEST(memcmp(json_object_get_string(root_object, "string with null"), "abc\0def", len) == 0);
TEST(json_object_get_number(root_object, "positive one") == 1.0); TEST(json_object_get_number(root_object, "positive one") == 1.0);
TEST(json_object_get_number(root_object, "negative one") == -1.0); TEST(json_object_get_number(root_object, "negative one") == -1.0);
TEST(fabs(json_object_get_number(root_object, "hard to parse number") - (-0.000314)) < EPSILON); TEST(fabs(json_object_get_number(root_object, "hard to parse number") - (-0.000314)) < EPSILON);
@ -370,6 +375,7 @@ void test_suite_5(void) {
TEST(json_object_set_string(obj, "utf string", "lorem ipsum") == JSONSuccess); TEST(json_object_set_string(obj, "utf string", "lorem ipsum") == JSONSuccess);
TEST(json_object_set_string(obj, "utf-8 string", "あいうえお") == JSONSuccess); TEST(json_object_set_string(obj, "utf-8 string", "あいうえお") == JSONSuccess);
TEST(json_object_set_string(obj, "surrogate string", "lorem𝄞ipsum𝍧lorem") == JSONSuccess); TEST(json_object_set_string(obj, "surrogate string", "lorem𝄞ipsum𝍧lorem") == JSONSuccess);
TEST(json_object_set_string_with_len(obj, "string with null", "abc\0def", 7) == JSONSuccess);
TEST(json_object_set_string(obj, "windows path", "C:\\Windows\\Path") == JSONSuccess); TEST(json_object_set_string(obj, "windows path", "C:\\Windows\\Path") == JSONSuccess);
TEST(json_value_equals(val_from_file, val)); TEST(json_value_equals(val_from_file, val));

View File

@ -26,6 +26,7 @@
"digit": "0123456789", "digit": "0123456789",
"0123456789": "digit", "0123456789": "digit",
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?", "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
"nullchar": "abc\u0000def",
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
"true": true, "true": true,
"false": false, "false": false,

View File

@ -3,6 +3,7 @@
"utf string" : "\u006corem\u0020ipsum", "utf string" : "\u006corem\u0020ipsum",
"utf-8 string": "あいうえお", "utf-8 string": "あいうえお",
"surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem", "surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem",
"string with null": "abc\u0000def",
"positive one" : 1, "positive one" : 1,
"negative one" : -1, "negative one" : -1,
"pi" : 3.14, "pi" : 3.14,

View File

@ -9,6 +9,7 @@
"utf string" : "\u006corem\u0020ipsum", // lorem ipsum // "utf string" : "\u006corem\u0020ipsum", // lorem ipsum //
"utf-8 string": "あいうえお", // /* lorem ipsum */ "utf-8 string": "あいうえお", // /* lorem ipsum */
"surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem", "surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem",
"string with null": "abc\u0000def",
"positive one" : 1, "positive one" : 1,
"negative one" : -1, "negative one" : -1,
"pi" : 3.14, "pi" : 3.14,

View File

@ -3,6 +3,7 @@
"utf string": "lorem ipsum", "utf string": "lorem ipsum",
"utf-8 string": "あいうえお", "utf-8 string": "あいうえお",
"surrogate string": "lorem𝄞ipsum𝍧lorem", "surrogate string": "lorem𝄞ipsum𝍧lorem",
"string with null": "abc\u0000def",
"positive one": 1, "positive one": 1,
"negative one": -1, "negative one": -1,
"pi": 3.1400000000000001, "pi": 3.1400000000000001,

View File

@ -11,5 +11,6 @@
"utf string" : "\u006corem\u0020ipsum", "utf string" : "\u006corem\u0020ipsum",
"utf-8 string": "あいうえお", "utf-8 string": "あいうえお",
"surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem", "surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem",
"string with null": "abc\u0000def",
"windows path": "C:\\Windows\\Path" "windows path": "C:\\Windows\\Path"
} }