Coverage Report

Created: 2026-10-16 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vulkan-loader/loader/cJSON.c
Line
Count
Source
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
#include "allocation.h"
62
63
/* define our own boolean type */
64
#ifdef true
65
#undef true
66
#endif
67
104M
#define true ((cJSON_bool)1)
68
69
#ifdef false
70
#undef false
71
#endif
72
42.3M
#define false ((cJSON_bool)0)
73
74
/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
75
#ifndef isinf
76
#define isinf(d) (isnan((d - d)) && !isnan(d))
77
#endif
78
#ifndef isnan
79
#define isnan(d) (d != d)
80
#endif
81
82
#ifndef NAN
83
#ifdef _WIN32
84
#define NAN sqrt(-1.0)
85
#else
86
#define NAN 0.0 / 0.0
87
#endif
88
#endif
89
90
typedef struct {
91
    const unsigned char *json;
92
    size_t position;
93
} error;
94
static error global_error = {NULL, 0};
95
96
0
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) { return (const char *)(global_error.json + global_error.position); }
97
98
8.12M
CJSON_PUBLIC(char *) loader_cJSON_GetStringValue(const cJSON *const item) {
99
8.12M
    if (!loader_cJSON_IsString(item)) {
100
2.05M
        return NULL;
101
2.05M
    }
102
103
6.06M
    return item->valuestring;
104
8.12M
}
105
106
0
CJSON_PUBLIC(double) loader_cJSON_GetNumberValue(const cJSON *const item) {
107
0
    if (!loader_cJSON_IsNumber(item)) {
108
0
        return (double)NAN;
109
0
    }
110
111
0
    return item->valuedouble;
112
0
}
113
114
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
115
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 19)
116
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
117
#endif
118
119
/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
120
156M
static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) {
121
156M
    if ((string1 == NULL) || (string2 == NULL)) {
122
105k
        return 1;
123
105k
    }
124
125
156M
    if (string1 == string2) {
126
0
        return 0;
127
0
    }
128
129
326M
    for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) {
130
183M
        if (*string1 == '\0') {
131
13.5M
            return 0;
132
13.5M
        }
133
183M
    }
134
135
143M
    return tolower(*string1) - tolower(*string2);
136
156M
}
137
138
/* strlen of character literals resolved at compile time */
139
0
#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
140
141
/* Internal constructor. */
142
48.7M
static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) {
143
48.7M
    cJSON *node = (cJSON *)loader_calloc(pAllocator, sizeof(cJSON), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
144
48.7M
    if (NULL != node) {
145
48.7M
        node->pAllocator = pAllocator;
146
48.7M
    }
147
48.7M
    return node;
148
48.7M
}
149
150
/* Delete a cJSON structure. */
151
10.3M
TEST_FUNCTION_EXPORT CJSON_PUBLIC(void) loader_cJSON_Delete(cJSON *item) {
152
10.3M
    cJSON *next = NULL;
153
59.0M
    while (item != NULL) {
154
48.7M
        next = item->next;
155
48.7M
        if (!(item->type & cJSON_IsReference) && (item->child != NULL)) {
156
9.02M
            loader_cJSON_Delete(item->child);
157
9.02M
        }
158
48.7M
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) {
159
24.9M
            loader_free(item->pAllocator, item->valuestring);
160
24.9M
            item->valuestring = NULL;
161
24.9M
        }
162
48.7M
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
163
27.0M
            loader_free(item->pAllocator, item->string);
164
27.0M
            item->string = NULL;
165
27.0M
        }
166
48.7M
        loader_free(item->pAllocator, item);
167
48.7M
        item = next;
168
48.7M
    }
