• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

thoni56 / c-xrefactory / 1779

16 Apr 2026 02:51PM UTC coverage: 85.037% (+1.7%) from 83.31%
1779

push

travis-ci

thoni56
[snapshot][version] Ignore snapshots with mismatching version, they will be recreated

16282 of 19147 relevant lines covered (85.04%)

15994227.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

43.31
src/3pp/cJSON/cJSON.c
1
/*
2
  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
3

4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
  of this software and associated documentation files (the "Software"), to deal
6
  in the Software without restriction, including without limitation the rights
7
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
  copies of the Software, and to permit persons to whom the Software is
9
  furnished to do so, subject to the following conditions:
10

11
  The above copyright notice and this permission notice shall be included in
12
  all copies or substantial portions of the Software.
13

14
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
  THE SOFTWARE.
21
*/
22

23
/* cJSON */
24
/* JSON parser in C. */
25

26
/* disable warnings about old C89 functions in MSVC */
27
#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
28
#define _CRT_SECURE_NO_DEPRECATE
29
#endif
30

31
#ifdef __GNUC__
32
#pragma GCC visibility push(default)
33
#endif
34
#if defined(_MSC_VER)
35
#pragma warning (push)
36
/* disable warning about single line comments in system headers */
37
#pragma warning (disable : 4001)
38
#endif
39

40
#include <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 "cJSON.h"
60

61
/* define our own boolean type */
62
#ifdef true
63
#undef true
64
#endif
65
#define true ((cJSON_bool)1)
66

67
#ifdef false
68
#undef false
69
#endif
70
#define false ((cJSON_bool)0)
71

72
/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
73
#ifndef isinf
74
#define isinf(d) (isnan((d - d)) && !isnan(d))
75
#endif
76
#ifndef isnan
77
#define isnan(d) (d != d)
78
#endif
79

80
#ifndef NAN
81
#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)
55✔
100
{
101
    if (!cJSON_IsString(item))
55✔
102
    {
103
        return NULL;
104
    }
105

106
    return item->valuestring;
55✔
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 != 19)
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)
328✔
134
{
135
    if ((string1 == NULL) || (string2 == NULL))
328✔
136
    {
137
        return 1;
138
    }
139

140
    if (string1 == string2)
328✔
141
    {
142
        return 0;
143
    }
144

145
    for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
1,170✔
146
    {
147
        if (*string1 == '\0')
994✔
148
        {
149
            return 0;
150
        }
151
    }
152

153
    return tolower(*string1) - tolower(*string2);
176✔
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)
331✔
189
{
190
    size_t length = 0;
331✔
191
    unsigned char *copy = NULL;
331✔
192

193
    if (string == NULL)
331✔
194
    {
195
        return NULL;
196
    }
197

198
    length = strlen((const char*)string) + sizeof("");
331✔
199
    copy = (unsigned char*)hooks->allocate(length);
331✔
200
    if (copy == NULL)
331✔
201
    {
202
        return NULL;
203
    }
204
    memcpy(copy, string, length);
331✔
205

206
    return copy;
331✔
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)
645✔
242
{
243
    cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
645✔
244
    if (node)
645✔
245
    {
246
        memset(node, '\0', sizeof(cJSON));
645✔
247
    }
248

249
    return node;
645✔
250
}
251

252
/* Delete a cJSON structure. */
253
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
244✔
254
{
255
    cJSON *next = NULL;
244✔
256
    while (item != NULL)
715✔
257
    {
258
        next = item->next;
471✔
259
        if (!(item->type & cJSON_IsReference) && (item->child != NULL))
471✔
260
        {
261
            cJSON_Delete(item->child);
179✔
262
        }
263
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
471✔
264
        {
265
            global_hooks.deallocate(item->valuestring);
155✔
266
            item->valuestring = NULL;
155✔
267
        }
268
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
471✔
269
        {
270
            global_hooks.deallocate(item->string);
394✔
271
            item->string = NULL;
394✔
272
        }
273
        global_hooks.deallocate(item);
471✔
274
        item = next;
471✔
275
    }
276
}
244✔
277

278
/* get the decimal point character of the current locale */
279
static unsigned char get_decimal_point(void)
131✔
280
{
281
#ifdef ENABLE_LOCALES
282
    struct lconv *lconv = localeconv();
283
    return (unsigned char) lconv->decimal_point[0];
284
#else
285
    return '.';
131✔
286
#endif
287
}
288

289
typedef 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. */
307
static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
68✔
308
{
309
    double number = 0;
68✔
310
    unsigned char *after_end = NULL;
68✔
311
    unsigned char *number_c_string;
68✔
312
    unsigned char decimal_point = get_decimal_point();
68✔
313
    size_t i = 0;
68✔
314
    size_t number_string_length = 0;
68✔
315
    cJSON_bool has_decimal_point = false;
68✔
316

317
    if ((input_buffer == NULL) || (input_buffer->content == NULL))
68✔
318
    {
319
        return false;
320
    }
321

322
    /* copy the number into a temporary buffer and replace '.' with the decimal point
323
     * of the current locale (for strtod)
324
     * This also takes care of '\0' not necessarily being available for marking the end of the input */
325
    for (i = 0; can_access_at_index(input_buffer, i); i++)
143✔
326
    {
327
        switch (buffer_at_offset(input_buffer)[i])
143✔
328
        {
329
            case '0':
75✔
330
            case '1':
331
            case '2':
332
            case '3':
333
            case '4':
334
            case '5':
335
            case '6':
336
            case '7':
337
            case '8':
338
            case '9':
339
            case '+':
340
            case '-':
341
            case 'e':
342
            case 'E':
343
                number_string_length++;
75✔
344
                break;
75✔
345

346
            case '.':
×
347
                number_string_length++;
×
348
                has_decimal_point = true;
×
349
                break;
×
350

351
            default:
68✔
352
                goto loop_end;
68✔
353
        }
354
    }
355
loop_end:
×
356
    /* malloc for temporary buffer, add 1 for '\0' */
357
    number_c_string = (unsigned char *) input_buffer->hooks.allocate(number_string_length + 1);
68✔
358
    if (number_c_string == NULL)
68✔
359
    {
360
        return false; /* allocation failure */
361
    }
362

363
    memcpy(number_c_string, buffer_at_offset(input_buffer), number_string_length);
68✔
364
    number_c_string[number_string_length] = '\0';
68✔
365

366
    if (has_decimal_point)
68✔
367
    {
368
        for (i = 0; i < number_string_length; i++)
×
369
        {
370
            if (number_c_string[i] == '.')
×
371
            {
372
                /* replace '.' with the decimal point of the current locale (for strtod) */
373
                number_c_string[i] = decimal_point;
×
374
            }
375
        }
376
    }
377

378
    number = strtod((const char*)number_c_string, (char**)&after_end);
68✔
379
    if (number_c_string == after_end)
68✔
380
    {
381
        /* free the temporary buffer */
382
        input_buffer->hooks.deallocate(number_c_string);
×
383
        return false; /* parse_error */
×
384
    }
385

386
    item->valuedouble = number;
68✔
387

388
    /* use saturation in case of overflow */
389
    if (number >= INT_MAX)
68✔
390
    {
391
        item->valueint = INT_MAX;
×
392
    }
393
    else if (number <= (double)INT_MIN)
68✔
394
    {
395
        item->valueint = INT_MIN;
×
396
    }
397
    else
398
    {
399
        item->valueint = (int)number;
68✔
400
    }
401

402
    item->type = cJSON_Number;
68✔
403

404
    input_buffer->offset += (size_t)(after_end - number_c_string);
68✔
405
    /* free the temporary buffer */
406
    input_buffer->hooks.deallocate(number_c_string);
68✔
407
    return true;
68✔
408
}
409

410
/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
411
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
×
412
{
413
    if (number >= INT_MAX)
×
414
    {
415
        object->valueint = INT_MAX;
×
416
    }
417
    else if (number <= (double)INT_MIN)
×
418
    {
419
        object->valueint = INT_MIN;
×
420
    }
421
    else
422
    {
423
        object->valueint = (int)number;
×
424
    }
425

426
    return object->valuedouble = number;
×
427
}
428

429
/* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as an error and return NULL */
430
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
×
431
{
432
    char *copy = NULL;
×
433
    size_t v1_len;
×
434
    size_t v2_len;
×
435
    /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
436
    if ((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference))
×
437
    {
438
        return NULL;
439
    }
440
    /* return NULL if the object is corrupted or valuestring is NULL */
441
    if (object->valuestring == NULL || valuestring == NULL)
×
442
    {
443
        return NULL;
444
    }
445

446
    v1_len = strlen(valuestring);
×
447
    v2_len = strlen(object->valuestring);
×
448

449
    if (v1_len <= v2_len)
×
450
    {
451
        /* strcpy does not handle overlapping string: [X1, X2] [Y1, Y2] => X2 < Y1 or Y2 < X1 */
452
        if (!( valuestring + v1_len < object->valuestring || object->valuestring + v2_len < valuestring ))
×
453
        {
454
            return NULL;
455
        }
456
        strcpy(object->valuestring, valuestring);
×
457
        return object->valuestring;
×
458
    }
459
    copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
×
460
    if (copy == NULL)
×
461
    {
462
        return NULL;
463
    }
464
    if (object->valuestring != NULL)
×
465
    {
466
        cJSON_free(object->valuestring);
×
467
    }
468
    object->valuestring = copy;
×
469

470
    return copy;
×
471
}
472

473
typedef struct
474
{
475
    unsigned char *buffer;
476
    size_t length;
477
    size_t offset;
478
    size_t depth; /* current nesting depth (for formatted printing) */
479
    cJSON_bool noalloc;
480
    cJSON_bool format; /* is this print a formatted print */
481
    internal_hooks hooks;
482
} printbuffer;
483

