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