Coverage Report

Created: 2026-10-16 06:55

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
20.6M
#define true ((cJSON_bool)1)
68
69
#ifdef false
70
#undef false
71
#endif
72
2.36M
#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
0
CJSON_PUBLIC(char *) loader_cJSON_GetStringValue(const cJSON *const item) {
99
0
    if (!loader_cJSON_IsString(item)) {
100
0
        return NULL;
101
0
    }
102
103
0
    return item->valuestring;
104
0
}
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
0
static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) {
121
0
    if ((string1 == NULL) || (string2 == NULL)) {
122
0
        return 1;
123
0
    }
124
125
0
    if (string1 == string2) {
126
0
        return 0;
127
0
    }
128
129
0
    for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) {
130
0
        if (*string1 == '\0') {
131
0
            return 0;
132
0
        }
133
0
    }
134
135
0
    return tolower(*string1) - tolower(*string2);
136
0
}
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
9.27M
static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) {
143
9.27M
    cJSON *node = (cJSON *)loader_calloc(pAllocator, sizeof(cJSON), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
144
9.27M
    if (NULL != node) {
145
9.27M
        node->pAllocator = pAllocator;
146
9.27M
    }
147
9.27M
    return node;
148
9.27M
}
149
150
/* Delete a cJSON structure. */
151
1.35M
TEST_FUNCTION_EXPORT CJSON_PUBLIC(void) loader_cJSON_Delete(cJSON *item) {
152
1.35M
    cJSON *next = NULL;
153
10.6M
    while (item != NULL) {
154
9.27M
        next = item->next;
155
9.27M
        if (!(item->type & cJSON_IsReference) && (item->child != NULL)) {
156
1.27M
            loader_cJSON_Delete(item->child);
157
1.27M
        }
158
9.27M
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) {
159
8.04k
            loader_free(item->pAllocator, item->valuestring);
160
8.04k
            item->valuestring = NULL;
161
8.04k
        }
162
9.27M
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
163
1.66M
            loader_free(item->pAllocator, item->string);
164
1.66M
            item->string = NULL;
165
1.66M
        }
166
9.27M
        loader_free(item->pAllocator, item);
167
9.27M
        item = next;
168
9.27M
    }
169
1.35M
}
170
171
/* get the decimal point character of the current locale */
172
4.00M
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
4.00M
    return '.';