484
/* realloc printbuffer if necessary to have at least "needed" bytes more */
485
static unsigned char* ensure(printbuffer * const p, size_t needed)
969✔
486
{
487
    unsigned char *newbuffer = NULL;
969✔
488
    size_t newsize = 0;
969✔
489

490
    if ((p == NULL) || (p->buffer == NULL))
969✔
491
    {
492
        return NULL;
493
    }
494

495
    if ((p->length > 0) && (p->offset >= p->length))
969✔
496
    {
497
        /* make sure that offset is valid */
498
        return NULL;
499
    }
500

501
    if (needed > INT_MAX)
969✔
502
    {
503
        /* sizes bigger than INT_MAX are currently not supported */
504
        return NULL;
505
    }
506

507
    needed += p->offset + 1;
969✔
508
    if (needed <= p->length)
969✔
509
    {
510
        return p->buffer + p->offset;
965✔
511
    }
512

513
    if (p->noalloc) {
4✔
514
        return NULL;
515
    }
516

517
    /* calculate new buffer size */
518
    if (needed > (INT_MAX / 2))
4✔
519
    {
520
        /* overflow of int, use INT_MAX if possible */
521
        if (needed <= INT_MAX)
×
522
        {
523
            newsize = INT_MAX;
524
        }
525
        else
526
        {
527
            return NULL;
528
        }
529
    }
530
    else
531
    {
532
        newsize = needed * 2;
4✔
533
    }
534

535
    if (p->hooks.reallocate != NULL)
4✔
536
    {
537
        /* reallocate with realloc if available */
538
        newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
4✔
539
        if (newbuffer == NULL)
4✔
540
        {
541
            p->hooks.deallocate(p->buffer);
×
542
            p->length = 0;
×
543
            p->buffer = NULL;
×
544

545
            return NULL;
×
546
        }
547
    }
548
    else
549
    {
550
        /* otherwise reallocate manually */
551
        newbuffer = (unsigned char*)p->hooks.allocate(newsize);
×
552
        if (!newbuffer)
×
553
        {
554
            p->hooks.deallocate(p->buffer);
×
555
            p->length = 0;
×
556
            p->buffer = NULL;
×
557

558
            return NULL;
×
559
        }
560

561
        memcpy(newbuffer, p->buffer, p->offset + 1);
×
562
        p->hooks.deallocate(p->buffer);
×
563
    }
564
    p->length = newsize;
4✔
565
    p->buffer = newbuffer;
4✔
566

567
    return newbuffer + p->offset;
4✔
568
}
569

570
/* calculate the new length of the string in a printbuffer and update the offset */
571
static void update_offset(printbuffer * const buffer)
448✔
572
{
573
    const unsigned char *buffer_pointer = NULL;
448✔
574
    if ((buffer == NULL) || (buffer->buffer == NULL))
448✔
575
    {
576
        return;
577
    }
578
    buffer_pointer = buffer->buffer + buffer->offset;
448✔
579

580
    buffer->offset += strlen((const char*)buffer_pointer);
448✔
581
}
582

583
/* securely comparison of floating-point variables */
584
static cJSON_bool compare_double(double a, double b)
×
585
{
586
    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
×
587
    return (fabs(a - b) <= maxVal * DBL_EPSILON);
×
588
}
589

590
/* Render the number nicely from the given item into a string. */
591
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
63✔
592
{
593
    unsigned char *output_pointer = NULL;
63✔
594
    double d = item->valuedouble;
63✔
595
    int length = 0;
63✔
596
    size_t i = 0;
63✔
597
    unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
63✔
598
    unsigned char decimal_point = get_decimal_point();
63✔
599
    double test = 0.0;
63✔
600

601
    if (output_buffer == NULL)
63✔
602
    {
603
        return false;
604
    }
605

606
    /* This checks for NaN and Infinity */
607
    if (isnan(d) || isinf(d))
63✔
608
    {
609
        length = sprintf((char*)number_buffer, "null");
×
610
    }
611
    else if(d == (double)item->valueint)
63✔
612
    {
613
        length = sprintf((char*)number_buffer, "%d", item->valueint);
63✔
614
    }
615
    else
616
    {
617
        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
618
        length = sprintf((char*)number_buffer, "%1.15g", d);
×
619

620
        /* Check whether the original double can be recovered */
621
        if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
×
622
        {
623
            /* If not, print with 17 decimal places of precision */
624
            length = sprintf((char*)number_buffer, "%1.17g", d);
×
625
        }
626
    }
627

628
    /* sprintf failed or buffer overrun occurred */
629
    if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
63✔
630
    {
631
        return false;
632
    }
633

634
    /* reserve appropriate space in the output */
635
    output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
63✔
636
    if (output_pointer == NULL)
63✔
637
    {
638
        return false;
639
    }
640

641
    /* copy the printed number to the output and replace locale
642
     * dependent decimal point with '.' */
643
    for (i = 0; i < ((size_t)length); i++)
136✔
644
    {
645
        if (number_buffer[i] == decimal_point)
646
        {
×
647
            output_pointer[i] = '.';
×
648
            continue;
649
        }
650

73✔
651
        output_pointer[i] = number_buffer[i];
652
    }
63✔
653
    output_pointer[i] = '\0';
654

63✔
655
    output_buffer->offset += (size_t)length;
656

63✔
657
    return true;
658
}
659

660
/* parse 4 digit hexadecimal number */
×
661
static unsigned parse_hex4(const unsigned char * const input)
662
{
×
663
    unsigned int h = 0;
×
664
    size_t i = 0;
665

×
666
    for (i = 0; i < 4; i++)
667
    {
668
        /* parse digit */
×
669
        if ((input[i] >= '0') && (input[i] <= '9'))
670
        {
×
671
            h += (unsigned int) input[i] - '0';
672
        }
×
673
        else if ((input[i] >= 'A') && (input[i] <= 'F'))
674
        {
×
675
            h += (unsigned int) 10 + input[i] - 'A';
676
        }
×
677
        else if ((input[i] >= 'a') && (input[i] <= 'f'))
678
        {
×
679
            h += (unsigned int) 10 + input[i] - 'a';
680
        }
681
        else /* invalid */
682
        {
683
            return 0;
684
        }
685

×
686
        if (i < 3)
687
        {
688
            /* shift left to make place for the next nibble */
×
689
            h = h << 4;
690
        }
691
    }
692

693
    return h;
694
}
695

696
/* converts a UTF-16 literal to UTF-8
697
 * A literal can be one or two sequences of the form \uXXXX */
×
698
static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
699
{
×
700
    long unsigned int codepoint = 0;
×
701
    unsigned int first_code = 0;
×
702
    const unsigned char *first_sequence = input_pointer;
×
703
    unsigned char utf8_length = 0;
×
704
    unsigned char utf8_position = 0;
×
705
    unsigned char sequence_length = 0;
×
706
    unsigned char first_byte_mark = 0;
707

×
708
    if ((input_end - first_sequence) < 6)
709
    {
710
        /* input ends unexpectedly */
×
711
        goto fail;
712
    }
713

714
    /* get the first utf16 sequence */
×
715
    first_code = parse_hex4(first_sequence + 2);
716

717
    /* check that the code is valid */
×
718
    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
719
    {
×
720
        goto fail;
721
    }
722

723
    /* UTF16 surrogate pair */
×
724
    if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
725
    {
×
726
        const unsigned char *second_sequence = first_sequence + 6;
×
727
        unsigned int second_code = 0;
×
728
        sequence_length = 12; /* \uXXXX\uXXXX */
729

×
730
        if ((input_end - second_sequence) < 6)
731
        {
732
            /* input ends unexpectedly */
×
733
            goto fail;
734
        }
735

×
736
        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
737
        {
738
            /* missing second half of the surrogate pair */
×
739
            goto fail;
740
        }
741

742
        /* get the second utf16 sequence */
×
743
        second_code = parse_hex4(second_sequence + 2);
744
        /* check that the code is valid */
×
745
        if ((second_code < 0xDC00) || (second_code > 0xDFFF))
746
        {
747
            /* invalid second half of the surrogate pair */
×
748
            goto fail;
749
        }
750

751

752
        /* calculate the unicode codepoint from the surrogate pair */
×
753
        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
754
    }
755
    else
756
    {
×
757
        sequence_length = 6; /* \uXXXX */
×
758
        codepoint = first_code;
759
    }
760

761
    /* encode as UTF-8
762
     * takes at maximum 4 bytes to encode:
763
     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
×
764
    if (codepoint < 0x80)
765
    {
766
        /* normal ascii, encoding 0xxxxxxx */
767
        utf8_length = 1;
768
    }
×
769
    else if (codepoint < 0x800)
770
    {
771
        /* two bytes, encoding 110xxxxx 10xxxxxx */
772
        utf8_length = 2;
773
        first_byte_mark = 0xC0; /* 11000000 */
774
    }
×
775
    else if (codepoint < 0x10000)
776
    {
777
        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
778
        utf8_length = 3;
779
        first_byte_mark = 0xE0; /* 11100000 */
780
    }
×
781
    else if (codepoint <= 0x10FFFF)
782
    {
783
        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
784
        utf8_length = 4;
785
        first_byte_mark = 0xF0; /* 11110000 */
786
    }
787
    else
788
    {
789
        /* invalid unicode codepoint */
×
790
        goto fail;
791
    }
792

793
    /* encode as utf8 */
×
794
    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
795
    {
796
        /* 10xxxxxx */
×
797
        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
×
798
        codepoint >>= 6;
799
    }
800
    /* encode first byte */
×
801
    if (utf8_length > 1)
802
    {
×
803
        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
804
    }
805
    else
806
    {
×
807
        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
808
    }
809

×
810
    *output_pointer += utf8_length;
811

×
812
    return sequence_length;
813

814
fail:
815
    return 0;
816
}
817

