diff --git a/README.md b/README.md index f074b63..5480b8e 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ For every value type there is a `cJSON_Create...` function that can be used to c All of these will allocate a `cJSON` struct that can later be deleted with `cJSON_Delete`. Note that you have to delete them at some point, otherwise you will get a memory leak. **Important**: If you have added an item to an array or an object already, you **mustn't** delete it with `cJSON_Delete`. Adding it to an array or object transfers its ownership so that when that array or object is deleted, -it gets deleted as well. You also could use `cJSON_SetValuestringToObject` to change a `cJSON_Object`'s `valuestring`, and you needn't to free the previous `valuestring` manually. +it gets deleted as well. You also could use `cJSON_SetValuestring` to change a `cJSON_String`'s `valuestring`, and you needn't to free the previous `valuestring` manually. #### Basic types diff --git a/cJSON.c b/cJSON.c index ff8d2b9..2433de3 100644 --- a/cJSON.c +++ b/cJSON.c @@ -368,23 +368,25 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) return object->valuedouble = number; } -CJSON_PUBLIC(char*) cJSON_SetValuestringToObject(cJSON *object, const char *valuestring) +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) { - size_t length = 0; char *copy = NULL; - /* if object->valuestring is NULL, it should not set valuestring */ - if (object->valuestring == NULL) + /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ + if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) { return NULL; } - length = strlen(valuestring) + sizeof(""); - copy = (char*) cJSON_malloc(length); + if (strlen(valuestring) <= strlen(object->valuestring)) + { + strcpy(object->valuestring, valuestring); + return object->valuestring; + } + copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); if (copy == NULL) { return NULL; } - memcpy(copy, valuestring, length); - if (!(object->type & cJSON_IsReference) && (object->valuestring != NULL)) + if (object->valuestring != NULL) { cJSON_free(object->valuestring); } diff --git a/cJSON.h b/cJSON.h index 1455ece..52ad8b4 100644 --- a/cJSON.h +++ b/cJSON.h @@ -278,8 +278,8 @@ CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * c /* helper for the cJSON_SetNumberValue macro */ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) -/* Only takes effect when type of object is JSON_Object */ -CJSON_PUBLIC(char*) cJSON_SetValuestringToObject(cJSON *object, const char *valuestring); +/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); /* Macro for iterating over an array or object */ #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index ba494f5..2538e8d 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -587,24 +587,34 @@ static void cjson_delete_item_from_array_should_not_broken_list_structure(void) static void cjson_set_valuestring_to_object_should_not_leak_memory(void) { cJSON *root = cJSON_Parse("{}"); - cJSON *item1 = cJSON_CreateString("valuestring could be changed safely"); - cJSON *item2 = cJSON_CreateStringReference("reference item should be freed by yourself"); - const char *newValuestring = "new valuestring which much longer than previous"; - char *returnValue = NULL; + const char *stringvalue = "valuestring could be changed safely"; + const char *reference_valuestring = "reference item should be freed by yourself"; + const char *short_valuestring = "shorter valuestring"; + const char *long_valuestring = "new valuestring which much longer than previous should be changed safely"; + cJSON *item1 = cJSON_CreateString(stringvalue); + cJSON *item2 = cJSON_CreateStringReference(reference_valuestring); + char *ptr1 = NULL; + char *return_value = NULL; cJSON_AddItemToObject(root, "one", item1); cJSON_AddItemToObject(root, "two", item2); - /* we needn't to free the original valuestring manually */ - returnValue = cJSON_SetValuestringToObject(cJSON_GetObjectItem(root, "one"), newValuestring); - TEST_ASSERT_NOT_NULL(returnValue); - TEST_ASSERT_EQUAL_STRING(newValuestring, cJSON_GetObjectItem(root, "one")->valuestring); + ptr1 = item1->valuestring; + return_value = cJSON_SetValuestring(cJSON_GetObjectItem(root, "one"), short_valuestring); + TEST_ASSERT_NOT_NULL(return_value); + TEST_ASSERT_EQUAL_PTR_MESSAGE(ptr1, return_value, "new valuestring shorter than old should not reallocate memory"); + TEST_ASSERT_EQUAL_STRING(short_valuestring, cJSON_GetObjectItem(root, "one")->valuestring); - returnValue = cJSON_SetValuestringToObject(cJSON_GetObjectItem(root, "two"), newValuestring); - TEST_ASSERT_NOT_NULL(returnValue); - TEST_ASSERT_EQUAL_STRING(newValuestring, cJSON_GetObjectItem(root, "two")->valuestring); - /* we must free the memory manually when the item's type is cJSON_IsReference */ - cJSON_free(item2->valuestring); + /* we needn't to free the original valuestring manually */ + ptr1 = item1->valuestring; + return_value = cJSON_SetValuestring(cJSON_GetObjectItem(root, "one"), long_valuestring); + TEST_ASSERT_NOT_NULL(return_value); + TEST_ASSERT_NOT_EQUAL_MESSAGE(ptr1, return_value, "new valuestring longer than old should reallocate memory") + TEST_ASSERT_EQUAL_STRING(long_valuestring, cJSON_GetObjectItem(root, "one")->valuestring); + + return_value = cJSON_SetValuestring(cJSON_GetObjectItem(root, "two"), long_valuestring); + TEST_ASSERT_NULL_MESSAGE(return_value, "valuestring of reference object should not be changed"); + TEST_ASSERT_EQUAL_STRING(reference_valuestring, cJSON_GetObjectItem(root, "two")->valuestring); cJSON_Delete(root); }