178
4.00M
#endif
179
4.00M
}
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
55.6M
#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
213M
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
193
50.7M
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
194
/* get a pointer to the buffer at the position */
195
153M
#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
2.28M
static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) {
199
2.28M
    double number = 0;
200
2.28M
    unsigned char *after_end = NULL;
201
2.28M
    unsigned char *number_c_string;
202
2.28M
    unsigned char decimal_point = get_decimal_point();
203
2.28M
    size_t i = 0;
204
2.28M
    size_t number_string_length = 0;
205
2.28M
    cJSON_bool has_decimal_point = false;
206
207
2.28M
    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
5.46M
    for (i = 0; can_access_at_index(input_buffer, i); i++) {
215
5.46M
        switch (buffer_at_offset(input_buffer)[i]) {
216
507k
            case '0':
217
650k
            case '1':
218
824k
            case '2':
219
1.04M
            case '3':
220
1.25M
            case '4':
221
1.30M
            case '5':
222
2.46M
            case '6':
223
2.62M
            case '7':
224
2.79M
            case '8':
225
3.10M
            case '9':
226
3.10M
            case '+':
227
3.11M
            case '-':
228
3.16M
            case 'e':
229
3.16M
            case 'E':
230
3.16M
                number_string_length++;
231
3.16M
                break;
232
233
6.83k
            case '.':
234
6.83k
                number_string_length++;
235
6.83k
                has_decimal_point = true;
236
6.83k
                break;
237
238
2.28M
            default:
239
2.28M
                goto loop_end;
240
5.46M
        }
241
5.46M
    }
242
2.28M
loop_end:
243
    /* malloc for temporary buffer, add 1 for '\0' */
244
2.28M
    number_c_string =
245
2.28M
        (unsigned char *)loader_calloc(input_buffer->pAllocator, number_string_length + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
246
2.28M
    if (number_c_string == NULL) {
247
0
        return false; /* allocation failure */
248
0
    }
249
250
2.28M
    memcpy(number_c_string, buffer_at_offset(input_buffer), number_string_length);
251
2.28M
    number_c_string[number_string_length] = '\0';
252
253
2.28M
    if (has_decimal_point) {
254
114k
        for (i = 0; i < number_string_length; i++) {
255
108k
            if (number_c_string[i] == '.') {
256
                /* replace '.' with the decimal point of the current locale (for strtod) */
257
6.83k
                number_c_string[i] = decimal_point;
258
6.83k
            }
259
108k
        }
260
6.65k
    }
261
262
2.28M
    number = strtod((const char *)number_c_string, (char **)&after_end);
263
2.28M
    if (number_c_string == after_end) {
264
        /* free the temporary buffer */
265
18
        loader_free(input_buffer->pAllocator, number_c_string);
266
18
        return false; /* parse_error */
267
18
    }
268
269
2.28M
    item->valuedouble = number;
270
271
    /* use saturation in case of overflow */
272
2.28M
    if (number >= INT_MAX) {
273
62.3k
        item->valueint = INT_MAX;
274
2.22M
    } else if (number <= (double)INT_MIN) {
275
639
        item->valueint = INT_MIN;
276
2.22M
    } else {
277
2.22M
        item->valueint = (int)number;
278
2.22M
    }
279
280
2.28M
    item->type = cJSON_Number;
281
282
2.28M
    input_buffer->offset += (size_t)(after_end - number_c_string);
283
    /* free the temporary buffer */
284
2.28M
    loader_free(input_buffer->pAllocator, number_c_string);
285
2.28M
    return true;
286
2.28M
}
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
27.2M
static unsigned char *ensure(printbuffer *const p, size_t needed, bool *out_of_memory) {
300
27.2M
    unsigned char *newbuffer = NULL;
301
27.2M
    size_t newsize = 0;
302
303
27.2M
    if ((p == NULL) || (p->buffer == NULL)) {
304
0
        return NULL;
305
0
    }
306
307
27.2M
    if ((p->length > 0) && (p->offset >= p->length)) {
308
        /* make sure that offset is valid */
309
0
        return NULL;
310
0
    }
311
312
27.2M
    if (needed > INT_MAX) {
313
        /* sizes bigger than INT_MAX are currently not supported */
314
0
        return NULL;
315
0
    }
316
317
27.2M
    needed += p->offset + 1;
318
27.2M
    if (needed <= p->length) {
319
27.2M
        return p->buffer + p->offset;
320
27.2M
    }
321
322
6.51k
    if (p->noalloc) {
323
0
        return NULL;
324
0
    }
325
326
    /* calculate new buffer size */
327
6.51k
    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
6.51k
    } else {
335
6.51k
        newsize = needed * 2;
336
6.51k
    }
337
338
6.51k
    newbuffer = (unsigned char *)loader_realloc(p->pAllocator, p->buffer, p->length, newsize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
339
6.51k
    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
6.51k
    p->length = newsize;
349
6.51k
    p->buffer = newbuffer;
350
351
6.51k
    return newbuffer + p->offset;
352
6.51k
}
353
354
/* calculate the new length of the string in a printbuffer and update the offset */
355
9.77M
static void update_offset(printbuffer *const buffer) {
356
9.77M
    const unsigned char *buffer_pointer = NULL;
357
9.77M
    if ((buffer == NULL) || (buffer->buffer == NULL)) {
358
0
        return;
359
0
    }
360
9.77M
    buffer_pointer = buffer->buffer + buffer->offset;
361
362
9.77M
    buffer->offset += strlen((const char *)buffer_pointer);
363
9.77M
}
364
365
/* securely comparison of floating-point variables */
366
8.49k
static cJSON_bool compare_double(double a, double b) {
367
8.49k
    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
368
8.49k
    return (fabs(a - b) <= maxVal * DBL_EPSILON);
369
8.49k
}
370
371
/* Render the number nicely from the given item into a string. */
372
1.72M
static cJSON_bool print_number(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
373
1.72M
    unsigned char *output_pointer = NULL;
374
1.72M
    double d = item->valuedouble;
375
1.72M
    int length = 0;
376
1.72M
    size_t i = 0;
377
1.72M
    unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
378
1.72M
    unsigned char decimal_point = get_decimal_point();
379
1.72M
    double test = 0.0;
380
381
1.72M
    if (output_buffer == NULL) {
382
0
        return false;
383
0
    }
384
385
    /* This checks for NaN and Infinity */
386
1.72M
    if (isnan(d) || isinf(d)) {
387
536
        length = snprintf((char *)number_buffer, 26, "null");
388
1.72M
    } else if (d == (double)item->valueint) {
389
1.71M
        length = snprintf((char *)number_buffer, 26, "%d", item->valueint);
390
1.71M
    } else {
391
        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
392
8.49k
        length = snprintf((char *)number_buffer, 26, "%1.15g", d);
393
394
        /* Check whether the original double can be recovered */
395
8.49k
        if ((sscanf((char *)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) {
396
            /* If not, print with 17 decimal places of precision */
397
6.32k
            length = snprintf((char *)number_buffer, 26, "%1.17g", d);
398
6.32k
        }
399
8.49k
    }
400
401
    /* snprintf failed or buffer overrun occurred */
402
1.72M
    if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) {
403
0
        return false;
404
0
    }
405
406
    /* reserve appropriate space in the output */
407
1.72M
    output_pointer = ensure(output_buffer, (size_t)length + sizeof(""), out_of_memory);
408
1.72M
    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
3.64M
    for (i = 0; i < ((size_t)length); i++) {
415
1.91M
        if (number_buffer[i] == decimal_point) {
416
6.34k
            output_pointer[i] = '.';
417
6.34k
            continue;
418
6.34k
        }
419
420
1.91M
        output_pointer[i] = number_buffer[i];
421
1.91M
    }
422
1.72M
    output_pointer[i] = '\0';
423
424
1.72M
    output_buffer->offset += (size_t)length;
425
426
1.72M
    return true;
427
1.72M
}
428
429
/* parse 4 digit hexadecimal number */
430
514k
static unsigned parse_hex4(const unsigned char *const input) {
431
514k
    unsigned int h = 0;
432
514k
    size_t i = 0;
433
434
1.93M
    for (i = 0; i < 4; i++) {
435
        /* parse digit */
436
1.64M
        if ((input[i] >= '0') && (input[i] <= '9')) {
437
802k
            h += (unsigned int)input[i] - '0';
438
838k
        } else if ((input[i] >= 'A') && (input[i] <= 'F')) {
439
298k
            h += (unsigned int)10 + input[i] - 'A';
440
539k
        } else if ((input[i] >= 'a') && (input[i] <= 'f')) {
441
318k
            h += (unsigned int)10 + input[i] - 'a';
442
318k
        } else /* invalid */
443
221k
        {
444
221k
            return 0;
445
221k
        }
446
447
1.41M
        if (i < 3) {
448
            /* shift left to make place for the next nibble */
449
1.12M
            h = h << 4;
450
1.12M
        }
451
1.41M
    }
452
453
293k
    return h;
454
514k
}
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
509k
                                           unsigned char **output_pointer) {
460
509k
    long unsigned int codepoint = 0;
461
509k
    unsigned int first_code = 0;
462
509k
    const unsigned char *first_sequence = input_pointer;
463
509k
    unsigned char utf8_length = 0;
464
509k
    unsigned char utf8_position = 0;
465
509k
    unsigned char sequence_length = 0;
466
509k
    unsigned char first_byte_mark = 0;
467
468
509k
    if ((input_end - first_sequence) < 6) {
469
        /* input ends unexpectedly */
470
11
        goto fail;
471
11
    }
472
473
    /* get the first utf16 sequence */
474
509k
    first_code = parse_hex4(first_sequence + 2);
475
476
    /* check that the code is valid */
477
509k
    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) {
478
19
        goto fail;
479
19
    }
480
481
    /* UTF16 surrogate pair */
482
509k
    if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) {
483
4.63k
        const unsigned char *second_sequence = first_sequence + 6;
484
4.63k
        unsigned int second_code = 0;
485
4.63k
        sequence_length = 12; /* \uXXXX\uXXXX */
486
487
4.63k
        if ((input_end - second_sequence) < 6) {
488
            /* input ends unexpectedly */
489
18
            goto fail;
490
18
        }
491
492
4.61k
        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) {
493
            /* missing second half of the surrogate pair */
494
29
            goto fail;
495
29
        }
