├── LICENSE ├── README.md └── src ├── LuaJsonLib.cpp ├── LuaJsonLib.h ├── cJSON.c └── cJSON.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Voidmatrix 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LuaJsonLib 2 | 3 | JSON 解析库 4 | 5 | ## API 总览 6 | 7 | | 名称 | 功能 | 8 | |:--------------------:|:-----------------------------------------------------:| 9 | | `value = Load(str)` | 将已编码的 JSON 对象解码为 Lua 对象 | 10 | | `value = LoadFromFile(path)` | 将指定路径文件中已编码的 JSON 对象解码为 Lua 对象 | 11 | | `str = Dump(value [, isFormat=false])` | 将 Lua 对象编码成 JSON 字符串 | 12 | | `DumpToFile(value, path [, isFormat=false])` | 将 Lua 对象编码成 JSON 字符串并存储到指定路径的文件中 | 13 | 14 | ## API 详述 15 | 16 | + ### value = Load(str) 17 | - *功能:* 18 | 将已编码的 JSON 对象解码为 Lua 对象 19 | - *参数列表:* 20 | * str [string]:已编码的 JSON 对象字符串 21 | - *返回值列表:* 22 | * value [nil / boolean / number / string / table]:解码后的 Lua 对象 23 | 24 | + ### value = LoadFromFile(path) 25 | - *功能:* 26 | 将指定路径文件中已编码的 JSON 对象解码为 Lua 对象 27 | - *参数列表:* 28 | * path [string]:存储已编码 JSON 对象的文件路径 29 | - *返回值列表:* 30 | * value [nil / boolean / number / string / table]:解码后的 Lua 对象 31 | 32 | + ### str = Dump(value [, isFormat=false]) 33 | - *功能:* 34 | 将 Lua 对象编码成 JSON 字符串 35 | - *参数列表:* 36 | * value [nil / boolean / number / string / table]:Lua 对象 37 | * isFormat [boolean]:(可选)是否对编码后的字符串格式化,默认不进行格式化 38 | - *返回值列表:* 39 | * str [string]:已编码的 JSON 对象字符串 40 | 41 | + ### DumpToFile(value, path [, isFormat=false]) 42 | - *功能:* 43 | 将 Lua 对象编码成 JSON 字符串并存储到指定路径的文件中 44 | - *参数列表:* 45 | * value [nil / boolean / number / string / table]:Lua 对象 46 | * path [string]:用以存储已编码 JSON 对象的文件路径 47 | * isFormat [boolean]:(可选)是否对编码后的字符串格式化,默认不进行格式化 48 | - *返回值列表:* 49 | 无 50 | 51 | ## 注意 52 | 53 | 由于 Lua 语法允许数字索引和字符串索引同处于一个 table 类型的变量中,故当两者并存时,调用 `Dump()` 或 `DumpToFile()` 方法会将数字索引转换为对应的字符串索引,如:`ExmpTable = { name = "xiaoming", "Here" }` 在进行编码后对应的 JSON 字符串可能为:`{ "1": "Here", "name": "xiaoming" }` 54 | 同样的,在对 JSON 字符串进行解码时,LuaJsonLib 也会优先将可能转换为数字索引的字符串键值转化数字索引存入对应的 table 中 55 | 所以,为避免编码的 JSON 数据与其他程序交互时产生二义性,请尽量避免对同时存在数字索引和字符串索引的 table 类型数据进行编码 56 | 57 | ## 特别感谢 58 | 59 | + [cJSON](https://github.com/DaveGamble/cJSON):为 LuaJsonLib 提供了跨平台的底层实现 60 | 61 | ## 其他 62 | 63 | 本项目已被 [LuaLibs](https://github.com/VoidmatrixHeathcliff/LuaLibs) 收录 64 | -------------------------------------------------------------------------------- /src/LuaJsonLib.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaJsonLib.h" 2 | 3 | bool CheckArrary(lua_State* L, int iIndex) 4 | { 5 | lua_pushnil(L); 6 | while (lua_next(L, iIndex) != 0) 7 | { 8 | switch (lua_type(L, -2)) 9 | { 10 | case LUA_TSTRING: 11 | lua_pop(L, 2); 12 | return false; 13 | case LUA_TNUMBER: 14 | break; 15 | default: 16 | luaL_argcheck(L, false, 1, (string("key not support to dump: ") + lua_typename(L, -2)).c_str()); 17 | break; 18 | } 19 | lua_pop(L, 1); 20 | } 21 | return true; 22 | } 23 | 24 | void LuaTable2CJson(cJSON*& pJsonNode, int iIndex, lua_State* L) 25 | { 26 | lua_pushnil(L); 27 | if (CheckArrary(L, iIndex)) 28 | { 29 | pJsonNode = cJSON_CreateArray(); 30 | while (lua_next(L, iIndex)) 31 | { 32 | switch (lua_type(L, -1)) 33 | { 34 | case LUA_TNIL: 35 | cJSON_AddItemToArray(pJsonNode, cJSON_CreateNull()); 36 | break; 37 | case LUA_TBOOLEAN: 38 | cJSON_AddItemToArray(pJsonNode, cJSON_CreateBool(lua_toboolean(L, -1))); 39 | break; 40 | case LUA_TNUMBER: 41 | cJSON_AddItemToArray(pJsonNode, cJSON_CreateNumber(lua_tonumber(L, -1))); 42 | break; 43 | case LUA_TSTRING: 44 | cJSON_AddItemToArray(pJsonNode, cJSON_CreateString(lua_tostring(L, -1))); 45 | break; 46 | case LUA_TTABLE: 47 | { 48 | cJSON* pNewJsonNode = nullptr; 49 | LuaTable2CJson(pNewJsonNode, lua_gettop(L), L); 50 | cJSON_AddItemToArray(pJsonNode, pNewJsonNode); 51 | } 52 | break; 53 | default: 54 | luaL_argcheck(L, false, 1, (string("value not support to dump: [") + lua_tostring(L, -2) + "]" + lua_typename(L, -1)).c_str()); 55 | break; 56 | } 57 | lua_pop(L, 1); 58 | } 59 | } 60 | else 61 | { 62 | pJsonNode = cJSON_CreateObject(); 63 | while (lua_next(L, iIndex)) 64 | { 65 | string strKey; 66 | if (lua_type(L, -2) == LUA_TSTRING) 67 | strKey = lua_tostring(L, -2); 68 | else 69 | strKey = to_string(lua_tointeger(L, -2)); 70 | switch (lua_type(L, -1)) 71 | { 72 | case LUA_TNIL: 73 | cJSON_AddItemToObject(pJsonNode, strKey.c_str(), cJSON_CreateNull()); 74 | break; 75 | case LUA_TBOOLEAN: 76 | cJSON_AddItemToObject(pJsonNode, strKey.c_str(), cJSON_CreateBool(lua_toboolean(L, -1))); 77 | break; 78 | case LUA_TNUMBER: 79 | cJSON_AddItemToObject(pJsonNode, strKey.c_str(), cJSON_CreateNumber(lua_tonumber(L, -1))); 80 | break; 81 | case LUA_TSTRING: 82 | cJSON_AddItemToObject(pJsonNode, strKey.c_str(), cJSON_CreateString(lua_tostring(L, -1))); 83 | break; 84 | case LUA_TTABLE: 85 | { 86 | cJSON* pNewJsonNode = nullptr; 87 | LuaTable2CJson(pNewJsonNode, lua_gettop(L), L); 88 | cJSON_AddItemToObject(pJsonNode, strKey.c_str(), pNewJsonNode); 89 | } 90 | break; 91 | default: 92 | luaL_argcheck(L, false, 1, (string("value not support to dump: [") + strKey.c_str() + "]" + lua_typename(L, -1)).c_str()); 93 | break; 94 | } 95 | lua_pop(L, 1); 96 | } 97 | } 98 | } 99 | 100 | char* LuaVaule2JSONStr(lua_State* L, bool bIsFormat) 101 | { 102 | cJSON* pJsonRoot = nullptr; 103 | switch (lua_type(L, 1)) 104 | { 105 | case LUA_TNIL: 106 | pJsonRoot = cJSON_CreateNull(); 107 | break; 108 | case LUA_TBOOLEAN: 109 | pJsonRoot = cJSON_CreateBool(lua_toboolean(L, 1)); 110 | break; 111 | case LUA_TNUMBER: 112 | pJsonRoot = cJSON_CreateNumber(lua_tonumber(L, 1)); 113 | break; 114 | case LUA_TSTRING: 115 | pJsonRoot = cJSON_CreateString(lua_tostring(L, 1)); 116 | break; 117 | case LUA_TTABLE: 118 | LuaTable2CJson(pJsonRoot, 1, L); 119 | break; 120 | default: 121 | luaL_argcheck(L, false, 1, string(lua_typename(L, 1)).append(" not support to dump").c_str()); 122 | break; 123 | } 124 | cJSON_Delete(pJsonRoot); 125 | return bIsFormat ? cJSON_Print(pJsonRoot) : cJSON_PrintUnformatted(pJsonRoot); 126 | } 127 | 128 | void CJson2LuaObj(cJSON* pJsonNode, lua_State* L) 129 | { 130 | if (pJsonNode->string) 131 | { 132 | int iKey = atoi(pJsonNode->string); 133 | if (iKey) 134 | lua_pushinteger(L, iKey); 135 | else 136 | lua_pushstring(L, pJsonNode->string); 137 | } 138 | switch (pJsonNode->type) 139 | { 140 | case cJSON_False: 141 | lua_pushboolean(L, false); 142 | break; 143 | case cJSON_True: 144 | lua_pushboolean(L, true); 145 | break; 146 | case cJSON_Number: 147 | lua_pushnumber(L, pJsonNode->valuedouble); 148 | break; 149 | case cJSON_String: 150 | lua_pushstring(L, pJsonNode->valuestring); 151 | break; 152 | case cJSON_Array: 153 | { 154 | lua_newtable(L); 155 | cJSON* pElement = pJsonNode->child; 156 | size_t iIndex = 1; 157 | while (pElement) 158 | { 159 | lua_pushnumber(L, iIndex++); 160 | CJson2LuaObj(pElement, L); 161 | pElement = pElement->next; 162 | lua_settable(L, -3); 163 | } 164 | } 165 | break; 166 | case cJSON_Object: 167 | { 168 | lua_newtable(L); 169 | cJSON* pElement = pJsonNode->child; 170 | while (pElement) 171 | { 172 | CJson2LuaObj(pElement, L); 173 | pElement = pElement->next; 174 | } 175 | } 176 | break; 177 | default: 178 | lua_pushnil(L); 179 | break; 180 | } 181 | if (pJsonNode->string) lua_settable(L, -3); 182 | } 183 | 184 | LIB_API api_Load(lua_State* L) 185 | { 186 | cJSON* pJsonRoot = cJSON_Parse(luaL_checkstring(L, 1)); 187 | luaL_argcheck(L, pJsonRoot, 1, string("JSON parse error before: ").append(cJSON_GetErrorPtr()).c_str()); 188 | CJson2LuaObj(pJsonRoot, L); 189 | cJSON_Delete(pJsonRoot); 190 | return 1; 191 | } 192 | 193 | LIB_API api_LoadFromFile(lua_State* L) 194 | { 195 | ifstream fin(luaL_checkstring(L, 1)); 196 | luaL_argcheck(L, fin.good(), 1, "no such JSON file"); 197 | stringstream ssContent; 198 | ssContent << fin.rdbuf(); 199 | fin.close(); fin.clear(); 200 | cJSON* pJsonRoot = cJSON_Parse(ssContent.str().c_str()); 201 | luaL_argcheck(L, pJsonRoot, 1, string("JSON parse error before: ").append(cJSON_GetErrorPtr()).c_str()); 202 | CJson2LuaObj(pJsonRoot, L); 203 | ssContent.clear(); cJSON_Delete(pJsonRoot); 204 | return 1; 205 | } 206 | 207 | LIB_API api_Dump(lua_State* L) 208 | { 209 | char* strJSON = LuaVaule2JSONStr(L, lua_toboolean(L, 2)); 210 | lua_pushstring(L, strJSON); 211 | free(strJSON); 212 | return 1; 213 | } 214 | 215 | LIB_API api_DumpToFile(lua_State* L) 216 | { 217 | ofstream fout(luaL_checkstring(L, 2)); 218 | luaL_argcheck(L, fout.good(), 1, "cannot open or create such JSON file"); 219 | char* strJSON = LuaVaule2JSONStr(L, lua_toboolean(L, 3)); 220 | fout << strJSON << endl; 221 | fout.close(); fout.clear(); 222 | free(strJSON); 223 | return 0; 224 | } 225 | 226 | static luaL_Reg cMethods[] = { 227 | { "Load", api_Load }, 228 | { "LoadFromFile", api_LoadFromFile }, 229 | { "Dump", api_Dump }, 230 | { "DumpToFile", api_DumpToFile }, 231 | { nullptr, nullptr } 232 | }; 233 | 234 | extern "C" __declspec(dllexport) 235 | int luaopen_LuaJsonLib(lua_State * L) 236 | { 237 | luaL_newlib(L, cMethods); 238 | return 1; 239 | } -------------------------------------------------------------------------------- /src/LuaJsonLib.h: -------------------------------------------------------------------------------- 1 | #ifndef _LUAJSONLIB_H_ 2 | 3 | #include "cJSON.h" 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | #define LIB_API extern "C" int 13 | 14 | bool CheckArrary(lua_State* L, int iIndex); 15 | 16 | void LuaTable2CJson(cJSON*& pJsonNode, int iIndex, lua_State* L); 17 | 18 | void CJson2LuaObj(cJSON* pJsonNode, lua_State* L); 19 | 20 | char* LuaVaule2JSONStr(lua_State* L, bool bIsFormat); 21 | 22 | LIB_API api_Load(lua_State* L); 23 | 24 | LIB_API api_LoadFromFile(lua_State* L); 25 | 26 | LIB_API api_Dump(lua_State* L); 27 | 28 | LIB_API api_DumpToFile(lua_State* L); 29 | 30 | #endif // !_LUAJSONLIB_H_ 31 | -------------------------------------------------------------------------------- /src/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 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #ifdef ENABLE_LOCALES 49 | #include 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(const cJSON * const 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(const cJSON * const item) 106 | { 107 | if (!cJSON_IsNumber(item)) 108 | { 109 | return (double) 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 != 14) 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 == '\0') 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, '\0', 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 '\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 | 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] = '\0'; 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] = '\0'; 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; /* \uXXXX\uXXXX */ 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++ = '\b'; 834 | break; 835 | case 'f': 836 | *output_pointer++ = '\f'; 837 | break; 838 | case 'n': 839 | *output_pointer++ = '\n'; 840 | break; 841 | case 'r': 842 | *output_pointer++ = '\r'; 843 | break; 844 | case 't': 845 | *output_pointer++ = '\t'; 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 = '\0'; 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 '\b': 931 | case '\f': 932 | case '\n': 933 | case '\r': 934 | case '\t': 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] = '\0'; 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 != '\0'; (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 '\b': 989 | *output_pointer = 'b'; 990 | break; 991 | case '\f': 992 | *output_pointer = 'f'; 993 | break; 994 | case '\n': 995 | *output_pointer = 'n'; 996 | break; 997 | case '\r': 998 | *output_pointer = 'r'; 999 | break; 1000 | case '\t': 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] = '\0'; 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), "\xEF\xBB\xBF", 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] != '\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] = '\0'; /* 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 | if (head != NULL) { 1513 | head->prev = current_item; 1514 | } 1515 | 1516 | item->type = cJSON_Array; 1517 | item->child = head; 1518 | 1519 | input_buffer->offset++; 1520 | 1521 | return true; 1522 | 1523 | fail: 1524 | if (head != NULL) 1525 | { 1526 | cJSON_Delete(head); 1527 | } 1528 | 1529 | return false; 1530 | } 1531 | 1532 | /* Render an array to text */ 1533 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) 1534 | { 1535 | unsigned char *output_pointer = NULL; 1536 | size_t length = 0; 1537 | cJSON *current_element = item->child; 1538 | 1539 | if (output_buffer == NULL) 1540 | { 1541 | return false; 1542 | } 1543 | 1544 | /* Compose the output array. */ 1545 | /* opening square bracket */ 1546 | output_pointer = ensure(output_buffer, 1); 1547 | if (output_pointer == NULL) 1548 | { 1549 | return false; 1550 | } 1551 | 1552 | *output_pointer = '['; 1553 | output_buffer->offset++; 1554 | output_buffer->depth++; 1555 | 1556 | while (current_element != NULL) 1557 | { 1558 | if (!print_value(current_element, output_buffer)) 1559 | { 1560 | return false; 1561 | } 1562 | update_offset(output_buffer); 1563 | if (current_element->next) 1564 | { 1565 | length = (size_t) (output_buffer->format ? 2 : 1); 1566 | output_pointer = ensure(output_buffer, length + 1); 1567 | if (output_pointer == NULL) 1568 | { 1569 | return false; 1570 | } 1571 | *output_pointer++ = ','; 1572 | if(output_buffer->format) 1573 | { 1574 | *output_pointer++ = ' '; 1575 | } 1576 | *output_pointer = '\0'; 1577 | output_buffer->offset += length; 1578 | } 1579 | current_element = current_element->next; 1580 | } 1581 | 1582 | output_pointer = ensure(output_buffer, 2); 1583 | if (output_pointer == NULL) 1584 | { 1585 | return false; 1586 | } 1587 | *output_pointer++ = ']'; 1588 | *output_pointer = '\0'; 1589 | output_buffer->depth--; 1590 | 1591 | return true; 1592 | } 1593 | 1594 | /* Build an object from the text. */ 1595 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) 1596 | { 1597 | cJSON *head = NULL; /* linked list head */ 1598 | cJSON *current_item = NULL; 1599 | 1600 | if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1601 | { 1602 | return false; /* to deeply nested */ 1603 | } 1604 | input_buffer->depth++; 1605 | 1606 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) 1607 | { 1608 | goto fail; /* not an object */ 1609 | } 1610 | 1611 | input_buffer->offset++; 1612 | buffer_skip_whitespace(input_buffer); 1613 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) 1614 | { 1615 | goto success; /* empty object */ 1616 | } 1617 | 1618 | /* check if we skipped to the end of the buffer */ 1619 | if (cannot_access_at_index(input_buffer, 0)) 1620 | { 1621 | input_buffer->offset--; 1622 | goto fail; 1623 | } 1624 | 1625 | /* step back to character in front of the first element */ 1626 | input_buffer->offset--; 1627 | /* loop through the comma separated array elements */ 1628 | do 1629 | { 1630 | /* allocate next item */ 1631 | cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1632 | if (new_item == NULL) 1633 | { 1634 | goto fail; /* allocation failure */ 1635 | } 1636 | 1637 | /* attach next item to list */ 1638 | if (head == NULL) 1639 | { 1640 | /* start the linked list */ 1641 | current_item = head = new_item; 1642 | } 1643 | else 1644 | { 1645 | /* add to the end and advance */ 1646 | current_item->next = new_item; 1647 | new_item->prev = current_item; 1648 | current_item = new_item; 1649 | } 1650 | 1651 | /* parse the name of the child */ 1652 | input_buffer->offset++; 1653 | buffer_skip_whitespace(input_buffer); 1654 | if (!parse_string(current_item, input_buffer)) 1655 | { 1656 | goto fail; /* failed to parse name */ 1657 | } 1658 | buffer_skip_whitespace(input_buffer); 1659 | 1660 | /* swap valuestring and string, because we parsed the name */ 1661 | current_item->string = current_item->valuestring; 1662 | current_item->valuestring = NULL; 1663 | 1664 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) 1665 | { 1666 | goto fail; /* invalid object */ 1667 | } 1668 | 1669 | /* parse the value */ 1670 | input_buffer->offset++; 1671 | buffer_skip_whitespace(input_buffer); 1672 | if (!parse_value(current_item, input_buffer)) 1673 | { 1674 | goto fail; /* failed to parse value */ 1675 | } 1676 | buffer_skip_whitespace(input_buffer); 1677 | } 1678 | while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1679 | 1680 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) 1681 | { 1682 | goto fail; /* expected end of object */ 1683 | } 1684 | 1685 | success: 1686 | input_buffer->depth--; 1687 | 1688 | if (head != NULL) { 1689 | head->prev = current_item; 1690 | } 1691 | 1692 | item->type = cJSON_Object; 1693 | item->child = head; 1694 | 1695 | input_buffer->offset++; 1696 | return true; 1697 | 1698 | fail: 1699 | if (head != NULL) 1700 | { 1701 | cJSON_Delete(head); 1702 | } 1703 | 1704 | return false; 1705 | } 1706 | 1707 | /* Render an object to text. */ 1708 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) 1709 | { 1710 | unsigned char *output_pointer = NULL; 1711 | size_t length = 0; 1712 | cJSON *current_item = item->child; 1713 | 1714 | if (output_buffer == NULL) 1715 | { 1716 | return false; 1717 | } 1718 | 1719 | /* Compose the output: */ 1720 | length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ 1721 | output_pointer = ensure(output_buffer, length + 1); 1722 | if (output_pointer == NULL) 1723 | { 1724 | return false; 1725 | } 1726 | 1727 | *output_pointer++ = '{'; 1728 | output_buffer->depth++; 1729 | if (output_buffer->format) 1730 | { 1731 | *output_pointer++ = '\n'; 1732 | } 1733 | output_buffer->offset += length; 1734 | 1735 | while (current_item) 1736 | { 1737 | if (output_buffer->format) 1738 | { 1739 | size_t i; 1740 | output_pointer = ensure(output_buffer, output_buffer->depth); 1741 | if (output_pointer == NULL) 1742 | { 1743 | return false; 1744 | } 1745 | for (i = 0; i < output_buffer->depth; i++) 1746 | { 1747 | *output_pointer++ = '\t'; 1748 | } 1749 | output_buffer->offset += output_buffer->depth; 1750 | } 1751 | 1752 | /* print key */ 1753 | if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) 1754 | { 1755 | return false; 1756 | } 1757 | update_offset(output_buffer); 1758 | 1759 | length = (size_t) (output_buffer->format ? 2 : 1); 1760 | output_pointer = ensure(output_buffer, length); 1761 | if (output_pointer == NULL) 1762 | { 1763 | return false; 1764 | } 1765 | *output_pointer++ = ':'; 1766 | if (output_buffer->format) 1767 | { 1768 | *output_pointer++ = '\t'; 1769 | } 1770 | output_buffer->offset += length; 1771 | 1772 | /* print value */ 1773 | if (!print_value(current_item, output_buffer)) 1774 | { 1775 | return false; 1776 | } 1777 | update_offset(output_buffer); 1778 | 1779 | /* print comma if not last */ 1780 | length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); 1781 | output_pointer = ensure(output_buffer, length + 1); 1782 | if (output_pointer == NULL) 1783 | { 1784 | return false; 1785 | } 1786 | if (current_item->next) 1787 | { 1788 | *output_pointer++ = ','; 1789 | } 1790 | 1791 | if (output_buffer->format) 1792 | { 1793 | *output_pointer++ = '\n'; 1794 | } 1795 | *output_pointer = '\0'; 1796 | output_buffer->offset += length; 1797 | 1798 | current_item = current_item->next; 1799 | } 1800 | 1801 | output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); 1802 | if (output_pointer == NULL) 1803 | { 1804 | return false; 1805 | } 1806 | if (output_buffer->format) 1807 | { 1808 | size_t i; 1809 | for (i = 0; i < (output_buffer->depth - 1); i++) 1810 | { 1811 | *output_pointer++ = '\t'; 1812 | } 1813 | } 1814 | *output_pointer++ = '}'; 1815 | *output_pointer = '\0'; 1816 | output_buffer->depth--; 1817 | 1818 | return true; 1819 | } 1820 | 1821 | /* Get Array size/item / object item. */ 1822 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) 1823 | { 1824 | cJSON *child = NULL; 1825 | size_t size = 0; 1826 | 1827 | if (array == NULL) 1828 | { 1829 | return 0; 1830 | } 1831 | 1832 | child = array->child; 1833 | 1834 | while(child != NULL) 1835 | { 1836 | size++; 1837 | child = child->next; 1838 | } 1839 | 1840 | /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ 1841 | 1842 | return (int)size; 1843 | } 1844 | 1845 | static cJSON* get_array_item(const cJSON *array, size_t index) 1846 | { 1847 | cJSON *current_child = NULL; 1848 | 1849 | if (array == NULL) 1850 | { 1851 | return NULL; 1852 | } 1853 | 1854 | current_child = array->child; 1855 | while ((current_child != NULL) && (index > 0)) 1856 | { 1857 | index--; 1858 | current_child = current_child->next; 1859 | } 1860 | 1861 | return current_child; 1862 | } 1863 | 1864 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) 1865 | { 1866 | if (index < 0) 1867 | { 1868 | return NULL; 1869 | } 1870 | 1871 | return get_array_item(array, (size_t)index); 1872 | } 1873 | 1874 | static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) 1875 | { 1876 | cJSON *current_element = NULL; 1877 | 1878 | if ((object == NULL) || (name == NULL)) 1879 | { 1880 | return NULL; 1881 | } 1882 | 1883 | current_element = object->child; 1884 | if (case_sensitive) 1885 | { 1886 | while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) 1887 | { 1888 | current_element = current_element->next; 1889 | } 1890 | } 1891 | else 1892 | { 1893 | while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) 1894 | { 1895 | current_element = current_element->next; 1896 | } 1897 | } 1898 | 1899 | if ((current_element == NULL) || (current_element->string == NULL)) { 1900 | return NULL; 1901 | } 1902 | 1903 | return current_element; 1904 | } 1905 | 1906 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) 1907 | { 1908 | return get_object_item(object, string, false); 1909 | } 1910 | 1911 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) 1912 | { 1913 | return get_object_item(object, string, true); 1914 | } 1915 | 1916 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) 1917 | { 1918 | return cJSON_GetObjectItem(object, string) ? 1 : 0; 1919 | } 1920 | 1921 | /* Utility for array list handling. */ 1922 | static void suffix_object(cJSON *prev, cJSON *item) 1923 | { 1924 | prev->next = item; 1925 | item->prev = prev; 1926 | } 1927 | 1928 | /* Utility for handling references. */ 1929 | static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) 1930 | { 1931 | cJSON *reference = NULL; 1932 | if (item == NULL) 1933 | { 1934 | return NULL; 1935 | } 1936 | 1937 | reference = cJSON_New_Item(hooks); 1938 | if (reference == NULL) 1939 | { 1940 | return NULL; 1941 | } 1942 | 1943 | memcpy(reference, item, sizeof(cJSON)); 1944 | reference->string = NULL; 1945 | reference->type |= cJSON_IsReference; 1946 | reference->next = reference->prev = NULL; 1947 | return reference; 1948 | } 1949 | 1950 | static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) 1951 | { 1952 | cJSON *child = NULL; 1953 | 1954 | if ((item == NULL) || (array == NULL) || (array == item)) 1955 | { 1956 | return false; 1957 | } 1958 | 1959 | child = array->child; 1960 | /* 1961 | * To find the last item in array quickly, we use prev in array 1962 | */ 1963 | if (child == NULL) 1964 | { 1965 | /* list is empty, start new one */ 1966 | array->child = item; 1967 | item->prev = item; 1968 | item->next = NULL; 1969 | } 1970 | else 1971 | { 1972 | /* append to the end */ 1973 | if (child->prev) 1974 | { 1975 | suffix_object(child->prev, item); 1976 | array->child->prev = item; 1977 | } 1978 | } 1979 | 1980 | return true; 1981 | } 1982 | 1983 | /* Add item to array/object. */ 1984 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) 1985 | { 1986 | return add_item_to_array(array, item); 1987 | } 1988 | 1989 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 1990 | #pragma GCC diagnostic push 1991 | #endif 1992 | #ifdef __GNUC__ 1993 | #pragma GCC diagnostic ignored "-Wcast-qual" 1994 | #endif 1995 | /* helper function to cast away const */ 1996 | static void* cast_away_const(const void* string) 1997 | { 1998 | return (void*)string; 1999 | } 2000 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 2001 | #pragma GCC diagnostic pop 2002 | #endif 2003 | 2004 | 2005 | 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) 2006 | { 2007 | char *new_key = NULL; 2008 | int new_type = cJSON_Invalid; 2009 | 2010 | if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) 2011 | { 2012 | return false; 2013 | } 2014 | 2015 | if (constant_key) 2016 | { 2017 | new_key = (char*)cast_away_const(string); 2018 | new_type = item->type | cJSON_StringIsConst; 2019 | } 2020 | else 2021 | { 2022 | new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); 2023 | if (new_key == NULL) 2024 | { 2025 | return false; 2026 | } 2027 | 2028 | new_type = item->type & ~cJSON_StringIsConst; 2029 | } 2030 | 2031 | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 2032 | { 2033 | hooks->deallocate(item->string); 2034 | } 2035 | 2036 | item->string = new_key; 2037 | item->type = new_type; 2038 | 2039 | return add_item_to_array(object, item); 2040 | } 2041 | 2042 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) 2043 | { 2044 | return add_item_to_object(object, string, item, &global_hooks, false); 2045 | } 2046 | 2047 | /* Add an item to an object with constant string as key */ 2048 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) 2049 | { 2050 | return add_item_to_object(object, string, item, &global_hooks, true); 2051 | } 2052 | 2053 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) 2054 | { 2055 | if (array == NULL) 2056 | { 2057 | return false; 2058 | } 2059 | 2060 | return add_item_to_array(array, create_reference(item, &global_hooks)); 2061 | } 2062 | 2063 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) 2064 | { 2065 | if ((object == NULL) || (string == NULL)) 2066 | { 2067 | return false; 2068 | } 2069 | 2070 | return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); 2071 | } 2072 | 2073 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) 2074 | { 2075 | cJSON *null = cJSON_CreateNull(); 2076 | if (add_item_to_object(object, name, null, &global_hooks, false)) 2077 | { 2078 | return null; 2079 | } 2080 | 2081 | cJSON_Delete(null); 2082 | return NULL; 2083 | } 2084 | 2085 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) 2086 | { 2087 | cJSON *true_item = cJSON_CreateTrue(); 2088 | if (add_item_to_object(object, name, true_item, &global_hooks, false)) 2089 | { 2090 | return true_item; 2091 | } 2092 | 2093 | cJSON_Delete(true_item); 2094 | return NULL; 2095 | } 2096 | 2097 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) 2098 | { 2099 | cJSON *false_item = cJSON_CreateFalse(); 2100 | if (add_item_to_object(object, name, false_item, &global_hooks, false)) 2101 | { 2102 | return false_item; 2103 | } 2104 | 2105 | cJSON_Delete(false_item); 2106 | return NULL; 2107 | } 2108 | 2109 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) 2110 | { 2111 | cJSON *bool_item = cJSON_CreateBool(boolean); 2112 | if (add_item_to_object(object, name, bool_item, &global_hooks, false)) 2113 | { 2114 | return bool_item; 2115 | } 2116 | 2117 | cJSON_Delete(bool_item); 2118 | return NULL; 2119 | } 2120 | 2121 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) 2122 | { 2123 | cJSON *number_item = cJSON_CreateNumber(number); 2124 | if (add_item_to_object(object, name, number_item, &global_hooks, false)) 2125 | { 2126 | return number_item; 2127 | } 2128 | 2129 | cJSON_Delete(number_item); 2130 | return NULL; 2131 | } 2132 | 2133 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) 2134 | { 2135 | cJSON *string_item = cJSON_CreateString(string); 2136 | if (add_item_to_object(object, name, string_item, &global_hooks, false)) 2137 | { 2138 | return string_item; 2139 | } 2140 | 2141 | cJSON_Delete(string_item); 2142 | return NULL; 2143 | } 2144 | 2145 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) 2146 | { 2147 | cJSON *raw_item = cJSON_CreateRaw(raw); 2148 | if (add_item_to_object(object, name, raw_item, &global_hooks, false)) 2149 | { 2150 | return raw_item; 2151 | } 2152 | 2153 | cJSON_Delete(raw_item); 2154 | return NULL; 2155 | } 2156 | 2157 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) 2158 | { 2159 | cJSON *object_item = cJSON_CreateObject(); 2160 | if (add_item_to_object(object, name, object_item, &global_hooks, false)) 2161 | { 2162 | return object_item; 2163 | } 2164 | 2165 | cJSON_Delete(object_item); 2166 | return NULL; 2167 | } 2168 | 2169 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) 2170 | { 2171 | cJSON *array = cJSON_CreateArray(); 2172 | if (add_item_to_object(object, name, array, &global_hooks, false)) 2173 | { 2174 | return array; 2175 | } 2176 | 2177 | cJSON_Delete(array); 2178 | return NULL; 2179 | } 2180 | 2181 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) 2182 | { 2183 | if ((parent == NULL) || (item == NULL)) 2184 | { 2185 | return NULL; 2186 | } 2187 | 2188 | if (item != parent->child) 2189 | { 2190 | /* not the first element */ 2191 | item->prev->next = item->next; 2192 | } 2193 | if (item->next != NULL) 2194 | { 2195 | /* not the last element */ 2196 | item->next->prev = item->prev; 2197 | } 2198 | 2199 | if (item == parent->child) 2200 | { 2201 | /* first element */ 2202 | parent->child = item->next; 2203 | } 2204 | else if (item->next == NULL) 2205 | { 2206 | /* last element */ 2207 | parent->child->prev = item->prev; 2208 | } 2209 | 2210 | /* make sure the detached item doesn't point anywhere anymore */ 2211 | item->prev = NULL; 2212 | item->next = NULL; 2213 | 2214 | return item; 2215 | } 2216 | 2217 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) 2218 | { 2219 | if (which < 0) 2220 | { 2221 | return NULL; 2222 | } 2223 | 2224 | return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); 2225 | } 2226 | 2227 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) 2228 | { 2229 | cJSON_Delete(cJSON_DetachItemFromArray(array, which)); 2230 | } 2231 | 2232 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) 2233 | { 2234 | cJSON *to_detach = cJSON_GetObjectItem(object, string); 2235 | 2236 | return cJSON_DetachItemViaPointer(object, to_detach); 2237 | } 2238 | 2239 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) 2240 | { 2241 | cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); 2242 | 2243 | return cJSON_DetachItemViaPointer(object, to_detach); 2244 | } 2245 | 2246 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) 2247 | { 2248 | cJSON_Delete(cJSON_DetachItemFromObject(object, string)); 2249 | } 2250 | 2251 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) 2252 | { 2253 | cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); 2254 | } 2255 | 2256 | /* Replace array/object items with new ones. */ 2257 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) 2258 | { 2259 | cJSON *after_inserted = NULL; 2260 | 2261 | if (which < 0) 2262 | { 2263 | return false; 2264 | } 2265 | 2266 | after_inserted = get_array_item(array, (size_t)which); 2267 | if (after_inserted == NULL) 2268 | { 2269 | return add_item_to_array(array, newitem); 2270 | } 2271 | 2272 | newitem->next = after_inserted; 2273 | newitem->prev = after_inserted->prev; 2274 | after_inserted->prev = newitem; 2275 | if (after_inserted == array->child) 2276 | { 2277 | array->child = newitem; 2278 | } 2279 | else 2280 | { 2281 | newitem->prev->next = newitem; 2282 | } 2283 | return true; 2284 | } 2285 | 2286 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) 2287 | { 2288 | if ((parent == NULL) || (replacement == NULL) || (item == NULL)) 2289 | { 2290 | return false; 2291 | } 2292 | 2293 | if (replacement == item) 2294 | { 2295 | return true; 2296 | } 2297 | 2298 | replacement->next = item->next; 2299 | replacement->prev = item->prev; 2300 | 2301 | if (replacement->next != NULL) 2302 | { 2303 | replacement->next->prev = replacement; 2304 | } 2305 | if (parent->child == item) 2306 | { 2307 | if (parent->child->prev == parent->child) 2308 | { 2309 | replacement->prev = replacement; 2310 | } 2311 | parent->child = replacement; 2312 | } 2313 | else 2314 | { /* 2315 | * To find the last item in array quickly, we use prev in array. 2316 | * We can't modify the last item's next pointer where this item was the parent's child 2317 | */ 2318 | if (replacement->prev != NULL) 2319 | { 2320 | replacement->prev->next = replacement; 2321 | } 2322 | if (replacement->next == NULL) 2323 | { 2324 | parent->child->prev = replacement; 2325 | } 2326 | } 2327 | 2328 | item->next = NULL; 2329 | item->prev = NULL; 2330 | cJSON_Delete(item); 2331 | 2332 | return true; 2333 | } 2334 | 2335 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) 2336 | { 2337 | if (which < 0) 2338 | { 2339 | return false; 2340 | } 2341 | 2342 | return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); 2343 | } 2344 | 2345 | static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) 2346 | { 2347 | if ((replacement == NULL) || (string == NULL)) 2348 | { 2349 | return false; 2350 | } 2351 | 2352 | /* replace the name in the replacement */ 2353 | if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) 2354 | { 2355 | cJSON_free(replacement->string); 2356 | } 2357 | replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2358 | replacement->type &= ~cJSON_StringIsConst; 2359 | 2360 | return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); 2361 | } 2362 | 2363 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) 2364 | { 2365 | return replace_item_in_object(object, string, newitem, false); 2366 | } 2367 | 2368 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) 2369 | { 2370 | return replace_item_in_object(object, string, newitem, true); 2371 | } 2372 | 2373 | /* Create basic types: */ 2374 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) 2375 | { 2376 | cJSON *item = cJSON_New_Item(&global_hooks); 2377 | if(item) 2378 | { 2379 | item->type = cJSON_NULL; 2380 | } 2381 | 2382 | return item; 2383 | } 2384 | 2385 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) 2386 | { 2387 | cJSON *item = cJSON_New_Item(&global_hooks); 2388 | if(item) 2389 | { 2390 | item->type = cJSON_True; 2391 | } 2392 | 2393 | return item; 2394 | } 2395 | 2396 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) 2397 | { 2398 | cJSON *item = cJSON_New_Item(&global_hooks); 2399 | if(item) 2400 | { 2401 | item->type = cJSON_False; 2402 | } 2403 | 2404 | return item; 2405 | } 2406 | 2407 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) 2408 | { 2409 | cJSON *item = cJSON_New_Item(&global_hooks); 2410 | if(item) 2411 | { 2412 | item->type = boolean ? cJSON_True : cJSON_False; 2413 | } 2414 | 2415 | return item; 2416 | } 2417 | 2418 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) 2419 | { 2420 | cJSON *item = cJSON_New_Item(&global_hooks); 2421 | if(item) 2422 | { 2423 | item->type = cJSON_Number; 2424 | item->valuedouble = num; 2425 | 2426 | /* use saturation in case of overflow */ 2427 | if (num >= INT_MAX) 2428 | { 2429 | item->valueint = INT_MAX; 2430 | } 2431 | else if (num <= (double)INT_MIN) 2432 | { 2433 | item->valueint = INT_MIN; 2434 | } 2435 | else 2436 | { 2437 | item->valueint = (int)num; 2438 | } 2439 | } 2440 | 2441 | return item; 2442 | } 2443 | 2444 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) 2445 | { 2446 | cJSON *item = cJSON_New_Item(&global_hooks); 2447 | if(item) 2448 | { 2449 | item->type = cJSON_String; 2450 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2451 | if(!item->valuestring) 2452 | { 2453 | cJSON_Delete(item); 2454 | return NULL; 2455 | } 2456 | } 2457 | 2458 | return item; 2459 | } 2460 | 2461 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) 2462 | { 2463 | cJSON *item = cJSON_New_Item(&global_hooks); 2464 | if (item != NULL) 2465 | { 2466 | item->type = cJSON_String | cJSON_IsReference; 2467 | item->valuestring = (char*)cast_away_const(string); 2468 | } 2469 | 2470 | return item; 2471 | } 2472 | 2473 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) 2474 | { 2475 | cJSON *item = cJSON_New_Item(&global_hooks); 2476 | if (item != NULL) { 2477 | item->type = cJSON_Object | cJSON_IsReference; 2478 | item->child = (cJSON*)cast_away_const(child); 2479 | } 2480 | 2481 | return item; 2482 | } 2483 | 2484 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { 2485 | cJSON *item = cJSON_New_Item(&global_hooks); 2486 | if (item != NULL) { 2487 | item->type = cJSON_Array | cJSON_IsReference; 2488 | item->child = (cJSON*)cast_away_const(child); 2489 | } 2490 | 2491 | return item; 2492 | } 2493 | 2494 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) 2495 | { 2496 | cJSON *item = cJSON_New_Item(&global_hooks); 2497 | if(item) 2498 | { 2499 | item->type = cJSON_Raw; 2500 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); 2501 | if(!item->valuestring) 2502 | { 2503 | cJSON_Delete(item); 2504 | return NULL; 2505 | } 2506 | } 2507 | 2508 | return item; 2509 | } 2510 | 2511 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) 2512 | { 2513 | cJSON *item = cJSON_New_Item(&global_hooks); 2514 | if(item) 2515 | { 2516 | item->type=cJSON_Array; 2517 | } 2518 | 2519 | return item; 2520 | } 2521 | 2522 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) 2523 | { 2524 | cJSON *item = cJSON_New_Item(&global_hooks); 2525 | if (item) 2526 | { 2527 | item->type = cJSON_Object; 2528 | } 2529 | 2530 | return item; 2531 | } 2532 | 2533 | /* Create Arrays: */ 2534 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) 2535 | { 2536 | size_t i = 0; 2537 | cJSON *n = NULL; 2538 | cJSON *p = NULL; 2539 | cJSON *a = NULL; 2540 | 2541 | if ((count < 0) || (numbers == NULL)) 2542 | { 2543 | return NULL; 2544 | } 2545 | 2546 | a = cJSON_CreateArray(); 2547 | for(i = 0; a && (i < (size_t)count); i++) 2548 | { 2549 | n = cJSON_CreateNumber(numbers[i]); 2550 | if (!n) 2551 | { 2552 | cJSON_Delete(a); 2553 | return NULL; 2554 | } 2555 | if(!i) 2556 | { 2557 | a->child = n; 2558 | } 2559 | else 2560 | { 2561 | suffix_object(p, n); 2562 | } 2563 | p = n; 2564 | } 2565 | a->child->prev = n; 2566 | 2567 | return a; 2568 | } 2569 | 2570 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) 2571 | { 2572 | size_t i = 0; 2573 | cJSON *n = NULL; 2574 | cJSON *p = NULL; 2575 | cJSON *a = NULL; 2576 | 2577 | if ((count < 0) || (numbers == NULL)) 2578 | { 2579 | return NULL; 2580 | } 2581 | 2582 | a = cJSON_CreateArray(); 2583 | 2584 | for(i = 0; a && (i < (size_t)count); i++) 2585 | { 2586 | n = cJSON_CreateNumber((double)numbers[i]); 2587 | if(!n) 2588 | { 2589 | cJSON_Delete(a); 2590 | return NULL; 2591 | } 2592 | if(!i) 2593 | { 2594 | a->child = n; 2595 | } 2596 | else 2597 | { 2598 | suffix_object(p, n); 2599 | } 2600 | p = n; 2601 | } 2602 | a->child->prev = n; 2603 | 2604 | return a; 2605 | } 2606 | 2607 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) 2608 | { 2609 | size_t i = 0; 2610 | cJSON *n = NULL; 2611 | cJSON *p = NULL; 2612 | cJSON *a = NULL; 2613 | 2614 | if ((count < 0) || (numbers == NULL)) 2615 | { 2616 | return NULL; 2617 | } 2618 | 2619 | a = cJSON_CreateArray(); 2620 | 2621 | for(i = 0;a && (i < (size_t)count); i++) 2622 | { 2623 | n = cJSON_CreateNumber(numbers[i]); 2624 | if(!n) 2625 | { 2626 | cJSON_Delete(a); 2627 | return NULL; 2628 | } 2629 | if(!i) 2630 | { 2631 | a->child = n; 2632 | } 2633 | else 2634 | { 2635 | suffix_object(p, n); 2636 | } 2637 | p = n; 2638 | } 2639 | a->child->prev = n; 2640 | 2641 | return a; 2642 | } 2643 | 2644 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) 2645 | { 2646 | size_t i = 0; 2647 | cJSON *n = NULL; 2648 | cJSON *p = NULL; 2649 | cJSON *a = NULL; 2650 | 2651 | if ((count < 0) || (strings == NULL)) 2652 | { 2653 | return NULL; 2654 | } 2655 | 2656 | a = cJSON_CreateArray(); 2657 | 2658 | for (i = 0; a && (i < (size_t)count); i++) 2659 | { 2660 | n = cJSON_CreateString(strings[i]); 2661 | if(!n) 2662 | { 2663 | cJSON_Delete(a); 2664 | return NULL; 2665 | } 2666 | if(!i) 2667 | { 2668 | a->child = n; 2669 | } 2670 | else 2671 | { 2672 | suffix_object(p,n); 2673 | } 2674 | p = n; 2675 | } 2676 | a->child->prev = n; 2677 | 2678 | return a; 2679 | } 2680 | 2681 | /* Duplication */ 2682 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) 2683 | { 2684 | cJSON *newitem = NULL; 2685 | cJSON *child = NULL; 2686 | cJSON *next = NULL; 2687 | cJSON *newchild = NULL; 2688 | 2689 | /* Bail on bad ptr */ 2690 | if (!item) 2691 | { 2692 | goto fail; 2693 | } 2694 | /* Create new item */ 2695 | newitem = cJSON_New_Item(&global_hooks); 2696 | if (!newitem) 2697 | { 2698 | goto fail; 2699 | } 2700 | /* Copy over all vars */ 2701 | newitem->type = item->type & (~cJSON_IsReference); 2702 | newitem->valueint = item->valueint; 2703 | newitem->valuedouble = item->valuedouble; 2704 | if (item->valuestring) 2705 | { 2706 | newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); 2707 | if (!newitem->valuestring) 2708 | { 2709 | goto fail; 2710 | } 2711 | } 2712 | if (item->string) 2713 | { 2714 | newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); 2715 | if (!newitem->string) 2716 | { 2717 | goto fail; 2718 | } 2719 | } 2720 | /* If non-recursive, then we're done! */ 2721 | if (!recurse) 2722 | { 2723 | return newitem; 2724 | } 2725 | /* Walk the ->next chain for the child. */ 2726 | child = item->child; 2727 | while (child != NULL) 2728 | { 2729 | newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ 2730 | if (!newchild) 2731 | { 2732 | goto fail; 2733 | } 2734 | if (next != NULL) 2735 | { 2736 | /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 2737 | next->next = newchild; 2738 | newchild->prev = next; 2739 | next = newchild; 2740 | } 2741 | else 2742 | { 2743 | /* Set newitem->child and move to it */ 2744 | newitem->child = newchild; 2745 | next = newchild; 2746 | } 2747 | child = child->next; 2748 | } 2749 | if (newitem && newitem->child) 2750 | { 2751 | newitem->child->prev = newchild; 2752 | } 2753 | 2754 | return newitem; 2755 | 2756 | fail: 2757 | if (newitem != NULL) 2758 | { 2759 | cJSON_Delete(newitem); 2760 | } 2761 | 2762 | return NULL; 2763 | } 2764 | 2765 | static void skip_oneline_comment(char **input) 2766 | { 2767 | *input += static_strlen("//"); 2768 | 2769 | for (; (*input)[0] != '\0'; ++(*input)) 2770 | { 2771 | if ((*input)[0] == '\n') { 2772 | *input += static_strlen("\n"); 2773 | return; 2774 | } 2775 | } 2776 | } 2777 | 2778 | static void skip_multiline_comment(char **input) 2779 | { 2780 | *input += static_strlen("/*"); 2781 | 2782 | for (; (*input)[0] != '\0'; ++(*input)) 2783 | { 2784 | if (((*input)[0] == '*') && ((*input)[1] == '/')) 2785 | { 2786 | *input += static_strlen("*/"); 2787 | return; 2788 | } 2789 | } 2790 | } 2791 | 2792 | static void minify_string(char **input, char **output) { 2793 | (*output)[0] = (*input)[0]; 2794 | *input += static_strlen("\""); 2795 | *output += static_strlen("\""); 2796 | 2797 | 2798 | for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { 2799 | (*output)[0] = (*input)[0]; 2800 | 2801 | if ((*input)[0] == '\"') { 2802 | (*output)[0] = '\"'; 2803 | *input += static_strlen("\""); 2804 | *output += static_strlen("\""); 2805 | return; 2806 | } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { 2807 | (*output)[1] = (*input)[1]; 2808 | *input += static_strlen("\""); 2809 | *output += static_strlen("\""); 2810 | } 2811 | } 2812 | } 2813 | 2814 | CJSON_PUBLIC(void) cJSON_Minify(char *json) 2815 | { 2816 | char *into = json; 2817 | 2818 | if (json == NULL) 2819 | { 2820 | return; 2821 | } 2822 | 2823 | while (json[0] != '\0') 2824 | { 2825 | switch (json[0]) 2826 | { 2827 | case ' ': 2828 | case '\t': 2829 | case '\r': 2830 | case '\n': 2831 | json++; 2832 | break; 2833 | 2834 | case '/': 2835 | if (json[1] == '/') 2836 | { 2837 | skip_oneline_comment(&json); 2838 | } 2839 | else if (json[1] == '*') 2840 | { 2841 | skip_multiline_comment(&json); 2842 | } else { 2843 | json++; 2844 | } 2845 | break; 2846 | 2847 | case '\"': 2848 | minify_string(&json, (char**)&into); 2849 | break; 2850 | 2851 | default: 2852 | into[0] = json[0]; 2853 | json++; 2854 | into++; 2855 | } 2856 | } 2857 | 2858 | /* and null-terminate. */ 2859 | *into = '\0'; 2860 | } 2861 | 2862 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) 2863 | { 2864 | if (item == NULL) 2865 | { 2866 | return false; 2867 | } 2868 | 2869 | return (item->type & 0xFF) == cJSON_Invalid; 2870 | } 2871 | 2872 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) 2873 | { 2874 | if (item == NULL) 2875 | { 2876 | return false; 2877 | } 2878 | 2879 | return (item->type & 0xFF) == cJSON_False; 2880 | } 2881 | 2882 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) 2883 | { 2884 | if (item == NULL) 2885 | { 2886 | return false; 2887 | } 2888 | 2889 | return (item->type & 0xff) == cJSON_True; 2890 | } 2891 | 2892 | 2893 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) 2894 | { 2895 | if (item == NULL) 2896 | { 2897 | return false; 2898 | } 2899 | 2900 | return (item->type & (cJSON_True | cJSON_False)) != 0; 2901 | } 2902 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) 2903 | { 2904 | if (item == NULL) 2905 | { 2906 | return false; 2907 | } 2908 | 2909 | return (item->type & 0xFF) == cJSON_NULL; 2910 | } 2911 | 2912 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) 2913 | { 2914 | if (item == NULL) 2915 | { 2916 | return false; 2917 | } 2918 | 2919 | return (item->type & 0xFF) == cJSON_Number; 2920 | } 2921 | 2922 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) 2923 | { 2924 | if (item == NULL) 2925 | { 2926 | return false; 2927 | } 2928 | 2929 | return (item->type & 0xFF) == cJSON_String; 2930 | } 2931 | 2932 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) 2933 | { 2934 | if (item == NULL) 2935 | { 2936 | return false; 2937 | } 2938 | 2939 | return (item->type & 0xFF) == cJSON_Array; 2940 | } 2941 | 2942 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) 2943 | { 2944 | if (item == NULL) 2945 | { 2946 | return false; 2947 | } 2948 | 2949 | return (item->type & 0xFF) == cJSON_Object; 2950 | } 2951 | 2952 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) 2953 | { 2954 | if (item == NULL) 2955 | { 2956 | return false; 2957 | } 2958 | 2959 | return (item->type & 0xFF) == cJSON_Raw; 2960 | } 2961 | 2962 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) 2963 | { 2964 | if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) 2965 | { 2966 | return false; 2967 | } 2968 | 2969 | /* check if type is valid */ 2970 | switch (a->type & 0xFF) 2971 | { 2972 | case cJSON_False: 2973 | case cJSON_True: 2974 | case cJSON_NULL: 2975 | case cJSON_Number: 2976 | case cJSON_String: 2977 | case cJSON_Raw: 2978 | case cJSON_Array: 2979 | case cJSON_Object: 2980 | break; 2981 | 2982 | default: 2983 | return false; 2984 | } 2985 | 2986 | /* identical objects are equal */ 2987 | if (a == b) 2988 | { 2989 | return true; 2990 | } 2991 | 2992 | switch (a->type & 0xFF) 2993 | { 2994 | /* in these cases and equal type is enough */ 2995 | case cJSON_False: 2996 | case cJSON_True: 2997 | case cJSON_NULL: 2998 | return true; 2999 | 3000 | case cJSON_Number: 3001 | if (compare_double(a->valuedouble, b->valuedouble)) 3002 | { 3003 | return true; 3004 | } 3005 | return false; 3006 | 3007 | case cJSON_String: 3008 | case cJSON_Raw: 3009 | if ((a->valuestring == NULL) || (b->valuestring == NULL)) 3010 | { 3011 | return false; 3012 | } 3013 | if (strcmp(a->valuestring, b->valuestring) == 0) 3014 | { 3015 | return true; 3016 | } 3017 | 3018 | return false; 3019 | 3020 | case cJSON_Array: 3021 | { 3022 | cJSON *a_element = a->child; 3023 | cJSON *b_element = b->child; 3024 | 3025 | for (; (a_element != NULL) && (b_element != NULL);) 3026 | { 3027 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3028 | { 3029 | return false; 3030 | } 3031 | 3032 | a_element = a_element->next; 3033 | b_element = b_element->next; 3034 | } 3035 | 3036 | /* one of the arrays is longer than the other */ 3037 | if (a_element != b_element) { 3038 | return false; 3039 | } 3040 | 3041 | return true; 3042 | } 3043 | 3044 | case cJSON_Object: 3045 | { 3046 | cJSON *a_element = NULL; 3047 | cJSON *b_element = NULL; 3048 | cJSON_ArrayForEach(a_element, a) 3049 | { 3050 | /* TODO This has O(n^2) runtime, which is horrible! */ 3051 | b_element = get_object_item(b, a_element->string, case_sensitive); 3052 | if (b_element == NULL) 3053 | { 3054 | return false; 3055 | } 3056 | 3057 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3058 | { 3059 | return false; 3060 | } 3061 | } 3062 | 3063 | /* doing this twice, once on a and b to prevent true comparison if a subset of b 3064 | * TODO: Do this the proper way, this is just a fix for now */ 3065 | cJSON_ArrayForEach(b_element, b) 3066 | { 3067 | a_element = get_object_item(a, b_element->string, case_sensitive); 3068 | if (a_element == NULL) 3069 | { 3070 | return false; 3071 | } 3072 | 3073 | if (!cJSON_Compare(b_element, a_element, case_sensitive)) 3074 | { 3075 | return false; 3076 | } 3077 | } 3078 | 3079 | return true; 3080 | } 3081 | 3082 | default: 3083 | return false; 3084 | } 3085 | } 3086 | 3087 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size) 3088 | { 3089 | return global_hooks.allocate(size); 3090 | } 3091 | 3092 | CJSON_PUBLIC(void) cJSON_free(void *object) 3093 | { 3094 | global_hooks.deallocate(object); 3095 | } 3096 | -------------------------------------------------------------------------------- /src/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 14 85 | 86 | #include 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(const cJSON * const item); 180 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const 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 ' ', '\t', '\r', '\n') 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 294 | --------------------------------------------------------------------------------