I'm trying to overwrite items within a JSON File with the content of another JSON file while using cJSON. before explaining further these are my 2 JSON documents:
the first one:
{
"Data":
{
"baud" : 9600 ,
"date" : "2022-10-10T13:01",
"dhcp" : false,
"display" : 10,
"ip" : "192.168.1.1"
}
}
the second one:
{
"dhcp": true,
"ip": "192.168.155.155",
"date": "1001-01-01T13:01",
"display": "3",
"baud": "115200"
}
noticeable, that the order of the second one is not matching the nested JSON of the first one.
as defined in RFC 7159 the order of items within a JSON object do not matter and the order of items within a nested JSON do not matter.
So now what I'm trying to do is to replace my items of the first JSON document with the Items of the second one.
I do it like that:
char* overwrite_JSON(char *second_JSON, char *first_JSON, char* buffer)
{
cJSON *json_File_Source = cJSON_Parse(data_file);
cJSON *json_File_Dest = cJSON_Parse(usersettings_content);
cJSON *data_Dest = cJSON_GetObjectItemCaseSensitive(json_File_Dest, "Data");
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "baud", cJSON_GetObjectItem(json_File_Source, "baud"));
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "date", cJSON_GetObjectItem(json_File_Source, "date"));
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "dhcp", cJSON_GetObjectItem(json_File_Source, "dhcp"));
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "display", cJSON_GetObjectItem(json_File_Source, "display"));
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "ip", cJSON_GetObjectItem(json_File_Source, "ip"));
buffer = cJSON_PrintUnformatted(json_File_Dest);
strncat(buffer, "\0", 2);
printf("\n here is my file: %s\n", buffer);
cJSON_Delete(json_File_Dest);
cJSON_Delete(json_File_Source);
return buffer;
After doing that, 2 problems arise, which most likely are bound to each other.
The first arises when printing my JSON: My items "baud", "date" and "dhcp" are getting edited the way they should. just "display" and "ip" are untouched.
{
"Data":
{
"baud" : 115200
"date" : "1001-01-01T13:01",
"dhcp" : true,
"display" : 10,
"ip" : "192.168.1.1"
}
}
the problem is caused by editing an item of an nested JSON with an item of an unnested object, which is not in the same order. When we analyse the following line of code:
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "baud", cJSON_GetObjectItem(json_File_Source, "baud"));
in this line we try to replace the value of the key "baud" within the nested JSON "data" and we want to replace it, by getting the value of the key "baud" of another JSON object. In this case it executes without problem, but in this line it does not:
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "display", cJSON_GetObjectItem(json_File_Source, "display"));
Whereas the order of the nested JSON is respected and the order of the object is not(which as mentioned before, should not be a problem).
Since this problem occured to me a few hours ago, i already know how to fix it, but as far as my understanding goes, this shouldn't cause a problem. I will attach the solution at the end of that question.
The second problem arises when deleting both JSON files:
cJSON_Delete(json_File_Dest);
cJSON_Delete(json_File_Source);
calling the second cJSON_Delete() my program crashes with the following message:
assert failed: tlsf_free heap_tlsf.c:872 (!block_is_free(block) && "block already marked as free")
This lead me to the assumption that by calling:
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "baud", cJSON_GetObjectItem(json_File_Source, "baud"));
both my JSON files weirdly bind to each other, by the rules of my JSON nested JSON. And I would love to understand why it behaves like that. Maybe it's intentional and I'm overlooking something. Either way, I would be happy to find an explanation to this behaviour.
Here's my Solution: By parsing the second JSON before adding it to the first:
//parsing it before binding to edit "display"
cJSON* object = cJSON_GetObjectItem(json_File_Source, "display");
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "baud", cJSON_GetObjectItem(json_File_Source, "baud"));
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "date", cJSON_GetObjectItem(json_File_Source, "date"));
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "dhcp", cJSON_GetObjectItem(json_File_Source, "dhcp"));
//insert the parsed item
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "display", object);
cJSON_ReplaceItemInObjectCaseSensitive(data_Dest, "ip", cJSON_GetObjectItem(json_File_Source, "ip"));
this fixed the problem, still i don't really get why. I somehow explain it to myself like that:
everytime I access an object of the second JSON, every element below it just gets out of scope. This leads to the disappearance of "display" after calling "date" and to the disappearance of "ip" after calling "dhcp"
The second problem is fixed by removing one of both cJSON_Delete(). Doesnt really matter which of both since they somehow are bound together, it removes both.(atleast that's what i assume. It could also lead to a memory leak.)