496
497
        /* get the second utf16 sequence */
498
4.58k
        second_code = parse_hex4(second_sequence + 2);
499
        /* check that the code is valid */
500
4.58k
        if ((second_code < 0xDC00) || (second_code > 0xDFFF)) {
501
            /* invalid second half of the surrogate pair */
502
49
            goto fail;
503
49
        }
504
505
        /* calculate the unicode codepoint from the surrogate pair */
506
4.53k
        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
507
505k
    } else {
508
505k
        sequence_length = 6; /* \uXXXX */
509
505k
        codepoint = first_code;
510
505k
    }
511
512
    /* encode as UTF-8
513
     * takes at maximum 4 bytes to encode:
514
     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
515
509k
    if (codepoint < 0x80) {
516
        /* normal ascii, encoding 0xxxxxxx */
517
232k
        utf8_length = 1;
518
277k
    } else if (codepoint < 0x800) {
519
        /* two bytes, encoding 110xxxxx 10xxxxxx */
520
248k
        utf8_length = 2;
521
248k
        first_byte_mark = 0xC0; /* 11000000 */
522
248k
    } else if (codepoint < 0x10000) {
523
        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
524
24.1k
        utf8_length = 3;
525
24.1k
        first_byte_mark = 0xE0; /* 11100000 */
526
24.1k
    } else if (codepoint <= 0x10FFFF) {
527
        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
528
4.53k
        utf8_length = 4;
529
4.53k
        first_byte_mark = 0xF0; /* 11110000 */
530
4.53k
    } else {
531
        /* invalid unicode codepoint */
532
0
        goto fail;
533
0
    }
534
535
    /* encode as utf8 */
536
820k
    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) {
537
        /* 10xxxxxx */
538
310k
        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
539
310k
        codepoint >>= 6;
540
310k
    }
541
    /* encode first byte */
542
509k
    if (utf8_length > 1) {
543
277k
        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
544
277k
    } else {
545
232k
        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
546
232k
    }
547
548
509k
    *output_pointer += utf8_length;
549
550
509k
    return sequence_length;
551
552
126
fail:
553
126
    return 0;
554
509k
}
555
556
/* Parse the input text into an unescaped cinput, and populate item. */
557
1.67M
static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
558
1.67M
    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
559
1.67M
    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
560
1.67M
    unsigned char *output_pointer = NULL;
561
1.67M
    unsigned char *output = NULL;
562
563
    /* not a string */
564
1.67M
    if (buffer_at_offset(input_buffer)[0] != '\"') {
565
156
        goto fail;
566
156
    }
567
568
1.67M
    {
569
        /* calculate approximate size of the output (overestimate) */
570
1.67M
        size_t allocation_length = 0;
571
1.67M
        size_t skipped_bytes = 0;
572
38.9M
        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) {
573
            /* is escape sequence */
574
37.2M
            if (input_end[0] == '\\') {
575
877k
                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
877k
                skipped_bytes++;
580
877k
                input_end++;
581
877k
            }
582
37.2M
            input_end++;
583
37.2M
        }
584
1.67M
        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) {
585
100
            goto fail; /* string ended unexpectedly */
586
100
        }
587
588
        /* This is at most how much we need for the output */
589
1.67M
        allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
590
1.67M
        output = (unsigned char *)loader_calloc(input_buffer->pAllocator, allocation_length + sizeof(""),
591
1.67M
                                                VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
592
1.67M
        if (output == NULL) {
593
0
            *out_of_memory = true;
594
0
            goto fail; /* allocation failure */
595
0
        }
596
1.67M
    }
597
598
1.67M
    output_pointer = output;
599
    /* loop through the string literal */
