• 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

    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>
    create_xml.xml
     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 }
    create.c
     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
    ", mxmlElementGetAttr(book, "category"));
    13 
    14     mxml_node_t* node = mxmlWalkNext(book, root, MXML_DESCEND_FIRST);
    15     printf("    title: %s
    ", mxmlGetText(node, 0)); 
    16 
    17     node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
    18     printf("    author: %s
    ", mxmlGetText(node, 0)); 
    19 
    20     node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
    21     printf("    year: %s
    ", mxmlGetText(node, 0)); 
    22 
    23     node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
    24     printf("    price: %s
    ", mxmlGetText(node, 0)); 
    25 
    26     fclose(fp);
    27 
    28     mxmlDelete(root);
    29 
    30     return 0;
    31 }
    parsexml.c

    (2)生成下面的xml

     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>
    create_xml.xml
     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 }
    create.c
     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
    ");
    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
    ");
    22         return 0;
    23     }
    24     while( city  )
    25     {
    26         printf("==================
    ");
    27         // 向下走一个节点
    28         mxml_node_t* node = mxmlWalkNext(city, root, MXML_DESCEND_FIRST);
    29         printf("city:   
    ");
    30         printf("    name = %s
    ", mxmlGetText(node, NULL));
    31         // 
    32         node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
    33         printf("    area = %s
    ", mxmlGetText(node, NULL));
    34         //
    35         node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
    36         printf("    population = %s
    ", 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 }
    parse_xml.c

    (3)xml 解析注意问题 

        注意:使用 minixml 开源库生成的 xml 会在一行,如果手动将调整 xml,则解析会有问题。下面的示例相同的xml,只是将在一行的xml进行调整,注意运行查看解析结果。

     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>
    car1.xml
    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>
    car2.xml
     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
    ");
     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
    ", 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
    ", mxmlGetText(node, 0));
    30             // color
    31             node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
    32             printf("    color: %s
    ", mxmlGetText(node, 0));
    33             // price
    34             node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
    35             printf("    price: %s
    ", mxmlGetText(node, 0));
    36             printf("    =========================================
    ");
    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 }
    parsecar.c

    上面代码编译: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

     1 {
     2     "奔驰":    {
     3         "factory":    "一汽大众",
     4         "last":    31,
     5         "price":    83,
     6         "sell":    49,
     7         "sum":    80,
     8         "other":    [124, "hello, world", false]
     9     }
    10 }
    car.json
     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 }
    create_car.c
       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 == '')
      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, '', 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; /* uXXXXuXXXX */
     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 != ''))
     563         {
     564             /* is escape sequence */
     565             if (input_end[0] == '\')
     566             {
     567                 if (input_end[1] == '')
     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 == '')
     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(''));
     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++ = '';
     607                     break;
     608                 case 'f':
     609                     *output_pointer++ = 'f';
     610                     break;
     611                 case 'n':
     612                     *output_pointer++ = '
    ';
     613                     break;
     614                 case 'r':
     615                     *output_pointer++ = '
    ';
     616                     break;
     617                 case 't':
     618                     *output_pointer++ = '	';
     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 = '';
     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 = '';
     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] = '';
     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(""\f
    
    	", 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 '':
     779                     *ptr2++ = 'b';
     780                     break;
     781                 case 'f':
     782                     *ptr2++ = 'f';
     783                     break;
     784                 case '
    ':
     785                     *ptr2++ = 'n';
     786                     break;
     787                 case '
    ':
     788                     *ptr2++ = 'r';
     789                     break;
     790                 case '	':
     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++ = '';
     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('');
    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 = '';
    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 = '';
    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, '', 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 = '';
    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 = '';
    1326             }
    1327             cJSON_free(entries[i]);
    1328         }
    1329         cJSON_free(entries);
    1330         *ptr++ = ']';
    1331         *ptr++ = '';
    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++ = '
    ';
    1475             for (i = 0; i < depth; i++)
    1476             {
    1477                 *ptr++ = '	';
    1478             }
    1479         }
    1480         *ptr++ = '}';
    1481         *ptr++ = '';
    1482 
    1483         return out;
    1484     }
    1485 
    1486     if (p)
    1487     {
    1488         /* Compose the output: */
    1489         i = p->offset;
    1490         len = fmt ? 2 : 1; /* fmt: {
     */
    1491         ptr = ensure(p, len + 1);
    1492         if (!ptr)
    1493         {
    1494             return NULL;
    1495         }
    1496 
    1497         *ptr++ = '{';
    1498         if (fmt)
    1499         {
    1500             *ptr++ = '
    ';
    1501         }
    1502         *ptr = '';
    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++ = '	';
    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++ = '	';
    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++ = '
    ';
    1565             }
    1566             *ptr = '';
    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++ = '	';
    1582             }
    1583         }
    1584         *ptr++ = '}';
    1585         *ptr = '';
    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, '', sizeof(unsigned char*) * numentries);
    1603         memset(names, '', 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++ = '
    ';
    1663         }
    1664         *ptr = '';
    1665         for (i = 0; i < numentries; i++)
    1666         {
    1667             if (fmt)
    1668             {
    1669                 for (j = 0; j < depth; j++)
    1670                 {
    1671                     *ptr++='	';
    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++ = '	';
    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++ = '
    ';
    1691             }
    1692             *ptr = '';
    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++ = '	';
    1704             }
    1705         }
    1706         *ptr++ = '}';
    1707         *ptr++ = '';
    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 == '	')
    2360         {
    2361             /* Whitespace characters. */
    2362             json++;
    2363         }
    2364         else if (*json == '
    ')
    2365         {
    2366             json++;
    2367         }
    2368         else if (*json=='
    ')
    2369         {
    2370             json++;
    2371         }
    2372         else if ((*json == '/') && (json[1] == '/'))
    2373         {
    2374             /* double-slash comments, to end of line. */
    2375             while (*json && (*json != '
    '))
    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 = '';
    2412 }
    cJSON.c
      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
    cJSON.h
     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
    ");
    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("奔驰:
    ");
    33         printf("    factory: %s
    ", cJSON_Print(factory));
    34         printf("    last: %s
    ", cJSON_Print(last));
    35         printf("    price: %s
    ", cJSON_Print(price));
    36         printf("    sell: %s
    ", cJSON_Print(sell));
    37         printf("    sum: %s
    ", cJSON_Print(sum));
    38 
    39         // 打印数组内容
    40         printf("    other:
    ");
    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  
    ", node->valuestring);
    50                 }
    51                 if(node->type == cJSON_Number)
    52                 {
    53                     printf("        %d
    ", node->valueint);
    54                 }
    55                 if(node->type == cJSON_True)
    56                 {
    57                     printf("        %d
    ", node->valueint);
    58                 }
    59                 if(node->type == cJSON_False)
    60                 {
    61                     printf("        %d
    ", node->valueint);
    62                 }
    63             }
    64         }
    65     }
    66 
    67     cJSON_Delete(root);
    68     fclose(fp);
    69 
    70 
    71     return 0;
    72 }
    parsejson.c

    注意:上面的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;
  • 相关阅读:
    B01-java学习-阶段2-面向对象
    A11-java学习-二维数组-面向对象概念-类的编写-测试类的编写-创建对象-使用对象-递归
    09-java学习-数组-冒泡排序-选择排序-数组工具类编写-查找-扩容
    08-java学习-数组-增强for循环-数组与方法-main函数参数
    07-java学习-方法重载-idea集成开发工具学习-项目-模块-包
    执行SQL语句---SELECT
    执行SQL语句---INSERT/UPDATE/DELETE
    undefined reference to `mysql_init'解决办法
    ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
    网络编程(三)---数据报套接字
  • 原文地址:https://www.cnblogs.com/xuejiale/p/10899035.html
Copyright © 2020-2023  润新知