From 102a4467e10c77ffcfde1d233798780acd719cc5 Mon Sep 17 00:00:00 2001 From: reuben olinsky Date: Thu, 16 Apr 2020 12:55:56 -0700 Subject: [PATCH] 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 --- .gitignore | 3 + CMakeLists.txt | 2 +- LICENSE | 2 +- package.json | 2 +- parson.c | 171 +++++++++++++++++++++++++++++--------- parson.h | 14 +++- tests.c | 8 +- tests/test_1_1.txt | 1 + tests/test_2.txt | 1 + tests/test_2_comments.txt | 1 + tests/test_2_pretty.txt | 1 + tests/test_5.txt | 1 + 12 files changed, 162 insertions(+), 45 deletions(-) diff --git a/.gitignore b/.gitignore index 8743bfc..0732721 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ .DS_Store test *.o +testcpp +tests/test_2_serialized.txt +tests/test_2_serialized_pretty.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index f369d16..69dbe2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(parson C) include (GNUInstallDirs) -set(PARSON_VERSION 1.0.2) +set(PARSON_VERSION 1.1.0) add_library(parson parson.c) target_include_directories(parson PUBLIC $) diff --git a/LICENSE b/LICENSE index 12cbc1b..c5ee57d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ 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 of this software and associated documentation files (the "Software"), to deal diff --git a/package.json b/package.json index b6953f1..570f063 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parson", - "version": "1.0.2", + "version": "1.1.0", "repo": "kgabis/parson", "description": "Small json parser and reader", "keywords": [ "json", "parser" ], diff --git a/parson.c b/parson.c index a8f1f61..20cb43f 100644 --- a/parson.c +++ b/parson.c @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: MIT - Parson 1.0.2 ( http://kgabis.github.com/parson/ ) - Copyright (c) 2012 - 2019 Krzysztof Gabis + Parson 1.1.0 ( http://kgabis.github.com/parson/ ) + Copyright (c) 2012 - 2020 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 @@ -68,9 +68,14 @@ static int parson_escape_slashes = 1; #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 */ typedef union json_value_value { - char *string; + JSON_String string; double number; JSON_Object *object; 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); /* 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 */ 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 len); -static char * get_quoted_string(const char **string); +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); @@ -145,12 +151,13 @@ 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, 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_string(char *buf, const char *string); /* Various */ 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); if (!output_string) { return NULL; @@ -536,14 +543,15 @@ static void json_array_free(JSON_Array *array) { } /* 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)); if (!new_value) { return NULL; } new_value->parent = NULL; new_value->type = JSONString; - new_value->value.string = string; + new_value->value.string.chars = string; + new_value->value.string.length = length; 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. 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; - size_t initial_size = (len + 1) * sizeof(char); + size_t initial_size = (input_len + 1) * sizeof(char); size_t final_size = 0; char *output = NULL, *output_ptr = NULL, *resized_output = NULL; output = (char*)parson_malloc(initial_size); @@ -627,7 +635,7 @@ static char* process_string(const char *input, size_t len) { goto error; } 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 == '\\') { input_ptr++; switch (*input_ptr) { @@ -664,6 +672,7 @@ static char* process_string(const char *input, size_t len) { goto error; } memcpy(resized_output, output, final_size); + *output_len = final_size - 1; parson_free(output); return resized_output; error: @@ -673,15 +682,15 @@ error: /* Return processed contents of a string between quotes and 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; - size_t string_len = 0; + size_t input_string_len = 0; JSON_Status status = skip_quotes(string); if (status != JSONSuccess) { return NULL; } - string_len = *string - string_start - 2; /* length without quotes */ - return process_string(string_start + 1, string_len); + input_string_len = *string - string_start - 2; /* length without quotes */ + return process_string(string_start + 1, input_string_len, output_string_len); } 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; } while (**string != '\0') { - new_key = get_quoted_string(string); - if (new_key == NULL) { + 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)) { json_value_free(output_value); 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) { 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) { 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) { parson_free(new_string); 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; double num = 0.0; int written = -1, written_total = 0; + size_t len = 0; switch (json_value_get_type(value)) { case JSONArray: @@ -934,7 +947,8 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le if (is_pretty) { 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) { return -1; } @@ -972,7 +986,8 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le if (string == NULL) { 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) { 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) { - size_t i = 0, len = strlen(string); +static int json_serialize_string(const char *string, size_t len, char *buf) { + size_t i = 0; char c = '\0'; int written = -1, written_total = 0; 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)); } +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) { 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)); } +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) { 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)); } +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) { 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; } +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) { - 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) { @@ -1315,7 +1352,7 @@ void json_value_free(JSON_Value *value) { json_object_free(value->value.object); break; case JSONString: - parson_free(value->value.string); + parson_free(value->value.string.chars); break; case JSONArray: 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) { + if (string == NULL) { + return NULL; + } + return json_value_init_string_with_len(string, strlen(string)); +} + +JSON_Value * json_value_init_string_with_len(const char *string, size_t length) { char *copy = NULL; JSON_Value *value; - size_t string_len = 0; if (string == NULL) { return NULL; } - string_len = strlen(string); - if (!is_valid_utf8(string, string_len)) { + if (!is_valid_utf8(string, length)) { return NULL; } - copy = parson_strndup(string, string_len); + copy = parson_strndup(string, length); if (copy == NULL) { return NULL; } - value = json_value_init_string_no_copy(copy); + value = json_value_init_string_no_copy(copy, length); if (value == NULL) { parson_free(copy); } @@ -1417,7 +1459,8 @@ JSON_Value * json_value_init_null(void) { JSON_Value * json_value_deep_copy(const JSON_Value *value) { size_t i = 0; 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; JSON_Array *temp_array = NULL, *temp_array_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: return json_value_init_number(json_value_get_number(value)); case JSONString: - temp_string = json_value_get_string(value); + temp_string = json_value_get_string_desc(value); if (temp_string == 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) { 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) { 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; } +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_Value *value = json_value_init_number(number); if (value == NULL) { @@ -1718,6 +1773,18 @@ JSON_Status json_array_append_string(JSON_Array *array, const char *string) { 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_Value *value = json_value_init_number(number); if (value == NULL) { @@ -1784,6 +1851,15 @@ JSON_Status json_object_set_string(JSON_Object *object, const char *name, const 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_Value *value = json_value_init_number(number); 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; } +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_Value *value = json_value_init_number(number); 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) { JSON_Object *a_object = NULL, *b_object = 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; size_t a_count = 0, b_count = 0, i = 0; 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; case JSONString: - a_string = json_value_get_string(a); - b_string = json_value_get_string(b); + 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 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: return json_value_get_boolean(a) == json_value_get_boolean(b); case JSONNumber: @@ -2062,6 +2151,10 @@ const char * json_string (const JSON_Value *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) { return json_value_get_number(value); } diff --git a/parson.h b/parson.h index c508dab..310c3a7 100644 --- a/parson.h +++ b/parson.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: MIT - Parson 1.0.2 ( http://kgabis.github.com/parson/ ) - Copyright (c) 2012 - 2019 Krzysztof Gabis + Parson 1.1.0 ( http://kgabis.github.com/parson/ ) + Copyright (c) 2012 - 2020 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 @@ -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); 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_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 */ @@ -125,6 +126,7 @@ int json_object_get_boolean(const JSON_Object *object, const char *nam this way. */ 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); +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_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 */ @@ -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_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_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_boolean(JSON_Object *object, const char *name, int boolean); 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_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_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_boolean(JSON_Object *object, const char *name, int boolean); 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); 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_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 */ @@ -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_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_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_boolean(JSON_Array *array, size_t i, int boolean); 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_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_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_boolean(JSON_Array *array, int boolean); 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_array (void); 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_boolean(int boolean); 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_Array * json_value_get_array (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); int json_value_get_boolean(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_Array * json_array (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); int json_boolean(const JSON_Value *value); diff --git a/tests.c b/tests.c index be4d829..72de9ae 100644 --- a/tests.c +++ b/tests.c @@ -2,7 +2,7 @@ SPDX-License-Identifier: MIT 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 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_Array *array; JSON_Value *array_value; + size_t len; size_t i; TEST(root_value); 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, "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, "negative one") == -1.0); 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-8 string", "あいうえお") == 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_value_equals(val_from_file, val)); diff --git a/tests/test_1_1.txt b/tests/test_1_1.txt index da78ef4..7b96c5b 100644 --- a/tests/test_1_1.txt +++ b/tests/test_1_1.txt @@ -26,6 +26,7 @@ "digit": "0123456789", "0123456789": "digit", "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "nullchar": "abc\u0000def", "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", "true": true, "false": false, diff --git a/tests/test_2.txt b/tests/test_2.txt index f473599..1abd463 100644 --- a/tests/test_2.txt +++ b/tests/test_2.txt @@ -3,6 +3,7 @@ "utf string" : "\u006corem\u0020ipsum", "utf-8 string": "あいうえお", "surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem", + "string with null": "abc\u0000def", "positive one" : 1, "negative one" : -1, "pi" : 3.14, diff --git a/tests/test_2_comments.txt b/tests/test_2_comments.txt index 504be86..ed8c2c6 100644 --- a/tests/test_2_comments.txt +++ b/tests/test_2_comments.txt @@ -9,6 +9,7 @@ "utf string" : "\u006corem\u0020ipsum", // lorem ipsum // "utf-8 string": "あいうえお", // /* lorem ipsum */ "surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem", + "string with null": "abc\u0000def", "positive one" : 1, "negative one" : -1, "pi" : 3.14, diff --git a/tests/test_2_pretty.txt b/tests/test_2_pretty.txt index 96aaaef..93fd2cb 100644 --- a/tests/test_2_pretty.txt +++ b/tests/test_2_pretty.txt @@ -3,6 +3,7 @@ "utf string": "lorem ipsum", "utf-8 string": "あいうえお", "surrogate string": "lorem𝄞ipsum𝍧lorem", + "string with null": "abc\u0000def", "positive one": 1, "negative one": -1, "pi": 3.1400000000000001, diff --git a/tests/test_5.txt b/tests/test_5.txt index fc71450..c87f0de 100644 --- a/tests/test_5.txt +++ b/tests/test_5.txt @@ -11,5 +11,6 @@ "utf string" : "\u006corem\u0020ipsum", "utf-8 string": "あいうえお", "surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem", + "string with null": "abc\u0000def", "windows path": "C:\\Windows\\Path" } \ No newline at end of file