600
30.8M
    while (input_pointer < input_end) {
601
29.1M
        if (*input_pointer != '\\') {
602
28.5M
            *output_pointer++ = *input_pointer++;
603
28.5M
        }
604
        /* escape sequence */
605
633k
        else {
606
633k
            unsigned char sequence_length = 2;
607
633k
            if ((input_end - input_pointer) < 1) {
608
0
                goto fail;
609
0
            }
610
611
633k
            switch (input_pointer[1]) {
612
76.2k
                case 'b':
613
76.2k
                    *output_pointer++ = '\b';
614
76.2k
                    break;
615
1.02k
                case 'f':
616
1.02k
                    *output_pointer++ = '\f';
617
1.02k
                    break;
618
6.00k
                case 'n':
619
6.00k
                    *output_pointer++ = '\n';
620
6.00k
                    break;
621
2.00k
                case 'r':
622
2.00k
                    *output_pointer++ = '\r';
623
2.00k
                    break;
624
33.9k
                case 't':
625
33.9k
                    *output_pointer++ = '\t';
626
33.9k
                    break;
627
1.66k
                case '\"':
628
2.26k
                case '\\':
629
4.35k
                case '/':
630
4.35k
                    *output_pointer++ = input_pointer[1];
631
4.35k
                    break;
632
633
                /* UTF-16 literal */
634
509k
                case 'u':
635
509k
                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
636
509k
                    if (sequence_length == 0) {
637
                        /* failed to convert UTF16-literal to UTF-8 */
638
126
                        goto fail;
639
126
                    }
640
509k
                    break;
641
642
509k
                default:
643
16
                    goto fail;
644
633k
            }
645
633k
            input_pointer += sequence_length;
646
633k
        }
647
29.1M
    }
648
649
    /* zero terminate the output */
650
1.67M
    *output_pointer = '\0';
651
652
1.67M
    item->type = cJSON_String;
653
1.67M
    item->valuestring = (char *)output;
654
655
1.67M
    input_buffer->offset = (size_t)(input_end - input_buffer->content);
656
1.67M
    input_buffer->offset++;
657
658
1.67M
    return true;
659
660
398
fail:
661
398
    if (output != NULL) {
662
142
        loader_free(input_buffer->pAllocator, output);
663
142
        output = NULL;
664
142
    }
665
666
398
    if (input_pointer != NULL) {
667
398
        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
668
398
    }
669
670
398
    return false;
671
1.67M
}
672
673
/* Render the cstring provided to an escaped version that can be printed. */
674
1.54M
static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer, bool *out_of_memory) {
675
1.54M
    const unsigned char *input_pointer = NULL;
676
1.54M
    unsigned char *output = NULL;
677
1.54M
    unsigned char *output_pointer = NULL;
678
1.54M
    size_t output_length = 0;
679
    /* numbers of additional characters needed for escaping */
680
1.54M
    size_t escape_characters = 0;
681
682
1.54M
    if (output_buffer == NULL) {
683
0
        return false;
684
0
    }
685
686
    /* empty string */
687
1.54M
    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
14.4M
    for (input_pointer = input; *input_pointer; input_pointer++) {
698
12.9M
        switch (*input_pointer) {
699
307
            case '\"':
700
588
            case '\\':
701
1.81k
            case '\b':
702
2.53k
            case '\f':
703
3.29k
            case '\n':
704
32.5k
            case '\r':
705
33.7k
            case '\t':
706
                /* one character escape sequence */
707
33.7k
                escape_characters++;
708
33.7k
                break;
709
12.9M
            default:
710
12.9M
                if (*input_pointer < 32) {
711
                    /* UTF-16 escape sequence uXXXX */
712
7.39M
                    escape_characters += 5;
713
7.39M
                }
714
12.9M
                break;
715
12.9M
        }
716
12.9M
    }
717
1.54M
    output_length = (size_t)(input_pointer - input) + escape_characters;
718
719
1.54M
    output = ensure(output_buffer, output_length + sizeof(""), out_of_memory);
720
1.54M
    if (output == NULL) {
721
0
        return false;
722
0
    }
723
724
    /* no characters have to be escaped */
725
1.54M
    if (escape_characters == 0) {
726
1.52M
        memcpy(output, input, output_length);
727
1.52M
        output[output_length] = '\0';
728
729
1.52M
        return true;
730
1.52M
    }
731
732
17.7k
    output_pointer = output;
733
    /* copy the string */
734
11.8M
    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) {
735
11.8M
        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) {
736
            /* normal character, copy */
737
4.43M
            *output_pointer = *input_pointer;
738
7.43M
        } 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
7.43M
            switch (*input_pointer) {
745
281
                case '\\':
746
281
                    *output_pointer = '\\';
747
281
                    break;
748
307
                case '\"':
749
307
                    *output_pointer = '\"';
750
307
                    break;
751
1.22k
                case '\b':
752
1.22k
                    *output_pointer = '\b';
753
1.22k
                    break;
754
720
                case '\f':
755
720
                    *output_pointer = '\f';
756
720
                    break;
757
757
                case '\n':
758
757
                    *output_pointer = '\n';
759
757
                    break;
760
29.2k
                case '\r':
761
29.2k
                    *output_pointer = '\r';
762
29.2k
                    break;
763
1.17k
                case '\t':
764
1.17k
                    *output_pointer = '\t';
765
1.17k
                    break;
766
7.39M
                default:
767
                    /* escape and print as unicode codepoint */
768
7.39M
                    snprintf((char *)output_pointer, output_length - (size_t)(output_pointer - output), "u%04x", *input_pointer);
769
7.39M
                    output_pointer += 4;
770
7.39M
                    break;
771
7.43M
            }
772
7.43M
        }
773
11.8M
    }
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
17.7k
    *output_pointer = '\0';
778
779
17.7k
    return true;
