1. An overview of the
CJSON source code is very simple, even the latest version of cJSON, its Cjson. c file is only more than 750 lines of code, cjson. h file 200 lines of code. The.h and.c files have no more than 1,000 lines of code, so they’re very concise and easy to read. This paper focuses on the analysis of its design framework and principle. For details on its use, see the JSON website.
Since RFC 7159 was updated, the root of a valid JSON file can be any type of JSON value. In RFC 4627, the root value can only be Object or Array. This is of particular concern, because I’ve run into colleagues who tend to think of JSON as just “object {}” or “array []”, which is not the case. Values in JSON can be objects, arrays, strings, and numeric values (true, False, or NULL), as shown below:
▲ List of all value types supported by JSON
The cjson. h header also defines the macro as follows:
False #define cJSON_True 1 // Boolean true #define cJSON_NULL 2 //NULL #define cJSON_Number 3 #define cJSON_String 4 // string #define cJSON_Array 5 // array #define cJSON_Object 6 // objectCopy the code
2. CJSON framework analysis
At the heart of cJOSN’s design is the use of bidirectional linked lists. CJSON items are continuously linked in the cJSON handle when the JSON handle is an object or array. Its data structure is defined as follows:
typedef struct cJSON { struct cJSON *next,*prev; // Next /prev allows you to iterate through groups/chains of objects. Or, use the use GetArraySize GetArrayItem/GetObjectItem struct cJSON * child; // The array or object item will have a child pointer to the necklace in the array/object int type; //cJSON item type, char * valueString as shown above; /* The item's string, if type==cJSON_String */ int valueint; /* The item's number, if type==cJSON_Number */ double valuedouble; /* The item's number, if type==cJSON_Number */ char *string; // The name of the item string (if the item is a child of the object or in the list of child items of the object)} cJSON;Copy the code
The use of cJSON is always inseparable from two topics: (1) assembling JSON packets, sending them over the network, and communicating with different processes
▲ Format the JSON as string text
(2) Parse the JSON packet to obtain the received data
▲ Parsing formatted JSON packets
Therefore, the code in all cjson. h files is divided into two main categories to begin with: JSON assembly-related and JSON parse-related. The first is a series of apis related to organizing JSON.
/ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / 1. Create a basic type of JSON / / / / / / / / / / / / / / / / / / / / / / / / / / cJSON * cJSON_CreateNull (void); cJSON *cJSON_CreateTrue(void); cJSON *cJSON_CreateFalse(void); cJSON *cJSON_CreateBool(int b); cJSON *cJSON_CreateNumber(double num); cJSON *cJSON_CreateString(const char *string); cJSON *cJSON_CreateArray(void); cJSON *cJSON_CreateObject(void); / / / / / / / / / / / / / / / / / / / / / / 2. When is a JSON Object/Array type and nested JSON item / / / / / / / / / / / / / / / / / / / / / / / / / / void cJSON_AddItemToArray (cJSON *array, cJSON *item); Void cJSON_AddItemToObject(cJSON *object,const char) void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / 3. Used to quickly create content of macro / / / / / / / / / / / / / / / / / / / / / / / / / / # define cJSON_AddNullToObject (object, name) cJSON_AddItemToObject (object, the name, cJSON_CreateNull()) #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) ///////////////////////////////////////// 4. The JSON formatted as text string / / / / / / / / / / / / / / / / / / / / / / / / / / char * cJSON_Print (cJSON * item). // Render cJSON entities as text for transfer/storage without any formatting required. Char * char* cJSON_PrintUnformatted(cJSON *item);Copy the code
2.1 Create a JSON for the basic data types (array, null, Boolean, string, empty array, and empty object)
(1) Create null JSON
Apply for an empty cJSON data structure memory space and set its member type to cJSON_NULL.
cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item(); if(item)item->type=cJSON_NULL; return item;Copy the code
▲ Create basic type (null) JSON
The cJSON data node text is formatted as follows. For example, if the JSON text to be formatted is of a null value type, apply for 5 bytes of space, copy the null string, and format it into the final text.
Char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0); } static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) { char *out=0; if (! item) return 0; If (p) {//cJSON_PrintBuffered function uses if branch} else {switch ((item->type)&255) {// Null JSON logic branch (to keep layout as simple as possible) Case cJSON_NULL: out=cJSON_strdup("null"); break; } } return out; }Copy the code
The cJSON_strdup function is a standard strdup() function. It is reimplemented to improve code portability because some platforms do not have strdup. For example, the ARM C compiler does not have strdup. Its internal implementation is as follows:
static char* cJSON_strdup(const char* str) { size_t len; char* copy; len = strlen(str) + 1; if (! (copy = (char*)cJSON_malloc(len))) return 0; memcpy(copy,str,len); return copy; }Copy the code
The other internal implementations are based on the same principle and will not be described here.
2.2 Creating a JSON Object
This example is simpler because the JSON object does not continue to nest items such as arrays/objects, and only inserts three key-value pairs into the JSON object. The keys are age, name, and address. The code is as follows:
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "cJSON.h"
int main()
{
cJSON *p = cJSON_CreateObject();
assert(p);
cJSON_AddNumberToObject(p, "age", 26);
cJSON_AddStringToObject(p, "name", "lixiaogang5");
cJSON_AddStringToObject(p, "address", "guizhousheng");
char *pBuf = cJSON_Print(p);
printf("\n%s\n", pBuf);
cJSON_Delete(p);
free(pBuf);
return 0;
}
Copy the code
The print results are shown in Figure 4
▲ Print the JSON object value formatted as a text string
When three simple types of key-value pairs are embedded into the JSON object, the schematic diagram is shown below.
▲ Print the JSON object value formatted as a text string
Note: ValueString in the lower left part of the preceding figure: GZ. Change the value to GuizHousheng. Also, the member value is 0 where it is not obvious in the image, because each simple JSON primitive type (true, false, NULL, Number, String, Object, and array) is created with a JOSN data structure memory space and then a memset of 0. As shown below:
▲ cJSON_New_Item Apply for memory space and memset
2.3 Creating a JSON of the Array type
cJSON *pRootArr = cJSON_CreateArray();
assert(pRootArr);
cJSON_AddItemToArray(pRootArr, cJSON_CreateString("Sunday"));
cJSON_AddItemToArray(pRootArr, cJSON_CreateString("Monday"));
cJSON_AddItemToArray(pRootArr, cJSON_CreateString("Tuesday"));
cJSON_AddItemToArray(pRootArr, cJSON_CreateString("Wednesday"));
cJSON_AddItemToArray(pRootArr, cJSON_CreateString("Thursday"));
cJSON_AddItemToArray(pRootArr, cJSON_CreateString("Friday"));
cJSON_AddItemToArray(pRootArr, cJSON_CreateString("Saturday"));
char *serialPcBuf = cJSON_Print(pRootArr);
printf("\n%s\n", serialPcBuf);
cJSON_Delete(pRootArr);
free(serialPcBuf);
Copy the code
Print the JSON serialized as a text string as shown in the figure below. The internal principle is the same as shown in Figure 5, so it will not be described here. Please refer to Figure 5 for details.
▲ JSON packets of array type
2.4 Create a JSON object with nested arrays
cJSON *pRoot = cJSON_CreateObject(); //pRoot -1 assert(pRoot); cJSON_AddItemToObject(pRoot, "name", cJSON_CreateString("lixiaogang5")); cJSON_AddItemToObject(pRoot, "sex", cJSON_CreateNumber(0)); //0- male 1-female cJSON *pSubObj = cJSON_CreateObject(); //pSubObj - 2 assert(pSubObj); cJSON_AddItemToObject(pSubObj, "ReadingBook", cJSON_CreateString("C++")); cJSON *pSubArr = cJSON_CreateArray(); //pSubArr - 3 assert(pSubArr); cJSON *pDataObj = cJSON_CreateObject(); //pDataObj - 4 cJSON_AddItemToObject(pDataObj, "B1", cJSON_CreateString("C++ Primer")); CJSON_AddItemToObject (pDataObj, "B2", cJSON_CreateString("C++ musings ")); CJSON_AddItemToObject (pDataObj, "B3", cJSON_CreateString(" understand C++11")); cJSON_AddItemToArray(pSubArr, pDataObj); cJSON_AddItemToObject(pSubObj, "info", pSubArr); cJSON_AddItemToObject(pRoot, "hobby", pSubObj); char *serialBuf = NULL; //serialBuf = cJSON_Print(pRoot); serialBuf = cJSON_PrintUnformatted(pRoot); printf("\n%s\n", serialBuf); cJSON_Delete(pRootArr); // Free cJSON (serialPcBuf);Copy the code
The print result is as follows:
The data parsed by the JSON online tool is:
{ "name": "lixiaogang5", "sex": 0, "hobby": { "ReadingBook": "C++", "info": [ { "B1": "C++ Primer", "B2": "C++ reflections ", "B3": "deep understanding of C++11"}]}Copy the code
The schematic diagram of the internal data structure of the JSON message is shown in Figure 8. The same principle applies even if several levels of arrays or objects are nested within JSON. As can be seen from the schematic diagram, when the cJSON packet is large, that is, when the n-layer array is nested internally, and then the array is nested under the array, the memory space is occupied and consumed quite large. For example, the cJSON website has the following description:
▲ Object type JSON embedded objects and arrays schematic
Deep nesting of arrays and objects: cJSON does not support nesting arrays and objects too deeply, as this can cause stack overflows. To prevent this CJSON_NESTING_LIMIT situation, cJSON limits the depth to 1000 by default, but this can be changed at compile time.
CJSON data structure: Prev, next, and Child What’s the use of having three Pointers? When to use Child, and when to use prev and next?
▲ cJSON data structure type declaration
Conclusion: These three Pointers are not used when creating simple data types such as false, true, NULL, and number, but only when creating object/array types with other primitive/complex types nested within them that satisfy JSON criteria. First, when a JSON object is nested, the first JSON data must be the child pointer to use. The first child of the head node. Second, subsequent JSON data items use the next and prev Pointers. Next and Prev Pointers are designed for easy traversal. Starting at a node, they can be traversed forward or backward, which is an advantage of bidirectional lists. It compensates for the disadvantage that one-way lists can only be accessed/traversed one way. As the name implies, the child pointer is a pointer to a child node after the header of a JSON object or array. Refer to Figure 8. Second, APIcJSON_GetArraySize, cJSON_GetArrayItem, and cJSON_GetObjectItem can also be seen in JSON packet parsing, as shown in Figure 11.
▲ cJSON packet parsing API
2.5 Create an Object type with nested arrays, which in turn contain JSON for each Object
The final JSON formatted message is:
/ / / / / / / / / / / / / / / / / / / 2.5 sample code / / / / / / / / / / / / / unsigned I = 0; char buf[10] = {0}; cJSON *pRoot = cJSON_CreateObject(); assert(pRoot); cJSON *prootArr = cJSON_CreateArray(); assert(prootArr); for(i = 0; i < 3; ++i) { cJSON *pDataObj = cJSON_CreateObject(); memset(buf, 0x00, sizeof(buf)); snprintf(buf, sizeof(buf), "Key_%d", i); cJSON_AddNumberToObject(pDataObj, buf, i); cJSON_AddItemToArray(prootArr, pDataObj); } cJSON_AddItemToObject(pRoot, "jsonData", prootArr); char *serialBuf = NULL; serialBuf = cJSON_Print(pRoot); //serialBuf = cJSON_PrintUnformatted(pRoot); printf("\n%s\n", serialBuf); cJSON_Delete(pRoot); free(serialBuf);Copy the code
The relationship between the internal cJSON data structure nodes is shown in Figure 12. Each parent node (root node) is associated with the first directly related child node through the child pointer, as concluded in Section 2.4.
▲ Internal correlation between cJSON data structure nodes
The detailed process of using cJSON_Print text to format the JSON message is as follows:
▲ Format the INTERNAL JSON logic
In general, it can be divided into two steps/processes. First, initialize the array part, and second, initialize the outermost object part + assemble the internal JSON array part. Finally, the text string from the first part and the text string from the second part are appending and assembled appropriately according to the FMT option, resulting in the final JSON-formatted text string. Each of the above two steps is described in more detail below.
The two processes described above correspond to parts of the two red dotted boxes in the figure below.
▲ There are two main processes for formatting JSON
The first step is to initialize the last layer of JSON (the root node pRoot). Note: This is only taken from the core of the printF_Object API. To illustrate the JSON text formatting string procedure.
(1) child=item->child = prootArr child=item->child; depth++; if (fmt) len+=depth; Name [I]= STR =print_string_ptr(child->string,0); /*print_vlaue (); /*print_vlaue (); /*print_vlaue (); /*print_vlaue () Internally, the function evaluates the current JSON * data node type to call the appropriate/corresponding function for initialization. */ entries[i++]=ret=print_value(child,depth,fmt,0); If (STR &&ret) len+=strlen(ret)+strlen(STR)+2+(FMT? 2+depth:0); else fail=1; // Iterate condition (4) continuously moves the pointer to point to the next node data, and determines whether the current node is the last node according to whether it is NULL. child=child->next; }Copy the code
child=item->child; The child pointer points to the pRootArr data node. Child =child->next; , child is NULL, so this loop will only go through once when pRoot is formatted here. The result is shown below.
Second, initialize the JSON array part (prootArr),
Child =item->child; while (child && ! fail) { ret=print_value(child,depth+1,fmt,0); entries[i++]=ret; if (ret) len+=strlen(ret)+2+(fmt? 1-0); else fail=1; child=child->next; }Copy the code
After the above two ends, the result is shown below.
2.6 cJSON_Print, cJSON_PrintUnformatted, and cJSON_PrintBuffered Formats organized JSON packets as text strings
Once the JSON message is organized, you can choose one of the apis above to format it as a text string for communication between network transport interactions. The differences between the three apis are as follows: cJSON_Print indents formatted JSON packets, such as newline and TAB, for easy reading. CJSON_PrintUnformatted without indentation or line feed, the entire TEXT string of the JSON packet is compressed into a string. It is difficult to read. You need to use some online tools to format the text. CJSON_PrintBuffered uses a caching strategy to render its JSON in text format, with or without indentation depending on the user’s choice. The complete interface declaration is as follows:
//item - organized JSON prebuffer- User preallocated space size FMT - Formatted or not: 1- Format char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int FMT); This article focuses on the cJSON_Print function interface. By analogy, the other two interfaces are the same as those called by cJSON_Print. Char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0); } /**@fn print_value * @brief Formats its key and value based on the JSON type (type) * @param[in] item JSON object to be formatted * @param[in] depth Depth of the JSON array * @param[in] FMT whether to format indent 0- No newline 1- Newline, space * @param[out] NONE * RETURN Formatted text string */ static char *print_value(cJSON) *item,int depth,int fmt,printbuffer *p) { char *out=0; if (! item) return 0; If (p) {/ / / / / / / / / / / / / / / / / / / / / cJSON_PrintBuffered function API walk the branch / / / / / / / / / / / / / / / / / / / / the switch ((item - > type) & 255) {case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break; } case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break; } case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break; } case cJSON_Number: out=print_number(item,p); break; case cJSON_String: out=print_string(item,p); break; case cJSON_Array: out=print_array(item,depth,fmt,p); break; case cJSON_Object: out=print_object(item,depth,fmt,p); break; }} else {/ / / / / / / / / / / / / / / / / / / / / / / cJSON_Print and cJSON_PrintUnformatted walk this branch / / / / / / / / / the switch ((item - > type) & 255) {case cJSON_NULL: out=cJSON_strdup("null"); break; case cJSON_False: out=cJSON_strdup("false"); break; case cJSON_True: out=cJSON_strdup("true"); break; case cJSON_Number: out=print_number(item,0); break; case cJSON_String: out=print_string(item,0); break; case cJSON_Array: out=print_array(item,depth,fmt,0); break; case cJSON_Object: out=print_object(item,depth,fmt,0); break; } } return out; }Copy the code
Print_value is the core API, especially when nested within a JSON object. This function is called until the last cJSON data structure object node is iterated over. The basic JSON types (arrays, booleans, controls, empty objects, and empty arrays, etc.) have been explained previously, but complex types nested within objects/arrays are described below. Again, I use the JSON message in Section 2.4 as an example to illustrate the complete process of formatting a cJSON message into a printable text string. Each key and value in THE JSON file is dynamically allocated memory space by using second-level Pointers, as shown in the following figure.
▲ Apply for memory space based on the key size and copy the key to the destination ADDRESS
▲ Apply for memory space based on the value size and copy the value to the destination address
No matter how many levels of JSON objects or arrays are nested inside the JSON, the key is always a string, while the value can be any data that meets the JSON criteria, but after internal subdivision, it is still the basic type in JSON, such as a value, a Boolean, or a string. Therefore, the core idea in cJSON is to use secondary Pointers to dynamically allocate memory space for keys and values, and to copy the response value to the destination address for text formatting. The resulting fully formatted JSON text is due to the Type member in the cJSON data structure design (each cJSON data structure initializes its corresponding Type member when creating), as shown in the figure below. (print_value)
▲ When creating a JSON basic type, initialize its corresponding type member
Therefore, the first step in formatting is to determine the cJSON data type. If the cJSON data type is normal, the corresponding key-value pair can be formatted using the methods shown in figure 12 and 13. Print_array and print_object are the two most important function apis.
▲ Iterate over and format data in Object/Array
- Print_object API internal implementation
// Render the object as text (item: Static char *print_object(cJSON *item,int depth,int FMT /*1- format 0- Unformatted */,printbuffer *p) {char **entries=0,**names=0; char *out=0,*ptr,*ret,*str; int len=7,i=0,j; cJSON *child=item->child; int numentries=0,fail=0; size_t tmplen=0; While (child) numentries++,child=child->next; // Display the empty object case if (! Numentries) {/ / if the JSON object is empty, it is built directly "| |} {| \ n | | 0" to return. The last byte stores the string terminator '\0'. // If formatting is chosen. The result: | | | | 0 attach - > only need 3 bytes. If (p) out=ensure(p, FMT? depth+4:3); else out=(char*)cJSON_malloc(fmt? depth+4:3); // If formatted, request 4 bytes of memory space; If (! out) return 0; ptr=out; *ptr++='{'; if (fmt) {*ptr++='\n'; for (i=0; i<depth-1; i++) *ptr++='\t'; } *ptr++='}'; *ptr++=0; return out; } if (p) {// merge the output. If the memory cache policy is used, go to this branch. len=fmt? 2-1. ptr=ensure(p,len+1); if (! ptr) return 0; *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; child=item->child; depth++; while (child) { if (fmt) { ptr=ensure(p,depth); if (! ptr) return 0; for (j=0; j<depth; j++) *ptr++='\t'; p->offset+=depth; } print_string_ptr(child->string,p); p->offset=update(p); len=fmt? 2-1. ptr=ensure(p,len); if (! ptr) return 0; *ptr++=':'; if (fmt) *ptr++='\t'; p->offset+=len; print_value(child,depth,fmt,p); p->offset=update(p); len=(fmt? 1:0)+(child->next? 1-0); ptr=ensure(p,len+1); if (! ptr) return 0; if (child->next) *ptr++=','; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; child=child->next; } ptr=ensure(p,fmt? (depth+1):2); if (! ptr) return 0; if (fmt) for (i=0; i<depth-1; i++) *ptr++='\t'; *ptr++='}'; *ptr=0; out=(p->buffer)+i; } else {/ / / / / / / / / / / / / / / / / / / / / / / / / / / / / and object allocate space for the name / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (! entries) return 0; names=(char**)cJSON_malloc(numentries*sizeof(char*)); if (! names) {cJSON_free(entries); return 0; } // It is recommended to use realloc or calloc for CJSON_malloc internal builds so that memset(entries,0,sizeof(char*)*numentries) is omitted; memset(names,0,sizeof(char*)*numentries); Child =item->child; depth++; if (fmt) len+=depth; Names [I]= STR =print_string_ptr(child->string,0); Print_vlaue very core API entries[i++]=ret=print_value(child,depth, FMT,0); If (STR &&ret) len+=strlen(ret)+strlen(STR)+2+(FMT? 2+depth:0); else fail=1; Child =child->next; } // Try to assign the output string if (! fail) out=(char*)cJSON_malloc(len); if (! out) fail=1; If (fail) {for (I =0; i<numentries; i++) {if (names[i]) cJSON_free(names[i]); if (entries[i]) cJSON_free(entries[i]); } cJSON_free(names); cJSON_free(entries); return 0; } // form and print *out='{'; ptr=out+1; if (fmt)*ptr++='\n'; *ptr=0; for (i=0; i<numentries; i++) { if (fmt) for (j=0; j<depth; j++) *ptr++='\t'; tmplen=strlen(names[i]); memcpy(ptr,names[i],tmplen); ptr+=tmplen; *ptr++=':'; if (fmt) *ptr++='\t'; strcpy(ptr,entries[i]); ptr+=strlen(entries[i]); if (i! =numentries-1) *ptr++=','; if (fmt) *ptr++='\n'; *ptr=0; cJSON_free(names[i]); cJSON_free(entries[i]); } cJSON_free(names); cJSON_free(entries); if (fmt) for (i=0; i<depth-1; i++) *ptr++='\t'; *ptr++='}'; *ptr++=0; //printf("out:\n%s\n", ptr); } return out; }Copy the code
The while part of the function iterates through each byte point under the object (via a successor pointer) until the Child pointer is null in Child = child->next, and combines all the already stringed data into a complete object.
- Print_array API internal implementation
Static char *print_array(cJSON *item,int depth,int FMT,printbuffer *p) {char **entries; char *out=0,*ptr,*ret; int len=5; cJSON *child=item->child; int numentries=0,i=0,fail=0; size_t tmplen=0; // How many items are in the array? while (child) numentries++,child=child->next; // Handle when the array is empty. Directly formatted as: out = | / | | | 0 if (! numentries) { if (p) out=ensure(p,3); else out=(char*)cJSON_malloc(3); if (out) strcpy(out,"[]"); return out; } if (p) { /* Compose the output array. */ i=p->offset; ptr=ensure(p,1); if (! ptr) return 0; *ptr='['; p->offset++; child=item->child; while (child && !fail) { print_value(child,depth+1,fmt,p); p->offset=update(p); if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} child=child->next; } ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']'; *ptr=0; out=(p->buffer)+i; } else { printf("entries[%d]\n", numentries); // Apply for/allocate an array to hold each value entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (! entries) return 0; memset(entries,0,numentries*sizeof(char*)); Child =item->child; while (child && ! fail) { ret=print_value(child,depth+1,fmt,0); entries[i++]=ret; if (ret) len+=strlen(ret)+2+(fmt? 1-0); else fail=1; child=child->next; } // If nothing fails, try malloc to print the string if (! fail) out=(char*)cJSON_malloc(len); // If malloc fails, it fails and ends if (! out) fail=1; If (fail) {for (I =0; i<numentries; i++) if (entries[i]) cJSON_free(entries[i]); cJSON_free(entries); return 0; } / / * out = '[' combination and output array; the PTR = out + 1 * PTR = 0; the for (I = 0; I < numentries; i++) { tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen; if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;} cJSON_free(entries[i]); } cJSON_free(entries); *ptr++=']'; *ptr++=0; } printf("out:\n%s\n", out); return out; }Copy the code
For this function interface, the most important inner core is the contents of the following while loop. JSON arrays can be nested with any number of data types that conform to JSON rules (including: Array, Boolean, null, string, object, etc.), the print_value function is called each time the loop is iterated, and the function internally evaluates the type of each cJSON data object, iterating recursively until the last child of the array is reached.
The detailed formatting process is shown in the following figure. Again, the Key in JSON format is always a string, and the Value can be a task primitive/complex nested type that satisfies JSON rules.
▲ Object/Array Internal nested object/array formatting process
3. Parse the formatted JSON text into a cJSON data structure
The main cJSON_Parse function. Its statement is as follows:
/ / / / / / / / / / / / / / / / / / / / / / cJSON. H file defines the extern cJSON * cJSON_Parse (const char * value); / / / / / / / / / / / / / / / / / / / / / / cJSON c function functions cJSON * cJSON_Parse (const char * value) {return cJSON_ParseWithOpts (value, 0, 0). } ///////////////////// cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) { const char *end=0; cJSON *c=cJSON_New_Item(); ep=0; if (! c) return 0; / / the memory failure end = parse_value (c, skip (value)); // If (! end) {cJSON_Delete(c); return 0; } // If null_terminated JSON is needed without garbage attached, skip and then check for empty terminators if (require_NULl_terminated) {end=skip(end); if (*end) {cJSON_Delete(c); ep=end; return 0; }} if (return_parse_end) *return_parse_end=end; return c; }Copy the code
The other three related functions are cJSON_GetArraySize, cJSON_GetArrayItem, and cJSON_GetObjectItem. Converting formatted JSON to a cJSON data structure is the reverse of formatting cJSON text. The interfaces and implementations are relatively simple, so they are not described here.
Extern int cJSON_GetArraySize(cJSON *array); extern int cJSON_GetArraySize(cJSON *array); // Retrieve the item number "item" from the array" array", if not, NULL extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); // Get "string" from the object. Extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);Copy the code