diff --git a/cJSON.c b/cJSON.c index 400821a..a839c42 100644 --- a/cJSON.c +++ b/cJSON.c @@ -898,7 +898,7 @@ static cJSON_bool print_string(const cJSON * const item, printbuffer * const p, /* Predeclare these prototypes. */ static const unsigned char *parse_value(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const ep, 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 const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); +static const unsigned char *parse_array(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const ep, 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 const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, 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); @@ -916,15 +916,20 @@ static const unsigned char *skip_whitespace(const unsigned char *in) static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) { - const unsigned char *skipped_pointer = NULL; - if ((buffer == NULL) || (buffer->content == NULL)) { return NULL; } - skipped_pointer = skip_whitespace(buffer_at_offset(buffer)); - buffer->offset = (size_t)(skipped_pointer - buffer->content); + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } return buffer; } @@ -1102,6 +1107,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const i /* Parser core - when encountering text, process appropriately. */ static const unsigned char *parse_value(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const error_pointer, const internal_hooks * const hooks) { + const unsigned char *content_pointer = NULL; if ((input_buffer == NULL) || (input_buffer->content == NULL)) { return NULL; /* no input */ @@ -1133,22 +1139,43 @@ static const unsigned char *parse_value(cJSON * const item, parse_buffer * cons /* string */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { - return parse_string(item, buffer_at_offset(input_buffer), error_pointer, hooks); + content_pointer = parse_string(item, buffer_at_offset(input_buffer), error_pointer, hooks); + if (content_pointer == NULL) + { + return NULL; + } + + input_buffer->offset = (size_t)(content_pointer - input_buffer->content); + return buffer_at_offset(input_buffer); } /* 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')))) { - return parse_number(item, buffer_at_offset(input_buffer)); + content_pointer = parse_number(item, buffer_at_offset(input_buffer)); + if (content_pointer == NULL) + { + return NULL; + } + + input_buffer->offset = (size_t)(content_pointer - input_buffer->content); + return buffer_at_offset(input_buffer); } /* array */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) { - return parse_array(item, buffer_at_offset(input_buffer), error_pointer, hooks); + return parse_array(item, input_buffer, error_pointer, hooks); } /* object */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) { - return parse_object(item, buffer_at_offset(input_buffer), error_pointer, hooks); + content_pointer = parse_object(item, buffer_at_offset(input_buffer), error_pointer, hooks); + if (content_pointer == NULL) + { + return NULL; + } + + input_buffer->offset = (size_t)(content_pointer - input_buffer->content); + return buffer_at_offset(input_buffer); } /* failure. */ @@ -1247,28 +1274,36 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons } /* Build an array from input text. */ -static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) +static const unsigned char *parse_array(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const error_pointer, const internal_hooks * const hooks) { cJSON *head = NULL; /* head of the linked list */ cJSON *current_item = NULL; - parse_buffer input_buffer; - if (*input != '[') + if (buffer_at_offset(input_buffer)[0] != '[') { /* not an array */ - *error_pointer = input; + *error_pointer = buffer_at_offset(input_buffer); goto fail; } - input = skip_whitespace(input + 1); - if (*input == ']') + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) { /* empty array */ goto success; } + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + *error_pointer = buffer_at_offset(input_buffer); + goto fail; + } + /* step back to character in front of the first element */ - input--; + input_buffer->offset--; /* loop through the comma separated array elements */ do { @@ -1294,22 +1329,19 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char } /* parse next value */ - input = skip_whitespace(input + 1); - input_buffer.content = (const unsigned char*)input; - input_buffer.offset = 0; - input_buffer.length = strlen((const char*)input) + sizeof(""); - input = parse_value(current_item, &input_buffer, error_pointer, hooks); - input = skip_whitespace(input); - if (input == NULL) + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (parse_value(current_item, input_buffer, error_pointer, hooks) == NULL) { goto fail; /* failed to parse value */ } + buffer_skip_whitespace(input_buffer); } - while (*input == ','); + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - if (*input != ']') + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { - *error_pointer = input; + *error_pointer = buffer_at_offset(input_buffer); goto fail; /* expected end of array */ } @@ -1317,7 +1349,9 @@ success: item->type = cJSON_Array; item->child = head; - return input + 1; + input_buffer->offset++; + + return buffer_at_offset(input_buffer); fail: if (head != NULL) diff --git a/tests/parse_array.c b/tests/parse_array.c index 47dd44f..c35f5ff 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -46,13 +46,23 @@ static void assert_is_array(cJSON *array_item) static void assert_not_array(const char *json) { - TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks)); + parse_buffer buffer; + buffer.content = (const unsigned char*)json; + buffer.length = strlen(json) + sizeof(""); + buffer.offset = 0; + + TEST_ASSERT_NULL(parse_array(item, &buffer, &error_pointer, &global_hooks)); assert_is_invalid(item); } static void assert_parse_array(const char *json) { - TEST_ASSERT_NOT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks)); + parse_buffer buffer; + buffer.content = (const unsigned char*)json; + buffer.length = strlen(json) + sizeof(""); + buffer.offset = 0; + + TEST_ASSERT_NOT_NULL(parse_array(item, &buffer, &error_pointer, &global_hooks)); assert_is_array(item); } diff --git a/tests/print_array.c b/tests/print_array.c index df32be6..128a106 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -35,6 +35,11 @@ static void assert_print_array(const char * const expected, const char * const i printbuffer formatted_buffer; printbuffer unformatted_buffer; + parse_buffer parsebuffer; + parsebuffer.content = (const unsigned char*)input; + parsebuffer.length = strlen(input) + sizeof(""); + parsebuffer.offset = 0; + /* buffer for formatted printing */ formatted_buffer.buffer = printed_formatted; formatted_buffer.length = sizeof(printed_formatted); @@ -48,7 +53,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_NOT_NULL_MESSAGE(parse_array(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse array."); + TEST_ASSERT_NOT_NULL_MESSAGE(parse_array(item, &parsebuffer, &error_pointer, &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.");