780
17.7k
}
781
782
/* Invoke print_string_ptr (which is useful) on an item. */
783
6.55k
static cJSON_bool print_string(const cJSON *const item, printbuffer *const p, bool *out_of_memory) {
784
6.55k
    return print_string_ptr((unsigned char *)item->valuestring, p, out_of_memory);
785
6.55k
}
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
28.7M
static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) {
797
28.7M
    if ((buffer == NULL) || (buffer->content == NULL)) {
798
0
        return NULL;
799
0
    }
800
801
28.7M
    if (cannot_access_at_index(buffer, 0)) {
802
0
        return buffer;
803
0
    }
804
805
35.0M
    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) {
806
6.31M
        buffer->offset++;
807
6.31M
    }
808
809
28.7M
    if (buffer->offset == buffer->length) {
810
599
        buffer->offset--;
811
599
    }
812
813
28.7M
    return buffer;
814
28.7M
}
815
816
/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
817
2.68k
static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) {
818
2.68k
    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) {
819
0
        return NULL;
820
0
    }
821
822
2.68k
    if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) {
823
21
        buffer->offset += 3;
824
21
    }
825
826
2.68k
    return buffer;
827
2.68k
}
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
2.68k
                                 const char **return_parse_end, cJSON_bool require_null_terminated, bool *out_of_memory) {
849
2.68k
    parse_buffer buffer = {0, 0, 0, 0, 0};
850
2.68k
    cJSON *item = NULL;
851
852
    /* reset error position */
853
    // global_error.json = NULL;
854
    // global_error.position = 0;
855
856
2.68k
    if (value == NULL || 0 == buffer_length) {
857
0
        goto fail;
858
0
    }
859
860
2.68k
    buffer.content = (const unsigned char *)value;
861
2.68k
    buffer.length = buffer_length;
862
2.68k
    buffer.offset = 0;
863
2.68k
    buffer.pAllocator = pAllocator;
864
865
2.68k
    item = cJSON_New_Item(pAllocator);
866
2.68k
    if (item == NULL) /* memory fail */
867
0
    {
868
0
        *out_of_memory = true;
869
0
        goto fail;
870
0
    }
871
872
2.68k
    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)), out_of_memory)) {
873
        /* parse failure. ep is set. */
874
904
        goto fail;
875
904
    }
876
877
    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
878
1.77k
    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
1.77k
    if (return_parse_end) {
885
0
        *return_parse_end = (const char *)buffer_at_offset(&buffer);
886
0
    }
887
888
1.77k
    return item;
889
890
904
fail:
891
904
    if (item != NULL) {
892
904
        loader_cJSON_Delete(item);
893
904
    }
894
895
904
    if (value != NULL) {
896
904
        error local_error;
897
904
        local_error.json = (const unsigned char *)value;
898
904
        local_error.position = 0;
899
900
904
        if (buffer.offset < buffer.length) {
901
769
            local_error.position = buffer.offset;
902
769
        } else if (buffer.length > 0) {
903
135
            local_error.position = buffer.length - 1;
904
135
        }
905
906
904
        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
904
    }
912
913
904
    return NULL;
914
1.77k
}
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
2.68k
                             bool *out_of_memory) {
924
2.68k
    return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, 0, 0, out_of_memory);
925
2.68k
}
926
927
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
928
929
1.77k
static unsigned char *print(const cJSON *const item, cJSON_bool format, bool *out_of_memory) {
930
1.77k
    static const size_t default_buffer_size = 256;
931
1.77k
    printbuffer buffer[1];
932
1.77k
    unsigned char *printed = NULL;
933
934
1.77k
    memset(buffer, 0, sizeof(buffer));
935
936
    /* create buffer */
937
1.77k
    buffer->buffer = (unsigned char *)loader_calloc(item->pAllocator, default_buffer_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
938
1.77k
    buffer->length = default_buffer_size;
939
1.77k
    buffer->format = format;
940
1.77k
    buffer->pAllocator = item->pAllocator;
941
1.77k
    if (buffer->buffer == NULL) {
942
0
        *out_of_memory = true;
943
0
        goto fail;
944
0
    }
945
946
    /* print the value */
947
1.77k
    if (!print_value(item, buffer, out_of_memory)) {
948
0
        goto fail;
949
0
    }
950
1.77k
    update_offset(buffer);
951
952
1.77k
    printed = (unsigned char *)loader_realloc(item->pAllocator, buffer->buffer, buffer->length, buffer->offset + 1,
953
1.77k
                                              VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
954
1.77k
    if (printed == NULL) {
955
0
        *out_of_memory = true;
956
0
        goto fail;
957
0
    }
958
1.77k
    buffer->buffer = NULL;
959
960
1.77k
    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
1.77k
}
975
976
/* Render a cJSON item/entity/structure to text. */
977
1.77k
TEST_FUNCTION_EXPORT CJSON_PUBLIC(char *) loader_cJSON_Print(const cJSON *item, bool *out_of_memory) {
978
1.77k
    return (char *)print(item, true, out_of_memory);
979
1.77k
}
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
0
    loader_cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) {
1015
0
    printbuffer p = {0, 0, 0, 0, 0, 0, 0};
1016
1017
0
    if ((length < 0) || (buffer == NULL)) {
1018
0
        return false;
1019
0
    }
1020
1021
0
    p.buffer = (unsigned char *)buffer;
1022
0
    p.length = (size_t)length;
1023
0
    p.offset = 0;
1024
0
    p.noalloc = true;
1025
0
    p.format = format;
1026
0
    p.pAllocator = item->pAllocator;
1027
0
    bool out_of_memory = false;
1028
0
    return print_value(item, &p, &out_of_memory);
1029
0
}
1030
1031
/* Parser core - when encountering text, process appropriately. */
1032
9.27M
static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1033
9.27M
    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
9.27M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) {
1040
3.10k
        item->type = cJSON_NULL;
1041
3.10k
        input_buffer->offset += 4;
1042
3.10k
        return true;
1043
3.10k
    }
1044
    /* false */
1045
9.27M
    if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) {
1046
2.93k
        item->type = cJSON_False;
1047
2.93k
        input_buffer->offset += 5;
1048
2.93k
        return true;
1049
2.93k
    }
1050
    /* true */
1051
9.27M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) {
1052
8.61k
        item->type = cJSON_True;
1053
8.61k
        item->valueint = 1;
1054
8.61k
        input_buffer->offset += 4;
1055
8.61k
        return true;
1056
8.61k
    }
1057
    /* string */
1058
9.26M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) {
1059
8.25k
        return parse_string(item, input_buffer, out_of_memory);
1060
8.25k
    }
1061
    /* number */
1062
9.25M
    if (can_access_at_index(input_buffer, 0) &&
1063
9.25M
        ((buffer_at_offset(input_buffer)[0] == '-') ||
1064
9.25M
         ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) {
1065
2.28M
        return parse_number(item, input_buffer);
1066
2.28M
    }
1067
    /* array */
1068
6.96M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) {
1069
406k
        return parse_array(item, input_buffer, out_of_memory);
1070
406k
    }
1071
    /* object */
1072
6.56M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) {
1073
6.56M
        return parse_object(item, input_buffer, out_of_memory);
1074
6.56M
    }
1075
1076
303
    return false;
1077
6.56M
}
1078
1079
/* Render a value to text. */
1080
8.23M
static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1081
8.23M
    unsigned char *output = NULL;
1082
1083
8.23M
    if ((item == NULL) || (output_buffer == NULL)) {
1084
0
        return false;
1085
0
    }
1086
1087
8.23M
    switch ((item->type) & 0xFF) {
1088
2.68k
        case cJSON_NULL:
1089
2.68k
            output = ensure(output_buffer, 5, out_of_memory);
1090
2.68k
            if (output == NULL) {
1091
0
                return false;
1092
0
            }
1093
2.68k
            strcpy((char *)output, "null");
1094
2.68k
            return true;
1095
1096
2.11k
        case cJSON_False:
1097
2.11k
            output = ensure(output_buffer, 6, out_of_memory);
1098
2.11k
            if (output == NULL) {
1099
0
                return false;
1100
0
            }
1101
2.11k
            strcpy((char *)output, "false");
1102
2.11k
            return true;
1103
1104
8.05k
        case cJSON_True:
1105
8.05k
            output = ensure(output_buffer, 5, out_of_memory);
1106
8.05k
            if (output == NULL) {
1107
0
                return false;
1108
0
            }
1109
8.05k
            strcpy((char *)output, "true");
1110
8.05k
            return true;
1111
1112
1.72M
        case cJSON_Number:
1113
1.72M
            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
6.55k
        case cJSON_String:
1131
6.55k
            return print_string(item, output_buffer, out_of_memory);
1132
1133
323k
        case cJSON_Array:
1134
323k
            return print_array(item, output_buffer, out_of_memory);
1135
1136
6.17M
        case cJSON_Object:
1137
6.17M
            return print_object(item, output_buffer, out_of_memory);
1138
1139
0
        default:
1140
0
            return false;
1141
8.23M
    }
1142
8.23M
}
1143
1144
/* Build an array from input text. */
1145
406k
static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1146
406k
    cJSON *head = NULL; /* head of the linked list */
1147
406k
    cJSON *current_item = NULL;
1148
1149
406k
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1150
7
        return false; /* to deeply nested */
1151
7
    }
1152
406k
    input_buffer->depth++;
1153
1154
406k
    if (buffer_at_offset(input_buffer)[0] != '[') {
1155
        /* not an array */
1156
0
        goto fail;
1157
0
    }
1158
1159
406k
    input_buffer->offset++;
1160
406k
    buffer_skip_whitespace(input_buffer);
1161
406k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) {
1162
        /* empty array */
1163
23.4k
        goto success;
1164
23.4k
    }
1165
1166
    /* check if we skipped to the end of the buffer */
1167
383k
    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
383k
    input_buffer->offset--;
1174
    /* loop through the comma separated array elements */
1175
7.61M
    do {
1176
        /* allocate next item */
1177
7.61M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1178
7.61M
        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
7.61M
        if (head == NULL) {
1185
            /* start the linked list */
1186
383k
            current_item = head = new_item;
1187
7.23M
        } else {
1188
            /* add to the end and advance */
1189
7.23M
            current_item->next = new_item;
1190
7.23M
            new_item->prev = current_item;
1191
7.23M
            current_item = new_item;
1192
7.23M
        }
1193
1194
        /* parse next value */
1195
7.61M
        input_buffer->offset++;
1196
7.61M
        buffer_skip_whitespace(input_buffer);
1197
7.61M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1198
62.8k
            goto fail; /* failed to parse value */
1199
62.8k
        }
1200
7.55M
        buffer_skip_whitespace(input_buffer);
1201
7.55M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1202
1203
320k
    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') {
1204
122
        goto fail; /* expected end of array */
1205
122
    }
1206
1207
343k
success:
1208
343k
    input_buffer->depth--;
1209
1210
343k
    if (head != NULL) {
1211
320k
        head->prev = current_item;
1212
320k
    }
1213
1214
343k
    item->type = cJSON_Array;
1215
343k
    item->child = head;
1216
1217
343k
    input_buffer->offset++;
1218
1219
343k
    return true;
1220
1221
63.0k
fail:
1222
63.0k
    if (head != NULL) {
1223
63.0k
        loader_cJSON_Delete(head);
1224
63.0k
    }
1225
1226
63.0k
    return false;
1227
320k
}
1228
1229
/* Render an array to text */
1230
323k
static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1231
323k
    unsigned char *output_pointer = NULL;
1232
323k
    size_t length = 0;
1233
323k
    cJSON *current_element = item->child;
1234
1235
323k
    if (output_buffer == NULL) {
1236
0
        return false;
1237
0
    }
1238
1239
323k
    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
323k
    output_pointer = ensure(output_buffer, 1, out_of_memory);
1246
323k
    if (output_pointer == NULL) {
1247
0
        return false;
1248
0
    }
1249
1250
323k
    *output_pointer = '[';
1251
323k
    output_buffer->offset++;
1252
323k
    output_buffer->depth++;
1253
1254
7.02M
    while (current_element != NULL) {
1255
6.69M
        if (!print_value(current_element, output_buffer, out_of_memory)) {
1256
0
            return false;
1257
0
        }
1258
6.69M
        update_offset(output_buffer);
1259
6.69M
        if (current_element->next) {
1260
6.39M
            length = (size_t)(output_buffer->format ? 2 : 1);
1261
6.39M
            output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1262
6.39M
            if (output_pointer == NULL) {
1263
0
                return false;
1264
0
            }
1265
6.39M
            *output_pointer++ = ',';
1266
6.39M
            if (output_buffer->format) {
1267
6.39M
                *output_pointer++ = ' ';
1268
6.39M
            }
1269
6.39M
            *output_pointer = '\0';
1270
6.39M
            output_buffer->offset += length;
1271
6.39M
        }
1272
6.69M
        current_element = current_element->next;
1273
6.69M
    }
1274
1275
323k
    output_pointer = ensure(output_buffer, 2, out_of_memory);
1276
323k
    if (output_pointer == NULL) {
1277
0
        return false;
1278
0
    }
1279
323k
    *output_pointer++ = ']';
1280
323k
    *output_pointer = '\0';
1281
323k
    output_buffer->depth--;
1282
1283
323k
    return true;
1284
323k
}
1285
1286
/* Build an object from the text. */
1287
6.56M
static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1288
6.56M
    cJSON *head = NULL; /* linked list head */
1289
6.56M
    cJSON *current_item = NULL;
1290
1291
6.56M
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1292
2
        return false; /* to deeply nested */
1293
2
    }
1294
6.56M
    input_buffer->depth++;
1295
1296
6.56M
    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
6.56M
    input_buffer->offset++;
1301
6.56M
    buffer_skip_whitespace(input_buffer);
1302
6.56M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) {
1303
5.59M
        goto success; /* empty object */
1304
5.59M
    }
1305
1306
    /* check if we skipped to the end of the buffer */
1307
967k
    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
967k
    input_buffer->offset--;
1314
    /* loop through the comma separated array elements */
1315
1.66M
    do {
1316
        /* allocate next item */
1317
1.66M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1318
1.66M
        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
1.66M
        if (head == NULL) {
1325
            /* start the linked list */
1326
967k
            current_item = head = new_item;
1327
967k
        } else {
1328
            /* add to the end and advance */
1329
695k
            current_item->next = new_item;
1330
695k
            new_item->prev = current_item;
1331
695k
            current_item = new_item;
1332
695k
        }
1333
1334
1.66M
        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
1.66M
        input_buffer->offset++;
1340
1.66M
        buffer_skip_whitespace(input_buffer);
1341
1.66M
        if (!parse_string(current_item, input_buffer, out_of_memory)) {
1342
191
            goto fail; /* failed to parse name */
1343
191
        }
1344
1.66M
        buffer_skip_whitespace(input_buffer);
1345
1346
        /* swap valuestring and string, because we parsed the name */
1347
1.66M
        current_item->string = current_item->valuestring;
1348
1.66M
        current_item->valuestring = NULL;
1349
1350
1.66M
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) {
1351
34
            goto fail; /* invalid object */
1352
34
        }
1353
1354
        /* parse the value */
1355
1.66M
        input_buffer->offset++;
1356
1.66M
        buffer_skip_whitespace(input_buffer);
1357
1.66M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1358
9.77k
            goto fail; /* failed to parse value */
1359
9.77k
        }
1360
1.65M
        buffer_skip_whitespace(input_buffer);
1361
1.65M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1362
1363
957k
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) {
1364
20
        goto fail; /* expected end of object */
1365
20
    }
1366
1367
6.55M
success:
1368
6.55M
    input_buffer->depth--;
1369
1370
6.55M
    if (head != NULL) {
1371
957k
        head->prev = current_item;
1372
957k
    }
1373
1374
6.55M
    item->type = cJSON_Object;
1375
6.55M
    item->child = head;
1376
1377
6.55M
    input_buffer->offset++;
1378
6.55M
    return true;
1379
1380
10.0k
fail:
1381
10.0k
    if (head != NULL) {
1382
10.0k
        loader_cJSON_Delete(head);
1383
10.0k
    }
1384
1385
10.0k
    return false;
1386
957k
}
1387
1388
/* Render an object to text. */
1389
6.17M
static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1390
6.17M
    unsigned char *output_pointer = NULL;
1391
6.17M
    size_t length = 0;
1392
6.17M
    cJSON *current_item = item->child;
1393
1394
6.17M
    if (output_buffer == NULL) {
1395
0
        return false;
1396
0
    }
1397
1398
6.17M
    if (output_buffer->depth >= CJSON_NESTING_LIMIT) {
1399
0
        return false; /* nesting is too deep */
1400
0
    }
1401
1402
    /* Compose the output: */
1403
6.17M
    length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */
1404
6.17M
    output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1405
6.17M
    if (output_pointer == NULL) {
1406
0
        return false;
1407
0
    }
1408
1409
6.17M
    *output_pointer++ = '{';
1410
6.17M
    output_buffer->depth++;
1411
6.17M
    if (output_buffer->format) {
1412
6.17M
        *output_pointer++ = '\n';
1413
6.17M
    }
1414
6.17M
    output_buffer->offset += length;
1415
1416
7.71M
    while (current_item) {
1417
1.53M
        if (output_buffer->format) {
1418
1.53M
            size_t i;
1419
1.53M
            output_pointer = ensure(output_buffer, output_buffer->depth, out_of_memory);
1420
1.53M
            if (output_pointer == NULL) {
1421
0
                return false;
1422
0
            }
1423
737M
            for (i = 0; i < output_buffer->depth; i++) {
1424
735M
                *output_pointer++ = '\t';
1425
735M
            }
1426
1.53M
            output_buffer->offset += output_buffer->depth;
1427
1.53M
        }
1428
1429
        /* print key */
1430
1.53M
        if (!print_string_ptr((unsigned char *)current_item->string, output_buffer, out_of_memory)) {
1431
0
            return false;
1432
0
        }
1433
1.53M
        update_offset(output_buffer);
1434
1435
1.53M
        length = (size_t)(output_buffer->format ? 2 : 1);
1436
1.53M
        output_pointer = ensure(output_buffer, length, out_of_memory);
1437
1.53M
        if (output_pointer == NULL) {
1438
0
            return false;
1439
0
        }
1440
1.53M
        *output_pointer++ = ':';
1441
1.53M
        if (output_buffer->format) {
1442
1.53M
            *output_pointer++ = '\t';
1443
1.53M
        }
1444
1.53M
        output_buffer->offset += length;
1445
1446
        /* print value */
1447
1.53M
        if (!print_value(current_item, output_buffer, out_of_memory)) {
1448
0
            return false;
1449
0
        }
1450
1.53M
        update_offset(output_buffer);
1451
1452
        /* print comma if not last */
1453
1.53M
        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
1454
1.53M
        output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1455
1.53M
        if (output_pointer == NULL) {
1456
0
            return false;
1457
0
        }
1458
1.53M
        if (current_item->next) {
1459
661k
            *output_pointer++ = ',';
1460
661k
        }
1461
1462
1.53M
        if (output_buffer->format) {
1463
1.53M
            *output_pointer++ = '\n';
1464
1.53M
        }
1465
1.53M
        *output_pointer = '\0';
1466
1.53M
        output_buffer->offset += length;
1467
1468
1.53M
        current_item = current_item->next;
1469
1.53M
    }
1470
1471
6.17M
    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2, out_of_memory);
1472
6.17M
    if (output_pointer == NULL) {
1473
0
        return false;
1474
0
    }
1475
6.17M
    if (output_buffer->format) {
1476
6.17M
        size_t i;
1477
4.85G
        for (i = 0; i < (output_buffer->depth - 1); i++) {
1478
4.84G
            *output_pointer++ = '\t';
1479
4.84G
        }
1480
6.17M
    }
1481
6.17M
    *output_pointer++ = '}';
1482
6.17M
    *output_pointer = '\0';
1483
6.17M
    output_buffer->depth--;
1484
1485
6.17M
    return true;
1486
6.17M
}
1487
1488
/* Get Array size/item / object item. */
1489
0
CJSON_PUBLIC(int) loader_cJSON_GetArraySize(const cJSON *array) {
1490
0
    cJSON *child = NULL;
1491
0
    size_t size = 0;
1492
1493
0
    if (array == NULL) {
1494
0
        return 0;
1495
0
    }
1496
1497
0
    child = array->child;
1498
1499
0
    while (child != NULL) {
1500
0
        size++;
1501
0
        child = child->next;
1502
0
    }
1503
1504
    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1505
1506
0
    return (int)size;
1507
0
}
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
0
static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) {
1534
0
    cJSON *current_element = NULL;
1535
1536
0
    if ((object == NULL) || (name == NULL)) {
1537
0
        return NULL;
1538
0
    }
1539
1540
0
    current_element = object->child;
1541
0
    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
0
    } else {
1546
0
        while ((current_element != NULL) &&
1547
0
               (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0)) {
1548
0
            current_element = current_element->next;
1549
0
        }
1550
0
    }
1551
1552
0
    if ((current_element == NULL) || (current_element->string == NULL)) {
1553
0
        return NULL;
1554
0
    }
1555
1556
0
    return current_element;
1557
0
}
1558
1559
0
CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItem(const cJSON *const object, const char *const string) {
1560
0
    return get_object_item(object, string, false);
1561
0
}
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
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsTrue(const cJSON *const item) {
1672
0
    if (item == NULL) {
1673
0
        return false;
1674
0
    }
1675
1676
0
    return (item->type & 0xff) == cJSON_True;
1677
0
}
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
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsString(const cJSON *const item) {
1703
0
    if (item == NULL) {
1704
0
        return false;
1705
0
    }
1706
1707
0
    return (item->type & 0xFF) == cJSON_String;
1708
0
}
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
}