169
10.3M
}
170
171
/* get the decimal point character of the current locale */
172
8.60M
static unsigned char get_decimal_point(void) {
173
#ifdef ENABLE_LOCALES
174
    struct lconv *lconv = localeconv();
175
    return (unsigned char)lconv->decimal_point[0];
176
#else
177
8.60M
    return '.';
178
8.60M
#endif
179
8.60M
}
180
181
typedef struct {
182
    const unsigned char *content;
183
    size_t length;
184
    size_t offset;
185
    size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
186
    const VkAllocationCallbacks *pAllocator;
187
} parse_buffer;
188
189
/* check if the given size is left to read in a given parse buffer (starting with 1) */
190
292M
#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
191
/* check if the buffer can be accessed at the given index (starting with 0) */
192
1.21G
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
193
302M
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
194
/* get a pointer to the buffer at the position */
195
949M
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
196
197
/* Parse the input text to generate a number, and populate the result into item. */
198
6.41M
static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) {
199
6.41M
    double number = 0;
200
6.41M
    unsigned char *after_end = NULL;
201
6.41M
    unsigned char *number_c_string;
202
6.41M
    unsigned char decimal_point = get_decimal_point();
203
6.41M
    size_t i = 0;
204
6.41M
    size_t number_string_length = 0;
205
6.41M
    cJSON_bool has_decimal_point = false;
206
207
6.41M
    if ((input_buffer == NULL) || (input_buffer->content == NULL)) {
208
0
        return false;
209
0
    }
210
211
    /* copy the number into a temporary buffer and replace '.' with the decimal point
212
     * of the current locale (for strtod)
213
     * This also takes care of '\0' not necessarily being available for marking the end of the input */
214
18.0M
    for (i = 0; can_access_at_index(input_buffer, i); i++) {
215
18.0M
        switch (buffer_at_offset(input_buffer)[i]) {
216
1.38M
            case '0':
217
4.69M
            case '1':
218
5.36M
            case '2':
219
5.83M
            case '3':
220
6.29M
            case '4':
221
6.65M
            case '5':
222
8.48M
            case '6':
223
9.31M
            case '7':
224
9.81M
            case '8':
225
10.8M
            case '9':
226
10.8M
            case '+':
227
10.9M
            case '-':
228
11.4M
            case 'e':
229
11.5M
            case 'E':
230
11.5M
                number_string_length++;
231
11.5M
                break;
232
233
84.7k
            case '.':
234
84.7k
                number_string_length++;
235
84.7k
                has_decimal_point = true;
236
84.7k
                break;
237
238
6.41M
            default:
239
6.41M
                goto loop_end;
240
18.0M
        }
241
18.0M
    }
242
6.41M
loop_end:
243
    /* malloc for temporary buffer, add 1 for '\0' */
244
6.41M
    number_c_string =
245
6.41M
        (unsigned char *)loader_calloc(input_buffer->pAllocator, number_string_length + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
246
6.41M
    if (number_c_string == NULL) {
247
0
        return false; /* allocation failure */
248
0
    }
249
250
6.41M
    memcpy(number_c_string, buffer_at_offset(input_buffer), number_string_length);
251
6.41M
    number_c_string[number_string_length] = '\0';
252
253
6.41M
    if (has_decimal_point) {
254
609k
        for (i = 0; i < number_string_length; i++) {
255
526k
            if (number_c_string[i] == '.') {
256
                /* replace '.' with the decimal point of the current locale (for strtod) */
257
84.7k
                number_c_string[i] = decimal_point;
258
84.7k
            }
259
526k
        }
260
83.5k
    }
261
262
6.41M
    number = strtod((const char *)number_c_string, (char **)&after_end);
263
6.41M
    if (number_c_string == after_end) {
264
        /* free the temporary buffer */
265
483
        loader_free(input_buffer->pAllocator, number_c_string);
266
483
        return false; /* parse_error */
267
483
    }
268
269
6.41M
    item->valuedouble = number;
270
271
    /* use saturation in case of overflow */
272
6.41M
    if (number >= INT_MAX) {
273
288k
        item->valueint = INT_MAX;
274
6.12M
    } else if (number <= (double)INT_MIN) {
275
27.6k
        item->valueint = INT_MIN;
276
6.09M
    } else {
277
6.09M
        item->valueint = (int)number;
278
6.09M
    }
279
280
6.41M
    item->type = cJSON_Number;
281
282
6.41M
    input_buffer->offset += (size_t)(after_end - number_c_string);
283
    /* free the temporary buffer */
284
6.41M
    loader_free(input_buffer->pAllocator, number_c_string);
285
6.41M
    return true;
286
6.41M
}
287
288
typedef struct {
289
    unsigned char *buffer;
290
    size_t length;
291
    size_t offset;
292
    size_t depth; /* current nesting depth (for formatted printing) */
293
    cJSON_bool noalloc;
294
    cJSON_bool format; /* is this print a formatted print */
295
    const VkAllocationCallbacks *pAllocator;
296
} printbuffer;
297
298
/* realloc printbuffer if necessary to have at least "needed" bytes more */
299
41.7M
static unsigned char *ensure(printbuffer *const p, size_t needed, bool *out_of_memory) {
300
41.7M
    unsigned char *newbuffer = NULL;
301
41.7M
    size_t newsize = 0;
302
303
41.7M
    if ((p == NULL) || (p->buffer == NULL)) {
304
0
        return NULL;
305
0
    }
306
307
41.7M
    if ((p->length > 0) && (p->offset >= p->length)) {
308
        /* make sure that offset is valid */
309
0
        return NULL;
310
0
    }
311
312
41.7M
    if (needed > INT_MAX) {
313
        /* sizes bigger than INT_MAX are currently not supported */
314
0
        return NULL;
315
0
    }
316
317
41.7M
    needed += p->offset + 1;
318
41.7M
    if (needed <= p->length) {
319
41.7M
        return p->buffer + p->offset;
320
41.7M
    }
321
322
32.7k
    if (p->noalloc) {
323
4.75k
        return NULL;
324
4.75k
    }
325
326
    /* calculate new buffer size */
327
27.9k
    if (needed > (INT_MAX / 2)) {
328
        /* overflow of int, use INT_MAX if possible */
329
0
        if (needed <= INT_MAX) {
330
0
            newsize = INT_MAX;
331
0
        } else {
332
0
            return NULL;
333
0
        }
334
27.9k
    } else {
335
27.9k
        newsize = needed * 2;
336
27.9k
    }
337
338
27.9k
    newbuffer = (unsigned char *)loader_realloc(p->pAllocator, p->buffer, p->length, newsize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
339
27.9k
    if (newbuffer == NULL) {
340
0
        *out_of_memory = true;
341
0
        loader_free(p->pAllocator, p->buffer);
342
0
        p->length = 0;
343
0
        p->buffer = NULL;
344
345
0
        return NULL;
346
0
    }
347
348
27.9k
    p->length = newsize;
349
27.9k
    p->buffer = newbuffer;
350
351
27.9k
    return newbuffer + p->offset;
352
27.9k
}
353
354
/* calculate the new length of the string in a printbuffer and update the offset */
355
16.4M
static void update_offset(printbuffer *const buffer) {
356
16.4M
    const unsigned char *buffer_pointer = NULL;
357
16.4M
    if ((buffer == NULL) || (buffer->buffer == NULL)) {
358
0
        return;
359
0
    }
360
16.4M
    buffer_pointer = buffer->buffer + buffer->offset;
361
362
16.4M
    buffer->offset += strlen((const char *)buffer_pointer);
363
16.4M
}
364
365
/* securely comparison of floating-point variables */
366
63.6k
static cJSON_bool compare_double(double a, double b) {
367
63.6k
    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
368
63.6k
    return (fabs(a - b) <= maxVal * DBL_EPSILON);
369
63.6k
}
370
371
/* Render the number nicely from the given item into a string. */
372
2.18M
static cJSON_bool print_number(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
373
2.18M
    unsigned char *output_pointer = NULL;
374
2.18M
    double d = item->valuedouble;
375
2.18M
    int length = 0;
376
2.18M
    size_t i = 0;
377
2.18M
    unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
378
2.18M
    unsigned char decimal_point = get_decimal_point();
379
2.18M
    double test = 0.0;
380
381
2.18M
    if (output_buffer == NULL) {
382
0
        return false;
383
0
    }
384
385
    /* This checks for NaN and Infinity */
386
2.18M
    if (isnan(d) || isinf(d)) {
387
1.70k
        length = snprintf((char *)number_buffer, 26, "null");
388
2.18M
    } else if (d == (double)item->valueint) {
389
2.12M
        length = snprintf((char *)number_buffer, 26, "%d", item->valueint);
390
2.12M
    } else {
391
        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
392
63.6k
        length = snprintf((char *)number_buffer, 26, "%1.15g", d);
393
394
        /* Check whether the original double can be recovered */
395
63.6k
        if ((sscanf((char *)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) {
396
            /* If not, print with 17 decimal places of precision */
397
8.43k
            length = snprintf((char *)number_buffer, 26, "%1.17g", d);
398
8.43k
        }
399
63.6k
    }
400
401
    /* snprintf failed or buffer overrun occurred */
402
2.18M
    if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) {
403
0
        return false;
404
0
    }
405
406
    /* reserve appropriate space in the output */
407
2.18M
    output_pointer = ensure(output_buffer, (size_t)length + sizeof(""), out_of_memory);
408
2.18M
    if (output_pointer == NULL) {
409
0
        return false;
410
0
    }
411
412
    /* copy the printed number to the output and replace locale
413
     * dependent decimal point with '.' */
414
4.84M
    for (i = 0; i < ((size_t)length); i++) {
415
2.65M
        if (number_buffer[i] == decimal_point) {
416
9.42k
            output_pointer[i] = '.';
417
9.42k
            continue;
418
9.42k
        }
419
420
2.65M
        output_pointer[i] = number_buffer[i];
421
2.65M
    }
422
2.18M
    output_pointer[i] = '\0';
423
424
2.18M
    output_buffer->offset += (size_t)length;
425
426
2.18M
    return true;
427
2.18M
}
428
429
/* parse 4 digit hexadecimal number */
430
2.54M
static unsigned parse_hex4(const unsigned char *const input) {
431
2.54M
    unsigned int h = 0;
432
2.54M
    size_t i = 0;
433
434
9.80M
    for (i = 0; i < 4; i++) {
435
        /* parse digit */
436
8.49M
        if ((input[i] >= '0') && (input[i] <= '9')) {
437
4.41M
            h += (unsigned int)input[i] - '0';
438
4.41M
        } else if ((input[i] >= 'A') && (input[i] <= 'F')) {
439
795k
            h += (unsigned int)10 + input[i] - 'A';
440
3.28M
        } else if ((input[i] >= 'a') && (input[i] <= 'f')) {
441
2.04M
            h += (unsigned int)10 + input[i] - 'a';
442
2.04M
        } else /* invalid */
443
1.24M
        {
444
1.24M
            return 0;
445
1.24M
        }
446
447
7.25M
        if (i < 3) {
448
            /* shift left to make place for the next nibble */
449
5.95M
            h = h << 4;
450
5.95M
        }
451
7.25M
    }
452
453
1.30M
    return h;
454
2.54M
}
455
456
/* converts a UTF-16 literal to UTF-8
457
 * A literal can be one or two sequences of the form \uXXXX */
458
static unsigned char utf16_literal_to_utf8(const unsigned char *const input_pointer, const unsigned char *const input_end,
459
2.53M
                                           unsigned char **output_pointer) {
460
2.53M
    long unsigned int codepoint = 0;
461
2.53M
    unsigned int first_code = 0;
462
2.53M
    const unsigned char *first_sequence = input_pointer;
463
2.53M
    unsigned char utf8_length = 0;
464
2.53M
    unsigned char utf8_position = 0;
465
2.53M
    unsigned char sequence_length = 0;
466
2.53M
    unsigned char first_byte_mark = 0;
467
468
2.53M
    if ((input_end - first_sequence) < 6) {
469
        /* input ends unexpectedly */
470
453
        goto fail;
471
453
    }
472
473
    /* get the first utf16 sequence */
474
2.52M
    first_code = parse_hex4(first_sequence + 2);
475
476
    /* check that the code is valid */
477
2.52M
    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) {
478
1.97k
        goto fail;
479
1.97k
    }
480
481
    /* UTF16 surrogate pair */
482
2.52M
    if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) {
483
19.7k
        const unsigned char *second_sequence = first_sequence + 6;
484
19.7k
        unsigned int second_code = 0;
485
19.7k
        sequence_length = 12; /* \uXXXX\uXXXX */
486
487
19.7k
        if ((input_end - second_sequence) < 6) {
488
            /* input ends unexpectedly */
489
796
            goto fail;
490
796
        }
491
492
18.9k
        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) {
493
            /* missing second half of the surrogate pair */
494
852
            goto fail;
495
852
        }
496
497
        /* get the second utf16 sequence */
498
18.0k
        second_code = parse_hex4(second_sequence + 2);
499
        /* check that the code is valid */
500
18.0k
        if ((second_code < 0xDC00) || (second_code > 0xDFFF)) {
501
            /* invalid second half of the surrogate pair */
502
524
            goto fail;
503
524
        }
504
505
        /* calculate the unicode codepoint from the surrogate pair */
506
17.5k
        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
507
2.50M
    } else {
508
2.50M
        sequence_length = 6; /* \uXXXX */
509
2.50M
        codepoint = first_code;
510
2.50M
    }
511
512
    /* encode as UTF-8
513
     * takes at maximum 4 bytes to encode:
514
     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
515
2.52M
    if (codepoint < 0x80) {
516
        /* normal ascii, encoding 0xxxxxxx */
517
1.28M
        utf8_length = 1;
518
1.28M
    } else if (codepoint < 0x800) {
519
        /* two bytes, encoding 110xxxxx 10xxxxxx */
520
367k
        utf8_length = 2;
521
367k
        first_byte_mark = 0xC0; /* 11000000 */
522
875k
    } else if (codepoint < 0x10000) {
523
        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
524
858k
        utf8_length = 3;
525
858k
        first_byte_mark = 0xE0; /* 11100000 */
526
858k
    } else if (codepoint <= 0x10FFFF) {
527
        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
528
17.5k
        utf8_length = 4;
529
17.5k
        first_byte_mark = 0xF0; /* 11110000 */
530
17.5k
    } else {
531
        /* invalid unicode codepoint */
532
0
        goto fail;
533
0
    }
