Linux C编程之二十 xml-json
一、XML
1. minixml官网地址
http://www.msweet.org/projects.php/Mini-XML
其他解析xml开源库:tinyxml pugixml
1)包含头文件: mxml.h
2)编译的时候需要添加动态库: libmxml.so
- -lmxml
- /usr/local/lib
2. minixml安装:
- ./configure --enable-threads=no && make
- sudo make install
3. 新目录需要一个文件头 - 标准
<?xml version="1.0" encoding="utf-8"?>
- version不可以省略
- encoding可以省略
4. 使用注意事项
- 必须有一个根元素(节点) -- (只有一个)
- xml标签对大小写敏感
- 标签大多成对使用, 有开始, 有结束
<date></date> <time></time>
5. 标签中可以添加属性
<node date="17/11/2017"> 属性值必须加引号
6. 标签注释
<!-- 这是注释 -->
7. 开源库minixml的使用
(1)跟标签的对应的节点,父亲节点是:文件头节点
(2)生成xml文件
1)创建一个新的xml文件
mxml_node_t *mxmlNewXML(const char *version);
- 返回新创建的xml文件节点.
- 默认的文件的编码为utf8
2)删除节点的内存
void mxmlDelete(mxml_node_t *node);
3)添加一个新的节点
mxml_node_t *mxmlNewElement( mxml_node_t *parent, // 父节点 const char *name // 新节点标签名 );
4)设置节点的属性名和属性值
void mxmlElementSetAttr( mxml_node_t *node, // 被设置属性的节点 const char *name, // 节点的属性名 const char *value // 属性值 );
5)创建节点的文本内容
mxml_node_t *mxmlNewText ( mxml_node_t *parent, // 节点地址 int whitespace, // 是否有空白 0 const char *string // 文本内容 );
6)保存节点到xml文件
int mxmlSaveFile( mxml_node_t *node, // 根节点 FILE *fp, // 文件指针 mxml_save_cb_t cb // 默认MXML_NO_CALLBACK );
(3)解析xml文件
1)从文件加载xml到内存
mxml_node_t *mxmlLoadFile( mxml_node_t *top, // 一般为NULL FILE *fp, // 文件指针 mxml_type_t (*cb)(mxml_node_t *) // 默认 MXML_NO_CALLBACK );
2)获取节点的属性
const char *mxmlElementGetAttr( mxml_node_t *node, // 带属性的节点的地址 const char *name // 属性名 );
3)获取指定节点的文本内容
const char *mxmlGetText( mxml_node_t *node, // 节点的地址 int *whitespace // 是否有空格 );
4)跳转到下一个节点
mxml_node_t *mxmlWalkNext( mxml_node_t *node, // 当前节点 mxml_node_t *top, // 根节点 int descend ); descend:搜索的规则 MXML_NO_DESCEND:查看同层级 MXML_DESCEND_FIRST:查看下一层级的第一个 MXML_DESCEND:一直向下搜索
5)查找节点
mxml_node_t *mxmlFindElement( mxml_node_t *node, // 当前节点 mxml_node_t *top, // 根节点 const char *name, // 查找的标签名 const char *attr, // 查找的标签的属性,没有属性传NULL const char *value, // 查找的标签的属性值,没有属性传NULL int descend // 同上 );
8. 示例
(1)生成下面的xml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?xml version="1.0" encoding="utf-8"?> 2 <bookstore> 3 <book category="儿童"> 4 <title>哈利波特</title> 5 <autoro>JK.Rowling</autoro> 6 <year>2005</year> 7 <price>29.99</price> 8 </book> 9 </bookstore>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include "mxml.h" 3 4 int main(int argc, const char* argv[]) 5 { 6 // 添加文件头 7 mxml_node_t* rootNode = mxmlNewXML("1.0"); 8 9 // 添加一个新节点 10 mxml_node_t *bookStore = mxmlNewElement(rootNode, "bookstore"); 11 // 添加子节点 - book 12 mxml_node_t* book = mxmlNewElement(bookStore, "book"); 13 // 添加book 的属性 14 mxmlElementSetAttr(book, "category", "儿童"); 15 // 添加标题 16 mxml_node_t* title = mxmlNewElement(book, "title"); 17 mxmlNewText(title, 0, "哈利波特"); 18 // 添加作者 19 mxml_node_t* author = mxmlNewElement(book, "autoro"); 20 mxmlNewText(author, 0, "JK.Rowling"); 21 // 添加时间 22 mxml_node_t* year = mxmlNewElement(book, "year"); 23 mxmlNewText(year, 0, "2005"); 24 // 添加价格 25 mxml_node_t* price = mxmlNewElement(book, "price"); 26 mxmlNewText(price, 0, "29.99"); 27 28 // 保存数据到文件 29 FILE* fp = fopen("book.xml", "w"); 30 mxmlSaveFile(rootNode, fp, MXML_NO_CALLBACK); 31 fclose(fp); 32 33 return 0; 34 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include "mxml.h" 3 4 int main(int argc, const char* argv[]) 5 { 6 // 加载xml文件 7 FILE* fp = fopen("book.xml", "r"); 8 mxml_node_t* root = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK); 9 10 // 查找book节点 11 mxml_node_t* book = mxmlFindElement(root, root, "book", "category", NULL, MXML_DESCEND); 12 printf("book attr: %s\n", mxmlElementGetAttr(book, "category")); 13 14 mxml_node_t* node = mxmlWalkNext(book, root, MXML_DESCEND_FIRST); 15 printf(" title: %s\n", mxmlGetText(node, 0)); 16 17 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 18 printf(" author: %s\n", mxmlGetText(node, 0)); 19 20 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 21 printf(" year: %s\n", mxmlGetText(node, 0)); 22 23 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 24 printf(" price: %s\n", mxmlGetText(node, 0)); 25 26 fclose(fp); 27 28 mxmlDelete(root); 29 30 return 0; 31 }
(2)生成下面的xml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?xml version="1.0" encoding="utf-8"?> 2 <China> 3 <City> 4 <Name isbig="true">北京</Name> 5 <Area>1.641万平方千米</Area> 6 <Population>2200万</Population> 7 </City> 8 <City> 9 <Name isbig="false">石家庄</Name> 10 <Area>15848平方千米</Area> 11 <Population>107万</Population> 12 </City> 13 </China>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <mxml.h> 3 4 int main(int argc, const char* argv[]) 5 { 6 // 创建xml文件头节点 7 mxml_node_t *xml = mxmlNewXML("1.0"); 8 9 // 创建xml根节点 - china 10 mxml_node_t* china = mxmlNewElement(xml, "China"); 11 12 13 // 创建城市节点 14 mxml_node_t* city = mxmlNewElement(china, "City"); 15 // 添加子节点 16 // name 17 mxml_node_t* name = mxmlNewElement(city, "Name"); 18 // 设置标签值 19 mxmlNewText(name, 0, "北京"); 20 mxmlElementSetAttr(name, "isbig", "true"); 21 // 面积 22 mxml_node_t* area = mxmlNewElement(city, "Area"); 23 mxmlNewText(area, 0, "1.641万平方千米"); 24 // 人口 25 mxml_node_t* popu = mxmlNewElement(city, "Population"); 26 mxmlNewText(popu, 0, "2200万"); 27 28 // 第二个城市节点 29 city = mxmlNewElement(china, "City"); 30 // name 31 name = mxmlNewElement(city, "Name"); 32 mxmlNewText(name, 0, "石家庄"); 33 mxmlElementSetAttr(name, "isbig", "false"); 34 area = mxmlNewElement(city, "Area"); 35 mxmlNewText(area, 0, "15848平方千米"); 36 popu = mxmlNewElement(city, "Population"); 37 mxmlNewText(popu, 0, "107万"); 38 39 // 将xml内容保存到磁盘 40 FILE* fp = fopen("china.xml", "w"); 41 mxmlSaveFile(xml, fp, MXML_NO_CALLBACK); 42 fclose(fp); 43 mxmlDelete(xml); 44 45 return 0; 46 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <mxml.h> 3 4 int main(int argc, const char* argv[]) 5 { 6 // 从磁盘加载xml文件 7 FILE* fp = fopen("china.xml", "r"); 8 if(fp == NULL) 9 { 10 printf("fopen error\n"); 11 return 0; 12 } 13 // root 节点指向xml文件头 14 mxml_node_t* root = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK); 15 16 // 遍历 - 取出各个节点的值 17 // 找到第一个城市节点 18 mxml_node_t* city = mxmlFindElement(root, root, "City", NULL, NULL, MXML_DESCEND); 19 if(city == NULL) 20 { 21 printf("xml node not found\n"); 22 return 0; 23 } 24 while( city ) 25 { 26 printf("==================\n"); 27 // 向下走一个节点 28 mxml_node_t* node = mxmlWalkNext(city, root, MXML_DESCEND_FIRST); 29 printf("city: \n"); 30 printf(" name = %s\n", mxmlGetText(node, NULL)); 31 // 32 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 33 printf(" area = %s\n", mxmlGetText(node, NULL)); 34 // 35 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 36 printf(" population = %s\n", mxmlGetText(node, NULL)); 37 // 搜索下一个城市节点 38 city = mxmlFindElement(city, root, "City", NULL, NULL, MXML_DESCEND); 39 } 40 41 fclose(fp); 42 mxmlDelete(root); 43 44 return 0; 45 }
(3)xml 解析注意问题
注意:使用 minixml 开源库生成的 xml 会在一行,如果手动将调整 xml,则解析会有问题。下面的示例相同的xml,只是将在一行的xml进行调整,注意运行查看解析结果。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?xml version="1.0" encoding="utf-8"?> 2 <car> 3 <factory> 4 <name>一汽大众</name> 5 <brand> 6 <name>高尔夫</name> 7 <color>红色</color> 8 <price>15万</price> 9 </brand> 10 <brand> 11 <name>速腾</name> 12 <color>银白</color> 13 <price>18万</price> 14 </brand> 15 <brand> 16 <name>迈腾</name> 17 <color>黑灰</color> 18 <price>28万</price> 19 </brand> 20 </factory> 21 <factory> 22 <brand> 23 <name>帕萨特</name> 24 <color>黑色</color> 25 <price>25万</price> 26 </brand> 27 <brand> 28 <name>POLO</name> 29 <color>灰色</color> 30 <price>8万</price> 31 </brand> 32 </factory> 33 </car>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?xml version="1.0" encoding="utf-8"?><car><factory name="一汽大众"><brand><name>高尔夫</name><color>红色</color><price>15万</price></brand><brand><name>速腾</name><color>银白</color><price>18万</price></brand><brand><name>迈腾</name><color>黑灰</color><price>28万</price></brand></factory><factory name="上海大众"><brand><name>帕萨特</name><color>黑色</color><price>25万</price></brand><brand><name>POLO</name><color>灰色</color><price>8万</price></brand></factory></car>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include "mxml.h" 3 4 int main(int argc, const char* argv[]) 5 { 6 if(argc < 2) 7 { 8 printf("./a.out filename\n"); 9 return 0; 10 } 11 // 加载xml文件 12 FILE* fp = fopen(argv[1], "r"); 13 mxml_node_t* root = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK); 14 15 // 找到第一个factory节点 16 mxml_node_t* factory = mxmlFindElement(root, root, "factory", "name", NULL, MXML_DESCEND); 17 // 循环查找 18 while( factory ) 19 { 20 // 打印几点的属性值 21 printf("factory attr: %s\n", mxmlElementGetAttr(factory, "name")); 22 23 // 向下移动一个节点 24 mxml_node_t* brand = mxmlWalkNext(factory, root, MXML_DESCEND); 25 while( brand ) 26 { 27 // name 28 mxml_node_t* node = mxmlWalkNext(brand, root, MXML_DESCEND_FIRST); 29 printf(" name: %s\n", mxmlGetText(node, 0)); 30 // color 31 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 32 printf(" color: %s\n", mxmlGetText(node, 0)); 33 // price 34 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 35 printf(" price: %s\n", mxmlGetText(node, 0)); 36 printf(" =========================================\n"); 37 38 // 找到下一个品牌节点 39 brand = mxmlFindElement(brand, root, "brand", NULL, NULL, MXML_NO_DESCEND); 40 } 41 // 打印该厂家对应的车辆品牌和属性信息 42 // 查找下一个节点 43 factory = mxmlFindElement(factory, root, "factory", "name", NULL, MXML_NO_DESCEND); 44 } 45 mxmlDelete(root); 46 fclose(fp); 47 48 return 0; 49 }
上面代码编译:gcc c文件 -lmxml -lpthread
二、JSON
1. cjson的使用
压缩包解压缩,直接使用里边的cJSON.c和cJSON.h即可
链接时还需要加上-lm 表示链接math库
2. json数组
- char array[23] = "slkjflajslfd";
- 中括号[整形, 字符串, 布尔类型, json数组, json对象],比如[123, 123.2, true, false, [12, 34, 56, "hello, world"]]
3. json对象
{}中是一些键值对
{ "name":"zhang3", "name2":"li4" } key值: 必须是 字符串, 不重复 value值: json对象, json数组, 布尔, 整形, 字符串
4. json数组+json对象
{ "name":"zhang3", "name2":"li4", "张三":{ "别名":"老王", "性别":"男", "年龄":34, "孩子":["小红", "小绿", "小黑"] } }
5. C语言json开源解析库 - cjson
(1)生成json文件
1)创建一个json对象
cJSON *cJSON_CreateObject(void);
2) 往json对象中添加数据成员
void cJSON_AddItemToObject( cJSON *object, // json对象 const char *string, // key值 cJSON *item // value值(int,string,array,obj) );
3)创建一个整型值
cJSON *cJSON_CreateNumber(double num);
4)创建一个字符串
cJSON *cJSON_CreateString(const char *string);
5)创建一个json数组
cJSON *cJSON_CreateArray(void); -- 空数组
6)创建默认有count个整形值的json数组
cJSON *cJSON_CreateIntArray(const int *numbers,int count);
- int arry[] = {8,3,4,5,6};
- cJSON_CreateIntArray(arry, 5);
7)往json数组中添加数据成员
void cJSON_AddItemToArray(cJSON *array, cJSON *item);
8)释放jSON结构指针
void cJSON_Delete(cJSON *c)
9)将JSON结构转化为字符串
char *cJSON_Print(cJSON *item);
- 返回值需要使用free释放
- FILE* fp = fopen();
- fwrite();
- fclose();
(2)解析json文件
1)将字符串解析为JSON结构
cJSON *cJSON_Parse(const char *value);
注意:返回值需要使用cJSON_Delete释放
2)根据键值查找json节点
cJSON *cJSON_GetObjectItem( cJSON *object, // 当前json对象 const char *string // key值 );
3)获取json数组中元素的个数
int cJSON_GetArraySize(cJSON *array);
4) 根据数组下标找到对应的数组元素
cJSON *cJSON_GetArrayItem(cJSON *array, int index);
5)判断是否有可以值对应的键值对
int cJSON_HasObjectItem(cJSON *object, const char *string);
(3)示例
生成下面的JSON
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 { 2 "奔驰": { 3 "factory": "一汽大众", 4 "last": 31, 5 "price": 83, 6 "sell": 49, 7 "sum": 80, 8 "other": [124, "hello, world", false] 9 } 10 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #include "cJSON.h" 4 5 int main(int argc, const char* argv[]) 6 { 7 // 创建json对象 8 cJSON* obj = cJSON_CreateObject(); 9 10 // 创建子对象 - 品牌 11 cJSON* brand = cJSON_CreateObject(); 12 // 添加键值对 13 cJSON_AddItemToObject(brand, "factory", cJSON_CreateString("一汽大众")); 14 cJSON_AddItemToObject(brand, "last", cJSON_CreateNumber(31)); 15 cJSON_AddItemToObject(brand, "price", cJSON_CreateNumber(83)); 16 cJSON_AddItemToObject(brand, "sell", cJSON_CreateNumber(49)); 17 cJSON_AddItemToObject(brand, "sum", cJSON_CreateNumber(80)); 18 19 // 创建json数组 20 cJSON* array = cJSON_CreateArray(); 21 cJSON_AddItemToArray(array, cJSON_CreateNumber(124)); 22 cJSON_AddItemToArray(array, cJSON_CreateString("hello, world")); 23 cJSON_AddItemToArray(array, cJSON_CreateBool(0)); 24 cJSON_AddItemToObject(brand, "other", array); 25 26 cJSON_AddItemToObject(obj, "奔驰", brand); 27 28 // 格式化json对象 29 char* text = cJSON_Print(obj); 30 FILE* fp = fopen("car.json", "w"); 31 fwrite(text, 1, strlen(text), fp); 32 fclose(fp); 33 34 return 0; 35 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 Copyright (c) 2009 Dave Gamble 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 THE SOFTWARE. 21 */ 22 23 /* cJSON */ 24 /* JSON parser in C. */ 25 26 #include <string.h> 27 #include <stdio.h> 28 #include <math.h> 29 #include <stdlib.h> 30 #include <float.h> 31 #include <limits.h> 32 #include <ctype.h> 33 #include "cJSON.h" 34 35 /* define our own boolean type */ 36 typedef int cjbool; 37 #define true ((cjbool)1) 38 #define false ((cjbool)0) 39 40 static const unsigned char *global_ep = NULL; 41 42 const char *cJSON_GetErrorPtr(void) 43 { 44 return (const char*) global_ep; 45 } 46 47 /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ 48 #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 3) || (CJSON_VERSION_PATCH != 0) 49 #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. 50 #endif 51 52 extern const char* cJSON_Version(void) 53 { 54 static char version[15]; 55 sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); 56 57 return version; 58 } 59 60 /* case insensitive strcmp */ 61 static int cJSON_strcasecmp(const unsigned char *s1, const unsigned char *s2) 62 { 63 if (!s1) 64 { 65 return (s1 == s2) ? 0 : 1; /* both NULL? */ 66 } 67 if (!s2) 68 { 69 return 1; 70 } 71 for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) 72 { 73 if (*s1 == '\0') 74 { 75 return 0; 76 } 77 } 78 79 return tolower(*s1) - tolower(*s2); 80 } 81 82 static void *(*cJSON_malloc)(size_t sz) = malloc; 83 static void (*cJSON_free)(void *ptr) = free; 84 85 static unsigned char* cJSON_strdup(const unsigned char* str) 86 { 87 size_t len = 0; 88 unsigned char *copy = NULL; 89 90 if (str == NULL) 91 { 92 return NULL; 93 } 94 95 len = strlen((const char*)str) + 1; 96 if (!(copy = (unsigned char*)cJSON_malloc(len))) 97 { 98 return NULL; 99 } 100 memcpy(copy, str, len); 101 102 return copy; 103 } 104 105 void cJSON_InitHooks(cJSON_Hooks* hooks) 106 { 107 if (!hooks) 108 { 109 /* Reset hooks */ 110 cJSON_malloc = malloc; 111 cJSON_free = free; 112 return; 113 } 114 115 cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc; 116 cJSON_free = (hooks->free_fn) ? hooks->free_fn : free; 117 } 118 119 /* Internal constructor. */ 120 static cJSON *cJSON_New_Item(void) 121 { 122 cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); 123 if (node) 124 { 125 memset(node, '\0', sizeof(cJSON)); 126 } 127 128 return node; 129 } 130 131 /* Delete a cJSON structure. */ 132 void cJSON_Delete(cJSON *c) 133 { 134 cJSON *next = NULL; 135 while (c) 136 { 137 next = c->next; 138 if (!(c->type & cJSON_IsReference) && c->child) 139 { 140 cJSON_Delete(c->child); 141 } 142 if (!(c->type & cJSON_IsReference) && c->valuestring) 143 { 144 cJSON_free(c->valuestring); 145 } 146 if (!(c->type & cJSON_StringIsConst) && c->string) 147 { 148 cJSON_free(c->string); 149 } 150 cJSON_free(c); 151 c = next; 152 } 153 } 154 155 /* Parse the input text to generate a number, and populate the result into item. */ 156 static const unsigned char *parse_number(cJSON * const item, const unsigned char * const input) 157 { 158 double number = 0; 159 unsigned char *after_end = NULL; 160 161 if (input == NULL) 162 { 163 return NULL; 164 } 165 166 number = strtod((const char*)input, (char**)&after_end); 167 if (input == after_end) 168 { 169 return NULL; /* parse_error */ 170 } 171 172 item->valuedouble = number; 173 174 /* use saturation in case of overflow */ 175 if (number >= INT_MAX) 176 { 177 item->valueint = INT_MAX; 178 } 179 else if (number <= INT_MIN) 180 { 181 item->valueint = INT_MIN; 182 } 183 else 184 { 185 item->valueint = (int)number; 186 } 187 188 item->type = cJSON_Number; 189 190 return after_end; 191 } 192 193 /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ 194 double cJSON_SetNumberHelper(cJSON *object, double number) 195 { 196 if (number >= INT_MAX) 197 { 198 object->valueint = INT_MAX; 199 } 200 else if (number <= INT_MIN) 201 { 202 object->valueint = INT_MIN; 203 } 204 else 205 { 206 object->valueint = cJSON_Number; 207 } 208 209 return object->valuedouble = number; 210 } 211 212 typedef struct 213 { 214 unsigned char *buffer; 215 size_t length; 216 size_t offset; 217 cjbool noalloc; 218 } printbuffer; 219 220 /* realloc printbuffer if necessary to have at least "needed" bytes more */ 221 static unsigned char* ensure(printbuffer *p, size_t needed) 222 { 223 unsigned char *newbuffer = NULL; 224 size_t newsize = 0; 225 226 if (needed > INT_MAX) 227 { 228 /* sizes bigger than INT_MAX are currently not supported */ 229 return NULL; 230 } 231 232 if (!p || !p->buffer) 233 { 234 return NULL; 235 } 236 needed += p->offset; 237 if (needed <= p->length) 238 { 239 return p->buffer + p->offset; 240 } 241 242 if (p->noalloc) { 243 return NULL; 244 } 245 246 /* calculate new buffer size */ 247 newsize = needed * 2; 248 if (newsize > INT_MAX) 249 { 250 /* overflow of int, use INT_MAX if possible */ 251 if (needed <= INT_MAX) 252 { 253 newsize = INT_MAX; 254 } 255 else 256 { 257 return NULL; 258 } 259 } 260 261 newbuffer = (unsigned char*)cJSON_malloc(newsize); 262 if (!newbuffer) 263 { 264 cJSON_free(p->buffer); 265 p->length = 0; 266 p->buffer = NULL; 267 268 return NULL; 269 } 270 if (newbuffer) 271 { 272 memcpy(newbuffer, p->buffer, p->length); 273 } 274 cJSON_free(p->buffer); 275 p->length = newsize; 276 p->buffer = newbuffer; 277 278 return newbuffer + p->offset; 279 } 280 281 /* calculate the new length of the string in a printbuffer */ 282 static size_t update(const printbuffer *p) 283 { 284 const unsigned char *str = NULL; 285 if (!p || !p->buffer) 286 { 287 return 0; 288 } 289 str = p->buffer + p->offset; 290 291 return p->offset + strlen((const char*)str); 292 } 293 294 /* Render the number nicely from the given item into a string. */ 295 static unsigned char *print_number(const cJSON *item, printbuffer *p) 296 { 297 unsigned char *str = NULL; 298 double d = item->valuedouble; 299 /* special case for 0. */ 300 if (d == 0) 301 { 302 if (p) 303 { 304 str = ensure(p, 2); 305 } 306 else 307 { 308 str = (unsigned char*)cJSON_malloc(2); 309 } 310 if (str) 311 { 312 strcpy((char*)str,"0"); 313 } 314 } 315 /* value is an int */ 316 else if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) 317 { 318 if (p) 319 { 320 str = ensure(p, 21); 321 } 322 else 323 { 324 /* 2^64+1 can be represented in 21 chars. */ 325 str = (unsigned char*)cJSON_malloc(21); 326 } 327 if (str) 328 { 329 sprintf((char*)str, "%d", item->valueint); 330 } 331 } 332 /* value is a floating point number */ 333 else 334 { 335 if (p) 336 { 337 /* This is a nice tradeoff. */ 338 str = ensure(p, 64); 339 } 340 else 341 { 342 /* This is a nice tradeoff. */ 343 str = (unsigned char*)cJSON_malloc(64); 344 } 345 if (str) 346 { 347 /* This checks for NaN and Infinity */ 348 if ((d * 0) != 0) 349 { 350 sprintf((char*)str, "null"); 351 } 352 else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) 353 { 354 sprintf((char*)str, "%.0f", d); 355 } 356 else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) 357 { 358 sprintf((char*)str, "%e", d); 359 } 360 else 361 { 362 sprintf((char*)str, "%f", d); 363 } 364 } 365 } 366 return str; 367 } 368 369 /* parse 4 digit hexadecimal number */ 370 static unsigned parse_hex4(const unsigned char * const input) 371 { 372 unsigned int h = 0; 373 size_t i = 0; 374 375 for (i = 0; i < 4; i++) 376 { 377 /* parse digit */ 378 if ((input[i] >= '0') && (input[i] <= '9')) 379 { 380 h += (unsigned int) input[i] - '0'; 381 } 382 else if ((input[i] >= 'A') && (input[i] <= 'F')) 383 { 384 h += (unsigned int) 10 + input[i] - 'A'; 385 } 386 else if ((input[i] >= 'a') && (input[i] <= 'f')) 387 { 388 h += (unsigned int) 10 + input[i] - 'a'; 389 } 390 else /* invalid */ 391 { 392 return 0; 393 } 394 395 if (i < 3) 396 { 397 /* shift left to make place for the next nibble */ 398 h = h << 4; 399 } 400 } 401 402 return h; 403 } 404 405 /* converts a UTF-16 literal to UTF-8 406 * A literal can be one or two sequences of the form \uXXXX */ 407 static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer, const unsigned char **error_pointer) 408 { 409 /* first bytes of UTF8 encoding for a given length in bytes */ 410 static const unsigned char firstByteMark[5] = 411 { 412 0x00, /* should never happen */ 413 0x00, /* 0xxxxxxx */ 414 0xC0, /* 110xxxxx */ 415 0xE0, /* 1110xxxx */ 416 0xF0 /* 11110xxx */ 417 }; 418 419 long unsigned int codepoint = 0; 420 unsigned int first_code = 0; 421 const unsigned char *first_sequence = input_pointer; 422 unsigned char utf8_length = 0; 423 unsigned char sequence_length = 0; 424 425 /* get the first utf16 sequence */ 426 first_code = parse_hex4(first_sequence + 2); 427 if ((input_end - first_sequence) < 6) 428 { 429 /* input ends unexpectedly */ 430 *error_pointer = first_sequence; 431 goto fail; 432 } 433 434 /* check that the code is valid */ 435 if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)) || (first_code == 0)) 436 { 437 *error_pointer = first_sequence; 438 goto fail; 439 } 440 441 /* UTF16 surrogate pair */ 442 if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) 443 { 444 const unsigned char *second_sequence = first_sequence + 6; 445 unsigned int second_code = 0; 446 sequence_length = 12; /* \uXXXX\uXXXX */ 447 448 if ((input_end - second_sequence) < 6) 449 { 450 /* input ends unexpectedly */ 451 *error_pointer = first_sequence; 452 goto fail; 453 } 454 455 if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) 456 { 457 /* missing second half of the surrogate pair */ 458 *error_pointer = first_sequence; 459 goto fail; 460 } 461 462 /* get the second utf16 sequence */ 463 second_code = parse_hex4(second_sequence + 2); 464 /* check that the code is valid */ 465 if ((second_code < 0xDC00) || (second_code > 0xDFFF)) 466 { 467 /* invalid second half of the surrogate pair */ 468 *error_pointer = first_sequence; 469 goto fail; 470 } 471 472 473 /* calculate the unicode codepoint from the surrogate pair */ 474 codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); 475 } 476 else 477 { 478 sequence_length = 6; /* \uXXXX */ 479 codepoint = first_code; 480 } 481 482 /* encode as UTF-8 483 * takes at maximum 4 bytes to encode: 484 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ 485 if (codepoint < 0x80) 486 { 487 /* normal ascii, encoding 0xxxxxxx */ 488 utf8_length = 1; 489 } 490 else if (codepoint < 0x800) 491 { 492 /* two bytes, encoding 110xxxxx 10xxxxxx */ 493 utf8_length = 2; 494 } 495 else if (codepoint < 0x10000) 496 { 497 /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ 498 utf8_length = 3; 499 } 500 else if (codepoint <= 0x10FFFF) 501 { 502 /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 503 utf8_length = 4; 504 } 505 else 506 { 507 /* invalid unicode codepoint */ 508 *error_pointer = first_sequence; 509 goto fail; 510 } 511 512 /* encode as utf8 */ 513 switch (utf8_length) 514 { 515 case 4: 516 /* 10xxxxxx */ 517 (*output_pointer)[3] = (unsigned char)((codepoint | 0x80) & 0xBF); 518 codepoint >>= 6; 519 case 3: 520 /* 10xxxxxx */ 521 (*output_pointer)[2] = (unsigned char)((codepoint | 0x80) & 0xBF); 522 codepoint >>= 6; 523 case 2: 524 (*output_pointer)[1] = (unsigned char)((codepoint | 0x80) & 0xBF); 525 codepoint >>= 6; 526 case 1: 527 /* depending on the length in bytes this determines the 528 encoding of the first UTF8 byte */ 529 (*output_pointer)[0] = (unsigned char)((codepoint | firstByteMark[utf8_length]) & 0xFF); 530 break; 531 default: 532 *error_pointer = first_sequence; 533 goto fail; 534 } 535 *output_pointer += utf8_length; 536 537 return sequence_length; 538 539 fail: 540 return 0; 541 } 542 543 /* Parse the input text into an unescaped cinput, and populate item. */ 544 static const unsigned char *parse_string(cJSON * const item, const unsigned char * const input, const unsigned char ** const error_pointer) 545 { 546 const unsigned char *input_pointer = input + 1; 547 const unsigned char *input_end = input + 1; 548 unsigned char *output_pointer = NULL; 549 unsigned char *output = NULL; 550 551 /* not a string */ 552 if (*input != '\"') 553 { 554 *error_pointer = input; 555 goto fail; 556 } 557 558 { 559 /* calculate approximate size of the output (overestimate) */ 560 size_t allocation_length = 0; 561 size_t skipped_bytes = 0; 562 while ((*input_end != '\"') && (*input_end != '\0')) 563 { 564 /* is escape sequence */ 565 if (input_end[0] == '\\') 566 { 567 if (input_end[1] == '\0') 568 { 569 /* prevent buffer overflow when last input character is a backslash */ 570 goto fail; 571 } 572 skipped_bytes++; 573 input_end++; 574 } 575 input_end++; 576 } 577 if (*input_end == '\0') 578 { 579 goto fail; /* string ended unexpectedly */ 580 } 581 582 /* This is at most how much we need for the output */ 583 allocation_length = (size_t) (input_end - input) - skipped_bytes; 584 output = (unsigned char*)cJSON_malloc(allocation_length + sizeof('\0')); 585 if (output == NULL) 586 { 587 goto fail; /* allocation failure */ 588 } 589 } 590 591 output_pointer = output; 592 /* loop through the string literal */ 593 while (input_pointer < input_end) 594 { 595 if (*input_pointer != '\\') 596 { 597 *output_pointer++ = *input_pointer++; 598 } 599 /* escape sequence */ 600 else 601 { 602 unsigned char sequence_length = 2; 603 switch (input_pointer[1]) 604 { 605 case 'b': 606 *output_pointer++ = '\b'; 607 break; 608 case 'f': 609 *output_pointer++ = '\f'; 610 break; 611 case 'n': 612 *output_pointer++ = '\n'; 613 break; 614 case 'r': 615 *output_pointer++ = '\r'; 616 break; 617 case 't': 618 *output_pointer++ = '\t'; 619 break; 620 case '\"': 621 case '\\': 622 case '/': 623 *output_pointer++ = input_pointer[1]; 624 break; 625 626 /* UTF-16 literal */ 627 case 'u': 628 sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer, error_pointer); 629 if (sequence_length == 0) 630 { 631 /* failed to convert UTF16-literal to UTF-8 */ 632 goto fail; 633 } 634 break; 635 636 default: 637 *error_pointer = input_pointer; 638 goto fail; 639 } 640 input_pointer += sequence_length; 641 } 642 } 643 644 /* zero terminate the output */ 645 *output_pointer = '\0'; 646 647 item->type = cJSON_String; 648 item->valuestring = (char*)output; 649 650 return input_end + 1; 651 652 fail: 653 if (output != NULL) 654 { 655 cJSON_free(output); 656 } 657 658 return NULL; 659 } 660 661 /* Render the cstring provided to an escaped version that can be printed. */ 662 static unsigned char *print_string_ptr(const unsigned char *str, printbuffer *p) 663 { 664 const unsigned char *ptr = NULL; 665 unsigned char *ptr2 = NULL; 666 unsigned char *out = NULL; 667 size_t len = 0; 668 cjbool flag = false; 669 unsigned char token = '\0'; 670 671 /* empty string */ 672 if (!str) 673 { 674 if (p) 675 { 676 out = ensure(p, 3); 677 } 678 else 679 { 680 out = (unsigned char*)cJSON_malloc(3); 681 } 682 if (!out) 683 { 684 return NULL; 685 } 686 strcpy((char*)out, "\"\""); 687 688 return out; 689 } 690 691 /* set "flag" to 1 if something needs to be escaped */ 692 for (ptr = str; *ptr; ptr++) 693 { 694 flag |= (((*ptr > 0) && (*ptr < 32)) /* unprintable characters */ 695 || (*ptr == '\"') /* double quote */ 696 || (*ptr == '\\')) /* backslash */ 697 ? 1 698 : 0; 699 } 700 /* no characters have to be escaped */ 701 if (!flag) 702 { 703 len = (size_t)(ptr - str); 704 if (p) 705 { 706 out = ensure(p, len + 3); 707 } 708 else 709 { 710 out = (unsigned char*)cJSON_malloc(len + 3); 711 } 712 if (!out) 713 { 714 return NULL; 715 } 716 717 ptr2 = out; 718 *ptr2++ = '\"'; 719 strcpy((char*)ptr2, (const char*)str); 720 ptr2[len] = '\"'; 721 ptr2[len + 1] = '\0'; 722 723 return out; 724 } 725 726 ptr = str; 727 /* calculate additional space that is needed for escaping */ 728 while ((token = *ptr)) 729 { 730 ++len; 731 if (strchr("\"\\\b\f\n\r\t", token)) 732 { 733 len++; /* +1 for the backslash */ 734 } 735 else if (token < 32) 736 { 737 len += 5; /* +5 for \uXXXX */ 738 } 739 ptr++; 740 } 741 742 if (p) 743 { 744 out = ensure(p, len + 3); 745 } 746 else 747 { 748 out = (unsigned char*)cJSON_malloc(len + 3); 749 } 750 if (!out) 751 { 752 return NULL; 753 } 754 755 ptr2 = out; 756 ptr = str; 757 *ptr2++ = '\"'; 758 /* copy the string */ 759 while (*ptr) 760 { 761 if ((*ptr > 31) && (*ptr != '\"') && (*ptr != '\\')) 762 { 763 /* normal character, copy */ 764 *ptr2++ = *ptr++; 765 } 766 else 767 { 768 /* character needs to be escaped */ 769 *ptr2++ = '\\'; 770 switch (token = *ptr++) 771 { 772 case '\\': 773 *ptr2++ = '\\'; 774 break; 775 case '\"': 776 *ptr2++ = '\"'; 777 break; 778 case '\b': 779 *ptr2++ = 'b'; 780 break; 781 case '\f': 782 *ptr2++ = 'f'; 783 break; 784 case '\n': 785 *ptr2++ = 'n'; 786 break; 787 case '\r': 788 *ptr2++ = 'r'; 789 break; 790 case '\t': 791 *ptr2++ = 't'; 792 break; 793 default: 794 /* escape and print as unicode codepoint */ 795 sprintf((char*)ptr2, "u%04x", token); 796 ptr2 += 5; 797 break; 798 } 799 } 800 } 801 *ptr2++ = '\"'; 802 *ptr2++ = '\0'; 803 804 return out; 805 } 806 807 /* Invoke print_string_ptr (which is useful) on an item. */ 808 static unsigned char *print_string(const cJSON *item, printbuffer *p) 809 { 810 return print_string_ptr((unsigned char*)item->valuestring, p); 811 } 812 813 /* Predeclare these prototypes. */ 814 static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const ep); 815 static unsigned char *print_value(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p); 816 static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); 817 static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p); 818 static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); 819 static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p); 820 821 /* Utility to jump whitespace and cr/lf */ 822 static const unsigned char *skip(const unsigned char *in) 823 { 824 while (in && *in && (*in <= 32)) 825 { 826 in++; 827 } 828 829 return in; 830 } 831 832 /* Parse an object - create a new root, and populate. */ 833 cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjbool require_null_terminated) 834 { 835 const unsigned char *end = NULL; 836 /* use global error pointer if no specific one was given */ 837 const unsigned char **ep = return_parse_end ? (const unsigned char**)return_parse_end : &global_ep; 838 cJSON *c = cJSON_New_Item(); 839 *ep = NULL; 840 if (!c) /* memory fail */ 841 { 842 return NULL; 843 } 844 845 end = parse_value(c, skip((const unsigned char*)value), ep); 846 if (!end) 847 { 848 /* parse failure. ep is set. */ 849 cJSON_Delete(c); 850 return NULL; 851 } 852 853 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 854 if (require_null_terminated) 855 { 856 end = skip(end); 857 if (*end) 858 { 859 cJSON_Delete(c); 860 *ep = end; 861 return NULL; 862 } 863 } 864 if (return_parse_end) 865 { 866 *return_parse_end = (const char*)end; 867 } 868 869 return c; 870 } 871 872 /* Default options for cJSON_Parse */ 873 cJSON *cJSON_Parse(const char *value) 874 { 875 return cJSON_ParseWithOpts(value, 0, 0); 876 } 877 878 /* Render a cJSON item/entity/structure to text. */ 879 char *cJSON_Print(const cJSON *item) 880 { 881 return (char*)print_value(item, 0, 1, 0); 882 } 883 884 char *cJSON_PrintUnformatted(const cJSON *item) 885 { 886 return (char*)print_value(item, 0, 0, 0); 887 } 888 889 char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) 890 { 891 printbuffer p; 892 893 if (prebuffer < 0) 894 { 895 return NULL; 896 } 897 898 p.buffer = (unsigned char*)cJSON_malloc((size_t)prebuffer); 899 if (!p.buffer) 900 { 901 return NULL; 902 } 903 904 p.length = (size_t)prebuffer; 905 p.offset = 0; 906 p.noalloc = false; 907 908 return (char*)print_value(item, 0, fmt, &p); 909 } 910 911 int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cjbool fmt) 912 { 913 printbuffer p; 914 915 if (len < 0) 916 { 917 return false; 918 } 919 920 p.buffer = (unsigned char*)buf; 921 p.length = (size_t)len; 922 p.offset = 0; 923 p.noalloc = true; 924 return print_value(item, 0, fmt, &p) != NULL; 925 } 926 927 /* Parser core - when encountering text, process appropriately. */ 928 static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const error_pointer) 929 { 930 if (input == NULL) 931 { 932 return NULL; /* no input */ 933 } 934 935 /* parse the different types of values */ 936 /* null */ 937 if (!strncmp((const char*)input, "null", 4)) 938 { 939 item->type = cJSON_NULL; 940 return input + 4; 941 } 942 /* false */ 943 if (!strncmp((const char*)input, "false", 5)) 944 { 945 item->type = cJSON_False; 946 return input + 5; 947 } 948 /* true */ 949 if (!strncmp((const char*)input, "true", 4)) 950 { 951 item->type = cJSON_True; 952 item->valueint = 1; 953 return input + 4; 954 } 955 /* string */ 956 if (*input == '\"') 957 { 958 return parse_string(item, input, error_pointer); 959 } 960 /* number */ 961 if ((*input == '-') || ((*input >= '0') && (*input <= '9'))) 962 { 963 return parse_number(item, input); 964 } 965 /* array */ 966 if (*input == '[') 967 { 968 return parse_array(item, input, error_pointer); 969 } 970 /* object */ 971 if (*input == '{') 972 { 973 return parse_object(item, input, error_pointer); 974 } 975 976 /* failure. */ 977 *error_pointer = input; 978 return NULL; 979 } 980 981 /* Render a value to text. */ 982 static unsigned char *print_value(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p) 983 { 984 unsigned char *out = NULL; 985 986 if (!item) 987 { 988 return NULL; 989 } 990 if (p) 991 { 992 switch ((item->type) & 0xFF) 993 { 994 case cJSON_NULL: 995 out = ensure(p, 5); 996 if (out) 997 { 998 strcpy((char*)out, "null"); 999 } 1000 break; 1001 case cJSON_False: 1002 out = ensure(p, 6); 1003 if (out) 1004 { 1005 strcpy((char*)out, "false"); 1006 } 1007 break; 1008 case cJSON_True: 1009 out = ensure(p, 5); 1010 if (out) 1011 { 1012 strcpy((char*)out, "true"); 1013 } 1014 break; 1015 case cJSON_Number: 1016 out = print_number(item, p); 1017 break; 1018 case cJSON_Raw: 1019 { 1020 size_t raw_length = 0; 1021 if (item->valuestring == NULL) 1022 { 1023 if (!p->noalloc) 1024 { 1025 cJSON_free(p->buffer); 1026 } 1027 out = NULL; 1028 break; 1029 } 1030 1031 raw_length = strlen(item->valuestring) + sizeof('\0'); 1032 out = ensure(p, raw_length); 1033 if (out) 1034 { 1035 memcpy(out, item->valuestring, raw_length); 1036 } 1037 break; 1038 } 1039 case cJSON_String: 1040 out = print_string(item, p); 1041 break; 1042 case cJSON_Array: 1043 out = print_array(item, depth, fmt, p); 1044 break; 1045 case cJSON_Object: 1046 out = print_object(item, depth, fmt, p); 1047 break; 1048 default: 1049 out = NULL; 1050 break; 1051 } 1052 } 1053 else 1054 { 1055 switch ((item->type) & 0xFF) 1056 { 1057 case cJSON_NULL: 1058 out = cJSON_strdup((const unsigned char*)"null"); 1059 break; 1060 case cJSON_False: 1061 out = cJSON_strdup((const unsigned char*)"false"); 1062 break; 1063 case cJSON_True: 1064 out = cJSON_strdup((const unsigned char*)"true"); 1065 break; 1066 case cJSON_Number: 1067 out = print_number(item, 0); 1068 break; 1069 case cJSON_Raw: 1070 out = cJSON_strdup((unsigned char*)item->valuestring); 1071 break; 1072 case cJSON_String: 1073 out = print_string(item, 0); 1074 break; 1075 case cJSON_Array: 1076 out = print_array(item, depth, fmt, 0); 1077 break; 1078 case cJSON_Object: 1079 out = print_object(item, depth, fmt, 0); 1080 break; 1081 default: 1082 out = NULL; 1083 break; 1084 } 1085 } 1086 1087 return out; 1088 } 1089 1090 /* Build an array from input text. */ 1091 static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const error_pointer) 1092 { 1093 cJSON *head = NULL; /* head of the linked list */ 1094 cJSON *current_item = NULL; 1095 1096 if (*input != '[') 1097 { 1098 /* not an array */ 1099 *error_pointer = input; 1100 goto fail; 1101 } 1102 1103 input = skip(input + 1); /* skip whitespace */ 1104 if (*input == ']') 1105 { 1106 /* empty array */ 1107 goto success; 1108 } 1109 1110 /* step back to character in front of the first element */ 1111 input--; 1112 /* loop through the comma separated array elements */ 1113 do 1114 { 1115 /* allocate next item */ 1116 cJSON *new_item = cJSON_New_Item(); 1117 if (new_item == NULL) 1118 { 1119 goto fail; /* allocation failure */ 1120 } 1121 1122 /* attach next item to list */ 1123 if (head == NULL) 1124 { 1125 /* start the linked list */ 1126 current_item = head = new_item; 1127 } 1128 else 1129 { 1130 /* add to the end and advance */ 1131 current_item->next = new_item; 1132 new_item->prev = current_item; 1133 current_item = new_item; 1134 } 1135 1136 /* parse next value */ 1137 input = skip(input + 1); /* skip whitespace before value */ 1138 input = parse_value(current_item, input, error_pointer); 1139 input = skip(input); /* skip whitespace after value */ 1140 if (input == NULL) 1141 { 1142 goto fail; /* failed to parse value */ 1143 } 1144 } 1145 while (*input == ','); 1146 1147 if (*input != ']') 1148 { 1149 *error_pointer = input; 1150 goto fail; /* expected end of array */ 1151 } 1152 1153 success: 1154 item->type = cJSON_Array; 1155 item->child = head; 1156 1157 return input + 1; 1158 1159 fail: 1160 if (head != NULL) 1161 { 1162 cJSON_Delete(head); 1163 } 1164 1165 return NULL; 1166 } 1167 1168 /* Render an array to text */ 1169 static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p) 1170 { 1171 unsigned char **entries; 1172 unsigned char *out = NULL; 1173 unsigned char *ptr = NULL; 1174 unsigned char *ret = NULL; 1175 size_t len = 5; 1176 cJSON *child = item->child; 1177 size_t numentries = 0; 1178 size_t i = 0; 1179 cjbool fail = false; 1180 size_t tmplen = 0; 1181 1182 /* How many entries in the array? */ 1183 while (child) 1184 { 1185 numentries++; 1186 child = child->next; 1187 } 1188 1189 /* Explicitly handle numentries == 0 */ 1190 if (!numentries) 1191 { 1192 if (p) 1193 { 1194 out = ensure(p, 3); 1195 } 1196 else 1197 { 1198 out = (unsigned char*)cJSON_malloc(3); 1199 } 1200 if (out) 1201 { 1202 strcpy((char*)out, "[]"); 1203 } 1204 1205 return out; 1206 } 1207 1208 if (p) 1209 { 1210 /* Compose the output array. */ 1211 /* opening square bracket */ 1212 i = p->offset; 1213 ptr = ensure(p, 1); 1214 if (!ptr) 1215 { 1216 return NULL; 1217 } 1218 *ptr = '['; 1219 p->offset++; 1220 1221 child = item->child; 1222 while (child && !fail) 1223 { 1224 if (!print_value(child, depth + 1, fmt, p)) 1225 { 1226 return NULL; 1227 } 1228 p->offset = update(p); 1229 if (child->next) 1230 { 1231 len = fmt ? 2 : 1; 1232 ptr = ensure(p, len + 1); 1233 if (!ptr) 1234 { 1235 return NULL; 1236 } 1237 *ptr++ = ','; 1238 if(fmt) 1239 { 1240 *ptr++ = ' '; 1241 } 1242 *ptr = '\0'; 1243 p->offset += len; 1244 } 1245 child = child->next; 1246 } 1247 ptr = ensure(p, 2); 1248 if (!ptr) 1249 { 1250 return NULL; 1251 } 1252 *ptr++ = ']'; 1253 *ptr = '\0'; 1254 out = (p->buffer) + i; 1255 } 1256 else 1257 { 1258 /* Allocate an array to hold the pointers to all printed values */ 1259 entries = (unsigned char**)cJSON_malloc(numentries * sizeof(unsigned char*)); 1260 if (!entries) 1261 { 1262 return NULL; 1263 } 1264 memset(entries, '\0', numentries * sizeof(unsigned char*)); 1265 1266 /* Retrieve all the results: */ 1267 child = item->child; 1268 while (child && !fail) 1269 { 1270 ret = print_value(child, depth + 1, fmt, 0); 1271 entries[i++] = ret; 1272 if (ret) 1273 { 1274 len += strlen((char*)ret) + 2 + (fmt ? 1 : 0); 1275 } 1276 else 1277 { 1278 fail = true; 1279 } 1280 child = child->next; 1281 } 1282 1283 /* If we didn't fail, try to malloc the output string */ 1284 if (!fail) 1285 { 1286 out = (unsigned char*)cJSON_malloc(len); 1287 } 1288 /* If that fails, we fail. */ 1289 if (!out) 1290 { 1291 fail = true; 1292 } 1293 1294 /* Handle failure. */ 1295 if (fail) 1296 { 1297 /* free all the entries in the array */ 1298 for (i = 0; i < numentries; i++) 1299 { 1300 if (entries[i]) 1301 { 1302 cJSON_free(entries[i]); 1303 } 1304 } 1305 cJSON_free(entries); 1306 return NULL; 1307 } 1308 1309 /* Compose the output array. */ 1310 *out='['; 1311 ptr = out + 1; 1312 *ptr = '\0'; 1313 for (i = 0; i < numentries; i++) 1314 { 1315 tmplen = strlen((char*)entries[i]); 1316 memcpy(ptr, entries[i], tmplen); 1317 ptr += tmplen; 1318 if (i != (numentries - 1)) 1319 { 1320 *ptr++ = ','; 1321 if(fmt) 1322 { 1323 *ptr++ = ' '; 1324 } 1325 *ptr = '\0'; 1326 } 1327 cJSON_free(entries[i]); 1328 } 1329 cJSON_free(entries); 1330 *ptr++ = ']'; 1331 *ptr++ = '\0'; 1332 } 1333 1334 return out; 1335 } 1336 1337 /* Build an object from the text. */ 1338 static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const error_pointer) 1339 { 1340 cJSON *head = NULL; /* linked list head */ 1341 cJSON *current_item = NULL; 1342 1343 if (*input != '{') 1344 { 1345 *error_pointer = input; 1346 goto fail; /* not an object */ 1347 } 1348 1349 input = skip(input + 1); /* skip whitespace */ 1350 if (*input == '}') 1351 { 1352 goto success; /* empty object */ 1353 } 1354 1355 /* step back to character in front of the first element */ 1356 input--; 1357 /* loop through the comma separated array elements */ 1358 do 1359 { 1360 /* allocate next item */ 1361 cJSON *new_item = cJSON_New_Item(); 1362 if (new_item == NULL) 1363 { 1364 goto fail; /* allocation failure */ 1365 } 1366 1367 /* attach next item to list */ 1368 if (head == NULL) 1369 { 1370 /* start the linked list */ 1371 current_item = head = new_item; 1372 } 1373 else 1374 { 1375 /* add to the end and advance */ 1376 current_item->next = new_item; 1377 new_item->prev = current_item; 1378 current_item = new_item; 1379 } 1380 1381 /* parse the name of the child */ 1382 input = skip(input + 1); /* skip whitespaces before name */ 1383 input = parse_string(current_item, input, error_pointer); 1384 input = skip(input); /* skip whitespaces after name */ 1385 if (input == NULL) 1386 { 1387 goto fail; /* faile to parse name */ 1388 } 1389 1390 /* swap valuestring and string, because we parsed the name */ 1391 current_item->string = current_item->valuestring; 1392 current_item->valuestring = NULL; 1393 1394 if (*input != ':') 1395 { 1396 *error_pointer = input; 1397 goto fail; /* invalid object */ 1398 } 1399 1400 /* parse the value */ 1401 input = skip(input + 1); /* skip whitespaces before value */ 1402 input = parse_value(current_item, input, error_pointer); 1403 input = skip(input); /* skip whitespaces after the value */ 1404 if (input == NULL) 1405 { 1406 goto fail; /* failed to parse value */ 1407 } 1408 } 1409 while (*input == ','); 1410 1411 if (*input != '}') 1412 { 1413 *error_pointer = input; 1414 goto fail; /* expected end of object */ 1415 } 1416 1417 success: 1418 item->type = cJSON_Object; 1419 item->child = head; 1420 1421 return input + 1; 1422 1423 fail: 1424 if (head != NULL) 1425 { 1426 cJSON_Delete(head); 1427 } 1428 1429 return NULL; 1430 } 1431 1432 /* Render an object to text. */ 1433 static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p) 1434 { 1435 unsigned char **entries = NULL; 1436 unsigned char **names = NULL; 1437 unsigned char *out = NULL; 1438 unsigned char *ptr = NULL; 1439 unsigned char *ret = NULL; 1440 unsigned char *str = NULL; 1441 size_t len = 7; 1442 size_t i = 0; 1443 size_t j = 0; 1444 cJSON *child = item->child; 1445 size_t numentries = 0; 1446 cjbool fail = false; 1447 size_t tmplen = 0; 1448 1449 /* Count the number of entries. */ 1450 while (child) 1451 { 1452 numentries++; 1453 child = child->next; 1454 } 1455 1456 /* Explicitly handle empty object case */ 1457 if (!numentries) 1458 { 1459 if (p) 1460 { 1461 out = ensure(p, fmt ? depth + 4 : 3); 1462 } 1463 else 1464 { 1465 out = (unsigned char*)cJSON_malloc(fmt ? depth + 4 : 3); 1466 } 1467 if (!out) 1468 { 1469 return NULL; 1470 } 1471 ptr = out; 1472 *ptr++ = '{'; 1473 if (fmt) { 1474 *ptr++ = '\n'; 1475 for (i = 0; i < depth; i++) 1476 { 1477 *ptr++ = '\t'; 1478 } 1479 } 1480 *ptr++ = '}'; 1481 *ptr++ = '\0'; 1482 1483 return out; 1484 } 1485 1486 if (p) 1487 { 1488 /* Compose the output: */ 1489 i = p->offset; 1490 len = fmt ? 2 : 1; /* fmt: {\n */ 1491 ptr = ensure(p, len + 1); 1492 if (!ptr) 1493 { 1494 return NULL; 1495 } 1496 1497 *ptr++ = '{'; 1498 if (fmt) 1499 { 1500 *ptr++ = '\n'; 1501 } 1502 *ptr = '\0'; 1503 p->offset += len; 1504 1505 child = item->child; 1506 depth++; 1507 while (child) 1508 { 1509 if (fmt) 1510 { 1511 ptr = ensure(p, depth); 1512 if (!ptr) 1513 { 1514 return NULL; 1515 } 1516 for (j = 0; j < depth; j++) 1517 { 1518 *ptr++ = '\t'; 1519 } 1520 p->offset += depth; 1521 } 1522 1523 /* print key */ 1524 if (!print_string_ptr((unsigned char*)child->string, p)) 1525 { 1526 return NULL; 1527 } 1528 p->offset = update(p); 1529 1530 len = fmt ? 2 : 1; 1531 ptr = ensure(p, len); 1532 if (!ptr) 1533 { 1534 return NULL; 1535 } 1536 *ptr++ = ':'; 1537 if (fmt) 1538 { 1539 *ptr++ = '\t'; 1540 } 1541 p->offset+=len; 1542 1543 /* print value */ 1544 if (!print_value(child, depth, fmt, p)) 1545 { 1546 return NULL; 1547 }; 1548 p->offset = update(p); 1549 1550 /* print comma if not last */ 1551 len = (size_t) (fmt ? 1 : 0) + (child->next ? 1 : 0); 1552 ptr = ensure(p, len + 1); 1553 if (!ptr) 1554 { 1555 return NULL; 1556 } 1557 if (child->next) 1558 { 1559 *ptr++ = ','; 1560 } 1561 1562 if (fmt) 1563 { 1564 *ptr++ = '\n'; 1565 } 1566 *ptr = '\0'; 1567 p->offset += len; 1568 1569 child = child->next; 1570 } 1571 1572 ptr = ensure(p, fmt ? (depth + 1) : 2); 1573 if (!ptr) 1574 { 1575 return NULL; 1576 } 1577 if (fmt) 1578 { 1579 for (i = 0; i < (depth - 1); i++) 1580 { 1581 *ptr++ = '\t'; 1582 } 1583 } 1584 *ptr++ = '}'; 1585 *ptr = '\0'; 1586 out = (p->buffer) + i; 1587 } 1588 else 1589 { 1590 /* Allocate space for the names and the objects */ 1591 entries = (unsigned char**)cJSON_malloc(numentries * sizeof(unsigned char*)); 1592 if (!entries) 1593 { 1594 return NULL; 1595 } 1596 names = (unsigned char**)cJSON_malloc(numentries * sizeof(unsigned char*)); 1597 if (!names) 1598 { 1599 cJSON_free(entries); 1600 return NULL; 1601 } 1602 memset(entries, '\0', sizeof(unsigned char*) * numentries); 1603 memset(names, '\0', sizeof(unsigned char*) * numentries); 1604 1605 /* Collect all the results into our arrays: */ 1606 child = item->child; 1607 depth++; 1608 if (fmt) 1609 { 1610 len += depth; 1611 } 1612 while (child && !fail) 1613 { 1614 names[i] = str = print_string_ptr((unsigned char*)child->string, 0); /* print key */ 1615 entries[i++] = ret = print_value(child, depth, fmt, 0); 1616 if (str && ret) 1617 { 1618 len += strlen((char*)ret) + strlen((char*)str) + 2 + (fmt ? 2 + depth : 0); 1619 } 1620 else 1621 { 1622 fail = true; 1623 } 1624 child = child->next; 1625 } 1626 1627 /* Try to allocate the output string */ 1628 if (!fail) 1629 { 1630 out = (unsigned char*)cJSON_malloc(len); 1631 } 1632 if (!out) 1633 { 1634 fail = true; 1635 } 1636 1637 /* Handle failure */ 1638 if (fail) 1639 { 1640 /* free all the printed keys and values */ 1641 for (i = 0; i < numentries; i++) 1642 { 1643 if (names[i]) 1644 { 1645 cJSON_free(names[i]); 1646 } 1647 if (entries[i]) 1648 { 1649 cJSON_free(entries[i]); 1650 } 1651 } 1652 cJSON_free(names); 1653 cJSON_free(entries); 1654 return NULL; 1655 } 1656 1657 /* Compose the output: */ 1658 *out = '{'; 1659 ptr = out + 1; 1660 if (fmt) 1661 { 1662 *ptr++ = '\n'; 1663 } 1664 *ptr = '\0'; 1665 for (i = 0; i < numentries; i++) 1666 { 1667 if (fmt) 1668 { 1669 for (j = 0; j < depth; j++) 1670 { 1671 *ptr++='\t'; 1672 } 1673 } 1674 tmplen = strlen((char*)names[i]); 1675 memcpy(ptr, names[i], tmplen); 1676 ptr += tmplen; 1677 *ptr++ = ':'; 1678 if (fmt) 1679 { 1680 *ptr++ = '\t'; 1681 } 1682 strcpy((char*)ptr, (char*)entries[i]); 1683 ptr += strlen((char*)entries[i]); 1684 if (i != (numentries - 1)) 1685 { 1686 *ptr++ = ','; 1687 } 1688 if (fmt) 1689 { 1690 *ptr++ = '\n'; 1691 } 1692 *ptr = '\0'; 1693 cJSON_free(names[i]); 1694 cJSON_free(entries[i]); 1695 } 1696 1697 cJSON_free(names); 1698 cJSON_free(entries); 1699 if (fmt) 1700 { 1701 for (i = 0; i < (depth - 1); i++) 1702 { 1703 *ptr++ = '\t'; 1704 } 1705 } 1706 *ptr++ = '}'; 1707 *ptr++ = '\0'; 1708 } 1709 1710 return out; 1711 } 1712 1713 /* Get Array size/item / object item. */ 1714 int cJSON_GetArraySize(const cJSON *array) 1715 { 1716 cJSON *c = array->child; 1717 size_t i = 0; 1718 while(c) 1719 { 1720 i++; 1721 c = c->next; 1722 } 1723 1724 /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ 1725 1726 return (int)i; 1727 } 1728 1729 cJSON *cJSON_GetArrayItem(const cJSON *array, int item) 1730 { 1731 cJSON *c = array ? array->child : NULL; 1732 while (c && item > 0) 1733 { 1734 item--; 1735 c = c->next; 1736 } 1737 1738 return c; 1739 } 1740 1741 cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string) 1742 { 1743 cJSON *c = object ? object->child : NULL; 1744 while (c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string)) 1745 { 1746 c = c->next; 1747 } 1748 return c; 1749 } 1750 1751 cjbool cJSON_HasObjectItem(const cJSON *object, const char *string) 1752 { 1753 return cJSON_GetObjectItem(object, string) ? 1 : 0; 1754 } 1755 1756 /* Utility for array list handling. */ 1757 static void suffix_object(cJSON *prev, cJSON *item) 1758 { 1759 prev->next = item; 1760 item->prev = prev; 1761 } 1762 1763 /* Utility for handling references. */ 1764 static cJSON *create_reference(const cJSON *item) 1765 { 1766 cJSON *ref = cJSON_New_Item(); 1767 if (!ref) 1768 { 1769 return NULL; 1770 } 1771 memcpy(ref, item, sizeof(cJSON)); 1772 ref->string = NULL; 1773 ref->type |= cJSON_IsReference; 1774 ref->next = ref->prev = NULL; 1775 return ref; 1776 } 1777 1778 /* Add item to array/object. */ 1779 void cJSON_AddItemToArray(cJSON *array, cJSON *item) 1780 { 1781 cJSON *child = NULL; 1782 1783 if ((item == NULL) || (array == NULL)) 1784 { 1785 return; 1786 } 1787 1788 child = array->child; 1789 1790 if (child == NULL) 1791 { 1792 /* list is empty, start new one */ 1793 array->child = item; 1794 } 1795 else 1796 { 1797 /* append to the end */ 1798 while (child->next) 1799 { 1800 child = child->next; 1801 } 1802 suffix_object(child, item); 1803 } 1804 } 1805 1806 void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) 1807 { 1808 /* call cJSON_AddItemToObjectCS for code reuse */ 1809 cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string), item); 1810 /* remove cJSON_StringIsConst flag */ 1811 item->type &= ~cJSON_StringIsConst; 1812 } 1813 1814 /* Add an item to an object with constant string as key */ 1815 void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) 1816 { 1817 if (!item) 1818 { 1819 return; 1820 } 1821 if (!(item->type & cJSON_StringIsConst) && item->string) 1822 { 1823 cJSON_free(item->string); 1824 } 1825 #pragma GCC diagnostic push 1826 #pragma GCC diagnostic ignored "-Wcast-qual" 1827 item->string = (char*)string; 1828 #pragma GCC diagnostic pop 1829 item->type |= cJSON_StringIsConst; 1830 cJSON_AddItemToArray(object, item); 1831 } 1832 1833 void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) 1834 { 1835 cJSON_AddItemToArray(array, create_reference(item)); 1836 } 1837 1838 void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) 1839 { 1840 cJSON_AddItemToObject(object, string, create_reference(item)); 1841 } 1842 1843 static cJSON *DetachItemFromArray(cJSON *array, size_t which) 1844 { 1845 cJSON *c = array->child; 1846 while (c && (which > 0)) 1847 { 1848 c = c->next; 1849 which--; 1850 } 1851 if (!c) 1852 { 1853 /* item doesn't exist */ 1854 return NULL; 1855 } 1856 if (c->prev) 1857 { 1858 /* not the first element */ 1859 c->prev->next = c->next; 1860 } 1861 if (c->next) 1862 { 1863 c->next->prev = c->prev; 1864 } 1865 if (c==array->child) 1866 { 1867 array->child = c->next; 1868 } 1869 /* make sure the detached item doesn't point anywhere anymore */ 1870 c->prev = c->next = NULL; 1871 1872 return c; 1873 } 1874 cJSON *cJSON_DetachItemFromArray(cJSON *array, int which) 1875 { 1876 if (which < 0) 1877 { 1878 return NULL; 1879 } 1880 1881 return DetachItemFromArray(array, (size_t)which); 1882 } 1883 1884 void cJSON_DeleteItemFromArray(cJSON *array, int which) 1885 { 1886 cJSON_Delete(cJSON_DetachItemFromArray(array, which)); 1887 } 1888 1889 cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string) 1890 { 1891 size_t i = 0; 1892 cJSON *c = object->child; 1893 while (c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string)) 1894 { 1895 i++; 1896 c = c->next; 1897 } 1898 if (c) 1899 { 1900 return DetachItemFromArray(object, i); 1901 } 1902 1903 return NULL; 1904 } 1905 1906 void cJSON_DeleteItemFromObject(cJSON *object, const char *string) 1907 { 1908 cJSON_Delete(cJSON_DetachItemFromObject(object, string)); 1909 } 1910 1911 /* Replace array/object items with new ones. */ 1912 void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) 1913 { 1914 cJSON *c = array->child; 1915 while (c && (which > 0)) 1916 { 1917 c = c->next; 1918 which--; 1919 } 1920 if (!c) 1921 { 1922 cJSON_AddItemToArray(array, newitem); 1923 return; 1924 } 1925 newitem->next = c; 1926 newitem->prev = c->prev; 1927 c->prev = newitem; 1928 if (c == array->child) 1929 { 1930 array->child = newitem; 1931 } 1932 else 1933 { 1934 newitem->prev->next = newitem; 1935 } 1936 } 1937 1938 static void ReplaceItemInArray(cJSON *array, size_t which, cJSON *newitem) 1939 { 1940 cJSON *c = array->child; 1941 while (c && (which > 0)) 1942 { 1943 c = c->next; 1944 which--; 1945 } 1946 if (!c) 1947 { 1948 return; 1949 } 1950 newitem->next = c->next; 1951 newitem->prev = c->prev; 1952 if (newitem->next) 1953 { 1954 newitem->next->prev = newitem; 1955 } 1956 if (c == array->child) 1957 { 1958 array->child = newitem; 1959 } 1960 else 1961 { 1962 newitem->prev->next = newitem; 1963 } 1964 c->next = c->prev = NULL; 1965 cJSON_Delete(c); 1966 } 1967 void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) 1968 { 1969 if (which < 0) 1970 { 1971 return; 1972 } 1973 1974 ReplaceItemInArray(array, (size_t)which, newitem); 1975 } 1976 1977 void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) 1978 { 1979 size_t i = 0; 1980 cJSON *c = object->child; 1981 while(c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string)) 1982 { 1983 i++; 1984 c = c->next; 1985 } 1986 if(c) 1987 { 1988 /* free the old string if not const */ 1989 if (!(newitem->type & cJSON_StringIsConst) && newitem->string) 1990 { 1991 cJSON_free(newitem->string); 1992 } 1993 1994 newitem->string = (char*)cJSON_strdup((const unsigned char*)string); 1995 ReplaceItemInArray(object, i, newitem); 1996 } 1997 } 1998 1999 /* Create basic types: */ 2000 cJSON *cJSON_CreateNull(void) 2001 { 2002 cJSON *item = cJSON_New_Item(); 2003 if(item) 2004 { 2005 item->type = cJSON_NULL; 2006 } 2007 2008 return item; 2009 } 2010 2011 cJSON *cJSON_CreateTrue(void) 2012 { 2013 cJSON *item = cJSON_New_Item(); 2014 if(item) 2015 { 2016 item->type = cJSON_True; 2017 } 2018 2019 return item; 2020 } 2021 2022 cJSON *cJSON_CreateFalse(void) 2023 { 2024 cJSON *item = cJSON_New_Item(); 2025 if(item) 2026 { 2027 item->type = cJSON_False; 2028 } 2029 2030 return item; 2031 } 2032 2033 cJSON *cJSON_CreateBool(cjbool b) 2034 { 2035 cJSON *item = cJSON_New_Item(); 2036 if(item) 2037 { 2038 item->type = b ? cJSON_True : cJSON_False; 2039 } 2040 2041 return item; 2042 } 2043 2044 cJSON *cJSON_CreateNumber(double num) 2045 { 2046 cJSON *item = cJSON_New_Item(); 2047 if(item) 2048 { 2049 item->type = cJSON_Number; 2050 item->valuedouble = num; 2051 2052 /* use saturation in case of overflow */ 2053 if (num >= INT_MAX) 2054 { 2055 item->valueint = INT_MAX; 2056 } 2057 else if (num <= INT_MIN) 2058 { 2059 item->valueint = INT_MIN; 2060 } 2061 else 2062 { 2063 item->valueint = (int)num; 2064 } 2065 } 2066 2067 return item; 2068 } 2069 2070 cJSON *cJSON_CreateString(const char *string) 2071 { 2072 cJSON *item = cJSON_New_Item(); 2073 if(item) 2074 { 2075 item->type = cJSON_String; 2076 item->valuestring = (char*)cJSON_strdup((const unsigned char*)string); 2077 if(!item->valuestring) 2078 { 2079 cJSON_Delete(item); 2080 return NULL; 2081 } 2082 } 2083 2084 return item; 2085 } 2086 2087 extern cJSON *cJSON_CreateRaw(const char *raw) 2088 { 2089 cJSON *item = cJSON_New_Item(); 2090 if(item) 2091 { 2092 item->type = cJSON_Raw; 2093 item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw); 2094 if(!item->valuestring) 2095 { 2096 cJSON_Delete(item); 2097 return NULL; 2098 } 2099 } 2100 2101 return item; 2102 } 2103 2104 cJSON *cJSON_CreateArray(void) 2105 { 2106 cJSON *item = cJSON_New_Item(); 2107 if(item) 2108 { 2109 item->type=cJSON_Array; 2110 } 2111 2112 return item; 2113 } 2114 2115 cJSON *cJSON_CreateObject(void) 2116 { 2117 cJSON *item = cJSON_New_Item(); 2118 if (item) 2119 { 2120 item->type = cJSON_Object; 2121 } 2122 2123 return item; 2124 } 2125 2126 /* Create Arrays: */ 2127 cJSON *cJSON_CreateIntArray(const int *numbers, int count) 2128 { 2129 size_t i = 0; 2130 cJSON *n = NULL; 2131 cJSON *p = NULL; 2132 cJSON *a = NULL; 2133 2134 if (count < 0) 2135 { 2136 return NULL; 2137 } 2138 2139 a = cJSON_CreateArray(); 2140 for(i = 0; a && (i < (size_t)count); i++) 2141 { 2142 n = cJSON_CreateNumber(numbers[i]); 2143 if (!n) 2144 { 2145 cJSON_Delete(a); 2146 return NULL; 2147 } 2148 if(!i) 2149 { 2150 a->child = n; 2151 } 2152 else 2153 { 2154 suffix_object(p, n); 2155 } 2156 p = n; 2157 } 2158 2159 return a; 2160 } 2161 2162 cJSON *cJSON_CreateFloatArray(const float *numbers, int count) 2163 { 2164 size_t i = 0; 2165 cJSON *n = NULL; 2166 cJSON *p = NULL; 2167 cJSON *a = NULL; 2168 2169 if (count < 0) 2170 { 2171 return NULL; 2172 } 2173 2174 a = cJSON_CreateArray(); 2175 2176 for(i = 0; a && (i < (size_t)count); i++) 2177 { 2178 n = cJSON_CreateNumber(numbers[i]); 2179 if(!n) 2180 { 2181 cJSON_Delete(a); 2182 return NULL; 2183 } 2184 if(!i) 2185 { 2186 a->child = n; 2187 } 2188 else 2189 { 2190 suffix_object(p, n); 2191 } 2192 p = n; 2193 } 2194 2195 return a; 2196 } 2197 2198 cJSON *cJSON_CreateDoubleArray(const double *numbers, int count) 2199 { 2200 size_t i = 0; 2201 cJSON *n = NULL; 2202 cJSON *p = NULL; 2203 cJSON *a = NULL; 2204 2205 if (count < 0) 2206 { 2207 return NULL; 2208 } 2209 2210 a = cJSON_CreateArray(); 2211 2212 for(i = 0;a && (i < (size_t)count); i++) 2213 { 2214 n = cJSON_CreateNumber(numbers[i]); 2215 if(!n) 2216 { 2217 cJSON_Delete(a); 2218 return NULL; 2219 } 2220 if(!i) 2221 { 2222 a->child = n; 2223 } 2224 else 2225 { 2226 suffix_object(p, n); 2227 } 2228 p = n; 2229 } 2230 2231 return a; 2232 } 2233 2234 cJSON *cJSON_CreateStringArray(const char **strings, int count) 2235 { 2236 size_t i = 0; 2237 cJSON *n = NULL; 2238 cJSON *p = NULL; 2239 cJSON *a = NULL; 2240 2241 if (count < 0) 2242 { 2243 return NULL; 2244 } 2245 2246 a = cJSON_CreateArray(); 2247 2248 for (i = 0; a && (i < (size_t)count); i++) 2249 { 2250 n = cJSON_CreateString(strings[i]); 2251 if(!n) 2252 { 2253 cJSON_Delete(a); 2254 return NULL; 2255 } 2256 if(!i) 2257 { 2258 a->child = n; 2259 } 2260 else 2261 { 2262 suffix_object(p,n); 2263 } 2264 p = n; 2265 } 2266 2267 return a; 2268 } 2269 2270 /* Duplication */ 2271 cJSON *cJSON_Duplicate(const cJSON *item, cjbool recurse) 2272 { 2273 cJSON *newitem = NULL; 2274 cJSON *child = NULL; 2275 cJSON *next = NULL; 2276 cJSON *newchild = NULL; 2277 2278 /* Bail on bad ptr */ 2279 if (!item) 2280 { 2281 goto fail; 2282 } 2283 /* Create new item */ 2284 newitem = cJSON_New_Item(); 2285 if (!newitem) 2286 { 2287 goto fail; 2288 } 2289 /* Copy over all vars */ 2290 newitem->type = item->type & (~cJSON_IsReference); 2291 newitem->valueint = item->valueint; 2292 newitem->valuedouble = item->valuedouble; 2293 if (item->valuestring) 2294 { 2295 newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring); 2296 if (!newitem->valuestring) 2297 { 2298 goto fail; 2299 } 2300 } 2301 if (item->string) 2302 { 2303 newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string); 2304 if (!newitem->string) 2305 { 2306 goto fail; 2307 } 2308 } 2309 /* If non-recursive, then we're done! */ 2310 if (!recurse) 2311 { 2312 return newitem; 2313 } 2314 /* Walk the ->next chain for the child. */ 2315 child = item->child; 2316 while (child != NULL) 2317 { 2318 newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ 2319 if (!newchild) 2320 { 2321 goto fail; 2322 } 2323 if (next != NULL) 2324 { 2325 /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 2326 next->next = newchild; 2327 newchild->prev = next; 2328 next = newchild; 2329 } 2330 else 2331 { 2332 /* Set newitem->child and move to it */ 2333 newitem->child = newchild; 2334 next = newchild; 2335 } 2336 child = child->next; 2337 } 2338 2339 return newitem; 2340 2341 fail: 2342 if (newitem != NULL) 2343 { 2344 cJSON_Delete(newitem); 2345 } 2346 2347 return NULL; 2348 } 2349 2350 void cJSON_Minify(char *json) 2351 { 2352 unsigned char *into = (unsigned char*)json; 2353 while (*json) 2354 { 2355 if (*json == ' ') 2356 { 2357 json++; 2358 } 2359 else if (*json == '\t') 2360 { 2361 /* Whitespace characters. */ 2362 json++; 2363 } 2364 else if (*json == '\r') 2365 { 2366 json++; 2367 } 2368 else if (*json=='\n') 2369 { 2370 json++; 2371 } 2372 else if ((*json == '/') && (json[1] == '/')) 2373 { 2374 /* double-slash comments, to end of line. */ 2375 while (*json && (*json != '\n')) 2376 { 2377 json++; 2378 } 2379 } 2380 else if ((*json == '/') && (json[1] == '*')) 2381 { 2382 /* multiline comments. */ 2383 while (*json && !((*json == '*') && (json[1] == '/'))) 2384 { 2385 json++; 2386 } 2387 json += 2; 2388 } 2389 else if (*json == '\"') 2390 { 2391 /* string literals, which are \" sensitive. */ 2392 *into++ = (unsigned char)*json++; 2393 while (*json && (*json != '\"')) 2394 { 2395 if (*json == '\\') 2396 { 2397 *into++ = (unsigned char)*json++; 2398 } 2399 *into++ = (unsigned char)*json++; 2400 } 2401 *into++ = (unsigned char)*json++; 2402 } 2403 else 2404 { 2405 /* All other characters. */ 2406 *into++ = (unsigned char)*json++; 2407 } 2408 } 2409 2410 /* and null-terminate. */ 2411 *into = '\0'; 2412 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 Copyright (c) 2009 Dave Gamble 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 THE SOFTWARE. 21 */ 22 23 #ifndef cJSON__h 24 #define cJSON__h 25 26 #ifdef __cplusplus 27 extern "C" 28 { 29 #endif 30 31 /* project version */ 32 #define CJSON_VERSION_MAJOR 1 33 #define CJSON_VERSION_MINOR 3 34 #define CJSON_VERSION_PATCH 0 35 36 /* returns the version of cJSON as a string */ 37 extern const char* cJSON_Version(void); 38 39 #include <stddef.h> 40 41 /* cJSON Types: */ 42 #define cJSON_Invalid (0) 43 #define cJSON_False (1 << 0) 44 #define cJSON_True (1 << 1) 45 #define cJSON_NULL (1 << 2) 46 #define cJSON_Number (1 << 3) 47 #define cJSON_String (1 << 4) 48 #define cJSON_Array (1 << 5) 49 #define cJSON_Object (1 << 6) 50 #define cJSON_Raw (1 << 7) /* raw json */ 51 52 #define cJSON_IsReference 256 53 #define cJSON_StringIsConst 512 54 55 /* The cJSON structure: */ 56 typedef struct cJSON 57 { 58 /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 59 struct cJSON *next; 60 struct cJSON *prev; 61 /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 62 struct cJSON *child; 63 64 /* The type of the item, as above. */ 65 int type; 66 67 /* The item's string, if type==cJSON_String and type == cJSON_Raw */ 68 char *valuestring; 69 /* The item's number, if type==cJSON_Number */ 70 int valueint; 71 /* The item's number, if type==cJSON_Number */ 72 double valuedouble; 73 74 /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 75 char *string; 76 } cJSON; 77 78 typedef struct cJSON_Hooks 79 { 80 void *(*malloc_fn)(size_t sz); 81 void (*free_fn)(void *ptr); 82 } cJSON_Hooks; 83 84 /* Supply malloc, realloc and free functions to cJSON */ 85 extern void cJSON_InitHooks(cJSON_Hooks* hooks); 86 87 88 /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ 89 extern cJSON *cJSON_Parse(const char *value); 90 /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ 91 extern char *cJSON_Print(const cJSON *item); 92 /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ 93 extern char *cJSON_PrintUnformatted(const cJSON *item); 94 /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 95 extern char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt); 96 /* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len. Returns 1 on success and 0 on failure. */ 97 extern int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt); 98 /* Delete a cJSON entity and all subentities. */ 99 extern void cJSON_Delete(cJSON *c); 100 101 /* Returns the number of items in an array (or object). */ 102 extern int cJSON_GetArraySize(const cJSON *array); 103 /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ 104 extern cJSON *cJSON_GetArrayItem(const cJSON *array, int item); 105 /* Get item "string" from object. Case insensitive. */ 106 extern cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string); 107 extern int cJSON_HasObjectItem(const cJSON *object, const char *string); 108 /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ 109 extern const char *cJSON_GetErrorPtr(void); 110 111 /* These calls create a cJSON item of the appropriate type. */ 112 extern cJSON *cJSON_CreateNull(void); 113 extern cJSON *cJSON_CreateTrue(void); 114 extern cJSON *cJSON_CreateFalse(void); 115 extern cJSON *cJSON_CreateBool(int b); 116 extern cJSON *cJSON_CreateNumber(double num); 117 extern cJSON *cJSON_CreateString(const char *string); 118 /* raw json */ 119 extern cJSON *cJSON_CreateRaw(const char *raw); 120 extern cJSON *cJSON_CreateArray(void); 121 extern cJSON *cJSON_CreateObject(void); 122 123 /* These utilities create an Array of count items. */ 124 extern cJSON *cJSON_CreateIntArray(const int *numbers, int count); 125 extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count); 126 extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count); 127 extern cJSON *cJSON_CreateStringArray(const char **strings, int count); 128 129 /* Append item to the specified array/object. */ 130 extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); 131 extern void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); 132 /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. 133 * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before 134 * writing to `item->string` */ 135 extern void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); 136 /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ 137 extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 138 extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); 139 140 /* Remove/Detatch items from Arrays/Objects. */ 141 extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which); 142 extern void cJSON_DeleteItemFromArray(cJSON *array, int which); 143 extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string); 144 extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string); 145 146 /* Update array items. */ 147 extern void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ 148 extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); 149 extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 150 151 /* Duplicate a cJSON item */ 152 extern cJSON *cJSON_Duplicate(const cJSON *item, int recurse); 153 /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 154 need to be released. With recurse!=0, it will duplicate any children connected to the item. 155 The item->next and ->prev pointers are always zero on return from Duplicate. */ 156 157 /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 158 /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ 159 extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated); 160 161 extern void cJSON_Minify(char *json); 162 163 /* Macros for creating things quickly. */ 164 #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) 165 #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) 166 #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) 167 #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) 168 #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) 169 #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) 170 #define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) 171 172 /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 173 #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) 174 /* helper for the cJSON_SetNumberValue macro */ 175 extern double cJSON_SetNumberHelper(cJSON *object, double number); 176 #define cJSON_SetNumberValue(object, number) ((object) ? cJSON_SetNumberHelper(object, (double)number) : (number)) 177 178 /* Macro for iterating over an array */ 179 #define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next) 180 181 #ifdef __cplusplus 182 } 183 #endif 184 185 #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #include "cJSON.h" 4 5 int main(int argc, const char* argv[]) 6 { 7 if(argc < 2) 8 { 9 printf("./a.out jsonfile\n"); 10 return 0; 11 } 12 13 // 加载json文件 14 FILE* fp = fopen(argv[1], "r"); 15 char buf[1024] = {0}; 16 fread(buf, 1, sizeof(buf), fp); 17 cJSON* root = cJSON_Parse(buf); 18 19 cJSON* subobj = cJSON_GetObjectItem(root, "奔驰"); 20 // 判断对象是否存在 21 if( subobj ) 22 { 23 // 获取子对象 24 cJSON* factory = cJSON_GetObjectItem(subobj, "factory"); 25 cJSON* last = cJSON_GetObjectItem(subobj, "last"); 26 cJSON* price = cJSON_GetObjectItem(subobj, "price"); 27 cJSON* sell = cJSON_GetObjectItem(subobj, "sell"); 28 cJSON* sum = cJSON_GetObjectItem(subobj, "sum"); 29 cJSON* other = cJSON_GetObjectItem(subobj, "other"); 30 31 // 打印value值 32 printf("奔驰:\n"); 33 printf(" factory: %s\n", cJSON_Print(factory)); 34 printf(" last: %s\n", cJSON_Print(last)); 35 printf(" price: %s\n", cJSON_Print(price)); 36 printf(" sell: %s\n", cJSON_Print(sell)); 37 printf(" sum: %s\n", cJSON_Print(sum)); 38 39 // 打印数组内容 40 printf(" other:\n"); 41 if(other->type == cJSON_Array) 42 { 43 for(int i=0; i<cJSON_GetArraySize(other); ++i) 44 { 45 cJSON* node = cJSON_GetArrayItem(other, i); 46 // 判断数据类型 47 if(node->type == cJSON_String) 48 { 49 printf(" %s \n", node->valuestring); 50 } 51 if(node->type == cJSON_Number) 52 { 53 printf(" %d\n", node->valueint); 54 } 55 if(node->type == cJSON_True) 56 { 57 printf(" %d\n", node->valueint); 58 } 59 if(node->type == cJSON_False) 60 { 61 printf(" %d\n", node->valueint); 62 } 63 } 64 } 65 } 66 67 cJSON_Delete(root); 68 fclose(fp); 69 70 71 return 0; 72 }
注意:上面的cJSON.c和cJSON.h是 cJSON-master.zip包里面的。
cJSON结构体:
#define cJSON_Invalid (0) #define cJSON_False (1 << 0) #define cJSON_True (1 << 1) #define cJSON_NULL (1 << 2) #define cJSON_Number (1 << 3) #define cJSON_String (1 << 4) #define cJSON_Array (1 << 5) #define cJSON_Object (1 << 6) #define cJSON_Raw (1 << 7) /* The cJSON structure: */ typedef struct cJSON { struct cJSON *next; struct cJSON *prev; struct cJSON *child; int type; char *valuestring; int valueint; double valuedouble; char *string; } cJSON;