Mercurial > wgsdk
comparison src/json.c @ 11:e6a594f16403
*: huge refactor
the config file has changed drastically, moving to an ini file from
that custom format; i *would* have used the win32 functions for those,
but they were barely functional, so I decided on using ini.h which is
lightweight enough.
additionally, I've added Deezer support so album art will be displayed!
unfortunately though winhttp is a pain in the ass so if I send a request
with any form of unicode chars in it it just returns a "bad request" error.
I've tried debugging this but I could never really come up with anything:
my hypothesis is that deezer expects their characters in percent-encoded
UTF-8, but winhttp is sending them in some other encoding.
the config dialog was moved out of config.c (overdue) and many more options
are given in the config as well.
main.c has been renamed to plugin.c to better differentiate it from...
everything else.
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Thu, 14 Mar 2024 20:25:37 -0400 |
parents | |
children | dd427b7cc459 |
comparison
equal
deleted
inserted
replaced
10:42ac054c0231 | 11:e6a594f16403 |
---|---|
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 } |