534
535
    /* encode as utf8 */
536
4.66M
    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) {
537
        /* 10xxxxxx */
538
2.13M
        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
539
2.13M
        codepoint >>= 6;
540
2.13M
    }
541
    /* encode first byte */
542
2.52M
    if (utf8_length > 1) {
543
1.24M
        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
544
1.28M
    } else {
545
1.28M
        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
546
1.28M
    }
547
548
2.52M
    *output_pointer += utf8_length;
549
550
2.52M
    return sequence_length;
551
552
4.60k
fail:
553
4.60k
    return 0;
554
2.52M
}
555
556
/* Parse the input text into an unescaped cinput, and populate item. */
557
51.9M
static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
558
51.9M
    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
559
51.9M
    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
560
51.9M
    unsigned char *output_pointer = NULL;
561
51.9M
    unsigned char *output = NULL;
562
563
    /* not a string */
564
51.9M
    if (buffer_at_offset(input_buffer)[0] != '\"') {
565
2.26k
        goto fail;
566
2.26k
    }
567
568
51.9M
    {
569
        /* calculate approximate size of the output (overestimate) */
570
51.9M
        size_t allocation_length = 0;
571
51.9M
        size_t skipped_bytes = 0;
572
1.01G
        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) {
573
            /* is escape sequence */
574
959M
            if (input_end[0] == '\\') {
575
3.81M
                if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) {
576
                    /* prevent buffer overflow when last input character is a backslash */
577
0
                    goto fail;
578
0
                }
579
3.81M
                skipped_bytes++;
580
3.81M
                input_end++;
581
3.81M
            }
582
959M
            input_end++;
583
959M
        }
584
51.9M
        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) {
585
3.09k
            goto fail; /* string ended unexpectedly */
586
3.09k
        }
587
588
        /* This is at most how much we need for the output */
589
51.9M
        allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
590
51.9M
        output = (unsigned char *)loader_calloc(input_buffer->pAllocator, allocation_length + sizeof(""),
591
51.9M
                                                VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
592
51.9M
        if (output == NULL) {
593
0
            *out_of_memory = true;
594
0
            goto fail; /* allocation failure */
595
0
        }
596
51.9M
    }
597
598
51.9M
    output_pointer = output;
599
    /* loop through the string literal */
600
933M
    while (input_pointer < input_end) {
601
881M
        if (*input_pointer != '\\') {
602
878M
            *output_pointer++ = *input_pointer++;
603
878M
        }
604
        /* escape sequence */
605
2.99M
        else {
606
2.99M
            unsigned char sequence_length = 2;
607
2.99M
            if ((input_end - input_pointer) < 1) {
608
0
                goto fail;
609
0
            }
610
611
2.99M
            switch (input_pointer[1]) {
612
114k
                case 'b':
613
114k
                    *output_pointer++ = '\b';
614
114k
                    break;
615
28.8k
                case 'f':
616
28.8k
                    *output_pointer++ = '\f';
617
28.8k
                    break;
618
13.8k
                case 'n':
619
13.8k
                    *output_pointer++ = '\n';
620
13.8k
                    break;
621
182k
                case 'r':
622
182k
                    *output_pointer++ = '\r';
623
182k
                    break;
624
52.3k
                case 't':
625
52.3k
                    *output_pointer++ = '\t';
626
52.3k
                    break;
627
7.24k
                case '\"':
628
45.3k
                case '\\':
629
71.1k
                case '/':
630
71.1k
                    *output_pointer++ = input_pointer[1];
631
71.1k
                    break;
632
633
                /* UTF-16 literal */
634
2.53M
                case 'u':
635
2.53M
                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
636
2.53M
                    if (sequence_length == 0) {
637
                        /* failed to convert UTF16-literal to UTF-8 */
638
4.60k
                        goto fail;
639
4.60k
                    }
640
2.52M
                    break;
641
642
2.52M
                default:
643
239
                    goto fail;
644
2.99M
            }
645
2.98M
            input_pointer += sequence_length;
646
2.98M
        }
647
881M
    }
648
649
    /* zero terminate the output */
650
51.9M
    *output_pointer = '\0';
651
652
51.9M
    item->type = cJSON_String;
653
51.9M
    item->valuestring = (char *)output;
654
655
51.9M
    input_buffer->offset = (size_t)(input_end - input_buffer->content);
656
51.9M
    input_buffer->offset++;
657
658
51.9M
    return true;
659
660
10.2k
fail:
661
10.2k
    if (output != NULL) {
662
4.84k
        loader_free(input_buffer->pAllocator, output);
663
4.84k
        output = NULL;
664
4.84k
    }
665
666
10.2k
    if (input_pointer != NULL) {
667
10.2k
        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
668
10.2k
    }
669
670
10.2k
    return false;
