2

I have a fairly simple struct Message which contains two fields of type Envelope.

struct Envelope
{
    char* Payload; //Byte array of message data
    char* Signature; //Byte array for signature of endorser
};

struct Message
{
    char* configSeq; //Byte array config sequence
    Envelope* configMsg;
    Envelope* normalMsg;
};

Everything boils down to a byte array (represented as char* since C has no byte type)

I just want to use cJSON to read in a JSON file and deserialize it into a Message object. I have read the entire documentation on the cJSON github page but it doesn't say how to do this. Here is an example of what I want to do:

char* message = checkForMessage();
if (message) //If a message exists
{
    //Must parse as JSON
    cJSON* json = cJSON_Parse(message);
    Message* msg = //have json convert to Message type
    checkMessage<<<1, 1>>>(msg, time(0));
}

I've tried using the cJSON functions with object in their name but all those do is modify/return a cJSON*. I need to get it from a cJSON into a different struct.

Thanks for any help.

Caleb Johnson
  • 376
  • 3
  • 21
  • What is `checkMessage<<<1, 1>>>`? That looks more like C++ than C, but there are too many `<` and `>` – Barmar Mar 24 '20 at 00:36
  • That's CUDA, you can ignore that, it's not part of the problem. I could remove it if that would be better – Caleb Johnson Mar 24 '20 at 00:38
  • Use the `valuestring` member of the `cJSON` object to get the string value of the element. – Barmar Mar 24 '20 at 00:42
  • `cJSON_Parse()` takes a standard 0-terminated string as its argument. That makes just memory mapping the file a pain (It really needs a length parameter too; there's an unmerged pull request for it), but you can read the entire file into a char array, make sure it's 0 terminated, and call it with that string. Then populate the struct based on the returned json object. – Shawn Mar 24 '20 at 00:43

1 Answers1

2

Use the valuestring member of the cJSON object to get string values, then just copy them into

cJSON *str;
str = cJSON_GetObjectItemCaseSensitive(json, "configSeq");
msg.configSeq = strdup(str.valuestring);

msg.configMsg = malloc(sizeof(*msg.configMsg));
cJSON *configMsg = cJSON_GetObjectItemCaseSensitive(json, "configMsg");
str = cJSON_GetObjectItemCaseSensitive(configMsg, "Payload");
msg.configMsg->Payload = strdup(str.valuestring);
str = cJSON_GetObjectItemCaseSensitive(configMsg, "Signature");
msg.configMsg->Signature = strdup(str.valuestring);

msg.normalMsg = malloc(sizeof(*msg.normalMsg));
cJSON *normalMsg = cJSON_GetObjectItemCaseSensitive(json, "normalMsg");
str = cJSON_GetObjectItemCaseSensitive(normaMsg, "Payload");
msg.normalMsg->Payload = strdup(str.valuestring);
str = cJSON_GetObjectItemCaseSensitive(normalMsg, "Signature");
msg.normalMsg->Signature = strdup(str.valuestring);

cJSON_Delete(json);

The above code assumes that the message JSON looks something like this:

{
  "configSeq": "String",
  "configMsg": {
    "Payload": "String",
    "Signature": "String"
  },
  "normalMsg": {
    "Payload": "String",
    "Signature": "String"
  }
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • That has a lot of use-after-free issues. – Shawn Mar 24 '20 at 01:02
  • Thank you! I guess I didn't expect you to have to manually do all that, I expected it to be like C# and Python where you can just directly populate an object from a JSON library – Caleb Johnson Mar 24 '20 at 01:03
  • I thought documentation said that the valuestring is not freed when you delete the cJSON object. @Shawn – Barmar Mar 24 '20 at 01:03
  • @ShadowShine57 Unfortunately no, because C doesn't have any introspection features that would allow automating it.[ – Barmar Mar 24 '20 at 01:04
  • That's talking about adding a string to a `cJSON` object with `cJSON_CreateStringReference()` if I'm looking at the same spot in the documentation as you. – Shawn Mar 24 '20 at 01:05
  • OK, I've reordered things and added `strdup()` calls to solve the use-after-free problem. – Barmar Mar 24 '20 at 01:08
  • There's also double-free problems because `cJSON_Delete()` is recursive for objects and arrays - you only need to use it with the initial object returned by `cJSON_Parse()`. – Shawn Mar 24 '20 at 01:08
  • thanks, that simplifies things since I can just delete the top-level object at the end and it will free everything. – Barmar Mar 24 '20 at 01:09