818
/* Parse the input text into an unescaped cinput, and populate item. */
416✔
819
static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
820
{
416✔
821
    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
416✔
822
    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
416✔
823
    unsigned char *output_pointer = NULL;
416✔
824
    unsigned char *output = NULL;
825

826
    /* not a string */
416✔
827
    if (buffer_at_offset(input_buffer)[0] != '\"')
828
    {
×
829
        goto fail;
830
    }
831

832
    {
833
        /* calculate approximate size of the output (overestimate) */
7,619✔
834
        size_t allocation_length = 0;
835
        size_t skipped_bytes = 0;
7,619✔
836
        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
837
        {
838
            /* is escape sequence */
7,203✔
839
            if (input_end[0] == '\\')
840
            {
190✔
841
                if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
842
                {
843
                    /* prevent buffer overflow when last input character is a backslash */
×
844
                    goto fail;
845
                }
190✔
846
                skipped_bytes++;
190✔
847
                input_end++;
848
            }
7,203✔
849
            input_end++;
850
        }
416✔
851
        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
852
        {
×
853
            goto fail; /* string ended unexpectedly */
854
        }
855

856
        /* This is at most how much we need for the output */
416✔
857
        allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
416✔
858
        output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
416✔
859
        if (output == NULL)
860
        {
×
861
            goto fail; /* allocation failure */
862
        }
863
    }
864

416✔
865
    output_pointer = output;
866
    /* loop through the string literal */
7,619✔
867
    while (input_pointer < input_end)
868
    {
7,203✔
869
        if (*input_pointer != '\\')
870
        {
7,013✔
871
            *output_pointer++ = *input_pointer++;
872
        }
873
        /* escape sequence */
874
        else
875
        {
190✔
876
            unsigned char sequence_length = 2;
190✔
877
            if ((input_end - input_pointer) < 1)
878
            {
×
879
                goto fail;
880
            }
881

190✔
882
            switch (input_pointer[1])
883
            {
×
884
                case 'b':
×
885
                    *output_pointer++ = '\b';
×
886
                    break;
×
887
                case 'f':
×
888
                    *output_pointer++ = '\f';
×
889
                    break;
135✔
890
                case 'n':
135✔
891
                    *output_pointer++ = '\n';
135✔
892
                    break;
×
893
                case 'r':
×
894
                    *output_pointer++ = '\r';
×
895
                    break;
×
896
                case 't':
×
897
                    *output_pointer++ = '\t';
×
898
                    break;
55✔
899
                case '\"':
900
                case '\\':
901
                case '/':
55✔
902
                    *output_pointer++ = input_pointer[1];
55✔
903
                    break;
904

905
                /* UTF-16 literal */
×
906
                case 'u':
×
907
                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
×
908
                    if (sequence_length == 0)
909
                    {
910
                        /* failed to convert UTF16-literal to UTF-8 */
×
911
                        goto fail;
912
                    }
913
                    break;
914

×
915
                default:
×
916
                    goto fail;
917
            }
190✔
918
            input_pointer += sequence_length;
919
        }
920
    }
921

922
    /* zero terminate the output */
416✔
923
    *output_pointer = '\0';
924

416✔
925
    item->type = cJSON_String;
416✔
926
    item->valuestring = (char*)output;
927

416✔
928
    input_buffer->offset = (size_t) (input_end - input_buffer->content);
416✔
929
    input_buffer->offset++;
930

416✔
931
    return true;
932

×
933
fail:
×
934
    if (output != NULL)
935
    {
×
936
        input_buffer->hooks.deallocate(output);
×
937
        output = NULL;
938
    }
939

×
940
    if (input_pointer != NULL)
941
    {
×
942
        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
943
    }
944

945
    return false;
946
}
947

948
/* Render the cstring provided to an escaped version that can be printed. */
265✔
949
static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
950
{
265✔
951
    const unsigned char *input_pointer = NULL;
265✔
952
    unsigned char *output = NULL;
265✔
953
    unsigned char *output_pointer = NULL;
265✔
954
    size_t output_length = 0;
955
    /* numbers of additional characters needed for escaping */
265✔
956
    size_t escape_characters = 0;
957

265✔
958
    if (output_buffer == NULL)
959
    {
960
        return false;
961
    }
962

963
    /* empty string */
265✔
964
    if (input == NULL)
965
    {
×
966
        output = ensure(output_buffer, sizeof("\"\""));
×
967
        if (output == NULL)
968
        {
969
            return false;
970
        }
×
971
        strcpy((char*)output, "\"\"");
972

×
973
        return true;
974
    }
975

976
    /* set "flag" to 1 if something needs to be escaped */
2,197✔
977
    for (input_pointer = input; *input_pointer; input_pointer++)
978
    {
1,932✔
979
        switch (*input_pointer)
980
        {
×
981
            case '\"':
982
            case '\\':
983
            case '\b':
984
            case '\f':
985
            case '\n':
986
            case '\r':
987
            case '\t':
988
                /* one character escape sequence */
×
989
                escape_characters++;
×
990
                break;
1,932✔
991
            default:
1,932✔
992
                if (*input_pointer < 32)
993
                {
994
                    /* UTF-16 escape sequence uXXXX */
×
995
                    escape_characters += 5;
996
                }
997
                break;
998
        }
999
    }
265✔
1000
    output_length = (size_t)(input_pointer - input) + escape_characters;
1001

265✔
1002
    output = ensure(output_buffer, output_length + sizeof("\"\""));
265✔
1003
    if (output == NULL)
1004
    {
1005
        return false;
1006
    }
1007

1008
    /* no characters have to be escaped */
265✔
1009
    if (escape_characters == 0)
1010
    {
265✔
1011
        output[0] = '\"';
265✔
1012
        memcpy(output + 1, input, output_length);
265✔
1013
        output[output_length + 1] = '\"';
265✔
1014
        output[output_length + 2] = '\0';
1015

265✔
1016
        return true;
1017
    }
1018

×
1019
    output[0] = '\"';
×
1020
    output_pointer = output + 1;
1021
    /* copy the string */
×
1022
    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
1023
    {
×
1024
        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
1025
        {
1026
            /* normal character, copy */
×
1027
            *output_pointer = *input_pointer;
1028
        }
1029
        else
1030
        {
1031
            /* character needs to be escaped */
×
1032
            *output_pointer++ = '\\';
×
1033
            switch (*input_pointer)
1034
            {
×
1035
                case '\\':
×
1036
                    *output_pointer = '\\';
×
1037
                    break;
×
1038
                case '\"':
×
1039
                    *output_pointer = '\"';
×
1040
                    break;
×
1041
                case '\b':
×
1042
                    *output_pointer = 'b';
×
1043
                    break;
×
1044
                case '\f':
×
1045
                    *output_pointer = 'f';
×
1046
                    break;
×
1047
                case '\n':
×
1048
                    *output_pointer = 'n';
×
1049
                    break;
×
1050
                case '\r':
×
1051
                    *output_pointer = 'r';
×
1052
                    break;
×
1053
                case '\t':
×
1054
                    *output_pointer = 't';
×
1055
                    break;
×
1056
                default:
1057
                    /* escape and print as unicode codepoint */
×
1058
                    sprintf((char*)output_pointer, "u%04x", *input_pointer);
×
1059
                    output_pointer += 4;
×
1060
                    break;
1061
            }
1062
        }
1063
    }
×
1064
    output[output_length + 1] = '\"';
×
1065
    output[output_length + 2] = '\0';
1066

×
1067
    return true;
1068
}
1069

1070
/* Invoke print_string_ptr (which is useful) on an item. */
60✔
1071
static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
1072
{
60✔
1073
    return print_string_ptr((unsigned char*)item->valuestring, p);
1074
}
1075

1076
/* Predeclare these prototypes. */
1077
static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
1078
static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
1079
static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
1080
static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
1081
static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
1082
static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
1083

1084
/* Utility to jump whitespace and cr/lf */
1,322✔
1085
static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
1086
{
1,322✔
1087
    if ((buffer == NULL) || (buffer->content == NULL))
1088
    {
1089
        return NULL;
1090
    }
1091

1,322✔
1092
    if (cannot_access_at_index(buffer, 0))
1093
    {
1094
        return buffer;
1095
    }
1096

3,306✔
1097
    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
1098
    {
1,984✔
1099
       buffer->offset++;
1100
    }
1101

1,322✔
1102
    if (buffer->offset == buffer->length)
1103
    {
×
1104
        buffer->offset--;
1105
    }
1106

1107
    return buffer;
1108
}
1109

1110
/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
53✔
1111
static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
1112
{
53✔
1113
    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
1114
    {
1115
        return NULL;
1116
    }
1117

53✔
1118
    if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
1119
    {
×
1120
        buffer->offset += 3;
1121
    }
1122

1123
    return buffer;
1124
}
1125

53✔
1126
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
1127
{
53✔
1128
    size_t buffer_length;
1129

53✔
1130
    if (NULL == value)
1131
    {
1132
        return NULL;
1133
    }
1134

1135
    /* Adding null character size due to require_null_terminated. */
53✔
1136
    buffer_length = strlen(value) + sizeof("");
1137

53✔
1138
    return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
1139
}
1140

1141
/* Parse an object - create a new root, and populate. */
53✔
1142
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
1143
{
53✔
1144
    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
53✔
1145
    cJSON *item = NULL;
1146

1147
    /* reset error position */
53✔
1148
    global_error.json = NULL;
53✔
1149
    global_error.position = 0;
1150

53✔
1151
    if (value == NULL || 0 == buffer_length)
1152
    {
×
1153
        goto fail;
1154
    }
1155

53✔
1156
    buffer.content = (const unsigned char*)value;
53✔
1157
    buffer.length = buffer_length;
53✔
1158
    buffer.offset = 0;
53✔
1159
    buffer.hooks = global_hooks;
1160

53✔
1161
    item = cJSON_New_Item(&global_hooks);
53✔
1162
    if (item == NULL) /* memory fail */
1163
    {
×
1164
        goto fail;
1165
    }
1166

53✔
1167
    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
1168
    {
1169
        /* parse failure. ep is set. */
×
1170
        goto fail;
1171
    }
1172

1173
    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
53✔
1174
    if (require_null_terminated)
1175
    {
×
1176
        buffer_skip_whitespace(&buffer);
×
1177
        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
1178
        {
×
1179
            goto fail;
1180
        }
1181
    }
53✔
1182
    if (return_parse_end)
1183
    {
×
1184
        *return_parse_end = (const char*)buffer_at_offset(&buffer);
1185
    }
1186

1187
    return item;
1188

×
1189
fail:
×
1190
    if (item != NULL)
1191
    {
×
1192
        cJSON_Delete(item);
1193
    }
1194

×
1195
    if (value != NULL)
1196
    {
×
1197
        error local_error;
×
1198
        local_error.json = (const unsigned char*)value;
×
1199
        local_error.position = 0;
1200

×
1201
        if (buffer.offset < buffer.length)
1202
        {
1203
            local_error.position = buffer.offset;
1204
        }
×
1205
        else if (buffer.length > 0)
1206
        {
×
1207
            local_error.position = buffer.length - 1;
1208
        }
1209

×
1210
        if (return_parse_end != NULL)
1211
        {
×
1212
            *return_parse_end = (const char*)local_error.json + local_error.position;
1213
        }
1214

×
1215
        global_error = local_error;
1216
    }
1217

1218
    return NULL;
1219
}
1220

1221
/* Default options for cJSON_Parse */
53✔
1222
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
1223
{
53✔
1224
    return cJSON_ParseWithOpts(value, 0, 0);
1225
}
1226

×
1227
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
1228
{
×
1229
    return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
1230
}
1231

1232
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
1233

