Coverage Report

Created: 2026-08-08 06:15

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