671
51.9M
}
672
673
/* Render the cstring provided to an escaped version that can be printed. */
674
11.3M
static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer, bool *out_of_memory) {
675
11.3M
    const unsigned char *input_pointer = NULL;
676
11.3M
    unsigned char *output = NULL;
677
11.3M
    unsigned char *output_pointer = NULL;
678
11.3M
    size_t output_length = 0;
679
    /* numbers of additional characters needed for escaping */
680
11.3M
    size_t escape_characters = 0;
681
682
11.3M
    if (output_buffer == NULL) {
683
0
        return false;
684
0
    }
685
686
    /* empty string */
687
11.3M
    if (input == NULL) {
688
0
        output = ensure(output_buffer, sizeof(""), out_of_memory);
689
0
        if (output == NULL) {
690
0
            return false;
691
0
        }
692
693
0
        return true;
694
0
    }
695
696
    /* set "flag" to 1 if something needs to be escaped */
697
203M
    for (input_pointer = input; *input_pointer; input_pointer++) {
698
191M
        switch (*input_pointer) {
699
2.55k
            case '\"':
700
9.72k
            case '\\':
701
56.2k
            case '\b':
702
127k
            case '\f':
703
307k
            case '\n':
704
424k
            case '\r':
705
584k
            case '\t':
706
                /* one character escape sequence */
707
584k
                escape_characters++;
708
584k
                break;
709
191M
            default:
710
191M
                if (*input_pointer < 32) {
711
                    /* UTF-16 escape sequence uXXXX */
712
127M
                    escape_characters += 5;
713
127M
                }
714
191M
                break;
715
191M
        }
716
191M
    }
717
11.3M
    output_length = (size_t)(input_pointer - input) + escape_characters;
718
719
11.3M
    output = ensure(output_buffer, output_length + sizeof(""), out_of_memory);
720
11.3M
    if (output == NULL) {
721
4.75k
        return false;
722
4.75k
    }
723
724
    /* no characters have to be escaped */
725
11.3M
    if (escape_characters == 0) {
726
10.8M
        memcpy(output, input, output_length);
727
10.8M
        output[output_length] = '\0';
728
729
10.8M
        return true;
730
10.8M
    }
731
732
547k
    output_pointer = output;
733
    /* copy the string */
734
144M
    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) {
735
144M
        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) {
736
            /* normal character, copy */
737
17.9M
            *output_pointer = *input_pointer;
738
126M
        } else {
739
            // Loader specific modification - don't add a backslash because that will 'double up' any existing back slashes.
740
            // This change was added right after vulkan's public release, so while it may not be a problem, there are plenty
741
            // of API calls made which might not work if the paths have "\\"" in them
742
            /* character needs to be escaped */
743
            //*output_pointer++ = '\\';
744
126M
            switch (*input_pointer) {
745
6.84k
                case '\\':
746
6.84k
                    *output_pointer = '\\';
747
6.84k
                    break;
748
1.98k
                case '\"':
749
1.98k
                    *output_pointer = '\"';
750
1.98k
                    break;
751
46.4k
                case '\b':
752
46.4k
                    *output_pointer = '\b';
753
46.4k
                    break;
754
71.2k
                case '\f':
755
71.2k
                    *output_pointer = '\f';
756
71.2k
                    break;
757
172k
                case '\n':
758
172k
                    *output_pointer = '\n';
759
172k
                    break;
760
115k
                case '\r':
761
115k
                    *output_pointer = '\r';
762
115k
                    break;
763
159k
                case '\t':
764
159k
                    *output_pointer = '\t';
765
159k
                    break;
766
125M
                default:
767
                    /* escape and print as unicode codepoint */
768
125M
                    snprintf((char *)output_pointer, output_length - (size_t)(output_pointer - output), "u%04x", *input_pointer);
769
125M
                    output_pointer += 4;
770
125M
                    break;
771
126M
            }
772
126M
        }
773
144M
    }
774
    // The loader-specific escaping above emits one byte where the standard form emits two, so the written
775
    // length is shorter than output_length. Terminate at the actual end, otherwise the bytes between it and
776
    // output_length (uninitialized when the caller buffer is not zeroed) get read back as part of the string.
777
547k
    *output_pointer = '\0';
778
779
547k
    return true;
780
547k
}
781
782
/* Invoke print_string_ptr (which is useful) on an item. */
783
9.04M
static cJSON_bool print_string(const cJSON *const item, printbuffer *const p, bool *out_of_memory) {
784
9.04M
    return print_string_ptr((unsigned char *)item->valuestring, p, out_of_memory);
785
9.04M
}
786
787
/* Predeclare these prototypes. */
788
static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory);
789
static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory);
790
static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory);
791
static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory);
792
static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory);
793
static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory);
794
795
/* Utility to jump whitespace and cr/lf */
796
167M
static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) {
797
167M
    if ((buffer == NULL) || (buffer->content == NULL)) {
798
0
        return NULL;
799
0
    }
800
801
167M
    if (cannot_access_at_index(buffer, 0)) {
802
0
        return buffer;
803
0
    }
804
805
304M
    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) {
806
137M
        buffer->offset++;
807
137M
    }
808
809
167M
    if (buffer->offset == buffer->length) {
810
37.8k
        buffer->offset--;
811
37.8k
    }
812
813
167M
    return buffer;
814
167M
}
815
816
/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
817
201k
static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) {
818
201k
    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) {
819
0
        return NULL;
820
0
    }
821
822
201k
    if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) {
823
1.06k
        buffer->offset += 3;
824
1.06k
    }
825
826
201k
    return buffer;
827
201k
}
828
829
CJSON_PUBLIC(cJSON *)
830
loader_cJSON_ParseWithOpts(const VkAllocationCallbacks *pAllocator, const char *value, const char **return_parse_end,
831
0
                           cJSON_bool require_null_terminated, bool *out_of_memory) {
832
0
    size_t buffer_length;
833
834
0
    if (NULL == value) {
835
0
        return NULL;
836
0
    }
837
838
    /* Adding null character size due to require_null_terminated. */
839
0
    buffer_length = strlen(value) + sizeof("");
840
841
0
    return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, return_parse_end, require_null_terminated,
842
0
                                            out_of_memory);
843
0
}
844
845
/* Parse an object - create a new root, and populate. */
846
CJSON_PUBLIC(cJSON *)
847
loader_cJSON_ParseWithLengthOpts(const VkAllocationCallbacks *pAllocator, const char *value, size_t buffer_length,
848
201k
                                 const char **return_parse_end, cJSON_bool require_null_terminated, bool *out_of_memory) {
849
201k
    parse_buffer buffer = {0, 0, 0, 0, 0};
850
201k
    cJSON *item = NULL;
851
852
    /* reset error position */
853
    // global_error.json = NULL;
854
    // global_error.position = 0;
855
856
201k
    if (value == NULL || 0 == buffer_length) {
857
0
        goto fail;
858
0
    }
859
860
201k
    buffer.content = (const unsigned char *)value;
861
201k
    buffer.length = buffer_length;
862
201k
    buffer.offset = 0;
863
201k
    buffer.pAllocator = pAllocator;
864
865
201k
    item = cJSON_New_Item(pAllocator);
866
201k
    if (item == NULL) /* memory fail */
867
0
    {
868
0
        *out_of_memory = true;
869
0
        goto fail;
870
0
    }
871
872
201k
    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)), out_of_memory)) {
873
        /* parse failure. ep is set. */
874
73.4k
        goto fail;
875
73.4k
    }
876
877
    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
878
128k
    if (require_null_terminated) {
879
0
        buffer_skip_whitespace(&buffer);
880
0
        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') {
881
0
            goto fail;
882
0
        }
883
0
    }
884
128k
    if (return_parse_end) {
885
0
        *return_parse_end = (const char *)buffer_at_offset(&buffer);
886
0
    }
887
888
128k
    return item;
889
890
73.4k
fail:
891
73.4k
    if (item != NULL) {
892
73.4k
        loader_cJSON_Delete(item);
893
73.4k
    }
894
895
73.4k
    if (value != NULL) {
896
73.4k
        error local_error;
897
73.4k
        local_error.json = (const unsigned char *)value;
898
73.4k
        local_error.position = 0;
899
900
73.4k
        if (buffer.offset < buffer.length) {
901
71.5k
            local_error.position = buffer.offset;
902
71.5k
        } else if (buffer.length > 0) {
903
1.96k
            local_error.position = buffer.length - 1;
904
1.96k
        }
905
906
73.4k
        if (return_parse_end != NULL) {
907
0
            *return_parse_end = (const char *)local_error.json + local_error.position;
908
0
        }
909
910
        // global_error = local_error;
911
73.4k
    }
912
913
73.4k
    return NULL;
914
128k
}
915
916
/* Default options for loader_cJSON_Parse */
917
0
CJSON_PUBLIC(cJSON *) loader_cJSON_Parse(const VkAllocationCallbacks *pAllocator, const char *value, bool *out_of_memory) {
918
0
    return loader_cJSON_ParseWithOpts(pAllocator, value, 0, 0, out_of_memory);
919
0
}
920
921
CJSON_PUBLIC(cJSON *)
922
loader_cJSON_ParseWithLength(const VkAllocationCallbacks *pAllocator, const char *value, size_t buffer_length,
923
201k
                             bool *out_of_memory) {
924
201k
    return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, 0, 0, out_of_memory);