26✔
1234
static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
1235
{
26✔
1236
    static const size_t default_buffer_size = 256;
26✔
1237
    printbuffer buffer[1];
26✔
1238
    unsigned char *printed = NULL;
1239

26✔
1240
    memset(buffer, 0, sizeof(buffer));
1241

1242
    /* create buffer */
26✔
1243
    buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
26✔
1244
    buffer->length = default_buffer_size;
26✔
1245
    buffer->format = format;
26✔
1246
    buffer->hooks = *hooks;
26✔
1247
    if (buffer->buffer == NULL)
1248
    {
×
1249
        goto fail;
1250
    }
1251

1252
    /* print the value */
26✔
1253
    if (!print_value(item, buffer))
1254
    {
×
1255
        goto fail;
1256
    }
26✔
1257
    update_offset(buffer);
1258

1259
    /* check if reallocate is available */
26✔
1260
    if (hooks->reallocate != NULL)
1261
    {
26✔
1262
        printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
26✔
1263
        if (printed == NULL) {
×
1264
            goto fail;
1265
        }
1266
        buffer->buffer = NULL;
1267
    }
1268
    else /* otherwise copy the JSON over to a new buffer */
1269
    {
×
1270
        printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
×
1271
        if (printed == NULL)
1272
        {
×
1273
            goto fail;
1274
        }
×
1275
        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
×
1276
        printed[buffer->offset] = '\0'; /* just to be sure */
1277

1278
        /* free the buffer */
×
1279
        hooks->deallocate(buffer->buffer);
×
1280
        buffer->buffer = NULL;
1281
    }
1282

1283
    return printed;
1284

×
1285
fail:
×
1286
    if (buffer->buffer != NULL)
1287
    {
×
1288
        hooks->deallocate(buffer->buffer);
×
1289
        buffer->buffer = NULL;
1290
    }
1291

×
1292
    if (printed != NULL)
1293
    {
×
1294
        hooks->deallocate(printed);
×
1295
        printed = NULL;
1296
    }
1297

1298
    return NULL;
1299
}
1300

1301
/* Render a cJSON item/entity/structure to text. */
×
1302
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
1303
{
×
1304
    return (char*)print(item, true, &global_hooks);
1305
}
1306

26✔
1307
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
1308
{
26✔
1309
    return (char*)print(item, false, &global_hooks);
1310
}
1311

×
1312
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
1313
{
×
1314
    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1315

×
1316
    if (prebuffer < 0)
1317
    {
1318
        return NULL;
1319
    }
1320

×
1321
    p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
×
1322
    if (!p.buffer)
1323
    {
1324
        return NULL;
1325
    }
1326

×
1327
    p.length = (size_t)prebuffer;
×
1328
    p.offset = 0;
×
1329
    p.noalloc = false;
×
1330
    p.format = fmt;
×
1331
    p.hooks = global_hooks;
1332

×
1333
    if (!print_value(item, &p))
1334
    {
×
1335
        global_hooks.deallocate(p.buffer);
×
1336
        p.buffer = NULL;
×
1337
        return NULL;
1338
    }
1339

×
1340
    return (char*)p.buffer;
1341
}
1342

×
1343
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
1344
{
×
1345
    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1346

×
1347
    if ((length < 0) || (buffer == NULL))
1348
    {
1349
        return false;
1350
    }
1351

×
1352
    p.buffer = (unsigned char*)buffer;
×
1353
    p.length = (size_t)length;
×
1354
    p.offset = 0;
×
1355
    p.noalloc = true;
×
1356
    p.format = format;
×
1357
    p.hooks = global_hooks;
1358

×
1359
    return print_value(item, &p);
1360
}
1361

1362
/* Parser core - when encountering text, process appropriately. */
340✔
1363
static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
1364
{
340✔
1365
    if ((input_buffer == NULL) || (input_buffer->content == NULL))
1366
    {
1367
        return false; /* no input */
1368
    }
1369

1370
    /* parse the different types of values */
1371
    /* null */
340✔
1372
    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
1373
    {
4✔
1374
        item->type = cJSON_NULL;
4✔
1375
        input_buffer->offset += 4;
4✔
1376
        return true;
1377
    }
1378
    /* false */
336✔
1379
    if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
1380
    {
×
1381
        item->type = cJSON_False;
×
1382
        input_buffer->offset += 5;
×
1383
        return true;
1384
    }
1385
    /* true */
336✔
1386
    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
1387
    {
×
1388
        item->type = cJSON_True;
×
1389
        item->valueint = 1;
×
1390
        input_buffer->offset += 4;
×
1391
        return true;
1392
    }
1393
    /* string */
336✔
1394
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
1395
    {
135✔
1396
        return parse_string(item, input_buffer);
1397
    }
1398
    /* number */
201✔
1399
    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'))))
1400
    {
68✔
1401
        return parse_number(item, input_buffer);
1402
    }
1403
    /* array */
133✔
1404
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
1405
    {
4✔
1406
        return parse_array(item, input_buffer);
1407
    }
1408
    /* object */
129✔
1409
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
1410
    {
129✔
1411
        return parse_object(item, input_buffer);
1412
    }
1413

1414
    return false;
1415
}
1416

1417
/* Render a value to text. */
243✔
1418
static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
1419
{
243✔
1420
    unsigned char *output = NULL;
1421

243✔
1422
    if ((item == NULL) || (output_buffer == NULL))
1423
    {
1424
        return false;
1425
    }
1426

243✔
1427
    switch ((item->type) & 0xFF)
1428
    {
5✔
1429
        case cJSON_NULL:
5✔
1430
            output = ensure(output_buffer, 5);
5✔
1431
            if (output == NULL)
1432
            {
1433
                return false;
1434
            }
5✔
1435
            strcpy((char*)output, "null");
5✔
1436
            return true;
1437

×
1438
        case cJSON_False:
×
1439
            output = ensure(output_buffer, 6);
×
1440
            if (output == NULL)
1441
            {
1442
                return false;
1443
            }
×
1444
            strcpy((char*)output, "false");
×
1445
            return true;
1446

8✔
1447
        case cJSON_True:
8✔
1448
            output = ensure(output_buffer, 5);
8✔
1449
            if (output == NULL)
1450
            {
1451
                return false;
1452
            }
8✔
1453
            strcpy((char*)output, "true");
8✔
1454
            return true;
1455

63✔
1456
        case cJSON_Number:
63✔
1457
            return print_number(item, output_buffer);
1458

×
1459
        case cJSON_Raw:
1460
        {
×
1461
            size_t raw_length = 0;
×
1462
            if (item->valuestring == NULL)
1463
            {
1464
                return false;
1465
            }
1466

×
1467
            raw_length = strlen(item->valuestring) + sizeof("");
×
1468
            output = ensure(output_buffer, raw_length);
×
1469
            if (output == NULL)
1470
            {
1471
                return false;
1472
            }
×
1473
            memcpy(output, item->valuestring, raw_length);
×
1474
            return true;
1475
        }
1476

60✔
1477
        case cJSON_String:
60✔
1478
            return print_string(item, output_buffer);
1479

8✔
1480
        case cJSON_Array:
8✔
1481
            return print_array(item, output_buffer);
1482

99✔
1483
        case cJSON_Object:
99✔
1484
            return print_object(item, output_buffer);
1485

1486
        default:
1487
            return false;
1488
    }
1489
}
1490

1491
/* Build an array from input text. */
4✔
1492
static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
1493
{
4✔
1494
    cJSON *head = NULL; /* head of the linked list */
4✔
1495
    cJSON *current_item = NULL;
1496

4✔
1497
    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1498
    {
1499
        return false; /* to deeply nested */
1500
    }
4✔
1501
    input_buffer->depth++;
1502

4✔
1503
    if (buffer_at_offset(input_buffer)[0] != '[')
1504
    {
1505
        /* not an array */
×
1506
        goto fail;
1507
    }
1508

4✔
1509
    input_buffer->offset++;
4✔
1510
    buffer_skip_whitespace(input_buffer);
4✔
1511
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
1512
    {
1513
        /* empty array */
×
1514
        goto success;
1515
    }
1516

1517
    /* check if we skipped to the end of the buffer */
4✔
1518
    if (cannot_access_at_index(input_buffer, 0))
1519
    {
×
1520
        input_buffer->offset--;
×
1521
        goto fail;
1522
    }
1523

1524
    /* step back to character in front of the first element */
4✔
1525
    input_buffer->offset--;
1526
    /* loop through the comma separated array elements */
6✔
1527
    do
1528
    {
1529
        /* allocate next item */
6✔
1530
        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
6✔
1531
        if (new_item == NULL)
1532
        {
×
1533
            goto fail; /* allocation failure */
1534
        }
1535

1536
        /* attach next item to list */
6✔
1537
        if (head == NULL)
1538
        {
1539
            /* start the linked list */
1540
            current_item = head = new_item;
1541
        }
1542
        else
1543
        {
1544
            /* add to the end and advance */
2✔
1545
            current_item->next = new_item;
2✔
1546
            new_item->prev = current_item;
2✔
1547
            current_item = new_item;
1548
        }
1549

1550
        /* parse next value */
6✔
1551
        input_buffer->offset++;
6✔
1552
        buffer_skip_whitespace(input_buffer);
6✔
1553
        if (!parse_value(current_item, input_buffer))
1554
        {
×
1555
            goto fail; /* failed to parse value */
1556
        }
6✔
1557
        buffer_skip_whitespace(input_buffer);
1558
    }
6✔
1559
    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1560

4✔
1561
    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
1562
    {
×
1563
        goto fail; /* expected end of array */
1564
    }
1565

4✔
1566
success:
4✔
1567
    input_buffer->depth--;
1568

4✔
1569
    if (head != NULL) {
4✔
1570
        head->prev = current_item;
1571
    }
1572

4✔
1573
    item->type = cJSON_Array;
4✔
1574
    item->child = head;
1575

4✔
1576
    input_buffer->offset++;
1577

4✔
1578
    return true;
1579

×
1580
fail:
×
1581
    if (head != NULL)
1582
    {
×
1583
        cJSON_Delete(head);
1584
    }
1585

1586
    return false;
1587
}
1588

1589
/* Render an array to text */
8✔
1590
static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
1591
{
8✔
1592
    unsigned char *output_pointer = NULL;
8✔
1593
    size_t length = 0;
8✔
1594
    cJSON *current_element = item->child;
1595

8✔
1596
    if (output_buffer == NULL)
1597
    {
1598
        return false;
1599
    }
1600

1601
    /* Compose the output array. */
1602
    /* opening square bracket */
8✔
1603
    output_pointer = ensure(output_buffer, 1);
8✔
1604
    if (output_pointer == NULL)
1605
    {
1606
        return false;
1607
    }
1608

8✔
1609
    *output_pointer = '[';
8✔
1610
    output_buffer->offset++;
8✔
1611
    output_buffer->depth++;
1612

20✔
1613
    while (current_element != NULL)
1614
    {
12✔
1615
        if (!print_value(current_element, output_buffer))
1616
        {
1617
            return false;
1618
        }
12✔
1619
        update_offset(output_buffer);
12✔
1620
        if (current_element->next)
1621
        {
4✔
1622
            length = (size_t) (output_buffer->format ? 2 : 1);
4✔
1623
            output_pointer = ensure(output_buffer, length + 1);
4✔
1624
            if (output_pointer == NULL)
1625
            {
1626
                return false;
1627
            }
4✔
1628
            *output_pointer++ = ',';
4✔
1629
            if(output_buffer->format)
1630
            {
×
1631
                *output_pointer++ = ' ';
1632
            }
4✔
1633
            *output_pointer = '\0';
4✔
1634
            output_buffer->offset += length;
1635
        }
12✔
1636
        current_element = current_element->next;
1637
    }
1638

8✔
1639
    output_pointer = ensure(output_buffer, 2);
8✔
1640
    if (output_pointer == NULL)
1641
    {
1642
        return false;
1643
    }
8✔
1644
    *output_pointer++ = ']';
8✔
1645
    *output_pointer = '\0';
8✔
1646
    output_buffer->depth--;
1647

8✔
1648
    return true;
1649
}
1650

