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