diff --git a/cJSON.c b/cJSON.c index d7c72363..fd5ec317 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1906,9 +1906,17 @@ CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) return get_array_item(array, (size_t)index); } +static int cJSON_DuplicateKeyMode = 0; + +CJSON_PUBLIC(void) cJSON_SetDuplicateKeyMode(int mode) +{ + cJSON_DuplicateKeyMode = mode; +} + static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) { cJSON *current_element = NULL; + cJSON *last_match = NULL; if ((object == NULL) || (name == NULL)) { @@ -1916,26 +1924,40 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam } current_element = object->child; - if (case_sensitive) + while (current_element != NULL) { - while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + if (case_sensitive) { - current_element = current_element->next; + if ((current_element->string != NULL) && (strcmp(name, current_element->string) == 0)) + { + if (cJSON_DuplicateKeyMode == 0) + { + return current_element; + } + else + { + last_match = current_element; + } + } } - } - else - { - while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + else { - current_element = current_element->next; + if ((current_element->string != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) == 0)) + { + if (cJSON_DuplicateKeyMode == 0) + { + return current_element; + } + else + { + last_match = current_element; + } + } } + current_element = current_element->next; } - if ((current_element == NULL) || (current_element->string == NULL)) { - return NULL; - } - - return current_element; + return last_match; } CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index a96c2fdc..02d3e8fe 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -782,6 +782,36 @@ static void cjson_set_bool_value_must_not_break_objects(void) cJSON_Delete(sobj); } +static void cjson_duplicate_keys_should_return_last_when_mode_is_set(void) +{ + cJSON *obj; + cJSON *item; + cJSON_SetDuplicateKeyMode(1); + + obj = cJSON_Parse("{\"key\":\"first\",\"key\":\"second\"}"); + TEST_ASSERT_NOT_NULL_MESSAGE(obj, "Failed to parse JSON with duplicate keys."); + + item = cJSON_GetObjectItem(obj, "key"); + TEST_ASSERT_NOT_NULL_MESSAGE(item, "Failed to get object item for duplicate key."); + TEST_ASSERT_EQUAL_STRING_MESSAGE("second", item->valuestring, "Duplicate key mode did not return last item."); + cJSON_Delete(obj); +} + +static void cjson_duplicate_keys_case_insensitive_should_return_last(void) +{ + cJSON *obj; + cJSON *item; + cJSON_SetDuplicateKeyMode(1); + + obj = cJSON_Parse("{\"Key\":\"first\",\"key\":\"second\"}"); + TEST_ASSERT_NOT_NULL_MESSAGE(obj, "Failed to parse JSON with duplicate keys (case insensitive)."); + + item = cJSON_GetObjectItem(obj, "key"); + TEST_ASSERT_NOT_NULL_MESSAGE(item, "Failed to get object item for duplicate key (case insensitive)."); + TEST_ASSERT_EQUAL_STRING_MESSAGE("second", item->valuestring, "Duplicate key mode (case insensitive) did not return last item."); + cJSON_Delete(obj); +} + int CJSON_CDECL main(void) { UNITY_BEGIN(); @@ -815,6 +845,7 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure); RUN_TEST(cjson_set_valuestring_to_object_should_not_leak_memory); RUN_TEST(cjson_set_bool_value_must_not_break_objects); - + RUN_TEST(cjson_duplicate_keys_should_return_last_when_mode_is_set); + RUN_TEST(cjson_duplicate_keys_case_insensitive_should_return_last); return UNITY_END(); }