1651
/* Build an object from the text. */
129✔
1652
static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
1653
{
129✔
1654
    cJSON *head = NULL; /* linked list head */
129✔
1655
    cJSON *current_item = NULL;
1656

129✔
1657
    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1658
    {
1659
        return false; /* to deeply nested */
1660
    }
129✔
1661
    input_buffer->depth++;
1662

129✔
1663
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
1664
    {
×
1665
        goto fail; /* not an object */
1666
    }
1667

129✔
1668
    input_buffer->offset++;
129✔
1669
    buffer_skip_whitespace(input_buffer);
129✔
1670
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
1671
    {
13✔
1672
        goto success; /* empty object */
1673
    }
1674

1675
    /* check if we skipped to the end of the buffer */
116✔
1676
    if (cannot_access_at_index(input_buffer, 0))
1677
    {
×
1678
        input_buffer->offset--;
×
1679
        goto fail;
1680
    }
1681

1682
    /* step back to character in front of the first element */
116✔
1683
    input_buffer->offset--;
1684
    /* loop through the comma separated array elements */
281✔
1685
    do
1686
    {
1687
        /* allocate next item */
281✔
1688
        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
281✔
1689
        if (new_item == NULL)
1690
        {
×
1691
            goto fail; /* allocation failure */
1692
        }
1693

1694
        /* attach next item to list */
281✔
1695
        if (head == NULL)
1696
        {
1697
            /* start the linked list */
1698
            current_item = head = new_item;
1699
        }
1700
        else
1701
        {
1702
            /* add to the end and advance */
165✔
1703
            current_item->next = new_item;
165✔
1704
            new_item->prev = current_item;
165✔
1705
            current_item = new_item;
1706
        }
1707

281✔
1708
        if (cannot_access_at_index(input_buffer, 1))
1709
        {
×
1710
            goto fail; /* nothing comes after the comma */
1711
        }
1712

1713
        /* parse the name of the child */
281✔
1714
        input_buffer->offset++;
281✔
1715
        buffer_skip_whitespace(input_buffer);
281✔
1716
        if (!parse_string(current_item, input_buffer))
1717
        {
×
1718
            goto fail; /* failed to parse name */
1719
        }
281✔
1720
        buffer_skip_whitespace(input_buffer);
1721

1722
        /* swap valuestring and string, because we parsed the name */
281✔
1723
        current_item->string = current_item->valuestring;
281✔
1724
        current_item->valuestring = NULL;
1725

281✔
1726
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
1727
        {
×
1728
            goto fail; /* invalid object */
1729
        }
1730

1731
        /* parse the value */
281✔
1732
        input_buffer->offset++;
281✔
1733
        buffer_skip_whitespace(input_buffer);
281✔
1734
        if (!parse_value(current_item, input_buffer))
1735
        {
×
1736
            goto fail; /* failed to parse value */
1737
        }
281✔
1738
        buffer_skip_whitespace(input_buffer);
1739
    }
281✔
1740
    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1741

116✔
1742
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
1743
    {
×
1744
        goto fail; /* expected end of object */
1745
    }
1746

116✔
1747
success:
129✔
1748
    input_buffer->depth--;
1749

129✔
1750
    if (head != NULL) {
116✔
1751
        head->prev = current_item;
1752
    }
1753

129✔
1754
    item->type = cJSON_Object;
129✔
1755
    item->child = head;
1756

129✔
1757
    input_buffer->offset++;
129✔
1758
    return true;
1759

×
1760
fail:
×
1761
    if (head != NULL)
1762
    {
×
1763
        cJSON_Delete(head);
1764
    }
1765

1766
    return false;
1767
}
1768

1769
/* Render an object to text. */
99✔
1770
static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
1771
{
99✔
1772
    unsigned char *output_pointer = NULL;
99✔
1773
    size_t length = 0;
99✔
1774
    cJSON *current_item = item->child;
1775

99✔
1776
    if (output_buffer == NULL)
1777
    {
1778
        return false;
1779
    }
1780

1781
    /* Compose the output: */
99✔
1782
    length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
99✔
1783
    output_pointer = ensure(output_buffer, length + 1);
99✔
1784
    if (output_pointer == NULL)
1785
    {
1786
        return false;
1787
    }
1788

99✔
1789
    *output_pointer++ = '{';
99✔
1790
    output_buffer->depth++;
99✔
1791
    if (output_buffer->format)
1792
    {
×
1793
        *output_pointer++ = '\n';
1794
    }
99✔
1795
    output_buffer->offset += length;
1796

304✔
1797
    while (current_item)
1798
    {
205✔
1799
        if (output_buffer->format)
1800
        {
×
1801
            size_t i;
×
1802
            output_pointer = ensure(output_buffer, output_buffer->depth);
×
1803
            if (output_pointer == NULL)
1804
            {
1805
                return false;
1806
            }
×
1807
            for (i = 0; i < output_buffer->depth; i++)
1808
            {
×
1809
                *output_pointer++ = '\t';
1810
            }
×
1811
            output_buffer->offset += output_buffer->depth;
1812
        }
1813

1814
        /* print key */
205✔
1815
        if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
1816
        {
1817
            return false;
1818
        }
205✔
1819
        update_offset(output_buffer);
1820

205✔
1821
        length = (size_t) (output_buffer->format ? 2 : 1);
205✔
1822
        output_pointer = ensure(output_buffer, length);
205✔
1823
        if (output_pointer == NULL)
1824
        {
1825
            return false;
1826
        }
205✔
1827
        *output_pointer++ = ':';
205✔
1828
        if (output_buffer->format)
1829
        {
×
1830
            *output_pointer++ = '\t';
1831
        }
205✔
1832
        output_buffer->offset += length;
1833

1834
        /* print value */
205✔
1835
        if (!print_value(current_item, output_buffer))
1836
        {
1837
            return false;
1838
        }
205✔
1839
        update_offset(output_buffer);
1840

1841
        /* print comma if not last */
410✔
1842
        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
205✔
1843
        output_pointer = ensure(output_buffer, length + 1);
205✔
1844
        if (output_pointer == NULL)
1845
        {
1846
            return false;
1847
        }
205✔
1848
        if (current_item->next)
1849
        {
108✔
1850
            *output_pointer++ = ',';
1851
        }
1852

205✔
1853
        if (output_buffer->format)
1854
        {
×
1855
            *output_pointer++ = '\n';
1856
        }
205✔
1857
        *output_pointer = '\0';
205✔
1858
        output_buffer->offset += length;
1859

205✔
1860
        current_item = current_item->next;
1861
    }
1862

99✔
1863
    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
1864
    if (output_pointer == NULL)
1865
    {
1866
        return false;
99✔
1867
    }
1868
    if (output_buffer->format)
1869
    {
×
1870
        size_t i;
1871
        for (i = 0; i < (output_buffer->depth - 1); i++)
×
1872
        {
1873
            *output_pointer++ = '\t';
1874
        }
99✔
1875
    }
99✔
1876
    *output_pointer++ = '}';
99✔
1877
    *output_pointer = '\0';
1878
    output_buffer->depth--;
99✔
1879

1880
    return true;
1881
}
1882

×
1883
/* Get Array size/item / object item. */
1884
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
×
1885
{
×
1886
    cJSON *child = NULL;
1887
    size_t size = 0;
×
1888

1889
    if (array == NULL)
1890
    {
1891
        return 0;
1892
    }
×
1893

1894
    child = array->child;
×
1895

1896
    while(child != NULL)
×
1897
    {
×
1898
        size++;
1899
        child = child->next;
1900
    }
1901

1902
    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
×
1903

1904
    return (int)size;
1905
}
×
1906

1907
static cJSON* get_array_item(const cJSON *array, size_t index)
×
1908
{
1909
    cJSON *current_child = NULL;
×
1910

1911
    if (array == NULL)
1912
    {
1913
        return NULL;
1914
    }
×
1915

×
1916
    current_child = array->child;
1917
    while ((current_child != NULL) && (index > 0))
×
1918
    {
×
1919
        index--;
1920
        current_child = current_child->next;
1921
    }
1922

1923
    return current_child;
1924
}
×
1925

1926
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
×
1927
{
1928
    if (index < 0)
1929
    {
1930
        return NULL;
1931
    }
×
1932

1933
    return get_array_item(array, (size_t)index);
1934
}
222✔
1935

1936
static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
222✔
1937
{
1938
    cJSON *current_element = NULL;
222✔
1939

1940
    if ((object == NULL) || (name == NULL))
1941
    {
1942
        return NULL;
1943
    }
222✔
1944

222✔
1945
    current_element = object->child;
1946
    if (case_sensitive)
108✔
1947
    {
1948
        while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
42✔
1949
        {
1950
            current_element = current_element->next;
1951
        }
1952
    }
1953
    else
332✔
1954
    {
1955
        while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
176✔
1956
        {
1957
            current_element = current_element->next;
1958
        }
1959
    }
222✔
1960

4✔
1961
    if ((current_element == NULL) || (current_element->string == NULL)) {
1962
        return NULL;
1963
    }
1964

1965
    return current_element;
1966
}
154✔
1967

1968
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
154✔
1969
{
1970
    return get_object_item(object, string, false);
1971
}
66✔
1972

1973
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
66✔
1974
{
1975
    return get_object_item(object, string, true);
1976
}
×
1977

1978
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
×
1979
{
1980
    return cJSON_GetObjectItem(object, string) ? 1 : 0;
1981
}
1982

100✔
1983
/* Utility for array list handling. */
1984
static void suffix_object(cJSON *prev, cJSON *item)
100✔
1985
{
100✔
1986
    prev->next = item;
100✔
1987
    item->prev = prev;
1988
}
1989

×
1990
/* Utility for handling references. */
1991
static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
×
1992
{
×
1993
    cJSON *reference = NULL;
1994
    if (item == NULL)
1995
    {
1996
        return NULL;
1997
    }
×
1998

×
1999
    reference = cJSON_New_Item(hooks);
2000
    if (reference == NULL)
2001
    {
2002
        return NULL;
2003
    }
×
2004

×
2005
    memcpy(reference, item, sizeof(cJSON));
×
2006
    reference->string = NULL;
×
2007
    reference->type |= cJSON_IsReference;
×
2008
    reference->next = reference->prev = NULL;
2009
    return reference;
2010
}
187✔
2011

