zoukankan      html  css  js  c++  java
  • 不可不知的JSON处理库(cJSON)

    ANSI C中的超轻量级JSON解析器

    JSON(JavaScript对象表示法)是一种轻量级的数据交换格式。人类易于阅读和书写。机器很容易解析和生成。它基于JavaScript编程语言标准ECMA-262第三版(1999年12月)的子集 。JSON是一种完全独立于语言的文本格式,但是使用C语言家族(包括C,C ++,C#,Java,JavaScript,Perl,Python等)的程序员熟悉的约定。这些属性使JSON成为理想的数据交换语言。

    cJSON旨在成为您可以完成工作的最简单的解析器。它是资源只有一个C的头文件和C文件,所以方便移植。它可以为你各种需要的json字符串处理,包括打包、解析、修改、删除、添加等。在这里将一探究竟。

    在这里将着重叙述json的打包和解析,更多处理玩法,见文章末尾链接。

    开始cJSON

    cJSON合并到您的项目

    因为整个库只有一个C文件和一个头文件,所以您只需复制cJSON.h并复制cJSON.c到项目源并开始使用它。

    cJSON用ANSI C(C89)编写,以便支持尽可能多的平台和编译器。

    下载:

    https://github.com/DaveGamble/cJSON/releases

    Cjson结构体

    /* 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;

    结构体项解析:

    next 和prev :Cjson结构体作为一个双向连表的环,可以通过 next 和prev 指针进行连表遍历

    child:可以是cJSON_Array、cJSON_Object类型数据

    type:当前项的类型

    valuestring:内容存储,当类型是cJSON_String和cJSON_Raw

    valueint:内容存储,整型,可以是cJSON_False、cJSON_True数据

    valuedouble:内容存储,浮点型,当类型是cJSON_Number

    string:键名

    数据类型

    l  cJSON_Invalid表示一个不包含任何值的无效项目。如果将项目设置为全零字节,则将自动具有此类型。

    l  cJSON_False表示一个false布尔值。您也可以使用来检查布尔值cJSON_IsBool

    l  cJSON_True表示一个true布尔值。您也可以使用来检查布尔值cJSON_IsBool

    l  cJSON_NULL表示一个null值

    l  cJSON_Number 表示一个数字值。该值存储为double in valuedouble和in valueint。如果数字超出整数范围,INT_MAX或INT_MIN用于valueint

    l  cJSON_String表示一个字符串值。它以零终止字符串的形式存储在中valuestring

    l  cJSON_Array表示一个数组值。这是通过指向表示数组中值child的cJSON项目的链接列表来实现的。使用next和将元素链接在一起prev,其中第一个元素具有prev.next == NULL和最后一个元素next == NULL

    l  cJSON_Object 表示一个对象值。对象的存储方式与数组相同,唯一的区别是对象中的项将其键存储在中string

    l  cJSON_Raw表示以JSON字符存储的零终止形式的任何JSON valuestring。例如,可以使用它来避免一遍又一遍地打印相同的静态JSON以节省性能。解析时,cJSON永远不会创建此类型。另请注意,cJSON不会检查其是否为有效JSON。

    类型

    #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) /* raw json */

    类型判断

    cJSON_IsInvalid(const cJSON * const item);
    cJSON_IsFalse(const cJSON * const item);
    cJSON_IsTrue(const cJSON * const item);
    cJSON_IsBool(const cJSON * const item);
    cJSON_IsNull(const cJSON * const item);
    cJSON_IsNumber(const cJSON * const item);
    cJSON_IsString(const cJSON * const item);
    cJSON_IsArray(const cJSON * const item);
    cJSON_IsObject(const cJSON * const item);
    cJSON_IsRaw(const cJSON * const item);

    注意

    创建cjson对象后,处理完需要进行内存释放:

    如果是cjson里的对象,请使用cJSON_Delete()

    如果不是对象:cJSON_free()或free()

    零字符

    cJSON不支持包含零字符''或的字符串u0000。对于当前的API,这是不可能的,因为字符串以零结尾。

    字符编码

    cJSON仅支持UTF-8编码的输入。但是在大多数情况下,它不会拒绝无效的UTF-8作为输入,而只是将其原样传播。只要输入不包含无效的UTF-8,输出将始终是有效的UTF-8。

    C标准

    cJSON用ANSI C(或C89,C90)编写。如果您的编译器或C库未遵循此标准,则不能保证正确的行为。

    注意:ANSI C不是C ++,因此不应使用C ++编译器进行编译。您可以使用C编译器对其进行编译,然后将其与C ++代码链接。尽管可以使用C ++编译器进行编译,但是不能保证正确的行为。

    浮点数字

    double除IEEE754双精度浮点数外,cJSON不正式支持任何实现。它可能仍然可以与其他实现一起使用,但是这些实现的错误将被视为无效。

    目前,cJSON支持的浮点文字的最大长度为63个字符。

    数组和对象的深层嵌套

    cJSON不支持嵌套太深的数组和对象,因为这会导致堆栈溢出。为了防止这种CJSON_NESTING_LIMIT情况,默认情况下,cJSON将深度限制为1000,但是可以在编译时进行更改。

    格式化输出

    按标准的格式输出json字符串,输出完后一定要记得释放内存

     代码

     1 #include <stdio.h>
     2 #include "cJSON.h"
     3 #include "cJSON.c"
     4 void main(){
     5     //待解析字符串 
     6     char *json_str="{"key1":"dongxiaodong","key2":1998,"key3":55778}";
     7     
     8     //输出原字符串
     9     printf("原字符串:%s
    ",json_str); 
    10 
    11     //解析成json对象 
    12     cJSON * json_obj = cJSON_Parse(json_str); 
    13 
    14     //格式输出
    15     char *json_print_str=NULL;
    16     json_print_str=cJSON_Print(json_obj);
    17     printf("
    输出内容:
    
    %s
    ",json_print_str);
    18     
    19     //释放资源 
    20     free(json_print_str);
    21     
    22     //释放资源 
    23     cJSON_Delete(json_obj);
    24 }

    json打包

    cJSON_CreateObject函数可创建一个根数据项,在此之后就可以添加各种数据类型的子节点了,使用完成后需要通过cJSON_Delete()释放内存。

    创建一层级的json

     代码:

     1 #include <stdio.h>
     2 #include "cJSON.h"
     3 #include "cJSON.c"
     4 void main(){
     5     cJSON *root_obj = NULL;//根,json对象 
     6     char *out_str = NULL; //输出结果 
     7     root_obj =cJSON_CreateObject();//创建 
     8      //添加一个字符串,参数(根对象,键,值) 
     9     cJSON_AddStringToObject(root_obj, "key1", "dongxiaodong");
    10     //添加一个整型,参数(根对象,键,值) 
    11     cJSON_AddNumberToObject(root_obj, "key2",1998);
    12     //添加一个浮点型,参数(根对象,键,值) 
    13     cJSON_AddNumberToObject(root_obj, "key3",22.33);
    14     //添加一个bool类型,参数(根对象,键,值) 
    15     //bool值可以是0/1或false/true 
    16     cJSON_AddBoolToObject(root_obj, "key4",0);
    17     //将json对象打包成字符串 
    18     out_str = cJSON_PrintUnformatted(root_obj);
    19     //销毁json对象,释放内存 
    20     cJSON_Delete(root_obj); 
    21     //输出值:{"key1":"dongxiaodong","key2":1998,"key3":22.33,"key4":false} 
    22     printf("%s",out_str);
    23 }

    类型创建函数还有:

    cJSON_AddNullToObject(cJSON * const object, const char * const name);

    cJSON_AddTrueToObject(cJSON * const object, const char * const name);

    cJSON_AddFalseToObject(cJSON * const object, const char * const name);

    cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);

    cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);

    cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);

    cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);

    cJSON_AddObjectToObject(cJSON * const object, const char * const name);

    cJSON_AddArrayToObject(cJSON * const object, const char * const name);

    创建多层级的json

     代码:

     1 #include <stdio.h>
     2 #include "cJSON.h"
     3 #include "cJSON.c"
     4 void main(){
     5     cJSON *root_obj = NULL;//根,json对象 
     6     cJSON *item_obj = NULL;//二级json对象 
     7     char *out_str = NULL; //输出结果 
     8     
     9     root_obj =cJSON_CreateObject();//创建 
    10      //添加一个字符串,参数(根对象,键,值) 
    11     cJSON_AddStringToObject(root_obj, "key1", "dongxiaodong");
    12     //添加一个整型,参数(根对象,键,值) 
    13     cJSON_AddNumberToObject(root_obj, "key2",1998);
    14     
    15     //创建一个子json对象
    16     item_obj= cJSON_AddObjectToObject(root_obj,"myson"); 
    17     //向孩子对象中添加内容
    18     cJSON_AddStringToObject(item_obj, "sonkey1", "东小东"); 
    19     cJSON_AddNumberToObject(item_obj, "sonkey2",2020);
    20       
    21     //将json对象打包成字符串 
    22     out_str = cJSON_PrintUnformatted(root_obj);
    23     //销毁json对象,释放内存 
    24     cJSON_Delete(root_obj); 
    25     //输出值:{"key1":"dongxiaodong","key2":1998,"myson":{"sonkey1":"东小东","sonkey2":2020}}
    26     printf("%s",out_str);
    27 }

    创建多层json(数组形式)

     

     代码

     1 #include <stdio.h>
     2 #include "cJSON.h"
     3 #include "cJSON.c"
     4 void main(){
     5     cJSON *root_obj = NULL;//根,json对象 
     6     cJSON *item_obj = NULL;//数组对象 
     7     char *out_str = NULL; //输出结果 
     8     
     9     root_obj =cJSON_CreateObject();//创建 
    10      //添加一个字符串,参数(根对象,键,值) 
    11     cJSON_AddStringToObject(root_obj, "key1", "dongxiaodong");
    12     //添加一个整型,参数(根对象,键,值) 
    13     cJSON_AddNumberToObject(root_obj, "key2",1998);
    14     
    15     //创建一个子数组对象 
    16     item_obj= cJSON_AddArrayToObject(root_obj,"myson"); 
    17     //向数组对象中添加内容
    18     cJSON_AddItemToArray(item_obj,cJSON_CreateTrue()); 
    19     cJSON_AddItemToArray(item_obj,cJSON_CreateNumber(22));
    20       
    21     //将json对象打包成字符串 
    22     out_str = cJSON_PrintUnformatted(root_obj);
    23     //销毁json对象,释放内存 
    24     cJSON_Delete(root_obj); 
    25     //输出值:{"key1":"dongxiaodong","key2":1998,"myson":[true,22]}
    26     printf("%s",out_str);
    27 }

    创建的对象还可以是下面这些

    cJSON_CreateNull(void);

    cJSON_CreateTrue(void);

    cJSON_CreateFalse(void);

    cJSON_CreateBool(cJSON_bool boolean);

    cJSON_CreateNumber(double num);

    cJSON_CreateString(const char *string);

    cJSON_CreateRaw(const char *raw);

    cJSON_CreateArray(void);

    cJSON_CreateObject(void);

    创建混合json

     代码

     1 #include <stdio.h>
     2 #include "cJSON.h"
     3 #include "cJSON.c"
     4 void main(){
     5     cJSON *root_obj = NULL;//根,json对象 
     6     cJSON *son_obj=NULL; 
     7     cJSON *item_obj = NULL;//数组对象 
     8     char *out_str = NULL; //输出结果 
     9     
    10     //根对象 
    11     root_obj =cJSON_CreateObject();//创建 
    12     //添加一个字符串,参数(根对象,键,值) 
    13     cJSON_AddStringToObject(root_obj, "key1", "dongxiaodong");
    14     //添加一个整型,参数(根对象,键,值) 
    15     cJSON_AddNumberToObject(root_obj, "key2",1998);
    16     
    17     //创建一个子数组对象 
    18     item_obj= cJSON_AddArrayToObject(root_obj,"myson"); 
    19     //向数组对象中添加内容
    20     cJSON_AddItemToArray(item_obj,cJSON_CreateTrue()); 
    21     cJSON_AddItemToArray(item_obj,cJSON_CreateNumber(22));
    22     
    23     //子对象 
    24     son_obj =cJSON_CreateObject();//创建 
    25     //添加一个字符串,参数(根对象,键,值) 
    26     cJSON_AddStringToObject(son_obj, "son1", "dongxiaodong");
    27     //添加一个整型,参数(根对象,键,值) 
    28     cJSON_AddNumberToObject(son_obj, "son2",1998);
    29     cJSON_AddItemToArray(item_obj,son_obj);
    30     
    31     //将json对象打包成字符串 
    32     out_str = cJSON_PrintUnformatted(root_obj);
    33     //销毁json对象,释放内存 
    34     cJSON_Delete(root_obj); 
    35     //输出值:{"key1":"dongxiaodong","key2":1998,"myson":[true,22,{"son1":"dongxiaodong","son2":1998}]}
    36     printf("%s",out_str);
    37 }

    json解析

    解析一层级的json

     

    代码:

     1 #include <stdio.h>
     2 #include "cJSON.h"
     3 #include "cJSON.c"
     4 void main(){
     5     //待解析字符串 
     6     char *json_str="{"key1":"dongxiaodong","key2":1998,"key3":22.33,"key4":true}";
     7     //解析成json对象 
     8     cJSON * json_obj = cJSON_Parse(json_str); 
     9     
    10     //项存储 
    11     cJSON *item=NULL;
    12     
    13     //输出原字符串
    14     printf("原字符串:%s
    ",json_str); 
    15     
    16     //获取string类型 
    17     item=cJSON_GetObjectItem(json_obj,"key1");  
    18     printf("
    key1:%s
    ",item->valuestring);
    19     cJSON_Delete(item);//释放资源 
    20      
    21     //获取数字 
    22     item=cJSON_GetObjectItem(json_obj,"key2");  
    23     printf("
    key2:%d
    ",item->valueint);
    24     cJSON_Delete(item);//释放资源 
    25     
    26     //获取数字 
    27     item=cJSON_GetObjectItem(json_obj,"key3");  
    28     printf("
    key3:%f
    ",item->valuedouble);
    29     cJSON_Delete(item);//释放资源 
    30     
    31     //获取bool 
    32     item=cJSON_GetObjectItem(json_obj,"key4");  
    33     printf("
    key4:%d
    ",item->valueint);
    34     cJSON_Delete(item);//释放资源 
    35     
    36     //是否资源 
    37     cJSON_Delete(json_obj);
    38 }

    解析多层级的json

     

    代码

     1 #include <stdio.h>
     2 #include "cJSON.h"
     3 #include "cJSON.c"
     4 void main(){
     5     //待解析字符串 
     6     char *json_str="{"key1":"dongxiaodong","key2":1998,"myson":{"sonkey1":"东小东","sonkey2":2020}}";
     7     //解析成json对象 
     8     cJSON * json_obj = cJSON_Parse(json_str); 
     9     
    10     //项存储 
    11     cJSON *item=NULL;
    12     //内部项存储
    13     cJSON * item_item=NULL; 
    14     
    15     //输出原字符串
    16     printf("原字符串:%s
    ",json_str); 
    17     
    18     //获取string类型 
    19     item=cJSON_GetObjectItem(json_obj,"key1");  
    20     printf("
    key1:%s
    ",item->valuestring);
    21     cJSON_Delete(item);//释放资源 
    22      
    23     //获取数字 
    24     item=cJSON_GetObjectItem(json_obj,"key2");  
    25     printf("
    key2:%d
    ",item->valueint);
    26     cJSON_Delete(item);//释放资源 
    27     
    28     //子串
    29     item=cJSON_GetObjectItem(json_obj,"myson");  
    30     item_item=cJSON_GetObjectItem(item,"sonkey1"); 
    31     printf("
    myson(sonkey1):%s
    ",item_item->valuestring);
    32     cJSON_Delete(item_item);//释放资源 
    33     
    34     item_item=cJSON_GetObjectItem(item,"sonkey2"); 
    35     printf("
    myson(sonkey2):%d
    ",item_item->valueint);
    36     cJSON_Delete(item_item);//释放资源 
    37     
    38     cJSON_Delete(item);//释放资源 
    39     
    40     //释放资源 
    41     cJSON_Delete(json_obj);
    42 }

     解析多层json(数组形式)

      

    代码

     1 #include <stdio.h>
     2 #include "cJSON.h"
     3 #include "cJSON.c"
     4 void main(){
     5     //待解析字符串 
     6     char *json_str="{"key1":"dongxiaodong","key2":1998,"myson":[true,113]}";
     7     //解析成json对象 
     8     cJSON * json_obj = cJSON_Parse(json_str); 
     9     
    10     //项存储 
    11     cJSON *item=NULL;
    12     //内部项存储
    13     cJSON * item_item=NULL; 
    14     
    15     //输出原字符串
    16     printf("原字符串:%s
    ",json_str); 
    17     
    18     //获取string类型 
    19     item=cJSON_GetObjectItem(json_obj,"key1");  
    20     printf("
    key1:%s
    ",item->valuestring);
    21     cJSON_Delete(item);//释放资源 
    22      
    23     //获取数字 
    24     item=cJSON_GetObjectItem(json_obj,"key2");  
    25     printf("
    key2:%d
    ",item->valueint);
    26     cJSON_Delete(item);//释放资源 
    27     
    28     //获取子串 
    29     item=cJSON_GetObjectItem(json_obj,"myson"); 
    30     
    31     //输出数组大小 
    32     printf("
    数组大小:%d
    ",cJSON_GetArraySize(item));
    33     
    34     //输出项1内容 
    35     item_item=cJSON_GetArrayItem(item,0); 
    36     printf("
    myson(0):%d
    ",item_item->valueint);
    37     //cJSON_Delete(item_item);//释放资源 
    38     
    39     //输出项2内容 
    40     item_item=cJSON_GetArrayItem(item,1);
    41     printf("
    myson(1):%d
    ",item_item->valueint);
    42     cJSON_Delete(item_item);//释放资源 
    43     
    44     cJSON_Delete(item);//释放资源 
    45     
    46     //释放资源 
    47     cJSON_Delete(json_obj);
    48 }

      解析混合json

    代码

     1 #include <stdio.h>
     2 #include "cJSON.h"
     3 #include "cJSON.c"
     4 void main(){
     5     //待解析字符串 
     6     char *json_str="{"key1":"dongxiaodong","key2":1998,"myson":[true,22,{"son1":"dongxiaodong","son2":1998}]}";
     7     //解析成json对象 
     8     cJSON * json_obj = cJSON_Parse(json_str); 
     9     
    10     //项存储 
    11     cJSON *item=NULL;
    12     //内部项存储
    13     cJSON * item_item=NULL; 
    14     
    15     //输出原字符串
    16     printf("原字符串:%s
    ",json_str); 
    17     
    18     //获取string类型 
    19     item=cJSON_GetObjectItem(json_obj,"key1");  
    20     printf("
    key1:%s
    ",item->valuestring);
    21     cJSON_Delete(item);//释放资源 
    22      
    23     //获取数字 
    24     item=cJSON_GetObjectItem(json_obj,"key2");  
    25     printf("
    key2:%d
    ",item->valueint);
    26     cJSON_Delete(item);//释放资源 
    27     
    28     //获取子串 
    29     item=cJSON_GetObjectItem(json_obj,"myson"); 
    30     
    31     //输出数组大小 
    32     printf("
    数组大小:%d
    ",cJSON_GetArraySize(item));
    33     
    34     //输出项1内容 
    35     item_item=cJSON_GetArrayItem(item,0); 
    36     printf("
    myson(0):%d
    ",item_item->valueint);
    37     //cJSON_Delete(item_item);//释放资源 
    38     
    39     //输出项2内容 
    40     item_item=cJSON_GetArrayItem(item,1);
    41     printf("
    myson(1):%d
    ",item_item->valueint);
    42     cJSON_Delete(item_item);//释放资源 
    43     
    44     //项3内容
    45     item_item=cJSON_GetArrayItem(item,2); 
    46     cJSON *item_item_son=NULL;
    47     
    48     item_item_son =cJSON_GetObjectItem(item_item,"son1");  
    49     printf("
    myson(2)(son1):%s
    ",item_item_son->valuestring);
    50     cJSON_Delete(item_item_son);//释放资源 
    51     
    52     item_item_son =cJSON_GetObjectItem(item_item,"son2");  
    53     printf("
    myson(2)(son2):%d
    ",item_item_son->valueint);
    54     cJSON_Delete(item_item_son);//释放资源
    55     cJSON_Delete(item_item);//释放资源   
    56     
    57     cJSON_Delete(item);//释放资源 
    58     
    59     //释放资源 
    60     cJSON_Delete(json_obj);
    61 }

     附件:

    cJSON.h

      1 /*
      2   Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
      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 #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
     32 #define __WINDOWS__
     33 #endif
     34 
     35 #ifdef __WINDOWS__
     36 
     37 /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention.  For windows you have 3 define options:
     38 
     39 CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
     40 CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
     41 CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
     42 
     43 For *nix builds that support visibility attribute, you can define similar behavior by
     44 
     45 setting default visibility to hidden by adding
     46 -fvisibility=hidden (for gcc)
     47 or
     48 -xldscope=hidden (for sun cc)
     49 to CFLAGS
     50 
     51 then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
     52 
     53 */
     54 
     55 #define CJSON_CDECL __cdecl
     56 #define CJSON_STDCALL __stdcall
     57 
     58 /* export symbols by default, this is necessary for copy pasting the C and header file */
     59 #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
     60 #define CJSON_EXPORT_SYMBOLS
     61 #endif
     62 
     63 #if defined(CJSON_HIDE_SYMBOLS)
     64 #define CJSON_PUBLIC(type)   type CJSON_STDCALL
     65 #elif defined(CJSON_EXPORT_SYMBOLS)
     66 #define CJSON_PUBLIC(type)   __declspec(dllexport) type CJSON_STDCALL
     67 #elif defined(CJSON_IMPORT_SYMBOLS)
     68 #define CJSON_PUBLIC(type)   __declspec(dllimport) type CJSON_STDCALL
     69 #endif
     70 #else /* !__WINDOWS__ */
     71 #define CJSON_CDECL
     72 #define CJSON_STDCALL
     73 
     74 #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
     75 #define CJSON_PUBLIC(type)   __attribute__((visibility("default"))) type
     76 #else
     77 #define CJSON_PUBLIC(type) type
     78 #endif
     79 #endif
     80 
     81 /* project version */
     82 #define CJSON_VERSION_MAJOR 1
     83 #define CJSON_VERSION_MINOR 7
     84 #define CJSON_VERSION_PATCH 13
     85 
     86 #include <stddef.h>
     87 
     88 /* cJSON Types: */
     89 #define cJSON_Invalid (0)
     90 #define cJSON_False  (1 << 0)
     91 #define cJSON_True   (1 << 1)
     92 #define cJSON_NULL   (1 << 2)
     93 #define cJSON_Number (1 << 3)
     94 #define cJSON_String (1 << 4)
     95 #define cJSON_Array  (1 << 5)
     96 #define cJSON_Object (1 << 6)
     97 #define cJSON_Raw    (1 << 7) /* raw json */
     98 
     99 #define cJSON_IsReference 256
    100 #define cJSON_StringIsConst 512
    101 
    102 /* The cJSON structure: */
    103 typedef struct cJSON
    104 {
    105     /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    106     struct cJSON *next;
    107     struct cJSON *prev;
    108     /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
    109     struct cJSON *child;
    110 
    111     /* The type of the item, as above. */
    112     int type;
    113 
    114     /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
    115     char *valuestring;
    116     /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    117     int valueint;
    118     /* The item's number, if type==cJSON_Number */
    119     double valuedouble;
    120 
    121     /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
    122     char *string;
    123 } cJSON;
    124 
    125 typedef struct cJSON_Hooks
    126 {
    127       /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
    128       void *(CJSON_CDECL *malloc_fn)(size_t sz);
    129       void (CJSON_CDECL *free_fn)(void *ptr);
    130 } cJSON_Hooks;
    131 
    132 typedef int cJSON_bool;
    133 
    134 /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
    135  * This is to prevent stack overflows. */
    136 #ifndef CJSON_NESTING_LIMIT
    137 #define CJSON_NESTING_LIMIT 1000
    138 #endif
    139 
    140 /* returns the version of cJSON as a string */
    141 CJSON_PUBLIC(const char*) cJSON_Version(void);
    142 
    143 /* Supply malloc, realloc and free functions to cJSON */
    144 CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
    145 
    146 /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
    147 /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
    148 CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
    149 CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
    150 /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
    151 /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
    152 CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
    153 CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
    154 
    155 /* Render a cJSON entity to text for transfer/storage. */
    156 CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
    157 /* Render a cJSON entity to text for transfer/storage without any formatting. */
    158 CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
    159 /* 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 */
    160 CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
    161 /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
    162 /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
    163 CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
    164 /* Delete a cJSON entity and all subentities. */
    165 CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
    166 
    167 /* Returns the number of items in an array (or object). */
    168 CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
    169 /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
    170 CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
    171 /* Get item "string" from object. Case insensitive. */
    172 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
    173 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
    174 CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
    175 /* 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. */
    176 CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
    177 
    178 /* Check item type and return its value */
    179 CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
    180 CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item);
    181 
    182 /* These functions check the type of an item */
    183 CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
    184 CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
    185 CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
    186 CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
    187 CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
    188 CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
    189 CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
    190 CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
    191 CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
    192 CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
    193 
    194 /* These calls create a cJSON item of the appropriate type. */
    195 CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
    196 CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
    197 CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
    198 CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
    199 CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
    200 CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
    201 /* raw json */
    202 CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
    203 CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
    204 CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
    205 
    206 /* Create a string where valuestring references a string so
    207  * it will not be freed by cJSON_Delete */
    208 CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
    209 /* Create an object/array that only references it's elements so
    210  * they will not be freed by cJSON_Delete */
    211 CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
    212 CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
    213 
    214 /* These utilities create an Array of count items.
    215  * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
    216 CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
    217 CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
    218 CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
    219 CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
    220 
    221 /* Append item to the specified array/object. */
    222 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
    223 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
    224 /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
    225  * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
    226  * writing to `item->string` */
    227 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
    228 /* 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. */
    229 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
    230 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
    231 
    232 /* Remove/Detach items from Arrays/Objects. */
    233 CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
    234 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
    235 CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
    236 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
    237 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
    238 CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
    239 CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
    240 
    241 /* Update array items. */
    242 CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
    243 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
    244 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
    245 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
    246 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
    247 
    248 /* Duplicate a cJSON item */
    249 CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
    250 /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
    251  * need to be released. With recurse!=0, it will duplicate any children connected to the item.
    252  * The item->next and ->prev pointers are always zero on return from Duplicate. */
    253 /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
    254  * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
    255 CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
    256 
    257 /* Minify a strings, remove blank characters(such as ' ', '	', '
    ', '
    ') from strings.
    258  * The input pointer json cannot point to a read-only address area, such as a string constant, 
    259  * but should point to a readable and writable adress area. */
    260 CJSON_PUBLIC(void) cJSON_Minify(char *json);
    261 
    262 /* Helper functions for creating and adding items to an object at the same time.
    263  * They return the added item or NULL on failure. */
    264 CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
    265 CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
    266 CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
    267 CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
    268 CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
    269 CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
    270 CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
    271 CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
    272 CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
    273 
    274 /* When assigning an integer value, it needs to be propagated to valuedouble too. */
    275 #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
    276 /* helper for the cJSON_SetNumberValue macro */
    277 CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
    278 #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
    279 /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
    280 CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
    281 
    282 /* Macro for iterating over an array or object */
    283 #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
    284 
    285 /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
    286 CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
    287 CJSON_PUBLIC(void) cJSON_free(void *object);
    288 
    289 #ifdef __cplusplus
    290 }
    291 #endif
    292 
    293 #endif
    View Code

    cJSON.c

       1 /*
       2   Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
       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 /* disable warnings about old C89 functions in MSVC */
      27 #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
      28 #define _CRT_SECURE_NO_DEPRECATE
      29 #endif
      30 
      31 #ifdef __GNUC__
      32 #pragma GCC visibility push(default)
      33 #endif
      34 #if defined(_MSC_VER)
      35 #pragma warning (push)
      36 /* disable warning about single line comments in system headers */
      37 #pragma warning (disable : 4001)
      38 #endif
      39 
      40 #include <string.h>
      41 #include <stdio.h>
      42 #include <math.h>
      43 #include <stdlib.h>
      44 #include <limits.h>
      45 #include <ctype.h>
      46 #include <float.h>
      47 
      48 #ifdef ENABLE_LOCALES
      49 #include <locale.h>
      50 #endif
      51 
      52 #if defined(_MSC_VER)
      53 #pragma warning (pop)
      54 #endif
      55 #ifdef __GNUC__
      56 #pragma GCC visibility pop
      57 #endif
      58 
      59 #include "cJSON.h"
      60 
      61 /* define our own boolean type */
      62 #ifdef true
      63 #undef true
      64 #endif
      65 #define true ((cJSON_bool)1)
      66 
      67 #ifdef false
      68 #undef false
      69 #endif
      70 #define false ((cJSON_bool)0)
      71 
      72 /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
      73 #ifndef isinf
      74 #define isinf(d) (isnan((d - d)) && !isnan(d))
      75 #endif
      76 #ifndef isnan
      77 #define isnan(d) (d != d)
      78 #endif
      79 
      80 #ifndef NAN
      81 #define NAN 0.0/0.0
      82 #endif
      83 
      84 typedef struct {
      85     const unsigned char *json;
      86     size_t position;
      87 } error;
      88 static error global_error = { NULL, 0 };
      89 
      90 CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
      91 {
      92     return (const char*) (global_error.json + global_error.position);
      93 }
      94 
      95 CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) 
      96 {
      97     if (!cJSON_IsString(item)) 
      98     {
      99         return NULL;
     100     }
     101 
     102     return item->valuestring;
     103 }
     104 
     105 CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item) 
     106 {
     107     if (!cJSON_IsNumber(item)) 
     108     {
     109         return NAN;
     110     }
     111 
     112     return item->valuedouble;
     113 }
     114 
     115 /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
     116 #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 13)
     117     #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
     118 #endif
     119 
     120 CJSON_PUBLIC(const char*) cJSON_Version(void)
     121 {
     122     static char version[15];
     123     sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
     124 
     125     return version;
     126 }
     127 
     128 /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
     129 static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
     130 {
     131     if ((string1 == NULL) || (string2 == NULL))
     132     {
     133         return 1;
     134     }
     135 
     136     if (string1 == string2)
     137     {
     138         return 0;
     139     }
     140 
     141     for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
     142     {
     143         if (*string1 == '')
     144         {
     145             return 0;
     146         }
     147     }
     148 
     149     return tolower(*string1) - tolower(*string2);
     150 }
     151 
     152 typedef struct internal_hooks
     153 {
     154     void *(CJSON_CDECL *allocate)(size_t size);
     155     void (CJSON_CDECL *deallocate)(void *pointer);
     156     void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
     157 } internal_hooks;
     158 
     159 #if defined(_MSC_VER)
     160 /* work around MSVC error C2322: '...' address of dllimport '...' is not static */
     161 static void * CJSON_CDECL internal_malloc(size_t size)
     162 {
     163     return malloc(size);
     164 }
     165 static void CJSON_CDECL internal_free(void *pointer)
     166 {
     167     free(pointer);
     168 }
     169 static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
     170 {
     171     return realloc(pointer, size);
     172 }
     173 #else
     174 #define internal_malloc malloc
     175 #define internal_free free
     176 #define internal_realloc realloc
     177 #endif
     178 
     179 /* strlen of character literals resolved at compile time */
     180 #define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
     181 
     182 static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
     183 
     184 static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
     185 {
     186     size_t length = 0;
     187     unsigned char *copy = NULL;
     188 
     189     if (string == NULL)
     190     {
     191         return NULL;
     192     }
     193 
     194     length = strlen((const char*)string) + sizeof("");
     195     copy = (unsigned char*)hooks->allocate(length);
     196     if (copy == NULL)
     197     {
     198         return NULL;
     199     }
     200     memcpy(copy, string, length);
     201 
     202     return copy;
     203 }
     204 
     205 CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
     206 {
     207     if (hooks == NULL)
     208     {
     209         /* Reset hooks */
     210         global_hooks.allocate = malloc;
     211         global_hooks.deallocate = free;
     212         global_hooks.reallocate = realloc;
     213         return;
     214     }
     215 
     216     global_hooks.allocate = malloc;
     217     if (hooks->malloc_fn != NULL)
     218     {
     219         global_hooks.allocate = hooks->malloc_fn;
     220     }
     221 
     222     global_hooks.deallocate = free;
     223     if (hooks->free_fn != NULL)
     224     {
     225         global_hooks.deallocate = hooks->free_fn;
     226     }
     227 
     228     /* use realloc only if both free and malloc are used */
     229     global_hooks.reallocate = NULL;
     230     if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
     231     {
     232         global_hooks.reallocate = realloc;
     233     }
     234 }
     235 
     236 /* Internal constructor. */
     237 static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
     238 {
     239     cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
     240     if (node)
     241     {
     242         memset(node, '', sizeof(cJSON));
     243     }
     244 
     245     return node;
     246 }
     247 
     248 /* Delete a cJSON structure. */
     249 CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
     250 {
     251     cJSON *next = NULL;
     252     while (item != NULL)
     253     {
     254         next = item->next;
     255         if (!(item->type & cJSON_IsReference) && (item->child != NULL))
     256         {
     257             cJSON_Delete(item->child);
     258         }
     259         if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
     260         {
     261             global_hooks.deallocate(item->valuestring);
     262         }
     263         if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
     264         {
     265             global_hooks.deallocate(item->string);
     266         }
     267         global_hooks.deallocate(item);
     268         item = next;
     269     }
     270 }
     271 
     272 /* get the decimal point character of the current locale */
     273 static unsigned char get_decimal_point(void)
     274 {
     275 #ifdef ENABLE_LOCALES
     276     struct lconv *lconv = localeconv();
     277     return (unsigned char) lconv->decimal_point[0];
     278 #else
     279     return '.';
     280 #endif
     281 }
     282 
     283 typedef struct
     284 {
     285     const unsigned char *content;
     286     size_t length;
     287     size_t offset;
     288     size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
     289     internal_hooks hooks;
     290 } parse_buffer;
     291 
     292 /* check if the given size is left to read in a given parse buffer (starting with 1) */
     293 #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
     294 /* check if the buffer can be accessed at the given index (starting with 0) */
     295 #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
     296 #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
     297 /* get a pointer to the buffer at the position */
     298 #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
     299 
     300 /* Parse the input text to generate a number, and populate the result into item. */
     301 static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
     302 {
     303     double number = 0;
     304     unsigned char *after_end = NULL;
     305     unsigned char number_c_string[64];
     306     unsigned char decimal_point = get_decimal_point();
     307     size_t i = 0;
     308 
     309     if ((input_buffer == NULL) || (input_buffer->content == NULL))
     310     {
     311         return false;
     312     }
     313 
     314     /* copy the number into a temporary buffer and replace '.' with the decimal point
     315      * of the current locale (for strtod)
     316      * This also takes care of '' not necessarily being available for marking the end of the input */
     317     for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
     318     {
     319         switch (buffer_at_offset(input_buffer)[i])
     320         {
     321             case '0':
     322             case '1':
     323             case '2':
     324             case '3':
     325             case '4':
     326             case '5':
     327             case '6':
     328             case '7':
     329             case '8':
     330             case '9':
     331             case '+':
     332             case '-':
     333             case 'e':
     334             case 'E':
     335                 number_c_string[i] = buffer_at_offset(input_buffer)[i];
     336                 break;
     337 
     338             case '.':
     339                 number_c_string[i] = decimal_point;
     340                 break;
     341 
     342             default:
     343                 goto loop_end;
     344         }
     345     }
     346 loop_end:
     347     number_c_string[i] = '';
     348 
     349     number = strtod((const char*)number_c_string, (char**)&after_end);
     350     if (number_c_string == after_end)
     351     {
     352         return false; /* parse_error */
     353     }
     354 
     355     item->valuedouble = number;
     356 
     357     /* use saturation in case of overflow */
     358     if (number >= INT_MAX)
     359     {
     360         item->valueint = INT_MAX;
     361     }
     362     else if (number <= (double)INT_MIN)
     363     {
     364         item->valueint = INT_MIN;
     365     }
     366     else
     367     {
     368         item->valueint = (int)number;
     369     }
     370 
     371     item->type = cJSON_Number;
     372 
     373     input_buffer->offset += (size_t)(after_end - number_c_string);
     374     return true;
     375 }
     376 
     377 /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
     378 CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
     379 {
     380     if (number >= INT_MAX)
     381     {
     382         object->valueint = INT_MAX;
     383     }
     384     else if (number <= (double)INT_MIN)
     385     {
     386         object->valueint = INT_MIN;
     387     }
     388     else
     389     {
     390         object->valueint = (int)number;
     391     }
     392 
     393     return object->valuedouble = number;
     394 }
     395 
     396 CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
     397 {
     398     char *copy = NULL;
     399     /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
     400     if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference))
     401     {
     402         return NULL;
     403     }
     404     if (strlen(valuestring) <= strlen(object->valuestring))
     405     {
     406         strcpy(object->valuestring, valuestring);
     407         return object->valuestring;
     408     }
     409     copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
     410     if (copy == NULL)
     411     {
     412         return NULL;
     413     }
     414     if (object->valuestring != NULL)
     415     {
     416         cJSON_free(object->valuestring);
     417     }
     418     object->valuestring = copy;
     419 
     420     return copy;
     421 }
     422 
     423 typedef struct
     424 {
     425     unsigned char *buffer;
     426     size_t length;
     427     size_t offset;
     428     size_t depth; /* current nesting depth (for formatted printing) */
     429     cJSON_bool noalloc;
     430     cJSON_bool format; /* is this print a formatted print */
     431     internal_hooks hooks;
     432 } printbuffer;
     433 
     434 /* realloc printbuffer if necessary to have at least "needed" bytes more */
     435 static unsigned char* ensure(printbuffer * const p, size_t needed)
     436 {
     437     unsigned char *newbuffer = NULL;
     438     size_t newsize = 0;
     439 
     440     if ((p == NULL) || (p->buffer == NULL))
     441     {
     442         return NULL;
     443     }
     444 
     445     if ((p->length > 0) && (p->offset >= p->length))
     446     {
     447         /* make sure that offset is valid */
     448         return NULL;
     449     }
     450 
     451     if (needed > INT_MAX)
     452     {
     453         /* sizes bigger than INT_MAX are currently not supported */
     454         return NULL;
     455     }
     456 
     457     needed += p->offset + 1;
     458     if (needed <= p->length)
     459     {
     460         return p->buffer + p->offset;
     461     }
     462 
     463     if (p->noalloc) {
     464         return NULL;
     465     }
     466 
     467     /* calculate new buffer size */
     468     if (needed > (INT_MAX / 2))
     469     {
     470         /* overflow of int, use INT_MAX if possible */
     471         if (needed <= INT_MAX)
     472         {
     473             newsize = INT_MAX;
     474         }
     475         else
     476         {
     477             return NULL;
     478         }
     479     }
     480     else
     481     {
     482         newsize = needed * 2;
     483     }
     484 
     485     if (p->hooks.reallocate != NULL)
     486     {
     487         /* reallocate with realloc if available */
     488         newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
     489         if (newbuffer == NULL)
     490         {
     491             p->hooks.deallocate(p->buffer);
     492             p->length = 0;
     493             p->buffer = NULL;
     494 
     495             return NULL;
     496         }
     497     }
     498     else
     499     {
     500         /* otherwise reallocate manually */
     501         newbuffer = (unsigned char*)p->hooks.allocate(newsize);
     502         if (!newbuffer)
     503         {
     504             p->hooks.deallocate(p->buffer);
     505             p->length = 0;
     506             p->buffer = NULL;
     507 
     508             return NULL;
     509         }
     510         if (newbuffer)
     511         {
     512             memcpy(newbuffer, p->buffer, p->offset + 1);
     513         }
     514         p->hooks.deallocate(p->buffer);
     515     }
     516     p->length = newsize;
     517     p->buffer = newbuffer;
     518 
     519     return newbuffer + p->offset;
     520 }
     521 
     522 /* calculate the new length of the string in a printbuffer and update the offset */
     523 static void update_offset(printbuffer * const buffer)
     524 {
     525     const unsigned char *buffer_pointer = NULL;
     526     if ((buffer == NULL) || (buffer->buffer == NULL))
     527     {
     528         return;
     529     }
     530     buffer_pointer = buffer->buffer + buffer->offset;
     531 
     532     buffer->offset += strlen((const char*)buffer_pointer);
     533 }
     534 
     535 /* securely comparison of floating-point variables */
     536 static cJSON_bool compare_double(double a, double b)
     537 {
     538     double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
     539     return (fabs(a - b) <= maxVal * DBL_EPSILON);
     540 }
     541 
     542 /* Render the number nicely from the given item into a string. */
     543 static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
     544 {
     545     unsigned char *output_pointer = NULL;
     546     double d = item->valuedouble;
     547     int length = 0;
     548     size_t i = 0;
     549     unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
     550     unsigned char decimal_point = get_decimal_point();
     551     double test = 0.0;
     552 
     553     if (output_buffer == NULL)
     554     {
     555         return false;
     556     }
     557 
     558     /* This checks for NaN and Infinity */
     559     if (isnan(d) || isinf(d))
     560     {
     561         length = sprintf((char*)number_buffer, "null");
     562     }
     563     else
     564     {
     565         /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
     566         length = sprintf((char*)number_buffer, "%1.15g", d);
     567 
     568         /* Check whether the original double can be recovered */
     569         if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
     570         {
     571             /* If not, print with 17 decimal places of precision */
     572             length = sprintf((char*)number_buffer, "%1.17g", d);
     573         }
     574     }
     575 
     576     /* sprintf failed or buffer overrun occurred */
     577     if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
     578     {
     579         return false;
     580     }
     581 
     582     /* reserve appropriate space in the output */
     583     output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
     584     if (output_pointer == NULL)
     585     {
     586         return false;
     587     }
     588 
     589     /* copy the printed number to the output and replace locale
     590      * dependent decimal point with '.' */
     591     for (i = 0; i < ((size_t)length); i++)
     592     {
     593         if (number_buffer[i] == decimal_point)
     594         {
     595             output_pointer[i] = '.';
     596             continue;
     597         }
     598 
     599         output_pointer[i] = number_buffer[i];
     600     }
     601     output_pointer[i] = '';
     602 
     603     output_buffer->offset += (size_t)length;
     604 
     605     return true;
     606 }
     607 
     608 /* parse 4 digit hexadecimal number */
     609 static unsigned parse_hex4(const unsigned char * const input)
     610 {
     611     unsigned int h = 0;
     612     size_t i = 0;
     613 
     614     for (i = 0; i < 4; i++)
     615     {
     616         /* parse digit */
     617         if ((input[i] >= '0') && (input[i] <= '9'))
     618         {
     619             h += (unsigned int) input[i] - '0';
     620         }
     621         else if ((input[i] >= 'A') && (input[i] <= 'F'))
     622         {
     623             h += (unsigned int) 10 + input[i] - 'A';
     624         }
     625         else if ((input[i] >= 'a') && (input[i] <= 'f'))
     626         {
     627             h += (unsigned int) 10 + input[i] - 'a';
     628         }
     629         else /* invalid */
     630         {
     631             return 0;
     632         }
     633 
     634         if (i < 3)
     635         {
     636             /* shift left to make place for the next nibble */
     637             h = h << 4;
     638         }
     639     }
     640 
     641     return h;
     642 }
     643 
     644 /* converts a UTF-16 literal to UTF-8
     645  * A literal can be one or two sequences of the form uXXXX */
     646 static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
     647 {
     648     long unsigned int codepoint = 0;
     649     unsigned int first_code = 0;
     650     const unsigned char *first_sequence = input_pointer;
     651     unsigned char utf8_length = 0;
     652     unsigned char utf8_position = 0;
     653     unsigned char sequence_length = 0;
     654     unsigned char first_byte_mark = 0;
     655 
     656     if ((input_end - first_sequence) < 6)
     657     {
     658         /* input ends unexpectedly */
     659         goto fail;
     660     }
     661 
     662     /* get the first utf16 sequence */
     663     first_code = parse_hex4(first_sequence + 2);
     664 
     665     /* check that the code is valid */
     666     if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
     667     {
     668         goto fail;
     669     }
     670 
     671     /* UTF16 surrogate pair */
     672     if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
     673     {
     674         const unsigned char *second_sequence = first_sequence + 6;
     675         unsigned int second_code = 0;
     676         sequence_length = 12; /* uXXXXuXXXX */
     677 
     678         if ((input_end - second_sequence) < 6)
     679         {
     680             /* input ends unexpectedly */
     681             goto fail;
     682         }
     683 
     684         if ((second_sequence[0] != '\') || (second_sequence[1] != 'u'))
     685         {
     686             /* missing second half of the surrogate pair */
     687             goto fail;
     688         }
     689 
     690         /* get the second utf16 sequence */
     691         second_code = parse_hex4(second_sequence + 2);
     692         /* check that the code is valid */
     693         if ((second_code < 0xDC00) || (second_code > 0xDFFF))
     694         {
     695             /* invalid second half of the surrogate pair */
     696             goto fail;
     697         }
     698 
     699 
     700         /* calculate the unicode codepoint from the surrogate pair */
     701         codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
     702     }
     703     else
     704     {
     705         sequence_length = 6; /* uXXXX */
     706         codepoint = first_code;
     707     }
     708 
     709     /* encode as UTF-8
     710      * takes at maximum 4 bytes to encode:
     711      * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
     712     if (codepoint < 0x80)
     713     {
     714         /* normal ascii, encoding 0xxxxxxx */
     715         utf8_length = 1;
     716     }
     717     else if (codepoint < 0x800)
     718     {
     719         /* two bytes, encoding 110xxxxx 10xxxxxx */
     720         utf8_length = 2;
     721         first_byte_mark = 0xC0; /* 11000000 */
     722     }
     723     else if (codepoint < 0x10000)
     724     {
     725         /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
     726         utf8_length = 3;
     727         first_byte_mark = 0xE0; /* 11100000 */
     728     }
     729     else if (codepoint <= 0x10FFFF)
     730     {
     731         /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
     732         utf8_length = 4;
     733         first_byte_mark = 0xF0; /* 11110000 */
     734     }
     735     else
     736     {
     737         /* invalid unicode codepoint */
     738         goto fail;
     739     }
     740 
     741     /* encode as utf8 */
     742     for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
     743     {
     744         /* 10xxxxxx */
     745         (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
     746         codepoint >>= 6;
     747     }
     748     /* encode first byte */
     749     if (utf8_length > 1)
     750     {
     751         (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
     752     }
     753     else
     754     {
     755         (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
     756     }
     757 
     758     *output_pointer += utf8_length;
     759 
     760     return sequence_length;
     761 
     762 fail:
     763     return 0;
     764 }
     765 
     766 /* Parse the input text into an unescaped cinput, and populate item. */
     767 static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
     768 {
     769     const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
     770     const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
     771     unsigned char *output_pointer = NULL;
     772     unsigned char *output = NULL;
     773 
     774     /* not a string */
     775     if (buffer_at_offset(input_buffer)[0] != '"')
     776     {
     777         goto fail;
     778     }
     779 
     780     {
     781         /* calculate approximate size of the output (overestimate) */
     782         size_t allocation_length = 0;
     783         size_t skipped_bytes = 0;
     784         while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '"'))
     785         {
     786             /* is escape sequence */
     787             if (input_end[0] == '\')
     788             {
     789                 if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
     790                 {
     791                     /* prevent buffer overflow when last input character is a backslash */
     792                     goto fail;
     793                 }
     794                 skipped_bytes++;
     795                 input_end++;
     796             }
     797             input_end++;
     798         }
     799         if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '"'))
     800         {
     801             goto fail; /* string ended unexpectedly */
     802         }
     803 
     804         /* This is at most how much we need for the output */
     805         allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
     806         output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
     807         if (output == NULL)
     808         {
     809             goto fail; /* allocation failure */
     810         }
     811     }
     812 
     813     output_pointer = output;
     814     /* loop through the string literal */
     815     while (input_pointer < input_end)
     816     {
     817         if (*input_pointer != '\')
     818         {
     819             *output_pointer++ = *input_pointer++;
     820         }
     821         /* escape sequence */
     822         else
     823         {
     824             unsigned char sequence_length = 2;
     825             if ((input_end - input_pointer) < 1)
     826             {
     827                 goto fail;
     828             }
     829 
     830             switch (input_pointer[1])
     831             {
     832                 case 'b':
     833                     *output_pointer++ = '';
     834                     break;
     835                 case 'f':
     836                     *output_pointer++ = 'f';
     837                     break;
     838                 case 'n':
     839                     *output_pointer++ = '
    ';
     840                     break;
     841                 case 'r':
     842                     *output_pointer++ = '
    ';
     843                     break;
     844                 case 't':
     845                     *output_pointer++ = '	';
     846                     break;
     847                 case '"':
     848                 case '\':
     849                 case '/':
     850                     *output_pointer++ = input_pointer[1];
     851                     break;
     852 
     853                 /* UTF-16 literal */
     854                 case 'u':
     855                     sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
     856                     if (sequence_length == 0)
     857                     {
     858                         /* failed to convert UTF16-literal to UTF-8 */
     859                         goto fail;
     860                     }
     861                     break;
     862 
     863                 default:
     864                     goto fail;
     865             }
     866             input_pointer += sequence_length;
     867         }
     868     }
     869 
     870     /* zero terminate the output */
     871     *output_pointer = '';
     872 
     873     item->type = cJSON_String;
     874     item->valuestring = (char*)output;
     875 
     876     input_buffer->offset = (size_t) (input_end - input_buffer->content);
     877     input_buffer->offset++;
     878 
     879     return true;
     880 
     881 fail:
     882     if (output != NULL)
     883     {
     884         input_buffer->hooks.deallocate(output);
     885     }
     886 
     887     if (input_pointer != NULL)
     888     {
     889         input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
     890     }
     891 
     892     return false;
     893 }
     894 
     895 /* Render the cstring provided to an escaped version that can be printed. */
     896 static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
     897 {
     898     const unsigned char *input_pointer = NULL;
     899     unsigned char *output = NULL;
     900     unsigned char *output_pointer = NULL;
     901     size_t output_length = 0;
     902     /* numbers of additional characters needed for escaping */
     903     size_t escape_characters = 0;
     904 
     905     if (output_buffer == NULL)
     906     {
     907         return false;
     908     }
     909 
     910     /* empty string */
     911     if (input == NULL)
     912     {
     913         output = ensure(output_buffer, sizeof(""""));
     914         if (output == NULL)
     915         {
     916             return false;
     917         }
     918         strcpy((char*)output, """");
     919 
     920         return true;
     921     }
     922 
     923     /* set "flag" to 1 if something needs to be escaped */
     924     for (input_pointer = input; *input_pointer; input_pointer++)
     925     {
     926         switch (*input_pointer)
     927         {
     928             case '"':
     929             case '\':
     930             case '':
     931             case 'f':
     932             case '
    ':
     933             case '
    ':
     934             case '	':
     935                 /* one character escape sequence */
     936                 escape_characters++;
     937                 break;
     938             default:
     939                 if (*input_pointer < 32)
     940                 {
     941                     /* UTF-16 escape sequence uXXXX */
     942                     escape_characters += 5;
     943                 }
     944                 break;
     945         }
     946     }
     947     output_length = (size_t)(input_pointer - input) + escape_characters;
     948 
     949     output = ensure(output_buffer, output_length + sizeof(""""));
     950     if (output == NULL)
     951     {
     952         return false;
     953     }
     954 
     955     /* no characters have to be escaped */
     956     if (escape_characters == 0)
     957     {
     958         output[0] = '"';
     959         memcpy(output + 1, input, output_length);
     960         output[output_length + 1] = '"';
     961         output[output_length + 2] = '';
     962 
     963         return true;
     964     }
     965 
     966     output[0] = '"';
     967     output_pointer = output + 1;
     968     /* copy the string */
     969     for (input_pointer = input; *input_pointer != ''; (void)input_pointer++, output_pointer++)
     970     {
     971         if ((*input_pointer > 31) && (*input_pointer != '"') && (*input_pointer != '\'))
     972         {
     973             /* normal character, copy */
     974             *output_pointer = *input_pointer;
     975         }
     976         else
     977         {
     978             /* character needs to be escaped */
     979             *output_pointer++ = '\';
     980             switch (*input_pointer)
     981             {
     982                 case '\':
     983                     *output_pointer = '\';
     984                     break;
     985                 case '"':
     986                     *output_pointer = '"';
     987                     break;
     988                 case '':
     989                     *output_pointer = 'b';
     990                     break;
     991                 case 'f':
     992                     *output_pointer = 'f';
     993                     break;
     994                 case '
    ':
     995                     *output_pointer = 'n';
     996                     break;
     997                 case '
    ':
     998                     *output_pointer = 'r';
     999                     break;
    1000                 case '	':
    1001                     *output_pointer = 't';
    1002                     break;
    1003                 default:
    1004                     /* escape and print as unicode codepoint */
    1005                     sprintf((char*)output_pointer, "u%04x", *input_pointer);
    1006                     output_pointer += 4;
    1007                     break;
    1008             }
    1009         }
    1010     }
    1011     output[output_length + 1] = '"';
    1012     output[output_length + 2] = '';
    1013 
    1014     return true;
    1015 }
    1016 
    1017 /* Invoke print_string_ptr (which is useful) on an item. */
    1018 static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
    1019 {
    1020     return print_string_ptr((unsigned char*)item->valuestring, p);
    1021 }
    1022 
    1023 /* Predeclare these prototypes. */
    1024 static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
    1025 static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
    1026 static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
    1027 static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
    1028 static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
    1029 static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
    1030 
    1031 /* Utility to jump whitespace and cr/lf */
    1032 static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
    1033 {
    1034     if ((buffer == NULL) || (buffer->content == NULL))
    1035     {
    1036         return NULL;
    1037     }
    1038 
    1039     if (cannot_access_at_index(buffer, 0))
    1040     {
    1041         return buffer;
    1042     }
    1043 
    1044     while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
    1045     {
    1046        buffer->offset++;
    1047     }
    1048 
    1049     if (buffer->offset == buffer->length)
    1050     {
    1051         buffer->offset--;
    1052     }
    1053 
    1054     return buffer;
    1055 }
    1056 
    1057 /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
    1058 static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
    1059 {
    1060     if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
    1061     {
    1062         return NULL;
    1063     }
    1064 
    1065     if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "xEFxBBxBF", 3) == 0))
    1066     {
    1067         buffer->offset += 3;
    1068     }
    1069 
    1070     return buffer;
    1071 }
    1072 
    1073 CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
    1074 {
    1075     size_t buffer_length;
    1076 
    1077     if (NULL == value)
    1078     {
    1079         return NULL;
    1080     }
    1081 
    1082     /* Adding null character size due to require_null_terminated. */
    1083     buffer_length = strlen(value) + sizeof("");
    1084 
    1085     return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
    1086 }
    1087 
    1088 /* Parse an object - create a new root, and populate. */
    1089 CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
    1090 {
    1091     parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
    1092     cJSON *item = NULL;
    1093 
    1094     /* reset error position */
    1095     global_error.json = NULL;
    1096     global_error.position = 0;
    1097 
    1098     if (value == NULL || 0 == buffer_length)
    1099     {
    1100         goto fail;
    1101     }
    1102 
    1103     buffer.content = (const unsigned char*)value;
    1104     buffer.length = buffer_length; 
    1105     buffer.offset = 0;
    1106     buffer.hooks = global_hooks;
    1107 
    1108     item = cJSON_New_Item(&global_hooks);
    1109     if (item == NULL) /* memory fail */
    1110     {
    1111         goto fail;
    1112     }
    1113 
    1114     if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
    1115     {
    1116         /* parse failure. ep is set. */
    1117         goto fail;
    1118     }
    1119 
    1120     /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
    1121     if (require_null_terminated)
    1122     {
    1123         buffer_skip_whitespace(&buffer);
    1124         if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '')
    1125         {
    1126             goto fail;
    1127         }
    1128     }
    1129     if (return_parse_end)
    1130     {
    1131         *return_parse_end = (const char*)buffer_at_offset(&buffer);
    1132     }
    1133 
    1134     return item;
    1135 
    1136 fail:
    1137     if (item != NULL)
    1138     {
    1139         cJSON_Delete(item);
    1140     }
    1141 
    1142     if (value != NULL)
    1143     {
    1144         error local_error;
    1145         local_error.json = (const unsigned char*)value;
    1146         local_error.position = 0;
    1147 
    1148         if (buffer.offset < buffer.length)
    1149         {
    1150             local_error.position = buffer.offset;
    1151         }
    1152         else if (buffer.length > 0)
    1153         {
    1154             local_error.position = buffer.length - 1;
    1155         }
    1156 
    1157         if (return_parse_end != NULL)
    1158         {
    1159             *return_parse_end = (const char*)local_error.json + local_error.position;
    1160         }
    1161 
    1162         global_error = local_error;
    1163     }
    1164 
    1165     return NULL;
    1166 }
    1167 
    1168 /* Default options for cJSON_Parse */
    1169 CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
    1170 {
    1171     return cJSON_ParseWithOpts(value, 0, 0);
    1172 }
    1173 
    1174 CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
    1175 {
    1176     return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
    1177 }
    1178 
    1179 #define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
    1180 
    1181 static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
    1182 {
    1183     static const size_t default_buffer_size = 256;
    1184     printbuffer buffer[1];
    1185     unsigned char *printed = NULL;
    1186 
    1187     memset(buffer, 0, sizeof(buffer));
    1188 
    1189     /* create buffer */
    1190     buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
    1191     buffer->length = default_buffer_size;
    1192     buffer->format = format;
    1193     buffer->hooks = *hooks;
    1194     if (buffer->buffer == NULL)
    1195     {
    1196         goto fail;
    1197     }
    1198 
    1199     /* print the value */
    1200     if (!print_value(item, buffer))
    1201     {
    1202         goto fail;
    1203     }
    1204     update_offset(buffer);
    1205 
    1206     /* check if reallocate is available */
    1207     if (hooks->reallocate != NULL)
    1208     {
    1209         printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
    1210         if (printed == NULL) {
    1211             goto fail;
    1212         }
    1213         buffer->buffer = NULL;
    1214     }
    1215     else /* otherwise copy the JSON over to a new buffer */
    1216     {
    1217         printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
    1218         if (printed == NULL)
    1219         {
    1220             goto fail;
    1221         }
    1222         memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
    1223         printed[buffer->offset] = ''; /* just to be sure */
    1224 
    1225         /* free the buffer */
    1226         hooks->deallocate(buffer->buffer);
    1227     }
    1228 
    1229     return printed;
    1230 
    1231 fail:
    1232     if (buffer->buffer != NULL)
    1233     {
    1234         hooks->deallocate(buffer->buffer);
    1235     }
    1236 
    1237     if (printed != NULL)
    1238     {
    1239         hooks->deallocate(printed);
    1240     }
    1241 
    1242     return NULL;
    1243 }
    1244 
    1245 /* Render a cJSON item/entity/structure to text. */
    1246 CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
    1247 {
    1248     return (char*)print(item, true, &global_hooks);
    1249 }
    1250 
    1251 CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
    1252 {
    1253     return (char*)print(item, false, &global_hooks);
    1254 }
    1255 
    1256 CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
    1257 {
    1258     printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
    1259 
    1260     if (prebuffer < 0)
    1261     {
    1262         return NULL;
    1263     }
    1264 
    1265     p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
    1266     if (!p.buffer)
    1267     {
    1268         return NULL;
    1269     }
    1270 
    1271     p.length = (size_t)prebuffer;
    1272     p.offset = 0;
    1273     p.noalloc = false;
    1274     p.format = fmt;
    1275     p.hooks = global_hooks;
    1276 
    1277     if (!print_value(item, &p))
    1278     {
    1279         global_hooks.deallocate(p.buffer);
    1280         return NULL;
    1281     }
    1282 
    1283     return (char*)p.buffer;
    1284 }
    1285 
    1286 CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
    1287 {
    1288     printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
    1289 
    1290     if ((length < 0) || (buffer == NULL))
    1291     {
    1292         return false;
    1293     }
    1294 
    1295     p.buffer = (unsigned char*)buffer;
    1296     p.length = (size_t)length;
    1297     p.offset = 0;
    1298     p.noalloc = true;
    1299     p.format = format;
    1300     p.hooks = global_hooks;
    1301 
    1302     return print_value(item, &p);
    1303 }
    1304 
    1305 /* Parser core - when encountering text, process appropriately. */
    1306 static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
    1307 {
    1308     if ((input_buffer == NULL) || (input_buffer->content == NULL))
    1309     {
    1310         return false; /* no input */
    1311     }
    1312 
    1313     /* parse the different types of values */
    1314     /* null */
    1315     if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
    1316     {
    1317         item->type = cJSON_NULL;
    1318         input_buffer->offset += 4;
    1319         return true;
    1320     }
    1321     /* false */
    1322     if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
    1323     {
    1324         item->type = cJSON_False;
    1325         input_buffer->offset += 5;
    1326         return true;
    1327     }
    1328     /* true */
    1329     if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
    1330     {
    1331         item->type = cJSON_True;
    1332         item->valueint = 1;
    1333         input_buffer->offset += 4;
    1334         return true;
    1335     }
    1336     /* string */
    1337     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '"'))
    1338     {
    1339         return parse_string(item, input_buffer);
    1340     }
    1341     /* number */
    1342     if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
    1343     {
    1344         return parse_number(item, input_buffer);
    1345     }
    1346     /* array */
    1347     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
    1348     {
    1349         return parse_array(item, input_buffer);
    1350     }
    1351     /* object */
    1352     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
    1353     {
    1354         return parse_object(item, input_buffer);
    1355     }
    1356 
    1357     return false;
    1358 }
    1359 
    1360 /* Render a value to text. */
    1361 static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
    1362 {
    1363     unsigned char *output = NULL;
    1364 
    1365     if ((item == NULL) || (output_buffer == NULL))
    1366     {
    1367         return false;
    1368     }
    1369 
    1370     switch ((item->type) & 0xFF)
    1371     {
    1372         case cJSON_NULL:
    1373             output = ensure(output_buffer, 5);
    1374             if (output == NULL)
    1375             {
    1376                 return false;
    1377             }
    1378             strcpy((char*)output, "null");
    1379             return true;
    1380 
    1381         case cJSON_False:
    1382             output = ensure(output_buffer, 6);
    1383             if (output == NULL)
    1384             {
    1385                 return false;
    1386             }
    1387             strcpy((char*)output, "false");
    1388             return true;
    1389 
    1390         case cJSON_True:
    1391             output = ensure(output_buffer, 5);
    1392             if (output == NULL)
    1393             {
    1394                 return false;
    1395             }
    1396             strcpy((char*)output, "true");
    1397             return true;
    1398 
    1399         case cJSON_Number:
    1400             return print_number(item, output_buffer);
    1401 
    1402         case cJSON_Raw:
    1403         {
    1404             size_t raw_length = 0;
    1405             if (item->valuestring == NULL)
    1406             {
    1407                 return false;
    1408             }
    1409 
    1410             raw_length = strlen(item->valuestring) + sizeof("");
    1411             output = ensure(output_buffer, raw_length);
    1412             if (output == NULL)
    1413             {
    1414                 return false;
    1415             }
    1416             memcpy(output, item->valuestring, raw_length);
    1417             return true;
    1418         }
    1419 
    1420         case cJSON_String:
    1421             return print_string(item, output_buffer);
    1422 
    1423         case cJSON_Array:
    1424             return print_array(item, output_buffer);
    1425 
    1426         case cJSON_Object:
    1427             return print_object(item, output_buffer);
    1428 
    1429         default:
    1430             return false;
    1431     }
    1432 }
    1433 
    1434 /* Build an array from input text. */
    1435 static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
    1436 {
    1437     cJSON *head = NULL; /* head of the linked list */
    1438     cJSON *current_item = NULL;
    1439 
    1440     if (input_buffer->depth >= CJSON_NESTING_LIMIT)
    1441     {
    1442         return false; /* to deeply nested */
    1443     }
    1444     input_buffer->depth++;
    1445 
    1446     if (buffer_at_offset(input_buffer)[0] != '[')
    1447     {
    1448         /* not an array */
    1449         goto fail;
    1450     }
    1451 
    1452     input_buffer->offset++;
    1453     buffer_skip_whitespace(input_buffer);
    1454     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
    1455     {
    1456         /* empty array */
    1457         goto success;
    1458     }
    1459 
    1460     /* check if we skipped to the end of the buffer */
    1461     if (cannot_access_at_index(input_buffer, 0))
    1462     {
    1463         input_buffer->offset--;
    1464         goto fail;
    1465     }
    1466 
    1467     /* step back to character in front of the first element */
    1468     input_buffer->offset--;
    1469     /* loop through the comma separated array elements */
    1470     do
    1471     {
    1472         /* allocate next item */
    1473         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
    1474         if (new_item == NULL)
    1475         {
    1476             goto fail; /* allocation failure */
    1477         }
    1478 
    1479         /* attach next item to list */
    1480         if (head == NULL)
    1481         {
    1482             /* start the linked list */
    1483             current_item = head = new_item;
    1484         }
    1485         else
    1486         {
    1487             /* add to the end and advance */
    1488             current_item->next = new_item;
    1489             new_item->prev = current_item;
    1490             current_item = new_item;
    1491         }
    1492 
    1493         /* parse next value */
    1494         input_buffer->offset++;
    1495         buffer_skip_whitespace(input_buffer);
    1496         if (!parse_value(current_item, input_buffer))
    1497         {
    1498             goto fail; /* failed to parse value */
    1499         }
    1500         buffer_skip_whitespace(input_buffer);
    1501     }
    1502     while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
    1503 
    1504     if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
    1505     {
    1506         goto fail; /* expected end of array */
    1507     }
    1508 
    1509 success:
    1510     input_buffer->depth--;
    1511 
    1512     item->type = cJSON_Array;
    1513     item->child = head;
    1514 
    1515     input_buffer->offset++;
    1516 
    1517     return true;
    1518 
    1519 fail:
    1520     if (head != NULL)
    1521     {
    1522         cJSON_Delete(head);
    1523     }
    1524 
    1525     return false;
    1526 }
    1527 
    1528 /* Render an array to text */
    1529 static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
    1530 {
    1531     unsigned char *output_pointer = NULL;
    1532     size_t length = 0;
    1533     cJSON *current_element = item->child;
    1534 
    1535     if (output_buffer == NULL)
    1536     {
    1537         return false;
    1538     }
    1539 
    1540     /* Compose the output array. */
    1541     /* opening square bracket */
    1542     output_pointer = ensure(output_buffer, 1);
    1543     if (output_pointer == NULL)
    1544     {
    1545         return false;
    1546     }
    1547 
    1548     *output_pointer = '[';
    1549     output_buffer->offset++;
    1550     output_buffer->depth++;
    1551 
    1552     while (current_element != NULL)
    1553     {
    1554         if (!print_value(current_element, output_buffer))
    1555         {
    1556             return false;
    1557         }
    1558         update_offset(output_buffer);
    1559         if (current_element->next)
    1560         {
    1561             length = (size_t) (output_buffer->format ? 2 : 1);
    1562             output_pointer = ensure(output_buffer, length + 1);
    1563             if (output_pointer == NULL)
    1564             {
    1565                 return false;
    1566             }
    1567             *output_pointer++ = ',';
    1568             if(output_buffer->format)
    1569             {
    1570                 *output_pointer++ = ' ';
    1571             }
    1572             *output_pointer = '';
    1573             output_buffer->offset += length;
    1574         }
    1575         current_element = current_element->next;
    1576     }
    1577 
    1578     output_pointer = ensure(output_buffer, 2);
    1579     if (output_pointer == NULL)
    1580     {
    1581         return false;
    1582     }
    1583     *output_pointer++ = ']';
    1584     *output_pointer = '';
    1585     output_buffer->depth--;
    1586 
    1587     return true;
    1588 }
    1589 
    1590 /* Build an object from the text. */
    1591 static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
    1592 {
    1593     cJSON *head = NULL; /* linked list head */
    1594     cJSON *current_item = NULL;
    1595 
    1596     if (input_buffer->depth >= CJSON_NESTING_LIMIT)
    1597     {
    1598         return false; /* to deeply nested */
    1599     }
    1600     input_buffer->depth++;
    1601 
    1602     if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
    1603     {
    1604         goto fail; /* not an object */
    1605     }
    1606 
    1607     input_buffer->offset++;
    1608     buffer_skip_whitespace(input_buffer);
    1609     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
    1610     {
    1611         goto success; /* empty object */
    1612     }
    1613 
    1614     /* check if we skipped to the end of the buffer */
    1615     if (cannot_access_at_index(input_buffer, 0))
    1616     {
    1617         input_buffer->offset--;
    1618         goto fail;
    1619     }
    1620 
    1621     /* step back to character in front of the first element */
    1622     input_buffer->offset--;
    1623     /* loop through the comma separated array elements */
    1624     do
    1625     {
    1626         /* allocate next item */
    1627         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
    1628         if (new_item == NULL)
    1629         {
    1630             goto fail; /* allocation failure */
    1631         }
    1632 
    1633         /* attach next item to list */
    1634         if (head == NULL)
    1635         {
    1636             /* start the linked list */
    1637             current_item = head = new_item;
    1638         }
    1639         else
    1640         {
    1641             /* add to the end and advance */
    1642             current_item->next = new_item;
    1643             new_item->prev = current_item;
    1644             current_item = new_item;
    1645         }
    1646 
    1647         /* parse the name of the child */
    1648         input_buffer->offset++;
    1649         buffer_skip_whitespace(input_buffer);
    1650         if (!parse_string(current_item, input_buffer))
    1651         {
    1652             goto fail; /* failed to parse name */
    1653         }
    1654         buffer_skip_whitespace(input_buffer);
    1655 
    1656         /* swap valuestring and string, because we parsed the name */
    1657         current_item->string = current_item->valuestring;
    1658         current_item->valuestring = NULL;
    1659 
    1660         if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
    1661         {
    1662             goto fail; /* invalid object */
    1663         }
    1664 
    1665         /* parse the value */
    1666         input_buffer->offset++;
    1667         buffer_skip_whitespace(input_buffer);
    1668         if (!parse_value(current_item, input_buffer))
    1669         {
    1670             goto fail; /* failed to parse value */
    1671         }
    1672         buffer_skip_whitespace(input_buffer);
    1673     }
    1674     while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
    1675 
    1676     if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
    1677     {
    1678         goto fail; /* expected end of object */
    1679     }
    1680 
    1681 success:
    1682     input_buffer->depth--;
    1683 
    1684     item->type = cJSON_Object;
    1685     item->child = head;
    1686 
    1687     input_buffer->offset++;
    1688     return true;
    1689 
    1690 fail:
    1691     if (head != NULL)
    1692     {
    1693         cJSON_Delete(head);
    1694     }
    1695 
    1696     return false;
    1697 }
    1698 
    1699 /* Render an object to text. */
    1700 static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
    1701 {
    1702     unsigned char *output_pointer = NULL;
    1703     size_t length = 0;
    1704     cJSON *current_item = item->child;
    1705 
    1706     if (output_buffer == NULL)
    1707     {
    1708         return false;
    1709     }
    1710 
    1711     /* Compose the output: */
    1712     length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {
     */
    1713     output_pointer = ensure(output_buffer, length + 1);
    1714     if (output_pointer == NULL)
    1715     {
    1716         return false;
    1717     }
    1718 
    1719     *output_pointer++ = '{';
    1720     output_buffer->depth++;
    1721     if (output_buffer->format)
    1722     {
    1723         *output_pointer++ = '
    ';
    1724     }
    1725     output_buffer->offset += length;
    1726 
    1727     while (current_item)
    1728     {
    1729         if (output_buffer->format)
    1730         {
    1731             size_t i;
    1732             output_pointer = ensure(output_buffer, output_buffer->depth);
    1733             if (output_pointer == NULL)
    1734             {
    1735                 return false;
    1736             }
    1737             for (i = 0; i < output_buffer->depth; i++)
    1738             {
    1739                 *output_pointer++ = '	';
    1740             }
    1741             output_buffer->offset += output_buffer->depth;
    1742         }
    1743 
    1744         /* print key */
    1745         if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
    1746         {
    1747             return false;
    1748         }
    1749         update_offset(output_buffer);
    1750 
    1751         length = (size_t) (output_buffer->format ? 2 : 1);
    1752         output_pointer = ensure(output_buffer, length);
    1753         if (output_pointer == NULL)
    1754         {
    1755             return false;
    1756         }
    1757         *output_pointer++ = ':';
    1758         if (output_buffer->format)
    1759         {
    1760             *output_pointer++ = '	';
    1761         }
    1762         output_buffer->offset += length;
    1763 
    1764         /* print value */
    1765         if (!print_value(current_item, output_buffer))
    1766         {
    1767             return false;
    1768         }
    1769         update_offset(output_buffer);
    1770 
    1771         /* print comma if not last */
    1772         length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
    1773         output_pointer = ensure(output_buffer, length + 1);
    1774         if (output_pointer == NULL)
    1775         {
    1776             return false;
    1777         }
    1778         if (current_item->next)
    1779         {
    1780             *output_pointer++ = ',';
    1781         }
    1782 
    1783         if (output_buffer->format)
    1784         {
    1785             *output_pointer++ = '
    ';
    1786         }
    1787         *output_pointer = '';
    1788         output_buffer->offset += length;
    1789 
    1790         current_item = current_item->next;
    1791     }
    1792 
    1793     output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
    1794     if (output_pointer == NULL)
    1795     {
    1796         return false;
    1797     }
    1798     if (output_buffer->format)
    1799     {
    1800         size_t i;
    1801         for (i = 0; i < (output_buffer->depth - 1); i++)
    1802         {
    1803             *output_pointer++ = '	';
    1804         }
    1805     }
    1806     *output_pointer++ = '}';
    1807     *output_pointer = '';
    1808     output_buffer->depth--;
    1809 
    1810     return true;
    1811 }
    1812 
    1813 /* Get Array size/item / object item. */
    1814 CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
    1815 {
    1816     cJSON *child = NULL;
    1817     size_t size = 0;
    1818 
    1819     if (array == NULL)
    1820     {
    1821         return 0;
    1822     }
    1823 
    1824     child = array->child;
    1825 
    1826     while(child != NULL)
    1827     {
    1828         size++;
    1829         child = child->next;
    1830     }
    1831 
    1832     /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
    1833 
    1834     return (int)size;
    1835 }
    1836 
    1837 static cJSON* get_array_item(const cJSON *array, size_t index)
    1838 {
    1839     cJSON *current_child = NULL;
    1840 
    1841     if (array == NULL)
    1842     {
    1843         return NULL;
    1844     }
    1845 
    1846     current_child = array->child;
    1847     while ((current_child != NULL) && (index > 0))
    1848     {
    1849         index--;
    1850         current_child = current_child->next;
    1851     }
    1852 
    1853     return current_child;
    1854 }
    1855 
    1856 CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
    1857 {
    1858     if (index < 0)
    1859     {
    1860         return NULL;
    1861     }
    1862 
    1863     return get_array_item(array, (size_t)index);
    1864 }
    1865 
    1866 static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
    1867 {
    1868     cJSON *current_element = NULL;
    1869 
    1870     if ((object == NULL) || (name == NULL))
    1871     {
    1872         return NULL;
    1873     }
    1874 
    1875     current_element = object->child;
    1876     if (case_sensitive)
    1877     {
    1878         while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
    1879         {
    1880             current_element = current_element->next;
    1881         }
    1882     }
    1883     else
    1884     {
    1885         while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
    1886         {
    1887             current_element = current_element->next;
    1888         }
    1889     }
    1890 
    1891     if ((current_element == NULL) || (current_element->string == NULL)) {
    1892         return NULL;
    1893     }
    1894 
    1895     return current_element;
    1896 }
    1897 
    1898 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
    1899 {
    1900     return get_object_item(object, string, false);
    1901 }
    1902 
    1903 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
    1904 {
    1905     return get_object_item(object, string, true);
    1906 }
    1907 
    1908 CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
    1909 {
    1910     return cJSON_GetObjectItem(object, string) ? 1 : 0;
    1911 }
    1912 
    1913 /* Utility for array list handling. */
    1914 static void suffix_object(cJSON *prev, cJSON *item)
    1915 {
    1916     prev->next = item;
    1917     item->prev = prev;
    1918 }
    1919 
    1920 /* Utility for handling references. */
    1921 static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
    1922 {
    1923     cJSON *reference = NULL;
    1924     if (item == NULL)
    1925     {
    1926         return NULL;
    1927     }
    1928 
    1929     reference = cJSON_New_Item(hooks);
    1930     if (reference == NULL)
    1931     {
    1932         return NULL;
    1933     }
    1934 
    1935     memcpy(reference, item, sizeof(cJSON));
    1936     reference->string = NULL;
    1937     reference->type |= cJSON_IsReference;
    1938     reference->next = reference->prev = NULL;
    1939     return reference;
    1940 }
    1941 
    1942 static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
    1943 {
    1944     cJSON *child = NULL;
    1945 
    1946     if ((item == NULL) || (array == NULL) || (array == item))
    1947     {
    1948         return false;
    1949     }
    1950 
    1951     child = array->child;
    1952     /*
    1953      * To find the last item in array quickly, we use prev in array
    1954      */
    1955     if (child == NULL)
    1956     {
    1957         /* list is empty, start new one */
    1958         array->child = item;
    1959         item->prev = item;
    1960         item->next = NULL;
    1961     }
    1962     else
    1963     {
    1964         /* append to the end */
    1965         if (child->prev)
    1966         {
    1967             suffix_object(child->prev, item);
    1968             array->child->prev = item;
    1969         }
    1970         else
    1971         {
    1972             while (child->next)
    1973             {
    1974                 child = child->next;
    1975             }
    1976             suffix_object(child, item);
    1977             array->child->prev = item;
    1978         }
    1979     }
    1980 
    1981     return true;
    1982 }
    1983 
    1984 /* Add item to array/object. */
    1985 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
    1986 {
    1987     return add_item_to_array(array, item);
    1988 }
    1989 
    1990 #if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
    1991     #pragma GCC diagnostic push
    1992 #endif
    1993 #ifdef __GNUC__
    1994 #pragma GCC diagnostic ignored "-Wcast-qual"
    1995 #endif
    1996 /* helper function to cast away const */
    1997 static void* cast_away_const(const void* string)
    1998 {
    1999     return (void*)string;
    2000 }
    2001 #if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
    2002     #pragma GCC diagnostic pop
    2003 #endif
    2004 
    2005 
    2006 static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
    2007 {
    2008     char *new_key = NULL;
    2009     int new_type = cJSON_Invalid;
    2010 
    2011     if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
    2012     {
    2013         return false;
    2014     }
    2015 
    2016     if (constant_key)
    2017     {
    2018         new_key = (char*)cast_away_const(string);
    2019         new_type = item->type | cJSON_StringIsConst;
    2020     }
    2021     else
    2022     {
    2023         new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
    2024         if (new_key == NULL)
    2025         {
    2026             return false;
    2027         }
    2028 
    2029         new_type = item->type & ~cJSON_StringIsConst;
    2030     }
    2031 
    2032     if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
    2033     {
    2034         hooks->deallocate(item->string);
    2035     }
    2036 
    2037     item->string = new_key;
    2038     item->type = new_type;
    2039 
    2040     return add_item_to_array(object, item);
    2041 }
    2042 
    2043 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
    2044 {
    2045     return add_item_to_object(object, string, item, &global_hooks, false);
    2046 }
    2047 
    2048 /* Add an item to an object with constant string as key */
    2049 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
    2050 {
    2051     return add_item_to_object(object, string, item, &global_hooks, true);
    2052 }
    2053 
    2054 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
    2055 {
    2056     if (array == NULL)
    2057     {
    2058         return false;
    2059     }
    2060 
    2061     return add_item_to_array(array, create_reference(item, &global_hooks));
    2062 }
    2063 
    2064 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
    2065 {
    2066     if ((object == NULL) || (string == NULL))
    2067     {
    2068         return false;
    2069     }
    2070 
    2071     return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
    2072 }
    2073 
    2074 CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
    2075 {
    2076     cJSON *null = cJSON_CreateNull();
    2077     if (add_item_to_object(object, name, null, &global_hooks, false))
    2078     {
    2079         return null;
    2080     }
    2081 
    2082     cJSON_Delete(null);
    2083     return NULL;
    2084 }
    2085 
    2086 CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
    2087 {
    2088     cJSON *true_item = cJSON_CreateTrue();
    2089     if (add_item_to_object(object, name, true_item, &global_hooks, false))
    2090     {
    2091         return true_item;
    2092     }
    2093 
    2094     cJSON_Delete(true_item);
    2095     return NULL;
    2096 }
    2097 
    2098 CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
    2099 {
    2100     cJSON *false_item = cJSON_CreateFalse();
    2101     if (add_item_to_object(object, name, false_item, &global_hooks, false))
    2102     {
    2103         return false_item;
    2104     }
    2105 
    2106     cJSON_Delete(false_item);
    2107     return NULL;
    2108 }
    2109 
    2110 CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
    2111 {
    2112     cJSON *bool_item = cJSON_CreateBool(boolean);
    2113     if (add_item_to_object(object, name, bool_item, &global_hooks, false))
    2114     {
    2115         return bool_item;
    2116     }
    2117 
    2118     cJSON_Delete(bool_item);
    2119     return NULL;
    2120 }
    2121 
    2122 CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
    2123 {
    2124     cJSON *number_item = cJSON_CreateNumber(number);
    2125     if (add_item_to_object(object, name, number_item, &global_hooks, false))
    2126     {
    2127         return number_item;
    2128     }
    2129 
    2130     cJSON_Delete(number_item);
    2131     return NULL;
    2132 }
    2133 
    2134 CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
    2135 {
    2136     cJSON *string_item = cJSON_CreateString(string);
    2137     if (add_item_to_object(object, name, string_item, &global_hooks, false))
    2138     {
    2139         return string_item;
    2140     }
    2141 
    2142     cJSON_Delete(string_item);
    2143     return NULL;
    2144 }
    2145 
    2146 CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
    2147 {
    2148     cJSON *raw_item = cJSON_CreateRaw(raw);
    2149     if (add_item_to_object(object, name, raw_item, &global_hooks, false))
    2150     {
    2151         return raw_item;
    2152     }
    2153 
    2154     cJSON_Delete(raw_item);
    2155     return NULL;
    2156 }
    2157 
    2158 CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
    2159 {
    2160     cJSON *object_item = cJSON_CreateObject();
    2161     if (add_item_to_object(object, name, object_item, &global_hooks, false))
    2162     {
    2163         return object_item;
    2164     }
    2165 
    2166     cJSON_Delete(object_item);
    2167     return NULL;
    2168 }
    2169 
    2170 CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
    2171 {
    2172     cJSON *array = cJSON_CreateArray();
    2173     if (add_item_to_object(object, name, array, &global_hooks, false))
    2174     {
    2175         return array;
    2176     }
    2177 
    2178     cJSON_Delete(array);
    2179     return NULL;
    2180 }
    2181 
    2182 CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
    2183 {
    2184     if ((parent == NULL) || (item == NULL))
    2185     {
    2186         return NULL;
    2187     }
    2188 
    2189     if (item != parent->child)
    2190     {
    2191         /* not the first element */
    2192         item->prev->next = item->next;
    2193     }
    2194     if (item->next != NULL)
    2195     {
    2196         /* not the last element */
    2197         item->next->prev = item->prev;
    2198     }
    2199 
    2200     if (item == parent->child)
    2201     {
    2202         /* first element */
    2203         parent->child = item->next;
    2204     }
    2205     /* make sure the detached item doesn't point anywhere anymore */
    2206     item->prev = NULL;
    2207     item->next = NULL;
    2208 
    2209     return item;
    2210 }
    2211 
    2212 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
    2213 {
    2214     if (which < 0)
    2215     {
    2216         return NULL;
    2217     }
    2218 
    2219     return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
    2220 }
    2221 
    2222 CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
    2223 {
    2224     cJSON_Delete(cJSON_DetachItemFromArray(array, which));
    2225 }
    2226 
    2227 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
    2228 {
    2229     cJSON *to_detach = cJSON_GetObjectItem(object, string);
    2230 
    2231     return cJSON_DetachItemViaPointer(object, to_detach);
    2232 }
    2233 
    2234 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
    2235 {
    2236     cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
    2237 
    2238     return cJSON_DetachItemViaPointer(object, to_detach);
    2239 }
    2240 
    2241 CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
    2242 {
    2243     cJSON_Delete(cJSON_DetachItemFromObject(object, string));
    2244 }
    2245 
    2246 CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
    2247 {
    2248     cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
    2249 }
    2250 
    2251 /* Replace array/object items with new ones. */
    2252 CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
    2253 {
    2254     cJSON *after_inserted = NULL;
    2255 
    2256     if (which < 0)
    2257     {
    2258         return false;
    2259     }
    2260 
    2261     after_inserted = get_array_item(array, (size_t)which);
    2262     if (after_inserted == NULL)
    2263     {
    2264         return add_item_to_array(array, newitem);
    2265     }
    2266 
    2267     newitem->next = after_inserted;
    2268     newitem->prev = after_inserted->prev;
    2269     after_inserted->prev = newitem;
    2270     if (after_inserted == array->child)
    2271     {
    2272         array->child = newitem;
    2273     }
    2274     else
    2275     {
    2276         newitem->prev->next = newitem;
    2277     }
    2278     return true;
    2279 }
    2280 
    2281 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
    2282 {
    2283     if ((parent == NULL) || (replacement == NULL) || (item == NULL))
    2284     {
    2285         return false;
    2286     }
    2287 
    2288     if (replacement == item)
    2289     {
    2290         return true;
    2291     }
    2292 
    2293     replacement->next = item->next;
    2294     replacement->prev = item->prev;
    2295 
    2296     if (replacement->next != NULL)
    2297     {
    2298         replacement->next->prev = replacement;
    2299     }
    2300     if (parent->child == item)
    2301     {
    2302         parent->child = replacement;
    2303     }
    2304     else
    2305     {   /*
    2306          * To find the last item in array quickly, we use prev in array.
    2307          * We can't modify the last item's next pointer where this item was the parent's child
    2308          */
    2309         if (replacement->prev != NULL)
    2310         {
    2311             replacement->prev->next = replacement;
    2312         }
    2313     }
    2314 
    2315     item->next = NULL;
    2316     item->prev = NULL;
    2317     cJSON_Delete(item);
    2318 
    2319     return true;
    2320 }
    2321 
    2322 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
    2323 {
    2324     if (which < 0)
    2325     {
    2326         return false;
    2327     }
    2328 
    2329     return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
    2330 }
    2331 
    2332 static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
    2333 {
    2334     if ((replacement == NULL) || (string == NULL))
    2335     {
    2336         return false;
    2337     }
    2338 
    2339     /* replace the name in the replacement */
    2340     if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
    2341     {
    2342         cJSON_free(replacement->string);
    2343     }
    2344     replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
    2345     replacement->type &= ~cJSON_StringIsConst;
    2346 
    2347     return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
    2348 }
    2349 
    2350 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
    2351 {
    2352     return replace_item_in_object(object, string, newitem, false);
    2353 }
    2354 
    2355 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
    2356 {
    2357     return replace_item_in_object(object, string, newitem, true);
    2358 }
    2359 
    2360 /* Create basic types: */
    2361 CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
    2362 {
    2363     cJSON *item = cJSON_New_Item(&global_hooks);
    2364     if(item)
    2365     {
    2366         item->type = cJSON_NULL;
    2367     }
    2368 
    2369     return item;
    2370 }
    2371 
    2372 CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
    2373 {
    2374     cJSON *item = cJSON_New_Item(&global_hooks);
    2375     if(item)
    2376     {
    2377         item->type = cJSON_True;
    2378     }
    2379 
    2380     return item;
    2381 }
    2382 
    2383 CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
    2384 {
    2385     cJSON *item = cJSON_New_Item(&global_hooks);
    2386     if(item)
    2387     {
    2388         item->type = cJSON_False;
    2389     }
    2390 
    2391     return item;
    2392 }
    2393 
    2394 CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
    2395 {
    2396     cJSON *item = cJSON_New_Item(&global_hooks);
    2397     if(item)
    2398     {
    2399         item->type = boolean ? cJSON_True : cJSON_False;
    2400     }
    2401 
    2402     return item;
    2403 }
    2404 
    2405 CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
    2406 {
    2407     cJSON *item = cJSON_New_Item(&global_hooks);
    2408     if(item)
    2409     {
    2410         item->type = cJSON_Number;
    2411         item->valuedouble = num;
    2412 
    2413         /* use saturation in case of overflow */
    2414         if (num >= INT_MAX)
    2415         {
    2416             item->valueint = INT_MAX;
    2417         }
    2418         else if (num <= (double)INT_MIN)
    2419         {
    2420             item->valueint = INT_MIN;
    2421         }
    2422         else
    2423         {
    2424             item->valueint = (int)num;
    2425         }
    2426     }
    2427 
    2428     return item;
    2429 }
    2430 
    2431 CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
    2432 {
    2433     cJSON *item = cJSON_New_Item(&global_hooks);
    2434     if(item)
    2435     {
    2436         item->type = cJSON_String;
    2437         item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
    2438         if(!item->valuestring)
    2439         {
    2440             cJSON_Delete(item);
    2441             return NULL;
    2442         }
    2443     }
    2444 
    2445     return item;
    2446 }
    2447 
    2448 CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
    2449 {
    2450     cJSON *item = cJSON_New_Item(&global_hooks);
    2451     if (item != NULL)
    2452     {
    2453         item->type = cJSON_String | cJSON_IsReference;
    2454         item->valuestring = (char*)cast_away_const(string);
    2455     }
    2456 
    2457     return item;
    2458 }
    2459 
    2460 CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
    2461 {
    2462     cJSON *item = cJSON_New_Item(&global_hooks);
    2463     if (item != NULL) {
    2464         item->type = cJSON_Object | cJSON_IsReference;
    2465         item->child = (cJSON*)cast_away_const(child);
    2466     }
    2467 
    2468     return item;
    2469 }
    2470 
    2471 CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
    2472     cJSON *item = cJSON_New_Item(&global_hooks);
    2473     if (item != NULL) {
    2474         item->type = cJSON_Array | cJSON_IsReference;
    2475         item->child = (cJSON*)cast_away_const(child);
    2476     }
    2477 
    2478     return item;
    2479 }
    2480 
    2481 CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
    2482 {
    2483     cJSON *item = cJSON_New_Item(&global_hooks);
    2484     if(item)
    2485     {
    2486         item->type = cJSON_Raw;
    2487         item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
    2488         if(!item->valuestring)
    2489         {
    2490             cJSON_Delete(item);
    2491             return NULL;
    2492         }
    2493     }
    2494 
    2495     return item;
    2496 }
    2497 
    2498 CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
    2499 {
    2500     cJSON *item = cJSON_New_Item(&global_hooks);
    2501     if(item)
    2502     {
    2503         item->type=cJSON_Array;
    2504     }
    2505 
    2506     return item;
    2507 }
    2508 
    2509 CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
    2510 {
    2511     cJSON *item = cJSON_New_Item(&global_hooks);
    2512     if (item)
    2513     {
    2514         item->type = cJSON_Object;
    2515     }
    2516 
    2517     return item;
    2518 }
    2519 
    2520 /* Create Arrays: */
    2521 CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
    2522 {
    2523     size_t i = 0;
    2524     cJSON *n = NULL;
    2525     cJSON *p = NULL;
    2526     cJSON *a = NULL;
    2527 
    2528     if ((count < 0) || (numbers == NULL))
    2529     {
    2530         return NULL;
    2531     }
    2532 
    2533     a = cJSON_CreateArray();
    2534     for(i = 0; a && (i < (size_t)count); i++)
    2535     {
    2536         n = cJSON_CreateNumber(numbers[i]);
    2537         if (!n)
    2538         {
    2539             cJSON_Delete(a);
    2540             return NULL;
    2541         }
    2542         if(!i)
    2543         {
    2544             a->child = n;
    2545         }
    2546         else
    2547         {
    2548             suffix_object(p, n);
    2549         }
    2550         p = n;
    2551     }
    2552 
    2553     return a;
    2554 }
    2555 
    2556 CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
    2557 {
    2558     size_t i = 0;
    2559     cJSON *n = NULL;
    2560     cJSON *p = NULL;
    2561     cJSON *a = NULL;
    2562 
    2563     if ((count < 0) || (numbers == NULL))
    2564     {
    2565         return NULL;
    2566     }
    2567 
    2568     a = cJSON_CreateArray();
    2569 
    2570     for(i = 0; a && (i < (size_t)count); i++)
    2571     {
    2572         n = cJSON_CreateNumber((double)numbers[i]);
    2573         if(!n)
    2574         {
    2575             cJSON_Delete(a);
    2576             return NULL;
    2577         }
    2578         if(!i)
    2579         {
    2580             a->child = n;
    2581         }
    2582         else
    2583         {
    2584             suffix_object(p, n);
    2585         }
    2586         p = n;
    2587     }
    2588 
    2589     return a;
    2590 }
    2591 
    2592 CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
    2593 {
    2594     size_t i = 0;
    2595     cJSON *n = NULL;
    2596     cJSON *p = NULL;
    2597     cJSON *a = NULL;
    2598 
    2599     if ((count < 0) || (numbers == NULL))
    2600     {
    2601         return NULL;
    2602     }
    2603 
    2604     a = cJSON_CreateArray();
    2605 
    2606     for(i = 0;a && (i < (size_t)count); i++)
    2607     {
    2608         n = cJSON_CreateNumber(numbers[i]);
    2609         if(!n)
    2610         {
    2611             cJSON_Delete(a);
    2612             return NULL;
    2613         }
    2614         if(!i)
    2615         {
    2616             a->child = n;
    2617         }
    2618         else
    2619         {
    2620             suffix_object(p, n);
    2621         }
    2622         p = n;
    2623     }
    2624 
    2625     return a;
    2626 }
    2627 
    2628 CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
    2629 {
    2630     size_t i = 0;
    2631     cJSON *n = NULL;
    2632     cJSON *p = NULL;
    2633     cJSON *a = NULL;
    2634 
    2635     if ((count < 0) || (strings == NULL))
    2636     {
    2637         return NULL;
    2638     }
    2639 
    2640     a = cJSON_CreateArray();
    2641 
    2642     for (i = 0; a && (i < (size_t)count); i++)
    2643     {
    2644         n = cJSON_CreateString(strings[i]);
    2645         if(!n)
    2646         {
    2647             cJSON_Delete(a);
    2648             return NULL;
    2649         }
    2650         if(!i)
    2651         {
    2652             a->child = n;
    2653         }
    2654         else
    2655         {
    2656             suffix_object(p,n);
    2657         }
    2658         p = n;
    2659     }
    2660 
    2661     return a;
    2662 }
    2663 
    2664 /* Duplication */
    2665 CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
    2666 {
    2667     cJSON *newitem = NULL;
    2668     cJSON *child = NULL;
    2669     cJSON *next = NULL;
    2670     cJSON *newchild = NULL;
    2671 
    2672     /* Bail on bad ptr */
    2673     if (!item)
    2674     {
    2675         goto fail;
    2676     }
    2677     /* Create new item */
    2678     newitem = cJSON_New_Item(&global_hooks);
    2679     if (!newitem)
    2680     {
    2681         goto fail;
    2682     }
    2683     /* Copy over all vars */
    2684     newitem->type = item->type & (~cJSON_IsReference);
    2685     newitem->valueint = item->valueint;
    2686     newitem->valuedouble = item->valuedouble;
    2687     if (item->valuestring)
    2688     {
    2689         newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
    2690         if (!newitem->valuestring)
    2691         {
    2692             goto fail;
    2693         }
    2694     }
    2695     if (item->string)
    2696     {
    2697         newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
    2698         if (!newitem->string)
    2699         {
    2700             goto fail;
    2701         }
    2702     }
    2703     /* If non-recursive, then we're done! */
    2704     if (!recurse)
    2705     {
    2706         return newitem;
    2707     }
    2708     /* Walk the ->next chain for the child. */
    2709     child = item->child;
    2710     while (child != NULL)
    2711     {
    2712         newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
    2713         if (!newchild)
    2714         {
    2715             goto fail;
    2716         }
    2717         if (next != NULL)
    2718         {
    2719             /* If newitem->child already set, then crosswire ->prev and ->next and move on */
    2720             next->next = newchild;
    2721             newchild->prev = next;
    2722             next = newchild;
    2723         }
    2724         else
    2725         {
    2726             /* Set newitem->child and move to it */
    2727             newitem->child = newchild;
    2728             next = newchild;
    2729         }
    2730         child = child->next;
    2731     }
    2732 
    2733     return newitem;
    2734 
    2735 fail:
    2736     if (newitem != NULL)
    2737     {
    2738         cJSON_Delete(newitem);
    2739     }
    2740 
    2741     return NULL;
    2742 }
    2743 
    2744 static void skip_oneline_comment(char **input)
    2745 {
    2746     *input += static_strlen("//");
    2747 
    2748     for (; (*input)[0] != ''; ++(*input))
    2749     {
    2750         if ((*input)[0] == '
    ') {
    2751             *input += static_strlen("
    ");
    2752             return;
    2753         }
    2754     }
    2755 }
    2756 
    2757 static void skip_multiline_comment(char **input)
    2758 {
    2759     *input += static_strlen("/*");
    2760 
    2761     for (; (*input)[0] != ''; ++(*input))
    2762     {
    2763         if (((*input)[0] == '*') && ((*input)[1] == '/'))
    2764         {
    2765             *input += static_strlen("*/");
    2766             return;
    2767         }
    2768     }
    2769 }
    2770 
    2771 static void minify_string(char **input, char **output) {
    2772     (*output)[0] = (*input)[0];
    2773     *input += static_strlen(""");
    2774     *output += static_strlen(""");
    2775 
    2776 
    2777     for (; (*input)[0] != ''; (void)++(*input), ++(*output)) {
    2778         (*output)[0] = (*input)[0];
    2779 
    2780         if ((*input)[0] == '"') {
    2781             (*output)[0] = '"';
    2782             *input += static_strlen(""");
    2783             *output += static_strlen(""");
    2784             return;
    2785         } else if (((*input)[0] == '\') && ((*input)[1] == '"')) {
    2786             (*output)[1] = (*input)[1];
    2787             *input += static_strlen(""");
    2788             *output += static_strlen(""");
    2789         }
    2790     }
    2791 }
    2792 
    2793 CJSON_PUBLIC(void) cJSON_Minify(char *json)
    2794 {
    2795     char *into = json;
    2796 
    2797     if (json == NULL)
    2798     {
    2799         return;
    2800     }
    2801 
    2802     while (json[0] != '')
    2803     {
    2804         switch (json[0])
    2805         {
    2806             case ' ':
    2807             case '	':
    2808             case '
    ':
    2809             case '
    ':
    2810                 json++;
    2811                 break;
    2812 
    2813             case '/':
    2814                 if (json[1] == '/')
    2815                 {
    2816                     skip_oneline_comment(&json);
    2817                 }
    2818                 else if (json[1] == '*')
    2819                 {
    2820                     skip_multiline_comment(&json);
    2821                 } else {
    2822                     json++;
    2823                 }
    2824                 break;
    2825 
    2826             case '"':
    2827                 minify_string(&json, (char**)&into);
    2828                 break;
    2829 
    2830             default:
    2831                 into[0] = json[0];
    2832                 json++;
    2833                 into++;
    2834         }
    2835     }
    2836 
    2837     /* and null-terminate. */
    2838     *into = '';
    2839 }
    2840 
    2841 CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
    2842 {
    2843     if (item == NULL)
    2844     {
    2845         return false;
    2846     }
    2847 
    2848     return (item->type & 0xFF) == cJSON_Invalid;
    2849 }
    2850 
    2851 CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
    2852 {
    2853     if (item == NULL)
    2854     {
    2855         return false;
    2856     }
    2857 
    2858     return (item->type & 0xFF) == cJSON_False;
    2859 }
    2860 
    2861 CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
    2862 {
    2863     if (item == NULL)
    2864     {
    2865         return false;
    2866     }
    2867 
    2868     return (item->type & 0xff) == cJSON_True;
    2869 }
    2870 
    2871 
    2872 CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
    2873 {
    2874     if (item == NULL)
    2875     {
    2876         return false;
    2877     }
    2878 
    2879     return (item->type & (cJSON_True | cJSON_False)) != 0;
    2880 }
    2881 CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
    2882 {
    2883     if (item == NULL)
    2884     {
    2885         return false;
    2886     }
    2887 
    2888     return (item->type & 0xFF) == cJSON_NULL;
    2889 }
    2890 
    2891 CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
    2892 {
    2893     if (item == NULL)
    2894     {
    2895         return false;
    2896     }
    2897 
    2898     return (item->type & 0xFF) == cJSON_Number;
    2899 }
    2900 
    2901 CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
    2902 {
    2903     if (item == NULL)
    2904     {
    2905         return false;
    2906     }
    2907 
    2908     return (item->type & 0xFF) == cJSON_String;
    2909 }
    2910 
    2911 CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
    2912 {
    2913     if (item == NULL)
    2914     {
    2915         return false;
    2916     }
    2917 
    2918     return (item->type & 0xFF) == cJSON_Array;
    2919 }
    2920 
    2921 CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
    2922 {
    2923     if (item == NULL)
    2924     {
    2925         return false;
    2926     }
    2927 
    2928     return (item->type & 0xFF) == cJSON_Object;
    2929 }
    2930 
    2931 CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
    2932 {
    2933     if (item == NULL)
    2934     {
    2935         return false;
    2936     }
    2937 
    2938     return (item->type & 0xFF) == cJSON_Raw;
    2939 }
    2940 
    2941 CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
    2942 {
    2943     if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
    2944     {
    2945         return false;
    2946     }
    2947 
    2948     /* check if type is valid */
    2949     switch (a->type & 0xFF)
    2950     {
    2951         case cJSON_False:
    2952         case cJSON_True:
    2953         case cJSON_NULL:
    2954         case cJSON_Number:
    2955         case cJSON_String:
    2956         case cJSON_Raw:
    2957         case cJSON_Array:
    2958         case cJSON_Object:
    2959             break;
    2960 
    2961         default:
    2962             return false;
    2963     }
    2964 
    2965     /* identical objects are equal */
    2966     if (a == b)
    2967     {
    2968         return true;
    2969     }
    2970 
    2971     switch (a->type & 0xFF)
    2972     {
    2973         /* in these cases and equal type is enough */
    2974         case cJSON_False:
    2975         case cJSON_True:
    2976         case cJSON_NULL:
    2977             return true;
    2978 
    2979         case cJSON_Number:
    2980             if (compare_double(a->valuedouble, b->valuedouble))
    2981             {
    2982                 return true;
    2983             }
    2984             return false;
    2985 
    2986         case cJSON_String:
    2987         case cJSON_Raw:
    2988             if ((a->valuestring == NULL) || (b->valuestring == NULL))
    2989             {
    2990                 return false;
    2991             }
    2992             if (strcmp(a->valuestring, b->valuestring) == 0)
    2993             {
    2994                 return true;
    2995             }
    2996 
    2997             return false;
    2998 
    2999         case cJSON_Array:
    3000         {
    3001             cJSON *a_element = a->child;
    3002             cJSON *b_element = b->child;
    3003 
    3004             for (; (a_element != NULL) && (b_element != NULL);)
    3005             {
    3006                 if (!cJSON_Compare(a_element, b_element, case_sensitive))
    3007                 {
    3008                     return false;
    3009                 }
    3010 
    3011                 a_element = a_element->next;
    3012                 b_element = b_element->next;
    3013             }
    3014 
    3015             /* one of the arrays is longer than the other */
    3016             if (a_element != b_element) {
    3017                 return false;
    3018             }
    3019 
    3020             return true;
    3021         }
    3022 
    3023         case cJSON_Object:
    3024         {
    3025             cJSON *a_element = NULL;
    3026             cJSON *b_element = NULL;
    3027             cJSON_ArrayForEach(a_element, a)
    3028             {
    3029                 /* TODO This has O(n^2) runtime, which is horrible! */
    3030                 b_element = get_object_item(b, a_element->string, case_sensitive);
    3031                 if (b_element == NULL)
    3032                 {
    3033                     return false;
    3034                 }
    3035 
    3036                 if (!cJSON_Compare(a_element, b_element, case_sensitive))
    3037                 {
    3038                     return false;
    3039                 }
    3040             }
    3041 
    3042             /* doing this twice, once on a and b to prevent true comparison if a subset of b
    3043              * TODO: Do this the proper way, this is just a fix for now */
    3044             cJSON_ArrayForEach(b_element, b)
    3045             {
    3046                 a_element = get_object_item(a, b_element->string, case_sensitive);
    3047                 if (a_element == NULL)
    3048                 {
    3049                     return false;
    3050                 }
    3051 
    3052                 if (!cJSON_Compare(b_element, a_element, case_sensitive))
    3053                 {
    3054                     return false;
    3055                 }
    3056             }
    3057 
    3058             return true;
    3059         }
    3060 
    3061         default:
    3062             return false;
    3063     }
    3064 }
    3065 
    3066 CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
    3067 {
    3068     return global_hooks.allocate(size);
    3069 }
    3070 
    3071 CJSON_PUBLIC(void) cJSON_free(void *object)
    3072 {
    3073     global_hooks.deallocate(object);
    3074 }
    View Code

     参考:

    https://blog.csdn.net/shizhe0123/article/details/94742514

    https://blog.csdn.net/fengxinlinux/article/details/53121287

    https://www.cnblogs.com/skullboyer/p/8152157.html

  • 相关阅读:
    MySQL8安装及使用当中的一些注意事项
    设计模式-观察者模式
    在线教育项目-day12【完善后端整合前端】
    在线教育项目-day12【微信扫码登录】
    在线教育项目-day12【OAuth2】
    在线教育项目-day12【完善登陆页面】
    在线教育项目-day12【整合前端登陆注册页面(2)】
    在线教育项目-day12【整合前端登陆注册页面(1)】
    在线教育项目-day12【解析oken信息】
    在线教育项目-day12【注册接口】
  • 原文地址:https://www.cnblogs.com/dongxiaodong/p/13053208.html
Copyright © 2011-2022 走看看