925
201k
}
926
927
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
928
929
4.57M
static unsigned char *print(const cJSON *const item, cJSON_bool format, bool *out_of_memory) {
930
4.57M
    static const size_t default_buffer_size = 256;
931
4.57M
    printbuffer buffer[1];
932
4.57M
    unsigned char *printed = NULL;
933
934
4.57M
    memset(buffer, 0, sizeof(buffer));
935
936
    /* create buffer */
937
4.57M
    buffer->buffer = (unsigned char *)loader_calloc(item->pAllocator, default_buffer_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
938
4.57M
    buffer->length = default_buffer_size;
939
4.57M
    buffer->format = format;
940
4.57M
    buffer->pAllocator = item->pAllocator;
941
4.57M
    if (buffer->buffer == NULL) {
942
0
        *out_of_memory = true;
943
0
        goto fail;
944
0
    }
945
946
    /* print the value */
947
4.57M
    if (!print_value(item, buffer, out_of_memory)) {
948
0
        goto fail;
949
0
    }
950
4.57M
    update_offset(buffer);
951
952
4.57M
    printed = (unsigned char *)loader_realloc(item->pAllocator, buffer->buffer, buffer->length, buffer->offset + 1,
953
4.57M
                                              VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
954
4.57M
    if (printed == NULL) {
955
0
        *out_of_memory = true;
956
0
        goto fail;
957
0
    }
958
4.57M
    buffer->buffer = NULL;
959
960
4.57M
    return printed;
961
962
0
fail:
963
0
    if (buffer->buffer != NULL) {
964
0
        loader_free(item->pAllocator, buffer->buffer);
965
0
        buffer->buffer = NULL;
966
0
    }
967
968
0
    if (printed != NULL) {
969
0
        loader_free(item->pAllocator, printed);
970
0
        printed = NULL;
971
0
    }
972
973
0
    return NULL;
974
4.57M
}
975
976
/* Render a cJSON item/entity/structure to text. */
977
4.57M
TEST_FUNCTION_EXPORT CJSON_PUBLIC(char *) loader_cJSON_Print(const cJSON *item, bool *out_of_memory) {
978
4.57M
    return (char *)print(item, true, out_of_memory);
979
4.57M
}
980
981
0
CJSON_PUBLIC(char *) loader_cJSON_PrintUnformatted(const cJSON *item, bool *out_of_memory) {
982
0
    return (char *)print(item, false, out_of_memory);
983
0
}
984
985
CJSON_PUBLIC(char *)
986
0
loader_cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt, bool *out_of_memory) {
987
0
    printbuffer p = {0, 0, 0, 0, 0, 0, 0};
988
989
0
    if (prebuffer < 0) {
990
0
        return NULL;
991
0
    }
992
993
0
    p.buffer = (unsigned char *)loader_alloc(item->pAllocator, (size_t)prebuffer, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
994
0
    if (!p.buffer) {
995
0
        return NULL;
996
0
    }
997
998
0
    p.length = (size_t)prebuffer;
999
0
    p.offset = 0;
1000
0
    p.noalloc = false;
1001
0
    p.format = fmt;
1002
0
    p.pAllocator = item->pAllocator;
1003
1004
0
    if (!print_value(item, &p, out_of_memory)) {
1005
0
        loader_free(item->pAllocator, p.buffer);
1006
0
        p.buffer = NULL;
1007
0
        return NULL;
1008
0
    }
1009
1010
0
    return (char *)p.buffer;
1011
0
}
1012
1013
TEST_FUNCTION_EXPORT CJSON_PUBLIC(cJSON_bool)
1014
4.39M
    loader_cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) {
1015
4.39M
    printbuffer p = {0, 0, 0, 0, 0, 0, 0};
1016
1017
4.39M
    if ((length < 0) || (buffer == NULL)) {
1018
0
        return false;
1019
0
    }
1020
1021
4.39M
    p.buffer = (unsigned char *)buffer;
1022
4.39M
    p.length = (size_t)length;
1023
4.39M
    p.offset = 0;
1024
4.39M
    p.noalloc = true;
1025
4.39M
    p.format = format;
1026
4.39M
    p.pAllocator = item->pAllocator;
1027
4.39M
    bool out_of_memory = false;
1028
4.39M
    return print_value(item, &p, &out_of_memory);
1029
4.39M
}
1030
1031
/* Parser core - when encountering text, process appropriately. */
1032
48.7M
static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1033
48.7M
    if ((input_buffer == NULL) || (input_buffer->content == NULL)) {
1034
0
        return false; /* no input */
1035
0
    }
1036
1037
    /* parse the different types of values */
1038
    /* null */
1039
48.7M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) {
1040
7.97k
        item->type = cJSON_NULL;
1041
7.97k
        input_buffer->offset += 4;
1042
7.97k
        return true;
1043
7.97k
    }
1044
    /* false */
1045
48.6M
    if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) {
1046
16.0k
        item->type = cJSON_False;
1047
16.0k
        input_buffer->offset += 5;
1048
16.0k
        return true;
1049
16.0k
    }
1050
    /* true */
1051
48.6M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) {
1052
246k
        item->type = cJSON_True;
1053
246k
        item->valueint = 1;
1054
246k
        input_buffer->offset += 4;
1055
246k
        return true;
1056
246k
    }
1057
    /* string */
1058
48.4M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) {
1059
24.9M
        return parse_string(item, input_buffer, out_of_memory);
1060
24.9M
    }
1061
    /* number */
1062
23.4M
    if (can_access_at_index(input_buffer, 0) &&
1063
23.4M
        ((buffer_at_offset(input_buffer)[0] == '-') ||
1064
23.4M
         ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) {
1065
6.41M
        return parse_number(item, input_buffer);
1066
6.41M
    }
1067
    /* array */
1068
17.0M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) {
1069
3.72M
        return parse_array(item, input_buffer, out_of_memory);
1070
3.72M
    }
1071
    /* object */
1072
13.3M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) {
1073
13.3M
        return parse_object(item, input_buffer, out_of_memory);
1074
13.3M
    }
1075
1076
58.9k
    return false;
1077
13.3M
}
1078
1079
/* Render a value to text. */
1080
18.5M
static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1081
18.5M
    unsigned char *output = NULL;
1082
1083
18.5M
    if ((item == NULL) || (output_buffer == NULL)) {
1084
0
        return false;
1085
0
    }
1086
1087
18.5M
    switch ((item->type) & 0xFF) {
1088
3.15k
        case cJSON_NULL:
1089
3.15k
            output = ensure(output_buffer, 5, out_of_memory);
1090
3.15k
            if (output == NULL) {
1091
0
                return false;
1092
0
            }
1093
3.15k
            strcpy((char *)output, "null");
1094
3.15k
            return true;
1095
1096
5.48k
        case cJSON_False:
1097
5.48k
            output = ensure(output_buffer, 6, out_of_memory);
1098
5.48k
            if (output == NULL) {
1099
0
                return false;
1100
0
            }
1101
5.48k
            strcpy((char *)output, "false");
1102
5.48k
            return true;
1103
1104
58.9k
        case cJSON_True:
1105
58.9k
            output = ensure(output_buffer, 5, out_of_memory);
1106
58.9k
            if (output == NULL) {
1107
0
                return false;
1108
0
            }
1109
58.9k
            strcpy((char *)output, "true");
1110
58.9k
            return true;
1111
1112
2.18M
        case cJSON_Number:
1113
2.18M
            return print_number(item, output_buffer, out_of_memory);
1114
1115
0
        case cJSON_Raw: {
1116
0
            size_t raw_length = 0;
1117
0
            if (item->valuestring == NULL) {
1118
0
                return false;
1119
0
            }
1120
1121
0
            raw_length = strlen(item->valuestring) + sizeof("");
1122
0
            output = ensure(output_buffer, raw_length, out_of_memory);
1123
0
            if (output == NULL) {
1124
0
                return false;
1125
0
            }
1126
0
            memcpy(output, item->valuestring, raw_length);
1127
0
            return true;
1128
0
        }
1129
1130
9.04M
        case cJSON_String:
1131
9.04M
            return print_string(item, output_buffer, out_of_memory);
1132
1133
542k
        case cJSON_Array:
1134
542k
            return print_array(item, output_buffer, out_of_memory);
1135
1136
6.69M
        case cJSON_Object:
1137
6.69M
            return print_object(item, output_buffer, out_of_memory);
1138
1139
0
        default:
1140
0
            return false;
1141
18.5M
    }