2012
static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
187✔
2013
{
2014
    cJSON *child = NULL;
187✔
2015

2016
    if ((item == NULL) || (array == NULL) || (array == item))
2017
    {
2018
        return false;
2019
    }
187✔
2020

2021
    child = array->child;
2022
    /*
2023
     * To find the last item in array quickly, we use prev in array
187✔
2024
     */
2025
    if (child == NULL)
2026
    {
87✔
2027
        /* list is empty, start new one */
87✔
2028
        array->child = item;
87✔
2029
        item->prev = item;
2030
        item->next = NULL;
2031
    }
2032
    else
2033
    {
100✔
2034
        /* append to the end */
2035
        if (child->prev)
100✔
2036
        {
100✔
2037
            suffix_object(child->prev, item);
2038
            array->child->prev = item;
2039
        }
2040
    }
2041

2042
    return true;
2043
}
2044

6✔
2045
/* Add item to array/object. */
2046
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
6✔
2047
{
2048
    return add_item_to_array(array, item);
2049
}
2050

2051
#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
2052
    #pragma GCC diagnostic push
2053
#endif
2054
#ifdef __GNUC__
2055
#pragma GCC diagnostic ignored "-Wcast-qual"
2056
#endif
×
2057
/* helper function to cast away const */
2058
static void* cast_away_const(const void* string)
×
2059
{
2060
    return (void*)string;
2061
}
2062
#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
2063
    #pragma GCC diagnostic pop
2064
#endif
2065

182✔
2066

2067
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)
182✔
2068
{
182✔
2069
    char *new_key = NULL;
2070
    int new_type = cJSON_Invalid;
182✔
2071

2072
    if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
2073
    {
2074
        return false;
2075
    }
181✔
2076

2077
    if (constant_key)
×
2078
    {
×
2079
        new_key = (char*)cast_away_const(string);
2080
        new_type = item->type | cJSON_StringIsConst;
2081
    }
2082
    else
181✔
2083
    {
181✔
2084
        new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
2085
        if (new_key == NULL)
2086
        {
2087
            return false;
2088
        }
181✔
2089

2090
        new_type = item->type & ~cJSON_StringIsConst;
2091
    }
181✔
2092

2093
    if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
×
2094
    {
2095
        hooks->deallocate(item->string);
2096
    }
181✔
2097

181✔
2098
    item->string = new_key;
2099
    item->type = new_type;
181✔
2100

2101
    return add_item_to_array(object, item);
2102
}
56✔
2103

2104
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
56✔
2105
{
2106
    return add_item_to_object(object, string, item, &global_hooks, false);
2107
}
2108

×
2109
/* Add an item to an object with constant string as key */
2110
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
×
2111
{
2112
    return add_item_to_object(object, string, item, &global_hooks, true);
2113
}
×
2114

2115
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
×
2116
{
2117
    if (array == NULL)
2118
    {
2119
        return false;
2120
    }
×
2121

2122
    return add_item_to_array(array, create_reference(item, &global_hooks));
2123
}
×
2124

2125
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
×
2126
{
2127
    if ((object == NULL) || (string == NULL))
2128
    {
2129
        return false;
2130
    }
×
2131

2132
    return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
2133
}
5✔
2134

2135
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
5✔
2136
{
5✔
2137
    cJSON *null = cJSON_CreateNull();
2138
    if (add_item_to_object(object, name, null, &global_hooks, false))
2139
    {
2140
        return null;
2141
    }
×
2142

×
2143
    cJSON_Delete(null);
2144
    return NULL;
2145
}
×
2146

2147
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
×
2148
{
×
2149
    cJSON *true_item = cJSON_CreateTrue();
2150
    if (add_item_to_object(object, name, true_item, &global_hooks, false))
2151
    {
2152
        return true_item;
2153
    }
×
2154

×
2155
    cJSON_Delete(true_item);
2156
    return NULL;
2157
}
×
2158

2159
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
×
2160
{
×
2161
    cJSON *false_item = cJSON_CreateFalse();
2162
    if (add_item_to_object(object, name, false_item, &global_hooks, false))
2163
    {
2164
        return false_item;
2165
    }
×
2166

×
2167
    cJSON_Delete(false_item);
2168
    return NULL;
2169
}
8✔
2170

2171
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
8✔
2172
{
8✔
2173
    cJSON *bool_item = cJSON_CreateBool(boolean);
2174
    if (add_item_to_object(object, name, bool_item, &global_hooks, false))
2175
    {
2176
        return bool_item;
2177
    }
×
2178

×
2179
    cJSON_Delete(bool_item);
2180
    return NULL;
2181
}
61✔
2182

2183
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
61✔
2184
{
61✔
2185
    cJSON *number_item = cJSON_CreateNumber(number);
2186
    if (add_item_to_object(object, name, number_item, &global_hooks, false))
2187
    {
2188
        return number_item;
2189
    }
×
2190

×
2191
    cJSON_Delete(number_item);
2192
    return NULL;
2193
}
52✔
2194

2195
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
52✔
2196
{
52✔
2197
    cJSON *string_item = cJSON_CreateString(string);
2198
    if (add_item_to_object(object, name, string_item, &global_hooks, false))
2199
    {
2200
        return string_item;
2201
    }
×
2202

×
2203
    cJSON_Delete(string_item);
2204
    return NULL;
2205
}
×
2206

2207
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
×
2208
{
×
2209
    cJSON *raw_item = cJSON_CreateRaw(raw);
2210
    if (add_item_to_object(object, name, raw_item, &global_hooks, false))
2211
    {
2212
        return raw_item;
2213
    }
×
2214

×
2215
    cJSON_Delete(raw_item);
2216
    return NULL;
2217
}
×
2218

2219
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
×
2220
{
×
2221
    cJSON *object_item = cJSON_CreateObject();
2222
    if (add_item_to_object(object, name, object_item, &global_hooks, false))
2223
    {
2224
        return object_item;
2225
    }
×
2226

×
2227
    cJSON_Delete(object_item);
2228
    return NULL;
2229
}
×
2230

2231
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
×
2232
{
×
2233
    cJSON *array = cJSON_CreateArray();
2234
    if (add_item_to_object(object, name, array, &global_hooks, false))
2235
    {
2236
        return array;
2237
    }
×
2238

×
2239
    cJSON_Delete(array);
2240
    return NULL;
2241
}
×
2242

2243
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
×
2244
{
2245
    if ((parent == NULL) || (item == NULL) || (item != parent->child && item->prev == NULL))
2246
    {
2247
        return NULL;
2248
    }
×
2249

2250
    if (item != parent->child)
2251
    {
×
2252
        /* not the first element */
2253
        item->prev->next = item->next;
×
2254
    }
2255
    if (item->next != NULL)
2256
    {
×
2257
        /* not the last element */
2258
        item->next->prev = item->prev;
2259
    }
×
2260

2261
    if (item == parent->child)
2262
    {
×
2263
        /* first element */
2264
        parent->child = item->next;
×
2265
    }
2266
    else if (item->next == NULL)
2267
    {
×
2268
        /* last element */
2269
        parent->child->prev = item->prev;
2270
    }
2271

×
2272
    /* make sure the detached item doesn't point anywhere anymore */
×
2273
    item->prev = NULL;
2274
    item->next = NULL;
×
2275

2276
    return item;
2277
}
×
2278

2279
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
×
2280
{
2281
    if (which < 0)
2282
    {
2283
        return NULL;
2284
    }
×
2285

2286
    return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
2287
}
×
2288

2289
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
×
2290
{
2291
    cJSON_Delete(cJSON_DetachItemFromArray(array, which));
2292
}
×
2293

2294
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
×
2295
{
2296
    cJSON *to_detach = cJSON_GetObjectItem(object, string);
×
2297

2298
    return cJSON_DetachItemViaPointer(object, to_detach);
2299
}
×
2300

2301
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
×
2302
{
2303
    cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
×
2304

2305
    return cJSON_DetachItemViaPointer(object, to_detach);
2306
}
×
2307

2308
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
×
2309
{
2310
    cJSON_Delete(cJSON_DetachItemFromObject(object, string));
2311
}
×
2312

2313
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
×
2314
{
2315
    cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
2316
}
2317

×
2318
/* Replace array/object items with new ones. */
2319
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
×
2320
{
2321
    cJSON *after_inserted = NULL;
×
2322

2323
    if (which < 0 || newitem == NULL)
2324
    {
2325
        return false;
2326
    }
×
2327

×
2328
    after_inserted = get_array_item(array, (size_t)which);
2329
    if (after_inserted == NULL)
×
2330
    {
2331
        return add_item_to_array(array, newitem);
2332
    }
×
2333

2334
    if (after_inserted != array->child && after_inserted->prev == NULL) {
2335
        /* return false if after_inserted is a corrupted array item */
2336
        return false;
2337
    }
×
2338

×
2339
    newitem->next = after_inserted;
×
2340
    newitem->prev = after_inserted->prev;
×
2341
    after_inserted->prev = newitem;
2342
    if (after_inserted == array->child)
×
2343
    {
2344
        array->child = newitem;
2345
    }
2346
    else
×
2347
    {
2348
        newitem->prev->next = newitem;
2349
    }
2350
    return true;
2351
}
2✔
2352

2353
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
2✔
2354
{
2355
    if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL) || (item == NULL))
2356
    {
2357
        return false;
2358
    }
×
2359

2360
    if (replacement == item)
2361
    {
2362
        return true;
2363
    }
×
2364

×
2365
    replacement->next = item->next;
2366
    replacement->prev = item->prev;
×
2367

2368
    if (replacement->next != NULL)
×
2369
    {
2370
        replacement->next->prev = replacement;
×
2371
    }
2372
    if (parent->child == item)
×
2373
    {
2374
        if (parent->child->prev == parent->child)
×
2375
        {
2376
            replacement->prev = replacement;
×
2377
        }
2378
        parent->child = replacement;
2379
    }
2380
    else
2381
    {   /*
2382
         * To find the last item in array quickly, we use prev in array.
2383
         * We can't modify the last item's next pointer where this item was the parent's child
×
2384
         */
2385
        if (replacement->prev != NULL)
×
2386
        {
2387
            replacement->prev->next = replacement;
×
2388
        }
2389
        if (replacement->next == NULL)
×
2390
        {
2391
            parent->child->prev = replacement;
2392
        }
2393
    }
×
2394

×
2395
    item->next = NULL;
