diff --git a/cJSON.c b/cJSON.c index 5b32d01..94f45b2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1930,35 +1930,41 @@ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newit } } -static void ReplaceItemInArray(cJSON *array, size_t which, cJSON *newitem) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) { - cJSON *replaced = get_array_item(array, which); - - if (replaced == NULL) + if ((parent == NULL) || (replacement == NULL)) { - return; + return false; } - newitem->next = replaced->next; - newitem->prev = replaced->prev; - if (newitem->next) + if (replacement == item) { - newitem->next->prev = newitem; - } - if (replaced == array->child) - { - array->child = newitem; - } - else - { - newitem->prev->next = newitem; + return true; } - replaced->next = NULL; - replaced->prev = NULL; + replacement->next = item->next; + replacement->prev = item->prev; - cJSON_Delete(replaced); + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (parent->child == item) + { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; } + CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) { if (which < 0) @@ -1966,29 +1972,12 @@ CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newi return; } - ReplaceItemInArray(array, (size_t)which, newitem); + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); } CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) { - size_t i = 0; - cJSON *c = object->child; - while(c && (case_insensitive_strcmp((unsigned char*)c->string, (const unsigned char*)string) != 0)) - { - i++; - c = c->next; - } - if(c) - { - /* free the old string if not const */ - if (!(newitem->type & cJSON_StringIsConst) && newitem->string) - { - global_hooks.deallocate(newitem->string); - } - - newitem->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - ReplaceItemInArray(object, i, newitem); - } + cJSON_ReplaceItemViaPointer(object, cJSON_GetObjectItem(object, string), newitem); } /* Create basic types: */ diff --git a/cJSON.h b/cJSON.h index 684efea..eec1121 100644 --- a/cJSON.h +++ b/cJSON.h @@ -213,6 +213,7 @@ CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const /* Update array items. */ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 31a115b..24a390d 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -257,6 +257,53 @@ static void cjson_detach_item_via_pointer_should_detach_items(void) TEST_ASSERT_NULL_MESSAGE(parent->child, "Child of the parent wasn't set to NULL."); } +static void cjson_replace_item_via_pointer_should_replace_items(void) +{ + cJSON replacements[3]; + cJSON *beginning = NULL; + cJSON *middle = NULL; + cJSON *end = NULL; + cJSON *array = NULL; + + beginning = cJSON_CreateNull(); + TEST_ASSERT_NOT_NULL(beginning); + middle = cJSON_CreateNull(); + TEST_ASSERT_NOT_NULL(middle); + end = cJSON_CreateNull(); + TEST_ASSERT_NOT_NULL(end); + + array = cJSON_CreateArray(); + TEST_ASSERT_NOT_NULL(array); + + cJSON_AddItemToArray(array, beginning); + cJSON_AddItemToArray(array, middle); + cJSON_AddItemToArray(array, end); + + + memset(replacements, '\0', sizeof(replacements)); + + /* replace beginning */ + TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, beginning, &(replacements[0]))); + TEST_ASSERT_NULL(replacements[0].prev); + TEST_ASSERT_TRUE(replacements[0].next == middle); + TEST_ASSERT_TRUE(middle->prev == &(replacements[0])); + TEST_ASSERT_TRUE(array->child == &(replacements[0])); + + /* replace middle */ + TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, middle, &(replacements[1]))); + TEST_ASSERT_TRUE(replacements[1].prev == &(replacements[0])); + TEST_ASSERT_TRUE(replacements[1].next == end); + TEST_ASSERT_TRUE(end->prev == &(replacements[1])); + + /* replace end */ + TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, end, &(replacements[2]))); + TEST_ASSERT_TRUE(replacements[2].prev == &(replacements[1])); + TEST_ASSERT_NULL(replacements[2].next); + TEST_ASSERT_TRUE(replacements[1].next == &(replacements[2])); + + cJSON_free(array); +} + int main(void) { UNITY_BEGIN(); @@ -269,6 +316,7 @@ int main(void) RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons); RUN_TEST(cjson_set_number_value_should_set_numbers); RUN_TEST(cjson_detach_item_via_pointer_should_detach_items); + RUN_TEST(cjson_replace_item_via_pointer_should_replace_items); return UNITY_END(); }