From 5baa77f86cb9dffe20b5f9ab85e00baa8fe70a0b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 3 Jul 2017 21:43:14 +0200 Subject: [PATCH] cJSON_Parse{,WithOpts}: Skip UTF-8 (Byte Order Marks) --- cJSON.c | 19 +++++++++++++++++-- tests/misc_tests.c | 26 ++++++++++++++++++++++++++ tests/parse_with_opts.c | 17 +++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index b689361..9c567ff 100644 --- a/cJSON.c +++ b/cJSON.c @@ -958,6 +958,22 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) return buffer; } +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + /* Parse an object - create a new root, and populate. */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) { @@ -984,7 +1000,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return goto fail; } - if (!parse_value(item, buffer_skip_whitespace(&buffer))) + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) { /* parse failure. ep is set. */ goto fail; @@ -1222,7 +1238,6 @@ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buf return parse_object(item, input_buffer); } - return false; } diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 7d51179..2f1efe4 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -410,6 +410,30 @@ static void cjson_functions_shouldnt_crash_with_null_pointers(void) cJSON_Delete(item); } +static void skip_utf8_bom_should_skip_bom(void) +{ + const unsigned char string[] = "\xEF\xBB\xBF{}"; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + buffer.content = string; + buffer.length = sizeof(string); + buffer.hooks = global_hooks; + + TEST_ASSERT_TRUE(skip_utf8_bom(&buffer) == &buffer); + TEST_ASSERT_EQUAL_UINT(3U, (unsigned int)buffer.offset); +} + +static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) +{ + const unsigned char string[] = " \xEF\xBB\xBF{}"; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + buffer.content = string; + buffer.length = sizeof(string); + buffer.hooks = global_hooks; + buffer.offset = 1; + + TEST_ASSERT_NULL(skip_utf8_bom(&buffer)); +} + int main(void) { UNITY_BEGIN(); @@ -425,6 +449,8 @@ int main(void) RUN_TEST(cjson_replace_item_via_pointer_should_replace_items); RUN_TEST(cjson_replace_item_in_object_should_preserve_name); RUN_TEST(cjson_functions_shouldnt_crash_with_null_pointers); + RUN_TEST(skip_utf8_bom_should_skip_bom); + RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); return UNITY_END(); } diff --git a/tests/parse_with_opts.c b/tests/parse_with_opts.c index 0557467..066d2cd 100644 --- a/tests/parse_with_opts.c +++ b/tests/parse_with_opts.c @@ -69,6 +69,22 @@ static void parse_with_opts_should_return_parse_end(void) cJSON_Delete(item); } +static void parse_with_opts_should_parse_utf8_bom(void) +{ + cJSON *with_bom = NULL; + cJSON *without_bom = NULL; + + with_bom = cJSON_ParseWithOpts("\xEF\xBB\xBF{}", NULL, true); + TEST_ASSERT_NOT_NULL(with_bom); + without_bom = cJSON_ParseWithOpts("{}", NULL, true); + TEST_ASSERT_NOT_NULL(with_bom); + + TEST_ASSERT_TRUE(cJSON_Compare(with_bom, without_bom, true)); + + cJSON_Delete(with_bom); + cJSON_Delete(without_bom); +} + int main(void) { UNITY_BEGIN(); @@ -77,6 +93,7 @@ int main(void) RUN_TEST(parse_with_opts_should_handle_empty_strings); RUN_TEST(parse_with_opts_should_require_null_if_requested); RUN_TEST(parse_with_opts_should_return_parse_end); + RUN_TEST(parse_with_opts_should_parse_utf8_bom); return UNITY_END(); }