×
2396
    item->prev = NULL;
2397
    cJSON_Delete(item);
×
2398

2399
    return true;
2400
}
×
2401

2402
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
×
2403
{
2404
    if (which < 0)
2405
    {
2406
        return false;
2407
    }
×
2408

2409
    return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
2410
}
2✔
2411

2412
static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
2✔
2413
{
2414
    if ((replacement == NULL) || (string == NULL))
2415
    {
2416
        return false;
2417
    }
2418

2✔
2419
    /* replace the name in the replacement */
2420
    if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
×
2421
    {
2422
        cJSON_free(replacement->string);
2✔
2423
    }
2✔
2424
    replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2425
    if (replacement->string == NULL)
2426
    {
2427
        return false;
2428
    }
2✔
2429

2430
    replacement->type &= ~cJSON_StringIsConst;
2✔
2431

2432
    return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
2433
}
2✔
2434

2435
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
2✔
2436
{
2437
    return replace_item_in_object(object, string, newitem, false);
2438
}
×
2439

2440
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
×
2441
{
2442
    return replace_item_in_object(object, string, newitem, true);
2443
}
2444

5✔
2445
/* Create basic types: */
2446
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
5✔
2447
{
5✔
2448
    cJSON *item = cJSON_New_Item(&global_hooks);
2449
    if(item)
5✔
2450
    {
2451
        item->type = cJSON_NULL;
2452
    }
5✔
2453

2454
    return item;
2455
}
×
2456

2457
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
×
2458
{
×
2459
    cJSON *item = cJSON_New_Item(&global_hooks);
2460
    if(item)
×
2461
    {
2462
        item->type = cJSON_True;
2463
    }
×
2464

2465
    return item;
2466
}
×
2467

2468
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
×
2469
{
×
2470
    cJSON *item = cJSON_New_Item(&global_hooks);
2471
    if(item)
×
2472
    {
2473
        item->type = cJSON_False;
2474
    }
×
2475

2476
    return item;
2477
}
8✔
2478

2479
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
8✔
2480
{
8✔
2481
    cJSON *item = cJSON_New_Item(&global_hooks);
2482
    if(item)
8✔
2483
    {
2484
        item->type = boolean ? cJSON_True : cJSON_False;
2485
    }
8✔
2486

2487
    return item;
2488
}
61✔
2489

2490
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
61✔
2491
{
61✔
2492
    cJSON *item = cJSON_New_Item(&global_hooks);
2493
    if(item)
61✔
2494
    {
61✔
2495
        item->type = cJSON_Number;
2496
        item->valuedouble = num;
2497

61✔
2498
        /* use saturation in case of overflow */
2499
        if (num >= INT_MAX)
×
2500
        {
2501
            item->valueint = INT_MAX;
61✔
2502
        }
2503
        else if (num <= (double)INT_MIN)
×
2504
        {
2505
            item->valueint = INT_MIN;
2506
        }
2507
        else
61✔
2508
        {
2509
            item->valueint = (int)num;
2510
        }
2511
    }
61✔
2512

2513
    return item;
2514
}
52✔
2515

2516
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
52✔
2517
{
52✔
2518
    cJSON *item = cJSON_New_Item(&global_hooks);
2519
    if(item)
52✔
2520
    {
52✔
2521
        item->type = cJSON_String;
52✔
2522
        item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2523
        if(!item->valuestring)
×
2524
        {
×
2525
            cJSON_Delete(item);
2526
            return NULL;
2527
        }
2528
    }
2529

2530
    return item;
2531
}
×
2532

2533
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
×
2534
{
×
2535
    cJSON *item = cJSON_New_Item(&global_hooks);
2536
    if (item != NULL)
×
2537
    {
×
2538
        item->type = cJSON_String | cJSON_IsReference;
2539
        item->valuestring = (char*)cast_away_const(string);
2540
    }
×
2541

2542
    return item;
2543
}
×
2544

2545
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
×
2546
{
×
2547
    cJSON *item = cJSON_New_Item(&global_hooks);
×
2548
    if (item != NULL) {
×
2549
        item->type = cJSON_Object | cJSON_IsReference;
2550
        item->child = (cJSON*)cast_away_const(child);
2551
    }
×
2552

2553
    return item;
2554
}
×
2555

×
2556
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
×
2557
    cJSON *item = cJSON_New_Item(&global_hooks);
×
2558
    if (item != NULL) {
×
2559
        item->type = cJSON_Array | cJSON_IsReference;
2560
        item->child = (cJSON*)cast_away_const(child);
2561
    }
×
2562

2563
    return item;
2564
}
×
2565

2566
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
×
2567
{
×
2568
    cJSON *item = cJSON_New_Item(&global_hooks);
2569
    if(item)
×
2570
    {
×
2571
        item->type = cJSON_Raw;
×
2572
        item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
2573
        if(!item->valuestring)
×
2574
        {
×
2575
            cJSON_Delete(item);
2576
            return NULL;
2577
        }
2578
    }
2579

2580
    return item;
2581
}
4✔
2582

2583
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
4✔
2584
{
4✔
2585
    cJSON *item = cJSON_New_Item(&global_hooks);
2586
    if(item)
4✔
2587
    {
2588
        item->type=cJSON_Array;
2589
    }
4✔
2590

2591
    return item;
2592
}
87✔
2593

2594
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
87✔
2595
{
87✔
2596
    cJSON *item = cJSON_New_Item(&global_hooks);
2597
    if (item)
87✔
2598
    {
2599
        item->type = cJSON_Object;
2600
    }
87✔
2601

2602
    return item;
2603
}
2604

×
2605
/* Create Arrays: */
2606
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
×
2607
{
×
2608
    size_t i = 0;
×
2609
    cJSON *n = NULL;
×
2610
    cJSON *p = NULL;
2611
    cJSON *a = NULL;
×
2612

2613
    if ((count < 0) || (numbers == NULL))
2614
    {
2615
        return NULL;
2616
    }
×
2617

2618
    a = cJSON_CreateArray();
×
2619

2620
    for(i = 0; a && (i < (size_t)count); i++)
×
2621
    {
×
2622
        n = cJSON_CreateNumber(numbers[i]);
2623
        if (!n)
×
2624
        {
×
2625
            cJSON_Delete(a);
2626
            return NULL;
×
2627
        }
2628
        if(!i)
×
2629
        {
2630
            a->child = n;
2631
        }
2632
        else
×
2633
        {
2634
            suffix_object(p, n);
×
2635
        }
2636
        p = n;
2637
    }
×
2638

×
2639
    if (a && a->child) {
2640
        a->child->prev = n;
2641
    }
2642

2643
    return a;
2644
}
×
2645

2646
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
×
2647
{
×
2648
    size_t i = 0;
×
2649
    cJSON *n = NULL;
×
2650
    cJSON *p = NULL;
2651
    cJSON *a = NULL;
×
2652

2653
    if ((count < 0) || (numbers == NULL))
2654
    {
2655
        return NULL;
2656
    }
×
2657

2658
    a = cJSON_CreateArray();
×
2659

2660
    for(i = 0; a && (i < (size_t)count); i++)
×
2661
    {
×
2662
        n = cJSON_CreateNumber((double)numbers[i]);
2663
        if(!n)
×
2664
        {
×
2665
            cJSON_Delete(a);
2666
            return NULL;
×
2667
        }
2668
        if(!i)
×
2669
        {
2670
            a->child = n;
2671
        }
2672
        else
×
2673
        {
2674
            suffix_object(p, n);
×
2675
        }
2676
        p = n;
2677
    }
×
2678

×
2679
    if (a && a->child) {
2680
        a->child->prev = n;
2681
    }
2682

2683
    return a;
2684
}
×
2685

2686
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
×
2687
{
×
2688
    size_t i = 0;
×
2689
    cJSON *n = NULL;
×
2690
    cJSON *p = NULL;
2691
    cJSON *a = NULL;
×
2692

2693
    if ((count < 0) || (numbers == NULL))
2694
    {
2695
        return NULL;
2696
    }
×
2697

2698
    a = cJSON_CreateArray();
×
2699

2700
    for(i = 0; a && (i < (size_t)count); i++)
×
2701
    {
×
2702
        n = cJSON_CreateNumber(numbers[i]);
2703
        if(!n)
×
2704
        {
×
2705
            cJSON_Delete(a);
2706
            return NULL;
×
2707
        }
2708
        if(!i)
×
2709
        {
2710
            a->child = n;
2711
        }
2712
        else
×
2713
        {
2714
            suffix_object(p, n);
×
2715
        }
2716
        p = n;
2717
    }
×
2718

×
2719
    if (a && a->child) {
2720
        a->child->prev = n;
2721
    }
2722

2723
    return a;
2724
}
×
2725

2726
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
×
2727
{
×
2728
    size_t i = 0;
×
2729
    cJSON *n = NULL;
×
2730
    cJSON *p = NULL;
2731
    cJSON *a = NULL;
×
2732

2733
    if ((count < 0) || (strings == NULL))
2734
    {
2735
        return NULL;
2736
    }
×
2737

2738
    a = cJSON_CreateArray();
×
2739

2740
    for (i = 0; a && (i < (size_t)count); i++)
×
2741
    {
×
2742
        n = cJSON_CreateString(strings[i]);
2743
        if(!n)
×
2744
        {
×
2745
            cJSON_Delete(a);
2746
            return NULL;
×
2747
        }
2748
        if(!i)
×
2749
        {
2750
            a->child = n;
2751
        }
2752
        else
×
2753
        {
2754
            suffix_object(p,n);
×
2755
        }
2756
        p = n;
2757
    }
×
2758

×
2759
    if (a && a->child) {
2760
        a->child->prev = n;
2761
    }
2762

2763
    return a;
2764
}
2765

2766
/* Duplication */
2767
cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse);
8✔
2768

2769
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
8✔
2770
{
2771
    return cJSON_Duplicate_rec(item, 0, recurse );
2772
}
88✔
2773