1142
18.5M
}
1143
1144
/* Build an array from input text. */
1145
3.72M
static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1146
3.72M
    cJSON *head = NULL; /* head of the linked list */
1147
3.72M
    cJSON *current_item = NULL;
1148
1149
3.72M
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1150
144
        return false; /* to deeply nested */
1151
144
    }
1152
3.72M
    input_buffer->depth++;
1153
1154
3.72M
    if (buffer_at_offset(input_buffer)[0] != '[') {
1155
        /* not an array */
1156
0
        goto fail;
1157
0
    }
1158
1159
3.72M
    input_buffer->offset++;
1160
3.72M
    buffer_skip_whitespace(input_buffer);
1161
3.72M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) {
1162
        /* empty array */
1163
1.06M
        goto success;
1164
1.06M
    }
1165
1166
    /* check if we skipped to the end of the buffer */
1167
2.65M
    if (cannot_access_at_index(input_buffer, 0)) {
1168
0
        input_buffer->offset--;
1169
0
        goto fail;
1170
0
    }
1171
1172
    /* step back to character in front of the first element */
1173
2.65M
    input_buffer->offset--;
1174
    /* loop through the comma separated array elements */
1175
21.4M
    do {
1176
        /* allocate next item */
1177
21.4M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1178
21.4M
        if (new_item == NULL) {
1179
0
            *out_of_memory = true;
1180
0
            goto fail; /* allocation failure */
1181
0
        }
1182
1183
        /* attach next item to list */
1184
21.4M
        if (head == NULL) {
1185
            /* start the linked list */
1186
2.65M
            current_item = head = new_item;
1187
18.8M
        } else {
1188
            /* add to the end and advance */
1189
18.8M
            current_item->next = new_item;
1190
18.8M
            new_item->prev = current_item;
1191
18.8M
            current_item = new_item;
1192
18.8M
        }
1193
1194
        /* parse next value */
1195
21.4M
        input_buffer->offset++;
1196
21.4M
        buffer_skip_whitespace(input_buffer);
1197
21.4M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1198
1.07M
            goto fail; /* failed to parse value */
1199
1.07M
        }
1200
20.4M
        buffer_skip_whitespace(input_buffer);
1201
20.4M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1202
1203
1.58M
    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') {
1204
1.31k
        goto fail; /* expected end of array */
1205
1.31k
    }
1206
1207
2.64M
success:
1208
2.64M
    input_buffer->depth--;
1209
1210
2.64M
    if (head != NULL) {
1211
1.58M
        head->prev = current_item;
1212
1.58M
    }
1213
1214
2.64M
    item->type = cJSON_Array;
1215
2.64M
    item->child = head;
1216
1217
2.64M
    input_buffer->offset++;
1218
1219
2.64M
    return true;
1220
1221
1.07M
fail:
1222
1.07M
    if (head != NULL) {
1223
1.07M
        loader_cJSON_Delete(head);
1224
1.07M
    }
1225
1226
1.07M
    return false;
1227
1.58M
}
1228
1229
/* Render an array to text */
1230
542k
static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1231
542k
    unsigned char *output_pointer = NULL;
1232
542k
    size_t length = 0;
1233
542k
    cJSON *current_element = item->child;
1234
1235
542k
    if (output_buffer == NULL) {
1236
0
        return false;
1237
0
    }
1238
1239
542k
    if (output_buffer->depth >= CJSON_NESTING_LIMIT) {
1240
0
        return false; /* nesting is too deep */
1241
0
    }
1242
1243
    /* Compose the output array. */
1244
    /* opening square bracket */
1245
542k
    output_pointer = ensure(output_buffer, 1, out_of_memory);
1246
542k
    if (output_pointer == NULL) {
1247
0
        return false;
1248
0
    }
1249
1250
542k
    *output_pointer = '[';
1251
542k
    output_buffer->offset++;
1252
542k
    output_buffer->depth++;
1253
1254
7.77M
    while (current_element != NULL) {
1255
7.23M
        if (!print_value(current_element, output_buffer, out_of_memory)) {
1256
0
            return false;
1257
0
        }
1258
7.23M
        update_offset(output_buffer);
1259
7.23M
        if (current_element->next) {
1260
6.71M
            length = (size_t)(output_buffer->format ? 2 : 1);
1261
6.71M
            output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1262
6.71M
            if (output_pointer == NULL) {
1263
0
                return false;
1264
0
            }
1265
6.71M
            *output_pointer++ = ',';
1266
6.71M
            if (output_buffer->format) {
1267
6.71M
                *output_pointer++ = ' ';
1268
6.71M
            }
1269
6.71M
            *output_pointer = '\0';
1270
6.71M
            output_buffer->offset += length;
1271
6.71M
        }
1272
7.23M
        current_element = current_element->next;
1273
7.23M
    }
1274
1275
542k
    output_pointer = ensure(output_buffer, 2, out_of_memory);
1276
542k
    if (output_pointer == NULL) {
1277
0
        return false;
1278
0
    }
1279
542k
    *output_pointer++ = ']';
1280
542k
    *output_pointer = '\0';
1281
542k
    output_buffer->depth--;
1282
1283
542k
    return true;
1284
542k
}
1285
1286
/* Build an object from the text. */
1287
13.3M
static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1288
13.3M
    cJSON *head = NULL; /* linked list head */
1289
13.3M
    cJSON *current_item = NULL;
1290
1291
13.3M
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1292
620
        return false; /* to deeply nested */
1293
620
    }
1294
13.3M
    input_buffer->depth++;
1295
1296
13.3M
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) {
1297
0
        goto fail; /* not an object */
1298
0
    }
1299
1300
13.3M
    input_buffer->offset++;
1301
13.3M
    buffer_skip_whitespace(input_buffer);
1302
13.3M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) {
1303
5.82M
        goto success; /* empty object */
1304
5.82M
    }
1305
1306
    /* check if we skipped to the end of the buffer */
1307
7.48M
    if (cannot_access_at_index(input_buffer, 0)) {
1308
0
        input_buffer->offset--;
1309
0
        goto fail;
1310
0
    }
1311
1312
    /* step back to character in front of the first element */
1313
7.48M
    input_buffer->offset--;
1314
    /* loop through the comma separated array elements */
1315
27.0M
    do {
1316
        /* allocate next item */
1317
27.0M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1318
27.0M
        if (new_item == NULL) {
1319
0
            *out_of_memory = true;
1320
0
            goto fail; /* allocation failure */
1321
0
        }
1322
1323
        /* attach next item to list */
1324
27.0M
        if (head == NULL) {
1325
            /* start the linked list */
1326
7.48M
            current_item = head = new_item;
1327
19.5M
        } else {
1328
            /* add to the end and advance */
1329
19.5M
            current_item->next = new_item;
1330
19.5M
            new_item->prev = current_item;
1331
19.5M
            current_item = new_item;
1332
19.5M
        }
1333
1334
27.0M
        if (cannot_access_at_index(input_buffer, 1)) {
1335
0
            goto fail; /* nothing comes after the comma */
1336
0
        }
1337
1338
        /* parse the name of the child */
1339
27.0M
        input_buffer->offset++;
1340
27.0M
        buffer_skip_whitespace(input_buffer);
1341
27.0M
        if (!parse_string(current_item, input_buffer, out_of_memory)) {
1342
3.85k
            goto fail; /* failed to parse name */
1343
3.85k
        }
1344
27.0M
        buffer_skip_whitespace(input_buffer);
1345
1346
        /* swap valuestring and string, because we parsed the name */
1347
27.0M
        current_item->string = current_item->valuestring;
1348
27.0M
        current_item->valuestring = NULL;
1349
1350
27.0M
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) {
1351
1.41k
            goto fail; /* invalid object */
1352
1.41k
        }
1353
1354
        /* parse the value */
1355
27.0M
        input_buffer->offset++;
1356
27.0M
        buffer_skip_whitespace(input_buffer);
1357
27.0M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1358
36.1k
            goto fail; /* failed to parse value */
1359
36.1k
        }
