11
|
1 /*
|
|
2 Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
|
3
|
|
4 Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5 of this software and associated documentation files (the "Software"), to deal
|
|
6 in the Software without restriction, including without limitation the rights
|
|
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8 copies of the Software, and to permit persons to whom the Software is
|
|
9 furnished to do so, subject to the following conditions:
|
|
10
|
|
11 The above copyright notice and this permission notice shall be included in
|
|
12 all copies or substantial portions of the Software.
|
|
13
|
|
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20 THE SOFTWARE.
|
|
21 */
|
|
22
|
|
23 /* cJSON */
|
|
24 /* JSON parser in C. */
|
|
25
|
|
26 /* disable warnings about old C89 functions in MSVC */
|
|
27 #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
|
|
28 #define _CRT_SECURE_NO_DEPRECATE
|
|
29 #endif
|
|
30
|
|
31 #ifdef __GNUC__
|
|
32 #pragma GCC visibility push(default)
|
|
33 #endif
|
|
34 #if defined(_MSC_VER)
|
|
35 #pragma warning (push)
|
|
36 /* disable warning about single line comments in system headers */
|
|
37 #pragma warning (disable : 4001)
|
|
38 #endif
|
|
39
|
|
40 #include <string.h>
|
|
41 #include <stdio.h>
|
|
42 #include <math.h>
|
|
43 #include <stdlib.h>
|
|
44 #include <limits.h>
|
|
45 #include <ctype.h>
|
|
46 #include <float.h>
|
|
47
|
|
48 #ifdef ENABLE_LOCALES
|
|
49 #include <locale.h>
|
|
50 #endif
|
|
51
|
|
52 #if defined(_MSC_VER)
|
|
53 #pragma warning (pop)
|
|
54 #endif
|
|
55 #ifdef __GNUC__
|
|
56 #pragma GCC visibility pop
|
|
57 #endif
|
|
58
|
|
59 #include "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 }
|