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