1360
26.9M
        buffer_skip_whitespace(input_buffer);
1361
26.9M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1362
1363
7.43M
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) {
1364
332
        goto fail; /* expected end of object */
1365
332
    }
1366
1367
13.2M
success:
1368
13.2M
    input_buffer->depth--;
1369
1370
13.2M
    if (head != NULL) {
1371
7.43M
        head->prev = current_item;
1372
7.43M
    }
1373
1374
13.2M
    item->type = cJSON_Object;
1375
13.2M
    item->child = head;
1376
1377
13.2M
    input_buffer->offset++;
1378
13.2M
    return true;
1379
1380
41.7k
fail:
1381
41.7k
    if (head != NULL) {
1382
41.7k
        loader_cJSON_Delete(head);
1383
41.7k
    }
1384
1385
41.7k
    return false;
1386
7.43M
}
1387
1388
/* Render an object to text. */
1389
6.69M
static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1390
6.69M
    unsigned char *output_pointer = NULL;
1391
6.69M
    size_t length = 0;
1392
6.69M
    cJSON *current_item = item->child;
1393
1394
6.69M
    if (output_buffer == NULL) {
1395
0
        return false;
1396
0
    }
1397
1398
6.69M
    if (output_buffer->depth >= CJSON_NESTING_LIMIT) {
1399
0
        return false; /* nesting is too deep */
1400
0
    }
1401
1402
    /* Compose the output: */
1403
6.69M
    length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */
1404
6.69M
    output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1405
6.69M
    if (output_pointer == NULL) {
1406
0
        return false;
1407
0
    }
1408
1409
6.69M
    *output_pointer++ = '{';
1410
6.69M
    output_buffer->depth++;
1411
6.69M
    if (output_buffer->format) {
1412
6.69M
        *output_pointer++ = '\n';
1413
6.69M
    }
1414
6.69M
    output_buffer->offset += length;
1415
1416
9.01M
    while (current_item) {
1417
2.32M
        if (output_buffer->format) {
1418
2.32M
            size_t i;
1419
2.32M
            output_pointer = ensure(output_buffer, output_buffer->depth, out_of_memory);
1420
2.32M
            if (output_pointer == NULL) {
1421
0
                return false;
1422
0
            }
1423
1.06G
            for (i = 0; i < output_buffer->depth; i++) {
1424
1.05G
                *output_pointer++ = '\t';
1425
1.05G
            }
1426
2.32M
            output_buffer->offset += output_buffer->depth;
1427
2.32M
        }
1428
1429
        /* print key */
1430
2.32M
        if (!print_string_ptr((unsigned char *)current_item->string, output_buffer, out_of_memory)) {
1431
0
            return false;
1432
0
        }
1433
2.32M
        update_offset(output_buffer);
1434
1435
2.32M
        length = (size_t)(output_buffer->format ? 2 : 1);
1436
2.32M
        output_pointer = ensure(output_buffer, length, out_of_memory);
1437
2.32M
        if (output_pointer == NULL) {
1438
0
            return false;
1439
0
        }
1440
2.32M
        *output_pointer++ = ':';
1441
2.32M
        if (output_buffer->format) {
1442
2.32M
            *output_pointer++ = '\t';
1443
2.32M
        }
1444
2.32M
        output_buffer->offset += length;
1445
1446
        /* print value */
1447
2.32M
        if (!print_value(current_item, output_buffer, out_of_memory)) {
1448
0
            return false;
1449
0
        }
1450
2.32M
        update_offset(output_buffer);
1451
1452
        /* print comma if not last */
1453
2.32M
        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
1454
2.32M
        output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1455
2.32M
        if (output_pointer == NULL) {
1456
0
            return false;
1457
0
        }
1458
2.32M
        if (current_item->next) {
1459
939k
            *output_pointer++ = ',';
1460
939k
        }
1461
1462
2.32M
        if (output_buffer->format) {
1463
2.32M
            *output_pointer++ = '\n';
1464
2.32M
        }
1465
2.32M
        *output_pointer = '\0';
1466
2.32M
        output_buffer->offset += length;
1467
1468
2.32M
        current_item = current_item->next;
1469
2.32M
    }
1470
1471
6.69M
    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2, out_of_memory);
1472
6.69M
    if (output_pointer == NULL) {
1473
0
        return false;
1474
0
    }
1475
6.69M
    if (output_buffer->format) {
1476
6.69M
        size_t i;
1477
5.06G
        for (i = 0; i < (output_buffer->depth - 1); i++) {
1478
5.05G
            *output_pointer++ = '\t';
1479
5.05G
        }
1480
6.69M
    }
1481
6.69M
    *output_pointer++ = '}';
1482
6.69M
    *output_pointer = '\0';
1483
6.69M
    output_buffer->depth--;
1484
1485
6.69M
    return true;
1486
6.69M
}
1487
1488
/* Get Array size/item / object item. */
1489
539k
CJSON_PUBLIC(int) loader_cJSON_GetArraySize(const cJSON *array) {
1490
539k
    cJSON *child = NULL;
1491
539k
    size_t size = 0;
1492
1493
539k
    if (array == NULL) {
1494
0
        return 0;
1495
0
    }
1496
1497
539k
    child = array->child;
1498
1499
4.08M
    while (child != NULL) {
1500
3.54M
        size++;
1501
3.54M
        child = child->next;
1502
3.54M
    }
1503
1504
    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1505
1506
539k
    return (int)size;
1507
539k
}
1508
1509
0
static cJSON *get_array_item(const cJSON *array, size_t index) {
1510
0
    cJSON *current_child = NULL;
1511
1512
0
    if (array == NULL) {
1513
0
        return NULL;
1514
0
    }
1515
1516
0
    current_child = array->child;
1517
0
    while ((current_child != NULL) && (index > 0)) {
1518
0
        index--;
1519
0
        current_child = current_child->next;
1520
0
    }
1521
1522
0
    return current_child;
1523
0
}
1524
1525
0
CJSON_PUBLIC(cJSON *) loader_cJSON_GetArrayItem(const cJSON *array, int index) {
1526
0
    if (index < 0) {
1527
0
        return NULL;
1528
0
    }
1529
1530
0
    return get_array_item(array, (size_t)index);
1531
0
}
1532
1533
28.2M
static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) {
1534
28.2M
    cJSON *current_element = NULL;
1535
1536
28.2M
    if ((object == NULL) || (name == NULL)) {
1537
0
        return NULL;
1538
0
    }
1539
1540
28.2M
    current_element = object->child;
1541
28.2M
    if (case_sensitive) {
1542
0
        while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) {
1543
0
            current_element = current_element->next;
1544
0
        }
1545
28.2M
    } else {
1546
171M
        while ((current_element != NULL) &&
1547
156M
               (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0)) {
1548
143M
            current_element = current_element->next;
1549
143M
        }
1550
28.2M
    }
1551
1552
28.2M
    if ((current_element == NULL) || (current_element->string == NULL)) {
1553
14.7M
        return NULL;
1554
14.7M
    }
1555
1556
13.5M
    return current_element;
1557
28.2M
}
1558
1559
28.2M
CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItem(const cJSON *const object, const char *const string) {
1560
28.2M
    return get_object_item(object, string, false);
1561
28.2M
}
1562
1563
0
CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItemCaseSensitive(const cJSON *const object, const char *const string) {
1564
0
    return get_object_item(object, string, true);
1565
0
}
1566
1567
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_HasObjectItem(const cJSON *object, const char *string) {
1568
0
    return loader_cJSON_GetObjectItem(object, string) ? 1 : 0;
1569
0
}
1570
1571
0
static void skip_oneline_comment(char **input) {
1572
0
    *input += static_strlen("//");
1573
1574
0
    for (; (*input)[0] != '\0'; ++(*input)) {
1575
0
        if ((*input)[0] == '\n') {
1576
0
            *input += static_strlen("\n");
1577
0
            return;
1578
0
        }
1579
0
    }
1580
0
}
1581
1582
0
static void skip_multiline_comment(char **input) {
1583
0
    *input += static_strlen("/*");
1584
1585
0
    for (; (*input)[0] != '\0'; ++(*input)) {
1586
0
        if (((*input)[0] == '*') && ((*input)[1] == '/')) {
1587
0
            *input += static_strlen("*/");
1588
0
            return;
1589
0
        }
1590
0
    }
1591
0
}
1592
1593
0
static void minify_string(char **input, char **output) {
1594
0
    (*output)[0] = (*input)[0];
1595
0
    *input += static_strlen("\"");
1596
0
    *output += static_strlen("\"");
1597
1598
0
    for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
1599
0
        (*output)[0] = (*input)[0];
1600
1601
0
        if ((*input)[0] == '\"') {
1602
0
            (*output)[0] = '\"';
1603
0
            *input += static_strlen("\"");
1604
0
            *output += static_strlen("\"");
1605
0
            return;
1606
0
        } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
1607
0
            (*output)[1] = (*input)[1];
1608
0
            *input += static_strlen("\"");
1609
0
            *output += static_strlen("\"");
1610
0
        }