2774
cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse)
88✔
2775
{
88✔
2776
    cJSON *newitem = NULL;
88✔
2777
    cJSON *child = NULL;
88✔
2778
    cJSON *next = NULL;
2779
    cJSON *newchild = NULL;
2780

88✔
2781
    /* Bail on bad ptr */
2782
    if (!item)
×
2783
    {
2784
        goto fail;
2785
    }
88✔
2786
    /* Create new item */
88✔
2787
    newitem = cJSON_New_Item(&global_hooks);
2788
    if (!newitem)
×
2789
    {
2790
        goto fail;
2791
    }
88✔
2792
    /* Copy over all vars */
88✔
2793
    newitem->type = item->type & (~cJSON_IsReference);
88✔
2794
    newitem->valueint = item->valueint;
88✔
2795
    newitem->valuedouble = item->valuedouble;
2796
    if (item->valuestring)
20✔
2797
    {
20✔
2798
        newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
2799
        if (!newitem->valuestring)
×
2800
        {
2801
            goto fail;
2802
        }
88✔
2803
    }
2804
    if (item->string)
76✔
2805
    {
76✔
2806
        newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
2807
        if (!newitem->string)
×
2808
        {
2809
            goto fail;
2810
        }
2811
    }
88✔
2812
    /* If non-recursive, then we're done! */
2813
    if (!recurse)
2814
    {
2815
        return newitem;
2816
    }
88✔
2817
    /* Walk the ->next chain for the child. */
168✔
2818
    child = item->child;
2819
    while (child != NULL)
80✔
2820
    {
×
2821
        if(depth >= CJSON_CIRCULAR_LIMIT) {
2822
            goto fail;
80✔
2823
        }
80✔
2824
        newchild = cJSON_Duplicate_rec(child, depth + 1, true); /* Duplicate (with recurse) each item in the ->next chain */
2825
        if (!newchild)
×
2826
        {
2827
            goto fail;
80✔
2828
        }
2829
        if (next != NULL)
2830
        {
40✔
2831
            /* If newitem->child already set, then crosswire ->prev and ->next and move on */
40✔
2832
            next->next = newchild;
40✔
2833
            newchild->prev = next;
2834
            next = newchild;
2835
        }
2836
        else
2837
        {
40✔
2838
            /* Set newitem->child and move to it */
40✔
2839
            newitem->child = newchild;
2840
            next = newchild;
80✔
2841
        }
2842
        child = child->next;
88✔
2843
    }
2844
    if (newitem && newitem->child)
40✔
2845
    {
2846
        newitem->child->prev = newchild;
2847
    }
2848

2849
    return newitem;
×
2850

×
2851
fail:
2852
    if (newitem != NULL)
×
2853
    {
2854
        cJSON_Delete(newitem);
2855
    }
2856

2857
    return NULL;
2858
}
×
2859

2860
static void skip_oneline_comment(char **input)
×
2861
{
2862
    *input += static_strlen("//");
×
2863

2864
    for (; (*input)[0] != '\0'; ++(*input))
×
2865
    {
×
2866
        if ((*input)[0] == '\n') {
×
2867
            *input += static_strlen("\n");
2868
            return;
2869
        }
2870
    }
2871
}
×
2872

2873
static void skip_multiline_comment(char **input)
×
2874
{
2875
    *input += static_strlen("/*");
×
2876

2877
    for (; (*input)[0] != '\0'; ++(*input))
×
2878
    {
2879
        if (((*input)[0] == '*') && ((*input)[1] == '/'))
×
2880
        {
×
2881
            *input += static_strlen("*/");
2882
            return;
2883
        }
2884
    }
2885
}
×
2886

×
2887
static void minify_string(char **input, char **output) {
×
2888
    (*output)[0] = (*input)[0];
×
2889
    *input += static_strlen("\"");
2890
    *output += static_strlen("\"");
2891

×
2892

×
2893
    for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
2894
        (*output)[0] = (*input)[0];
×
2895

×
2896
        if ((*input)[0] == '\"') {
×
2897
            (*output)[0] = '\"';
×
2898
            *input += static_strlen("\"");
×
2899
            *output += static_strlen("\"");
×
2900
            return;
×
2901
        } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
×
2902
            (*output)[1] = (*input)[1];
×
2903
            *input += static_strlen("\"");
2904
            *output += static_strlen("\"");
2905
        }
2906
    }
2907
}
×
2908

2909
CJSON_PUBLIC(void) cJSON_Minify(char *json)
×
2910
{
2911
    char *into = json;
×
2912

2913
    if (json == NULL)
×
2914
    {
2915
        return;
2916
    }
×
2917

2918
    while (json[0] != '\0')
×
2919
    {
2920
        switch (json[0])
×
2921
        {
2922
            case ' ':
2923
            case '\t':
2924
            case '\r':
×
2925
            case '\n':
×
2926
                json++;
2927
                break;
×
2928

×
2929
            case '/':
2930
                if (json[1] == '/')
×
2931
                {
2932
                    skip_oneline_comment(&json);
×
2933
                }
2934
                else if (json[1] == '*')
×
2935
                {
2936
                    skip_multiline_comment(&json);
×
2937
                } else {
2938
                    json++;
2939
                }
2940
                break;
×
2941

×
2942
            case '\"':
×
2943
                minify_string(&json, (char**)&into);
2944
                break;
×
2945

×
2946
            default:
×
2947
                into[0] = json[0];
×
2948
                json++;
2949
                into++;
2950
        }
2951
    }
2952

×
2953
    /* and null-terminate. */
2954
    *into = '\0';
2955
}
×
2956

2957
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
×
2958
{
2959
    if (item == NULL)
2960
    {
2961
        return false;
2962
    }
×
2963

2964
    return (item->type & 0xFF) == cJSON_Invalid;
2965
}
×
2966

2967
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
×
2968
{
2969
    if (item == NULL)
2970
    {
2971
        return false;
2972
    }
×
2973

2974
    return (item->type & 0xFF) == cJSON_False;
2975
}
×
2976

2977
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
×
2978
{
2979
    if (item == NULL)
2980
    {
2981
        return false;
2982
    }
×
2983

2984
    return (item->type & 0xff) == cJSON_True;
2985
}
2986

×
2987

2988
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
×
2989
{
2990
    if (item == NULL)
2991
    {
2992
        return false;
2993
    }
×
2994

2995
    return (item->type & (cJSON_True | cJSON_False)) != 0;
×
2996
}
2997
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
×
2998
{
2999
    if (item == NULL)
3000
    {
3001
        return false;
3002
    }
×
3003

3004
    return (item->type & 0xFF) == cJSON_NULL;
3005
}
×
3006

3007
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
×
3008
{
3009
    if (item == NULL)
3010
    {
3011
        return false;
3012
    }
×
3013

3014
    return (item->type & 0xFF) == cJSON_Number;
3015
}
55✔
3016

3017
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
55✔
3018
{
3019
    if (item == NULL)
3020
    {
3021
        return false;
3022
    }
55✔
3023

3024
    return (item->type & 0xFF) == cJSON_String;
3025
}
×
3026

3027
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
×
3028
{
3029
    if (item == NULL)
3030
    {
3031
        return false;
3032
    }
×
3033

3034
    return (item->type & 0xFF) == cJSON_Array;
3035
}
×
3036

3037
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
×
3038
{
3039
    if (item == NULL)
3040
    {
3041
        return false;
3042
    }
×
3043

3044
    return (item->type & 0xFF) == cJSON_Object;
3045
}
×
3046

3047
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
×
3048
{
3049
    if (item == NULL)
3050
    {
3051
        return false;
3052
    }
×
3053

3054
    return (item->type & 0xFF) == cJSON_Raw;
3055
}
×
3056

3057
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
×
3058
{
3059
    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
3060
    {
3061
        return false;
3062
    }
3063

×
3064
    /* check if type is valid */
3065
    switch (a->type & 0xFF)
3066
    {
3067
        case cJSON_False:
3068
        case cJSON_True:
3069
        case cJSON_NULL:
3070
        case cJSON_Number:
3071
        case cJSON_String:
3072
        case cJSON_Raw:
3073
        case cJSON_Array:
×
3074
        case cJSON_Object:
3075
            break;
3076

3077
        default:
3078
            return false;
3079
    }
3080

×
3081
    /* identical objects are equal */
3082
    if (a == b)
3083
    {
3084
        return true;
3085
    }
×
3086

3087
    switch (a->type & 0xFF)
3088
    {
3089
        /* in these cases and equal type is enough */
3090
        case cJSON_False:
3091
        case cJSON_True:
3092
        case cJSON_NULL:
3093
            return true;
×
3094

×
3095
        case cJSON_Number:
3096
            if (compare_double(a->valuedouble, b->valuedouble))
×
3097
            {
3098
                return true;
3099
            }
3100
            return false;
×
3101

3102
        case cJSON_String:
×
3103
        case cJSON_Raw:
3104
            if ((a->valuestring == NULL) || (b->valuestring == NULL))
3105
            {
3106
                return false;
×
3107
            }
3108
            if (strcmp(a->valuestring, b->valuestring) == 0)
×
3109
            {
3110
                return true;
3111
            }
3112

3113
            return false;
×
3114

3115
        case cJSON_Array:
×
3116
        {
×
3117
            cJSON *a_element = a->child;
3118
            cJSON *b_element = b->child;
×
3119

3120
            for (; (a_element != NULL) && (b_element != NULL);)
×
3121
            {
3122
                if (!cJSON_Compare(a_element, b_element, case_sensitive))
3123
                {
3124
                    return false;
3125
                }
×
3126

×
3127
                a_element = a_element->next;
3128
                b_element = b_element->next;
3129
            }
3130

×
3131
            /* one of the arrays is longer than the other */
×
3132
            if (a_element != b_element) {
3133
                return false;
3134
            }
3135

3136
            return true;
3137
        }
×
3138

3139
        case cJSON_Object:
×
3140
        {
×
3141
            cJSON *a_element = NULL;
×
3142
            cJSON *b_element = NULL;
3143
            cJSON_ArrayForEach(a_element, a)
3144
            {
×
3145
                /* TODO This has O(n^2) runtime, which is horrible! */
×
3146
                b_element = get_object_item(b, a_element->string, case_sensitive);
3147
                if (b_element == NULL)
3148
                {
3149
                    return false;
3150
                }
×
3151

3152
                if (!cJSON_Compare(a_element, b_element, case_sensitive))
3153
                {
3154
                    return false;
3155
                }
3156
            }
3157

3158
            /* doing this twice, once on a and b to prevent true comparison if a subset of b
×
3159
             * TODO: Do this the proper way, this is just a fix for now */
3160
            cJSON_ArrayForEach(b_element, b)
×
3161
            {
×
3162
                a_element = get_object_item(a, b_element->string, case_sensitive);
3163
                if (a_element == NULL)
3164
                {
3165
                    return false;
3166
                }
×
3167

3168
                if (!cJSON_Compare(b_element, a_element, case_sensitive))
3169
                {
3170
                    return false;
3171
                }
3172
            }
3173

3174
            return true;
3175
        }
×
3176

×
3177
        default:
3178
            return false;
3179
    }
3180
}
×
3181

3182
CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
×
3183
{
3184
    return global_hooks.allocate(size);
3185
}
×
3186

3187
CJSON_PUBLIC(void) cJSON_free(void *object)
×
3188
{
×
3189
    global_hooks.deallocate(object);
3190
    object = NULL;
3191
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc