Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add new function of cJSON_SetValuestring #451

Merged
merged 4 commits into from
Apr 2, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,21 +197,22 @@ The type can be one of the following:
* `cJSON_NULL` (check with `cJSON_IsNull`): Represents a `null` value.
* `cJSON_Number` (check with `cJSON_IsNumber`): Represents a number value. The value is stored as a double in `valuedouble` and also in `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint`.
* `cJSON_String` (check with `cJSON_IsString`): Represents a string value. It is stored in the form of a zero terminated string in `valuestring`.
* `cJSON_Array` (check with `cJSON_IsArray`): Represent an array value. This is implemented by pointing `child` to a linked list of `cJSON` items that represent the values in the array. The elements are linked together using `next` and `prev`, where the first element has `prev == NULL` and the last element `next == NULL`.
* `cJSON_Array` (check with `cJSON_IsArray`): Represent an array value. This is implemented by pointing `child` to a linked list of `cJSON` items that represent the values in the array. The elements are linked together using `next` and `prev`, where the first element has `prev.next == NULL` and the last element `next == NULL`.
* `cJSON_Object` (check with `cJSON_IsObject`): Represents an object value. Objects are stored same way as an array, the only difference is that the items in the object store their keys in `string`.
* `cJSON_Raw` (check with `cJSON_IsRaw`): Represents any kind of JSON that is stored as a zero terminated array of characters in `valuestring`. This can be used, for example, to avoid printing the same static JSON over and over again to save performance. cJSON will never create this type when parsing. Also note that cJSON doesn't check if it is valid JSON.

Additionally there are the following two flags:

* `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not its children/valuestring.
* `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not its `child`/`valuestring`.
* `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`.

### Working with the data structure

For every value type there is a `cJSON_Create...` function that can be used to create an item of that type.
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.
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.

#### Basic types

Expand Down
25 changes: 25 additions & 0 deletions cJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,31 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
return object->valuedouble = number;
}

CJSON_PUBLIC(char*) cJSON_SetValuestringToObject(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)
{
return NULL;
}
length = strlen(valuestring) + sizeof("");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the new str length does not exceed the current value, whether to re-allocate memory

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a good suggestion, In this case, we don't need to allocate memory, just re-assign the valuestring

copy = (char*) cJSON_malloc(length);
if (copy == NULL)
{
return NULL;
}
memcpy(copy, valuestring, length);
if (!(object->type & cJSON_IsReference) && (object->valuestring != NULL))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repeated check in a single thread

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks your reminder!

{
cJSON_free(object->valuestring);
}
object->valuestring = copy;

return copy;
}

typedef struct
{
unsigned char *buffer;
Expand Down
2 changes: 2 additions & 0 deletions cJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +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);

/* 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)
Expand Down
43 changes: 35 additions & 8 deletions tests/misc_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,19 +550,20 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al
cJSON_Delete(object);
}

static void cjson_delete_item_from_array_should_not_broken_list_structure(void) {
static void cjson_delete_item_from_array_should_not_broken_list_structure(void)
{
const char expected_json1[] = "{\"rd\":[{\"a\":\"123\"}]}";
const char expected_json2[] = "{\"rd\":[{\"a\":\"123\"},{\"b\":\"456\"}]}";
const char expected_json3[] = "{\"rd\":[{\"b\":\"456\"}]}";
char* str1 = NULL;
char* str2 = NULL;
char* str3 = NULL;
char *str1 = NULL;
char *str2 = NULL;
char *str3 = NULL;

cJSON* root = cJSON_Parse("{}");
cJSON *root = cJSON_Parse("{}");

cJSON* array = cJSON_AddArrayToObject(root, "rd");
cJSON* item1 = cJSON_Parse("{\"a\":\"123\"}");
cJSON* item2 = cJSON_Parse("{\"b\":\"456\"}");
cJSON *array = cJSON_AddArrayToObject(root, "rd");
cJSON *item1 = cJSON_Parse("{\"a\":\"123\"}");
cJSON *item2 = cJSON_Parse("{\"b\":\"456\"}");

cJSON_AddItemToArray(array, item1);
str1 = cJSON_PrintUnformatted(root);
Expand All @@ -583,6 +584,31 @@ static void cjson_delete_item_from_array_should_not_broken_list_structure(void)
cJSON_Delete(root);
}

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;

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);

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);

cJSON_Delete(root);
}

int CJSON_CDECL main(void)
{
UNITY_BEGIN();
Expand All @@ -609,6 +635,7 @@ int CJSON_CDECL main(void)
RUN_TEST(cjson_create_array_reference_should_create_an_array_reference);
RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased);
RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure);
RUN_TEST(cjson_set_valuestring_to_object_should_not_leak_memory);

return UNITY_END();
}