0

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:

enter image description here

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

Dansen
  • 55
  • 1
  • 8
  • 1
    I don't know cJSON, so this is just a guess. Is it possible that the `cJSON_ReplaceItemInObjectCaseSensitive` calls bind to the string value to the pointer returned by `cJSON_GetObjectItem`, without duplicating it beforehand? This would explain the "free" error. – joH1 Sep 08 '22 at 13:47
  • @joH1 I'm not really sure, since the documentation is pretty minimalistic. I haven't had the time to search for an answer within the .h/.c files of that function. – Dansen Sep 08 '22 at 13:49
  • 1
    I don't see an JSON array in the samples. Arrays should contain `[ ... ]` and multiple instances with similar structure in between. You just have nested structures/objects. – Gerhardh Sep 08 '22 at 15:26
  • Did you notice that the types of your values in the nested object also differ? You have strings in one and numbers in the other example – Gerhardh Sep 08 '22 at 15:59
  • Hello @Gerhardh thanks for pointing out that mistake. I just edited the question. Eventhough the Order should not matter since it is a simple nested JSON, i couldn't edit my file by changing the order of the nested JSON. To be honest this complicates it for me even more. And Yeah i know about the type difference, but since the problem occurs with "ip" which is in both matters a String. I assume this isn't causing the problem. – Dansen Sep 08 '22 at 19:40

0 Answers0