1611
0
    }
1612
0
}
1613
1614
0
CJSON_PUBLIC(void) loader_cJSON_Minify(char *json) {
1615
0
    char *into = json;
1616
1617
0
    if (json == NULL) {
1618
0
        return;
1619
0
    }
1620
1621
0
    while (json[0] != '\0') {
1622
0
        switch (json[0]) {
1623
0
            case ' ':
1624
0
            case '\t':
1625
0
            case '\r':
1626
0
            case '\n':
1627
0
                json++;
1628
0
                break;
1629
1630
0
            case '/':
1631
0
                if (json[1] == '/') {
1632
0
                    skip_oneline_comment(&json);
1633
0
                } else if (json[1] == '*') {
1634
0
                    skip_multiline_comment(&json);
1635
0
                } else {
1636
0
                    json++;
1637
0
                }
1638
0
                break;
1639
1640
0
            case '\"':
1641
0
                minify_string(&json, (char **)&into);
1642
0
                break;
1643
1644
0
            default:
1645
0
                into[0] = json[0];
1646
0
                json++;
1647
0
                into++;
1648
0
        }
1649
0
    }
1650
1651
    /* and null-terminate. */
1652
0
    *into = '\0';
1653
0
}
1654
1655
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsInvalid(const cJSON *const item) {
1656
0
    if (item == NULL) {
1657
0
        return false;
1658
0
    }
1659
1660
0
    return (item->type & 0xFF) == cJSON_Invalid;
1661
0
}
1662
1663
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsFalse(const cJSON *const item) {
1664
0
    if (item == NULL) {
1665
0
        return false;
1666
0
    }
1667
1668
0
    return (item->type & 0xFF) == cJSON_False;
1669
0
}
1670
1671
29
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsTrue(const cJSON *const item) {
1672
29
    if (item == NULL) {
1673
29
        return false;
1674
29
    }
1675
1676
0
    return (item->type & 0xff) == cJSON_True;
1677
29
}
1678
1679
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsBool(const cJSON *const item) {
1680
0
    if (item == NULL) {
1681
0
        return false;
1682
0
    }
1683
1684
0
    return (item->type & (cJSON_True | cJSON_False)) != 0;
1685
0
}
1686
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsNull(const cJSON *const item) {
1687
0
    if (item == NULL) {
1688
0
        return false;
1689
0
    }
1690
1691
0
    return (item->type & 0xFF) == cJSON_NULL;
1692
0
}
1693
1694
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsNumber(const cJSON *const item) {
1695
0
    if (item == NULL) {
1696
0
        return false;
1697
0
    }
1698
1699
0
    return (item->type & 0xFF) == cJSON_Number;
1700
0
}
1701
1702
8.12M
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsString(const cJSON *const item) {
1703
8.12M
    if (item == NULL) {
1704
2.05M
        return false;
1705
2.05M
    }
1706
1707
6.07M
    return (item->type & 0xFF) == cJSON_String;
1708
8.12M
}
1709
1710
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsArray(const cJSON *const item) {
1711
0
    if (item == NULL) {
1712
0
        return false;
1713
0
    }
1714
1715
0
    return (item->type & 0xFF) == cJSON_Array;
1716
0
}
1717
1718
0
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON *const item) {
1719
0
    if (item == NULL) {
1720
0
        return false;
1721
0
    }
1722
1723
0
    return (item->type & 0xFF) == cJSON_Object;
1724
0
}
1725
1726
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsRaw(const cJSON *const item) {
1727
0
    if (item == NULL) {
1728
0
        return false;
1729
0
    }
1730
1731
0
    return (item->type & 0xFF) == cJSON_Raw;
1732
0
}
1733
1734
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive) {
1735
0
    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) {
1736
0
        return false;
1737
0
    }
1738
1739
    /* check if type is valid */
1740
0
    switch (a->type & 0xFF) {
1741
0
        case cJSON_False:
1742
0
        case cJSON_True:
1743
0
        case cJSON_NULL:
1744
0
        case cJSON_Number:
1745
0
        case cJSON_String:
1746
0
        case cJSON_Raw:
1747
0
        case cJSON_Array:
1748
0
        case cJSON_Object:
1749
0
            break;
1750
1751
0
        default:
1752
0
            return false;
1753
0
    }
1754
1755
    /* identical objects are equal */
1756
0
    if (a == b) {
1757
0
        return true;
1758
0
    }
1759
1760
0
    switch (a->type & 0xFF) {
1761
        /* in these cases and equal type is enough */
1762
0
        case cJSON_False:
1763
0
        case cJSON_True:
1764
0
        case cJSON_NULL:
1765
0
            return true;
1766
1767
0
        case cJSON_Number:
1768
0
            if (compare_double(a->valuedouble, b->valuedouble)) {
1769
0
                return true;
1770
0
            }
1771
0
            return false;
1772
1773
0
        case cJSON_String:
1774
0
        case cJSON_Raw:
1775
0
            if ((a->valuestring == NULL) || (b->valuestring == NULL)) {
1776
0
                return false;
1777
0
            }
1778
0
            if (strcmp(a->valuestring, b->valuestring) == 0) {
1779
0
                return true;
1780
0
            }
1781
1782
0
            return false;
1783
1784
0
        case cJSON_Array: {
1785
0
            cJSON *a_element = a->child;
1786
0
            cJSON *b_element = b->child;
1787
1788
0
            for (; (a_element != NULL) && (b_element != NULL);) {
1789
0
                if (!loader_cJSON_Compare(a_element, b_element, case_sensitive)) {
1790
0
                    return false;
1791
0
                }
1792
1793
0
                a_element = a_element->next;
1794
0
                b_element = b_element->next;
1795
0
            }
1796
1797
            /* one of the arrays is longer than the other */
1798
0
            if (a_element != b_element) {
1799
0
                return false;
1800
0
            }
1801
1802
0
            return true;
1803
0
        }
1804
1805
0
        case cJSON_Object: {
1806
0
            cJSON *a_element = NULL;
1807
0
            cJSON *b_element = NULL;
1808
0
            cJSON_ArrayForEach(a_element, a) {
1809
                /* TODO This has O(n^2) runtime, which is horrible! */
1810
0
                b_element = get_object_item(b, a_element->string, case_sensitive);
1811
0
                if (b_element == NULL) {
1812
0
                    return false;
1813
0
                }
1814
1815
0
                if (!loader_cJSON_Compare(a_element, b_element, case_sensitive)) {
1816
0
                    return false;
1817
0
                }
1818
0
            }
1819
1820
            /* doing this twice, once on a and b to prevent true comparison if a subset of b
1821
             * TODO: Do this the proper way, this is just a fix for now */
1822
0
            cJSON_ArrayForEach(b_element, b) {
1823
0
                a_element = get_object_item(a, b_element->string, case_sensitive);
1824
0
                if (a_element == NULL) {
1825
0
                    return false;
1826
0
                }
1827
1828
0
                if (!loader_cJSON_Compare(b_element, a_element, case_sensitive)) {
1829
0
                    return false;
1830
0
                }
1831
0
            }
1832
1833
0
            return true;
1834
0
        }
1835
1836
0
        default:
1837
0
            return false;
1838
0
    }
1839
0
}