From 2683589d93d85a1a2559b43c66498edab7ac269d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 21 Mar 2017 21:41:37 +0100 Subject: [PATCH] parser: Construct error pointer from buffer offset --- cJSON.c | 91 +++++++++++++++++++------------------------- tests/parse_array.c | 6 +-- tests/parse_object.c | 6 +-- tests/parse_string.c | 6 +-- tests/parse_value.c | 3 +- tests/print_array.c | 3 +- tests/print_object.c | 3 +- tests/print_value.c | 3 +- 8 files changed, 49 insertions(+), 72 deletions(-) diff --git a/cJSON.c b/cJSON.c index c1a2e24..ada428a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -535,7 +535,7 @@ static unsigned parse_hex4(const unsigned char * const input) /* converts a UTF-16 literal to UTF-8 * A literal can be one or two sequences of the form \uXXXX */ -static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer, const unsigned char **error_pointer) +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) { long unsigned int codepoint = 0; unsigned int first_code = 0; @@ -548,7 +548,6 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi if ((input_end - first_sequence) < 6) { /* input ends unexpectedly */ - *error_pointer = first_sequence; goto fail; } @@ -558,7 +557,6 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi /* check that the code is valid */ if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) { - *error_pointer = first_sequence; goto fail; } @@ -572,14 +570,12 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi if ((input_end - second_sequence) < 6) { /* input ends unexpectedly */ - *error_pointer = first_sequence; goto fail; } if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) { /* missing second half of the surrogate pair */ - *error_pointer = first_sequence; goto fail; } @@ -589,7 +585,6 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi if ((second_code < 0xDC00) || (second_code > 0xDFFF)) { /* invalid second half of the surrogate pair */ - *error_pointer = first_sequence; goto fail; } @@ -632,7 +627,6 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi else { /* invalid unicode codepoint */ - *error_pointer = first_sequence; goto fail; } @@ -662,7 +656,7 @@ fail: } /* Parse the input text into an unescaped cinput, and populate item. */ -static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const error_pointer, const internal_hooks * const hooks) +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks) { const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; @@ -672,7 +666,6 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu /* not a string */ if (buffer_at_offset(input_buffer)[0] != '\"') { - *error_pointer = buffer_at_offset(input_buffer); goto fail; } @@ -751,7 +744,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu /* UTF-16 literal */ case 'u': - sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer, error_pointer); + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); if (sequence_length == 0) { /* failed to convert UTF16-literal to UTF-8 */ @@ -760,7 +753,6 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu break; default: - *error_pointer = input_pointer; goto fail; } input_pointer += sequence_length; @@ -784,6 +776,11 @@ fail: hooks->deallocate(output); } + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + return false; } @@ -916,11 +913,11 @@ static cJSON_bool print_string(const cJSON * const item, printbuffer * const p, } /* Predeclare these prototypes. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const ep, const internal_hooks * const hooks); +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks); static cJSON_bool print_value(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const ep, const internal_hooks * const hooks); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks); static cJSON_bool print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const ep, const internal_hooks * const hooks); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks); static cJSON_bool print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); /* Utility to jump whitespace and cr/lf */ @@ -951,15 +948,8 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return /* use global error pointer if no specific one was given */ const unsigned char **error_pointer = (return_parse_end != NULL) ? (const unsigned char**)return_parse_end : &global_ep; cJSON *item = NULL; - *error_pointer = NULL; - item = cJSON_New_Item(&global_hooks); - if (item == NULL) /* memory fail */ - { - goto fail; - } - if (value == NULL) { goto fail; @@ -969,7 +959,13 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return buffer.length = strlen((const char*)value) + sizeof(""); buffer.offset = 0; - if (!parse_value(item, buffer_skip_whitespace(&buffer), error_pointer, &global_hooks)) + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(&buffer), &global_hooks)) { /* parse failure. ep is set. */ goto fail; @@ -981,7 +977,6 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return buffer_skip_whitespace(&buffer); if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') { - *error_pointer = buffer_at_offset(&buffer); goto fail; } } @@ -998,6 +993,18 @@ fail: cJSON_Delete(item); } + if (value != NULL) + { + if (buffer.offset < buffer.length) + { + *error_pointer = buffer_at_offset(&buffer); + } + else if (buffer.length > 0) + { + *error_pointer = buffer.content + buffer.length - 1; + } + } + return NULL; } @@ -1113,7 +1120,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const i } /* Parser core - when encountering text, process appropriately. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const error_pointer, const internal_hooks * const hooks) +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks) { if ((input_buffer == NULL) || (input_buffer->content == NULL)) { @@ -1146,7 +1153,7 @@ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buf /* string */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { - return parse_string(item, input_buffer, error_pointer, hooks); + return parse_string(item, input_buffer, hooks); } /* number */ if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) @@ -1156,27 +1163,14 @@ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buf /* array */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) { - return parse_array(item, input_buffer, error_pointer, hooks); + return parse_array(item, input_buffer, hooks); } /* object */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) { - return parse_object(item, input_buffer, error_pointer, hooks); + return parse_object(item, input_buffer, hooks); } - /* failure. */ - if (can_access_at_index(input_buffer, 0)) - { - *error_pointer = buffer_at_offset(input_buffer); - } - else if (input_buffer->length > 0) - { - *error_pointer = input_buffer->content + input_buffer->length - 1; - } - else - { - *error_pointer = input_buffer->content; - } return false; } @@ -1260,7 +1254,7 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons } /* Build an array from input text. */ -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const error_pointer, const internal_hooks * const hooks) +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks) { cJSON *head = NULL; /* head of the linked list */ cJSON *current_item = NULL; @@ -1268,7 +1262,6 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf if (buffer_at_offset(input_buffer)[0] != '[') { /* not an array */ - *error_pointer = buffer_at_offset(input_buffer); goto fail; } @@ -1284,7 +1277,6 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf if (cannot_access_at_index(input_buffer, 0)) { input_buffer->offset--; - *error_pointer = buffer_at_offset(input_buffer); goto fail; } @@ -1317,7 +1309,7 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf /* parse next value */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer, error_pointer, hooks)) + if (!parse_value(current_item, input_buffer, hooks)) { goto fail; /* failed to parse value */ } @@ -1327,7 +1319,6 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { - *error_pointer = buffer_at_offset(input_buffer); goto fail; /* expected end of array */ } @@ -1409,14 +1400,13 @@ static cJSON_bool print_array(const cJSON * const item, const size_t depth, cons } /* Build an object from the text. */ -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const error_pointer, const internal_hooks * const hooks) +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks) { cJSON *head = NULL; /* linked list head */ cJSON *current_item = NULL; if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) { - *error_pointer = buffer_at_offset(input_buffer); goto fail; /* not an object */ } @@ -1431,7 +1421,6 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu if (cannot_access_at_index(input_buffer, 0)) { input_buffer->offset--; - *error_pointer = buffer_at_offset(input_buffer); goto fail; } @@ -1464,7 +1453,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu /* parse the name of the child */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (!parse_string(current_item, input_buffer, error_pointer, hooks)) + if (!parse_string(current_item, input_buffer, hooks)) { goto fail; /* faile to parse name */ } @@ -1476,14 +1465,13 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) { - *error_pointer = buffer_at_offset(input_buffer); goto fail; /* invalid object */ } /* parse the value */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer, error_pointer, hooks)) + if (!parse_value(current_item, input_buffer, hooks)) { goto fail; /* failed to parse value */ } @@ -1493,7 +1481,6 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) { - *error_pointer = buffer_at_offset(input_buffer); goto fail; /* expected end of object */ } diff --git a/tests/parse_array.c b/tests/parse_array.c index a328af4..a089db5 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -30,8 +30,6 @@ static cJSON item[1]; -static const unsigned char *error_pointer = NULL; - static void assert_is_array(cJSON *array_item) { TEST_ASSERT_NOT_NULL_MESSAGE(array_item, "Item is NULL."); @@ -51,7 +49,7 @@ static void assert_not_array(const char *json) buffer.length = strlen(json) + sizeof(""); buffer.offset = 0; - TEST_ASSERT_FALSE(parse_array(item, &buffer, &error_pointer, &global_hooks)); + TEST_ASSERT_FALSE(parse_array(item, &buffer, &global_hooks)); assert_is_invalid(item); } @@ -62,7 +60,7 @@ static void assert_parse_array(const char *json) buffer.length = strlen(json) + sizeof(""); buffer.offset = 0; - TEST_ASSERT_TRUE(parse_array(item, &buffer, &error_pointer, &global_hooks)); + TEST_ASSERT_TRUE(parse_array(item, &buffer, &global_hooks)); assert_is_array(item); } diff --git a/tests/parse_object.c b/tests/parse_object.c index ad6fd83..4973b93 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -30,8 +30,6 @@ static cJSON item[1]; -static const unsigned char *error_pointer = NULL; - static void assert_is_object(cJSON *object_item) { TEST_ASSERT_NOT_NULL_MESSAGE(object_item, "Item is NULL."); @@ -59,7 +57,7 @@ static void assert_not_object(const char *json) parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.offset = 0; - TEST_ASSERT_FALSE(parse_object(item, &parsebuffer, &error_pointer, &global_hooks)); + TEST_ASSERT_FALSE(parse_object(item, &parsebuffer, &global_hooks)); assert_is_invalid(item); reset(item); } @@ -71,7 +69,7 @@ static void assert_parse_object(const char *json) parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.offset = 0; - TEST_ASSERT_TRUE(parse_object(item, &parsebuffer, &error_pointer, &global_hooks)); + TEST_ASSERT_TRUE(parse_object(item, &parsebuffer, &global_hooks)); assert_is_object(item); } diff --git a/tests/parse_string.c b/tests/parse_string.c index 54b3adf..a95e078 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -30,8 +30,6 @@ static cJSON item[1]; -static const unsigned char *error_pointer = NULL; - static void assert_is_string(cJSON *string_item) { TEST_ASSERT_NOT_NULL_MESSAGE(string_item, "Item is NULL."); @@ -52,7 +50,7 @@ static void assert_parse_string(const char *string, const char *expected) buffer.length = strlen(string) + sizeof(""); buffer.offset = 0; - TEST_ASSERT_TRUE_MESSAGE(parse_string(item, &buffer, &error_pointer, &global_hooks), "Couldn't parse string."); + TEST_ASSERT_TRUE_MESSAGE(parse_string(item, &buffer, &global_hooks), "Couldn't parse string."); assert_is_string(item); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected."); global_hooks.deallocate(item->valuestring); @@ -66,7 +64,7 @@ static void assert_not_parse_string(const char * const string) buffer.length = strlen(string) + sizeof(""); buffer.offset = 0; - TEST_ASSERT_FALSE_MESSAGE(parse_string(item, &buffer, &error_pointer, &global_hooks), "Malformed string should not be accepted."); + TEST_ASSERT_FALSE_MESSAGE(parse_string(item, &buffer, &global_hooks), "Malformed string should not be accepted."); assert_is_invalid(item); } diff --git a/tests/parse_value.c b/tests/parse_value.c index 3766f97..7a10dbf 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -29,7 +29,6 @@ #include "common.h" static cJSON item[1]; -const unsigned char *error_pointer = NULL; static void assert_is_value(cJSON *value_item, int type) { @@ -48,7 +47,7 @@ static void assert_parse_value(const char *string, int type) buffer.content = (const unsigned char*) string; buffer.length = strlen(string) + sizeof(""); buffer.offset = 0; - TEST_ASSERT_TRUE(parse_value(item, &buffer, &error_pointer, &global_hooks)); + TEST_ASSERT_TRUE(parse_value(item, &buffer, &global_hooks)); assert_is_value(item, type); } diff --git a/tests/print_array.c b/tests/print_array.c index e326dc6..c0b4e05 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -29,7 +29,6 @@ static void assert_print_array(const char * const expected, const char * const i unsigned char printed_unformatted[1024]; unsigned char printed_formatted[1024]; - const unsigned char *error_pointer; cJSON item[1]; printbuffer formatted_buffer; @@ -53,7 +52,7 @@ static void assert_print_array(const char * const expected, const char * const i unformatted_buffer.noalloc = true; memset(item, 0, sizeof(item)); - TEST_ASSERT_TRUE_MESSAGE(parse_array(item, &parsebuffer, &error_pointer, &global_hooks), "Failed to parse array."); + TEST_ASSERT_TRUE_MESSAGE(parse_array(item, &parsebuffer, &global_hooks), "Failed to parse array."); TEST_ASSERT_TRUE_MESSAGE(print_array(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct."); diff --git a/tests/print_object.c b/tests/print_object.c index dbde069..5b4e34b 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -29,7 +29,6 @@ static void assert_print_object(const char * const expected, const char * const unsigned char printed_unformatted[1024]; unsigned char printed_formatted[1024]; - const unsigned char *error_pointer; cJSON item[1]; printbuffer formatted_buffer; @@ -54,7 +53,7 @@ static void assert_print_object(const char * const expected, const char * const unformatted_buffer.noalloc = true; memset(item, 0, sizeof(item)); - TEST_ASSERT_TRUE_MESSAGE(parse_object(item, &parsebuffer, &error_pointer, &global_hooks), "Failed to parse object."); + TEST_ASSERT_TRUE_MESSAGE(parse_object(item, &parsebuffer, &global_hooks), "Failed to parse object."); TEST_ASSERT_TRUE_MESSAGE(print_object(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct."); diff --git a/tests/print_value.c b/tests/print_value.c index bb892b2..56614d0 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -31,7 +31,6 @@ static void assert_print_value(const char *input) { unsigned char printed[1024]; - const unsigned char *error_pointer = NULL; cJSON item[1]; printbuffer buffer; parse_buffer parsebuffer; @@ -46,7 +45,7 @@ static void assert_print_value(const char *input) memset(item, 0, sizeof(item)); - TEST_ASSERT_TRUE_MESSAGE(parse_value(item, &parsebuffer, &error_pointer, &global_hooks), "Failed to parse value."); + TEST_ASSERT_TRUE_MESSAGE(parse_value(item, &parsebuffer, &global_hooks), "Failed to parse value."); TEST_ASSERT_TRUE_MESSAGE(print_value(item, 0, false, &buffer, &global_hooks), "Failed to print value."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, buffer.buffer, "Printed value is not as expected."); -- GitLab