Coverage Report

Created: 2026-10-19 06:59

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
21.9M
#define true ((cJSON_bool)1)
68
69
#ifdef false
70
#undef false
71
#endif
72
2.35M
#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.94M
static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) {
143
9.94M
    cJSON *node = (cJSON *)loader_calloc(pAllocator, sizeof(cJSON), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
144
9.94M
    if (NULL != node) {
145
9.94M
        node->pAllocator = pAllocator;
146
9.94M
    }
147
9.94M
    return node;
148
9.94M
}
149
150
/* Delete a cJSON structure. */
151
1.34M
TEST_FUNCTION_EXPORT CJSON_PUBLIC(void) loader_cJSON_Delete(cJSON *item) {
152
1.34M
    cJSON *next = NULL;
153
11.2M
    while (item != NULL) {
154
9.94M
        next = item->next;
155
9.94M
        if (!(item->type & cJSON_IsReference) && (item->child != NULL)) {
156
1.27M
            loader_cJSON_Delete(item->child);
157
1.27M
        }
158
9.94M
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) {
159
8.23k
            loader_free(item->pAllocator, item->valuestring);
160
8.23k
            item->valuestring = NULL;
161
8.23k
        }
162
9.94M
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
163
1.64M
            loader_free(item->pAllocator, item->string);
164
1.64M
            item->string = NULL;
165
1.64M
        }
166
9.94M
        loader_free(item->pAllocator, item);
167
9.94M
        item = next;
168
9.94M
    }
169
1.34M
}
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
59.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
226M
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
193
53.9M
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
194
/* get a pointer to the buffer at the position */
195
163M
#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.27M
static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) {
199
2.27M
    double number = 0;
200
2.27M
    unsigned char *after_end = NULL;
201
2.27M
    unsigned char *number_c_string;
202
2.27M
    unsigned char decimal_point = get_decimal_point();
203
2.27M
    size_t i = 0;
204
2.27M
    size_t number_string_length = 0;
205
2.27M
    cJSON_bool has_decimal_point = false;
206
207
2.27M
    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.27M
    for (i = 0; can_access_at_index(input_buffer, i); i++) {
215
5.27M
        switch (buffer_at_offset(input_buffer)[i]) {
216
489k
            case '0':
217
630k
            case '1':
218
792k
            case '2':
219
928k
            case '3':
220
1.13M
            case '4':
221
1.18M
            case '5':
222
2.32M
            case '6':
223
2.47M
            case '7':
224
2.63M
            case '8':
225
2.94M
            case '9':
226
2.94M
            case '+':
227
2.94M
            case '-':
228
2.98M
            case 'e':
229
2.99M
            case 'E':
230
2.99M
                number_string_length++;
231
2.99M
                break;
232
233
1.86k
            case '.':
234
1.86k
                number_string_length++;
235
1.86k
                has_decimal_point = true;
236
1.86k
                break;
237
238
2.27M
            default:
239
2.27M
                goto loop_end;
240
5.27M
        }
241
5.27M
    }
242
2.27M
loop_end:
243
    /* malloc for temporary buffer, add 1 for '\0' */
244
2.27M
    number_c_string =
245
2.27M
        (unsigned char *)loader_calloc(input_buffer->pAllocator, number_string_length + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
246
2.27M
    if (number_c_string == NULL) {
247
0
        return false; /* allocation failure */
248
0
    }
249
250
2.27M
    memcpy(number_c_string, buffer_at_offset(input_buffer), number_string_length);
251
2.27M
    number_c_string[number_string_length] = '\0';
252
253
2.27M
    if (has_decimal_point) {
254
18.9k
        for (i = 0; i < number_string_length; i++) {
255
17.2k
            if (number_c_string[i] == '.') {
256
                /* replace '.' with the decimal point of the current locale (for strtod) */
257
1.86k
                number_c_string[i] = decimal_point;
258
1.86k
            }
259
17.2k
        }
260
1.68k
    }
261
262
2.27M
    number = strtod((const char *)number_c_string, (char **)&after_end);
263
2.27M
    if (number_c_string == after_end) {
264
        /* free the temporary buffer */
265
23
        loader_free(input_buffer->pAllocator, number_c_string);
266
23
        return false; /* parse_error */
267
23
    }
268
269
2.27M
    item->valuedouble = number;
270
271
    /* use saturation in case of overflow */
272
2.27M
    if (number >= INT_MAX) {
273
51.5k
        item->valueint = INT_MAX;
274
2.22M
    } else if (number <= (double)INT_MIN) {
275
616
        item->valueint = INT_MIN;
276
2.22M
    } else {
277
2.22M
        item->valueint = (int)number;
278
2.22M
    }
279
280
2.27M
    item->type = cJSON_Number;
281
282
2.27M
    input_buffer->offset += (size_t)(after_end - number_c_string);
283
    /* free the temporary buffer */
284
2.27M
    loader_free(input_buffer->pAllocator, number_c_string);
285
2.27M
    return true;
286
2.27M
}
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
29.1M
static unsigned char *ensure(printbuffer *const p, size_t needed, bool *out_of_memory) {
300
29.1M
    unsigned char *newbuffer = NULL;
301
29.1M
    size_t newsize = 0;
302
303
29.1M
    if ((p == NULL) || (p->buffer == NULL)) {
304
0
        return NULL;
305
0
    }
306
307
29.1M
    if ((p->length > 0) && (p->offset >= p->length)) {
308
        /* make sure that offset is valid */
309
0
        return NULL;
310
0
    }
311
312
29.1M
    if (needed > INT_MAX) {
313
        /* sizes bigger than INT_MAX are currently not supported */
314
0
        return NULL;
315
0
    }
316
317
29.1M
    needed += p->offset + 1;
318
29.1M
    if (needed <= p->length) {
319
29.1M
        return p->buffer + p->offset;
320
29.1M
    }
321
322
6.67k
    if (p->noalloc) {
323
0
        return NULL;
324
0
    }
325
326
    /* calculate new buffer size */
327
6.67k
    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.67k
    } else {
335
6.67k
        newsize = needed * 2;
336
6.67k
    }
337
338
6.67k
    newbuffer = (unsigned char *)loader_realloc(p->pAllocator, p->buffer, p->length, newsize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
339
6.67k
    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.67k
    p->length = newsize;
349
6.67k
    p->buffer = newbuffer;
350
351
6.67k
    return newbuffer + p->offset;
352
6.67k
}
353
354
/* calculate the new length of the string in a printbuffer and update the offset */
355
10.3M
static void update_offset(printbuffer *const buffer) {
356
10.3M
    const unsigned char *buffer_pointer = NULL;
357
10.3M
    if ((buffer == NULL) || (buffer->buffer == NULL)) {
358
0
        return;
359
0
    }
360
10.3M
    buffer_pointer = buffer->buffer + buffer->offset;
361
362
10.3M
    buffer->offset += strlen((const char *)buffer_pointer);
363
10.3M
}
364
365
/* securely comparison of floating-point variables */
366
1.74k
static cJSON_bool compare_double(double a, double b) {
367
1.74k
    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
368
1.74k
    return (fabs(a - b) <= maxVal * DBL_EPSILON);
369
1.74k
}
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
560
        length = snprintf((char *)number_buffer, 26, "null");
388
1.72M
    } else if (d == (double)item->valueint) {
389
1.72M
        length = snprintf((char *)number_buffer, 26, "%d", item->valueint);
390
1.72M
    } else {
391
        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
392
1.74k
        length = snprintf((char *)number_buffer, 26, "%1.15g", d);
393
394
        /* Check whether the original double can be recovered */
395
1.74k
        if ((sscanf((char *)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) {
396
            /* If not, print with 17 decimal places of precision */
397
840
            length = snprintf((char *)number_buffer, 26, "%1.17g", d);
398
840
        }
399
1.74k
    }
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.52M
    for (i = 0; i < ((size_t)length); i++) {
415
1.79M
        if (number_buffer[i] == decimal_point) {
416
1.08k
            output_pointer[i] = '.';
417
1.08k
            continue;
418
1.08k
        }
419
420
1.79M
        output_pointer[i] = number_buffer[i];
421
1.79M
    }
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
523k
static unsigned parse_hex4(const unsigned char *const input) {
431
523k
    unsigned int h = 0;
432
523k
    size_t i = 0;
433
434
1.91M
    for (i = 0; i < 4; i++) {
435
        /* parse digit */
436
1.63M
        if ((input[i] >= '0') && (input[i] <= '9')) {
437
792k
            h += (unsigned int)input[i] - '0';
438
844k
        } else if ((input[i] >= 'A') && (input[i] <= 'F')) {
439
300k
            h += (unsigned int)10 + input[i] - 'A';
440
544k
        } else if ((input[i] >= 'a') && (input[i] <= 'f')) {
441
297k
            h += (unsigned int)10 + input[i] - 'a';
442
297k
        } else /* invalid */
443
247k
        {
444
247k
            return 0;
445
247k
        }
446
447
1.38M
        if (i < 3) {
448
            /* shift left to make place for the next nibble */
449
1.11M
            h = h << 4;
450
1.11M
        }
451
1.38M
    }
452
453
276k
    return h;
454
523k
}
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
520k
                                           unsigned char **output_pointer) {
460
520k
    long unsigned int codepoint = 0;
461
520k
    unsigned int first_code = 0;
462
520k
    const unsigned char *first_sequence = input_pointer;
463
520k
    unsigned char utf8_length = 0;
464
520k
    unsigned char utf8_position = 0;
465
520k
    unsigned char sequence_length = 0;
466
520k
    unsigned char first_byte_mark = 0;
467
468
520k
    if ((input_end - first_sequence) < 6) {
469
        /* input ends unexpectedly */
470
10
        goto fail;
471
10
    }
472
473
    /* get the first utf16 sequence */
474
520k
    first_code = parse_hex4(first_sequence + 2);
475
476
    /* check that the code is valid */
477
520k
    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) {
478
15
        goto fail;
479
15
    }
480
481
    /* UTF16 surrogate pair */
482
520k
    if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) {
483
2.98k
        const unsigned char *second_sequence = first_sequence + 6;
484
2.98k
        unsigned int second_code = 0;
485
2.98k
        sequence_length = 12; /* \uXXXX\uXXXX */
486
487
2.98k
        if ((input_end - second_sequence) < 6) {
488
            /* input ends unexpectedly */
489
16
            goto fail;
490
16
        }
491
492
2.97k
        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) {
493
            /* missing second half of the surrogate pair */
494
31
            goto fail;
495
31
        }
496
497
        /* get the second utf16 sequence */
498
2.94k
        second_code = parse_hex4(second_sequence + 2);
499
        /* check that the code is valid */
500
2.94k
        if ((second_code < 0xDC00) || (second_code > 0xDFFF)) {
501
            /* invalid second half of the surrogate pair */
502
54
            goto fail;
503
54
        }
504
505
        /* calculate the unicode codepoint from the surrogate pair */
506
2.88k
        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
507
517k
    } else {
508
517k
        sequence_length = 6; /* \uXXXX */
509
517k
        codepoint = first_code;
510
517k
    }
511
512
    /* encode as UTF-8
513
     * takes at maximum 4 bytes to encode:
514
     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
515
520k
    if (codepoint < 0x80) {
516
        /* normal ascii, encoding 0xxxxxxx */
517
258k
        utf8_length = 1;
518
262k
    } else if (codepoint < 0x800) {
519
        /* two bytes, encoding 110xxxxx 10xxxxxx */
520
231k
        utf8_length = 2;
521
231k
        first_byte_mark = 0xC0; /* 11000000 */
522
231k
    } else if (codepoint < 0x10000) {
523
        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
524
27.5k
        utf8_length = 3;
525
27.5k
        first_byte_mark = 0xE0; /* 11100000 */
526
27.5k
    } else if (codepoint <= 0x10FFFF) {
527
        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
528
2.88k
        utf8_length = 4;
529
2.88k
        first_byte_mark = 0xF0; /* 11110000 */
530
2.88k
    } else {
531
        /* invalid unicode codepoint */
532
0
        goto fail;
533
0
    }
534
535
    /* encode as utf8 */
536
815k
    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) {
537
        /* 10xxxxxx */
538
295k
        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
539
295k
        codepoint >>= 6;
540
295k
    }
541
    /* encode first byte */
542
520k
    if (utf8_length > 1) {
543
262k
        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
544
262k
    } else {
545
258k
        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
546
258k
    }
547
548
520k
    *output_pointer += utf8_length;
549
550
520k
    return sequence_length;
551
552
126
fail:
553
126
    return 0;
554
520k
}
555
556
/* Parse the input text into an unescaped cinput, and populate item. */
557
1.64M
static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
558
1.64M
    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
559
1.64M
    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
560
1.64M
    unsigned char *output_pointer = NULL;
561
1.64M
    unsigned char *output = NULL;
562
563
    /* not a string */
564
1.64M
    if (buffer_at_offset(input_buffer)[0] != '\"') {
565
153
        goto fail;
566
153
    }
567
568
1.64M
    {
569
        /* calculate approximate size of the output (overestimate) */
570
1.64M
        size_t allocation_length = 0;
571
1.64M
        size_t skipped_bytes = 0;
572
39.1M
        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) {
573
            /* is escape sequence */
574
37.5M
            if (input_end[0] == '\\') {
575
934k
                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
934k
                skipped_bytes++;
580
934k
                input_end++;
581
934k
            }
582
37.5M
            input_end++;
583
37.5M
        }
584
1.64M
        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) {
585
101
            goto fail; /* string ended unexpectedly */
586
101
        }
587
588
        /* This is at most how much we need for the output */
589
1.64M
        allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
590
1.64M
        output = (unsigned char *)loader_calloc(input_buffer->pAllocator, allocation_length + sizeof(""),
591
1.64M
                                                VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
592
1.64M
        if (output == NULL) {
593
0
            *out_of_memory = true;
594
0
            goto fail; /* allocation failure */
595
0
        }
596
1.64M
    }
597
598
1.64M
    output_pointer = output;
599
    /* loop through the string literal */
600
30.1M
    while (input_pointer < input_end) {
601
28.4M
        if (*input_pointer != '\\') {
602
27.8M
            *output_pointer++ = *input_pointer++;
603
27.8M
        }
604
        /* escape sequence */
605
652k
        else {
606
652k
            unsigned char sequence_length = 2;
607
652k
            if ((input_end - input_pointer) < 1) {
608
0
                goto fail;
609
0
            }
610
611
652k
            switch (input_pointer[1]) {
612
80.7k
                case 'b':
613
80.7k
                    *output_pointer++ = '\b';
614
80.7k
                    break;
615
1.31k
                case 'f':
616
1.31k
                    *output_pointer++ = '\f';
617
1.31k
                    break;
618
7.18k
                case 'n':
619
7.18k
                    *output_pointer++ = '\n';
620
7.18k
                    break;
621
3.23k
                case 'r':
622
3.23k
                    *output_pointer++ = '\r';
623
3.23k
                    break;
624
35.0k
                case 't':
625
35.0k
                    *output_pointer++ = '\t';
626
35.0k
                    break;
627
1.58k
                case '\"':
628
2.35k
                case '\\':
629
4.63k
                case '/':
630
4.63k
                    *output_pointer++ = input_pointer[1];
631
4.63k
                    break;
632
633
                /* UTF-16 literal */
634
520k
                case 'u':
635
520k
                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
636
520k
                    if (sequence_length == 0) {
637
                        /* failed to convert UTF16-literal to UTF-8 */
638
126
                        goto fail;
639
126
                    }
640
520k
                    break;
641
642
520k
                default:
643
15
                    goto fail;
644
652k
            }
645
652k
            input_pointer += sequence_length;
646
652k
        }
647
28.4M
    }
648
649
    /* zero terminate the output */
650
1.64M
    *output_pointer = '\0';
651
652
1.64M
    item->type = cJSON_String;
653
1.64M
    item->valuestring = (char *)output;
654
655
1.64M
    input_buffer->offset = (size_t)(input_end - input_buffer->content);
656
1.64M
    input_buffer->offset++;
657
658
1.64M
    return true;
659
660
395
fail:
661
395
    if (output != NULL) {
662
141
        loader_free(input_buffer->pAllocator, output);
663
141
        output = NULL;
664
141
    }
665
666
395
    if (input_pointer != NULL) {
667
395
        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
668
395
    }
669
670
395
    return false;
671
1.64M
}
672
673
/* Render the cstring provided to an escaped version that can be printed. */
674
1.52M
static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer, bool *out_of_memory) {
675
1.52M
    const unsigned char *input_pointer = NULL;
676
1.52M
    unsigned char *output = NULL;
677
1.52M
    unsigned char *output_pointer = NULL;
678
1.52M
    size_t output_length = 0;
679
    /* numbers of additional characters needed for escaping */
680
1.52M
    size_t escape_characters = 0;
681
682
1.52M
    if (output_buffer == NULL) {
683
0
        return false;
684
0
    }
685
686
    /* empty string */
687
1.52M
    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
13.9M
    for (input_pointer = input; *input_pointer; input_pointer++) {
698
12.4M
        switch (*input_pointer) {
699
308
            case '\"':
700
682
            case '\\':
701
2.25k
            case '\b':
702
5.19k
            case '\f':
703
6.06k
            case '\n':
704
35.2k
            case '\r':
705
36.6k
            case '\t':
706
                /* one character escape sequence */
707
36.6k
                escape_characters++;
708
36.6k
                break;
709
12.3M
            default:
710
12.3M
                if (*input_pointer < 32) {
711
                    /* UTF-16 escape sequence uXXXX */
712
7.19M
                    escape_characters += 5;
713
7.19M
                }
714
12.3M
                break;
715
12.4M
        }
716
12.4M
    }
717
1.52M
    output_length = (size_t)(input_pointer - input) + escape_characters;
718
719
1.52M
    output = ensure(output_buffer, output_length + sizeof(""), out_of_memory);
720
1.52M
    if (output == NULL) {
721
0
        return false;
722
0
    }
723
724
    /* no characters have to be escaped */
725
1.52M
    if (escape_characters == 0) {
726
1.50M
        memcpy(output, input, output_length);
727
1.50M
        output[output_length] = '\0';
728
729
1.50M
        return true;
730
1.50M
    }
731
732
17.3k
    output_pointer = output;
733
    /* copy the string */
734
11.3M
    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) {
735
11.3M
        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) {
736
            /* normal character, copy */
737
4.07M
            *output_pointer = *input_pointer;
738
7.22M
        } 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.22M
            switch (*input_pointer) {
745
374
                case '\\':
746
374
                    *output_pointer = '\\';
747
374
                    break;
748
308
                case '\"':
749
308
                    *output_pointer = '\"';
750
308
                    break;
751
1.57k
                case '\b':
752
1.57k
                    *output_pointer = '\b';
753
1.57k
                    break;
754
2.93k
                case '\f':
755
2.93k
                    *output_pointer = '\f';
756
2.93k
                    break;
757
875
                case '\n':
758
875
                    *output_pointer = '\n';
759
875
                    break;
760
29.1k
                case '\r':
761
29.1k
                    *output_pointer = '\r';
762
29.1k
                    break;
763
1.39k
                case '\t':
764
1.39k
                    *output_pointer = '\t';
765
1.39k
                    break;
766
7.19M
                default:
767
                    /* escape and print as unicode codepoint */
768
7.19M
                    snprintf((char *)output_pointer, output_length - (size_t)(output_pointer - output), "u%04x", *input_pointer);
769
7.19M
                    output_pointer += 4;
770
7.19M
                    break;
771
7.22M
            }
772
7.22M
        }
773
11.3M
    }
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.3k
    *output_pointer = '\0';
778
779
17.3k
    return true;
780
17.3k
}
781
782
/* Invoke print_string_ptr (which is useful) on an item. */
783
7.09k
static cJSON_bool print_string(const cJSON *const item, printbuffer *const p, bool *out_of_memory) {
784
7.09k
    return print_string_ptr((unsigned char *)item->valuestring, p, out_of_memory);
785
7.09k
}
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
30.7M
static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) {
797
30.7M
    if ((buffer == NULL) || (buffer->content == NULL)) {
798
0
        return NULL;
799
0
    }
800
801
30.7M
    if (cannot_access_at_index(buffer, 0)) {
802
0
        return buffer;
803
0
    }
804
805
36.5M
    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) {
806
5.81M
        buffer->offset++;
807
5.81M
    }
808
809
30.7M
    if (buffer->offset == buffer->length) {
810
605
        buffer->offset--;
811
605
    }
812
813
30.7M
    return buffer;
814
30.7M
}
815
816
/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
817
2.72k
static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) {
818
2.72k
    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) {
819
0
        return NULL;
820
0
    }
821
822
2.72k
    if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) {
823
29
        buffer->offset += 3;
824
29
    }
825
826
2.72k
    return buffer;
827
2.72k
}
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.72k
                                 const char **return_parse_end, cJSON_bool require_null_terminated, bool *out_of_memory) {
849
2.72k
    parse_buffer buffer = {0, 0, 0, 0, 0};
850
2.72k
    cJSON *item = NULL;
851
852
    /* reset error position */
853
    // global_error.json = NULL;
854
    // global_error.position = 0;
855
856
2.72k
    if (value == NULL || 0 == buffer_length) {
857
0
        goto fail;
858
0
    }
859
860
2.72k
    buffer.content = (const unsigned char *)value;
861
2.72k
    buffer.length = buffer_length;
862
2.72k
    buffer.offset = 0;
863
2.72k
    buffer.pAllocator = pAllocator;
864
865
2.72k
    item = cJSON_New_Item(pAllocator);
866
2.72k
    if (item == NULL) /* memory fail */
867
0
    {
868
0
        *out_of_memory = true;
869
0
        goto fail;
870
0
    }
871
872
2.72k
    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)), out_of_memory)) {
873
        /* parse failure. ep is set. */
874
913
        goto fail;
875
913
    }
876
877
    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
878
1.81k
    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.81k
    if (return_parse_end) {
885
0
        *return_parse_end = (const char *)buffer_at_offset(&buffer);
886
0
    }
887
888
1.81k
    return item;
889
890
913
fail:
891
913
    if (item != NULL) {
892
913
        loader_cJSON_Delete(item);
893
913
    }
894
895
913
    if (value != NULL) {
896
913
        error local_error;
897
913
        local_error.json = (const unsigned char *)value;
898
913
        local_error.position = 0;
899
900
913
        if (buffer.offset < buffer.length) {
901
779
            local_error.position = buffer.offset;
902
779
        } else if (buffer.length > 0) {
903
134
            local_error.position = buffer.length - 1;
904
134
        }
905
906
913
        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
913
    }
912
913
913
    return NULL;
914
1.81k
}
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.72k
                             bool *out_of_memory) {
924
2.72k
    return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, 0, 0, out_of_memory);
925
2.72k
}
926
927
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
928
929
1.81k
static unsigned char *print(const cJSON *const item, cJSON_bool format, bool *out_of_memory) {
930
1.81k
    static const size_t default_buffer_size = 256;
931
1.81k
    printbuffer buffer[1];
932
1.81k
    unsigned char *printed = NULL;
933
934
1.81k
    memset(buffer, 0, sizeof(buffer));
935
936
    /* create buffer */
937
1.81k
    buffer->buffer = (unsigned char *)loader_calloc(item->pAllocator, default_buffer_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
938
1.81k
    buffer->length = default_buffer_size;
939
1.81k
    buffer->format = format;
940
1.81k
    buffer->pAllocator = item->pAllocator;
941
1.81k
    if (buffer->buffer == NULL) {
942
0
        *out_of_memory = true;
943
0
        goto fail;
944
0
    }
945
946
    /* print the value */
947
1.81k
    if (!print_value(item, buffer, out_of_memory)) {
948
0
        goto fail;
949
0
    }
950
1.81k
    update_offset(buffer);
951
952
1.81k
    printed = (unsigned char *)loader_realloc(item->pAllocator, buffer->buffer, buffer->length, buffer->offset + 1,
953
1.81k
                                              VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
954
1.81k
    if (printed == NULL) {
955
0
        *out_of_memory = true;
956
0
        goto fail;
957
0
    }
958
1.81k
    buffer->buffer = NULL;
959
960
1.81k
    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.81k
}
975
976
/* Render a cJSON item/entity/structure to text. */
977
1.81k
TEST_FUNCTION_EXPORT CJSON_PUBLIC(char *) loader_cJSON_Print(const cJSON *item, bool *out_of_memory) {
978
1.81k
    return (char *)print(item, true, out_of_memory);
979
1.81k
}
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.94M
static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1033
9.94M
    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.94M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) {
1040
3.31k
        item->type = cJSON_NULL;
1041
3.31k
        input_buffer->offset += 4;
1042
3.31k
        return true;
1043
3.31k
    }
1044
    /* false */
1045
9.93M
    if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) {
1046
2.84k
        item->type = cJSON_False;
1047
2.84k
        input_buffer->offset += 5;
1048
2.84k
        return true;
1049
2.84k
    }
1050
    /* true */
1051
9.93M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) {
1052
8.49k
        item->type = cJSON_True;
1053
8.49k
        item->valueint = 1;
1054
8.49k
        input_buffer->offset += 4;
1055
8.49k
        return true;
1056
8.49k
    }
1057
    /* string */
1058
9.92M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) {
1059
8.44k
        return parse_string(item, input_buffer, out_of_memory);
1060
8.44k
    }
1061
    /* number */
1062
9.91M
    if (can_access_at_index(input_buffer, 0) &&
1063
9.91M
        ((buffer_at_offset(input_buffer)[0] == '-') ||
1064
9.91M
         ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) {
1065
2.27M
        return parse_number(item, input_buffer);
1066
2.27M
    }
1067
    /* array */
1068
7.63M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) {
1069
428k
        return parse_array(item, input_buffer, out_of_memory);
1070
428k
    }
1071
    /* object */
1072
7.20M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) {
1073
7.20M
        return parse_object(item, input_buffer, out_of_memory);
1074
7.20M
    }
1075
1076
313
    return false;
1077
7.20M
}
1078
1079
/* Render a value to text. */
1080
8.87M
static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1081
8.87M
    unsigned char *output = NULL;
1082
1083
8.87M
    if ((item == NULL) || (output_buffer == NULL)) {
1084
0
        return false;
1085
0
    }
1086
1087
8.87M
    switch ((item->type) & 0xFF) {
1088
2.82k
        case cJSON_NULL:
1089
2.82k
            output = ensure(output_buffer, 5, out_of_memory);
1090
2.82k
            if (output == NULL) {
1091
0
                return false;
1092
0
            }
1093
2.82k
            strcpy((char *)output, "null");
1094
2.82k
            return true;
1095
1096
2.16k
        case cJSON_False:
1097
2.16k
            output = ensure(output_buffer, 6, out_of_memory);
1098
2.16k
            if (output == NULL) {
1099
0
                return false;
1100
0
            }
1101
2.16k
            strcpy((char *)output, "false");
1102
2.16k
            return true;
1103
1104
7.87k
        case cJSON_True:
1105
7.87k
            output = ensure(output_buffer, 5, out_of_memory);
1106
7.87k
            if (output == NULL) {
1107
0
                return false;
1108
0
            }
1109
7.87k
            strcpy((char *)output, "true");
1110
7.87k
            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
7.09k
        case cJSON_String:
1131
7.09k
            return print_string(item, output_buffer, out_of_memory);
1132
1133
344k
        case cJSON_Array:
1134
344k
            return print_array(item, output_buffer, out_of_memory);
1135
1136
6.78M
        case cJSON_Object:
1137
6.78M
            return print_object(item, output_buffer, out_of_memory);
1138
1139
0
        default:
1140
0
            return false;
1141
8.87M
    }
1142
8.87M
}
1143
1144
/* Build an array from input text. */
1145
428k
static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1146
428k
    cJSON *head = NULL; /* head of the linked list */
1147
428k
    cJSON *current_item = NULL;
1148
1149
428k
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1150
7
        return false; /* to deeply nested */
1151
7
    }
1152
428k
    input_buffer->depth++;
1153
1154
428k
    if (buffer_at_offset(input_buffer)[0] != '[') {
1155
        /* not an array */
1156
0
        goto fail;
1157
0
    }
1158
1159
428k
    input_buffer->offset++;
1160
428k
    buffer_skip_whitespace(input_buffer);
1161
428k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) {
1162
        /* empty array */
1163
24.1k
        goto success;
1164
24.1k
    }
1165
1166
    /* check if we skipped to the end of the buffer */
1167
404k
    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
404k
    input_buffer->offset--;
1174
    /* loop through the comma separated array elements */
1175
8.29M
    do {
1176
        /* allocate next item */
1177
8.29M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1178
8.29M
        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
8.29M
        if (head == NULL) {
1185
            /* start the linked list */
1186
404k
            current_item = head = new_item;
1187
7.89M
        } else {
1188
            /* add to the end and advance */
1189
7.89M
            current_item->next = new_item;
1190
7.89M
            new_item->prev = current_item;
1191
7.89M
            current_item = new_item;
1192
7.89M
        }
1193
1194
        /* parse next value */
1195
8.29M
        input_buffer->offset++;
1196
8.29M
        buffer_skip_whitespace(input_buffer);
1197
8.29M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1198
62.3k
            goto fail; /* failed to parse value */
1199
62.3k
        }
1200
8.23M
        buffer_skip_whitespace(input_buffer);
1201
8.23M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1202
1203
342k
    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') {
1204
120
        goto fail; /* expected end of array */
1205
120
    }
1206
1207
366k
success:
1208
366k
    input_buffer->depth--;
1209
1210
366k
    if (head != NULL) {
1211
342k
        head->prev = current_item;
1212
342k
    }
1213
1214
366k
    item->type = cJSON_Array;
1215
366k
    item->child = head;
1216
1217
366k
    input_buffer->offset++;
1218
1219
366k
    return true;
1220
1221
62.4k
fail:
1222
62.4k
    if (head != NULL) {
1223
62.4k
        loader_cJSON_Delete(head);
1224
62.4k
    }
1225
1226
62.4k
    return false;
1227
342k
}
1228
1229
/* Render an array to text */
1230
344k
static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1231
344k
    unsigned char *output_pointer = NULL;
1232
344k
    size_t length = 0;
1233
344k
    cJSON *current_element = item->child;
1234
1235
344k
    if (output_buffer == NULL) {
1236
0
        return false;
1237
0
    }
1238
1239
344k
    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
344k
    output_pointer = ensure(output_buffer, 1, out_of_memory);
1246
344k
    if (output_pointer == NULL) {
1247
0
        return false;
1248
0
    }
1249
1250
344k
    *output_pointer = '[';
1251
344k
    output_buffer->offset++;
1252
344k
    output_buffer->depth++;
1253
1254
7.70M
    while (current_element != NULL) {
1255
7.35M
        if (!print_value(current_element, output_buffer, out_of_memory)) {
1256
0
            return false;
1257
0
        }
1258
7.35M
        update_offset(output_buffer);
1259
7.35M
        if (current_element->next) {
1260
7.03M
            length = (size_t)(output_buffer->format ? 2 : 1);
1261
7.03M
            output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1262
7.03M
            if (output_pointer == NULL) {
1263
0
                return false;
1264
0
            }
1265
7.03M
            *output_pointer++ = ',';
1266
7.03M
            if (output_buffer->format) {
1267
7.03M
                *output_pointer++ = ' ';
1268
7.03M
            }
1269
7.03M
            *output_pointer = '\0';
1270
7.03M
            output_buffer->offset += length;
1271
7.03M
        }
1272
7.35M
        current_element = current_element->next;
1273
7.35M
    }
1274
1275
344k
    output_pointer = ensure(output_buffer, 2, out_of_memory);
1276
344k
    if (output_pointer == NULL) {
1277
0
        return false;
1278
0
    }
1279
344k
    *output_pointer++ = ']';
1280
344k
    *output_pointer = '\0';
1281
344k
    output_buffer->depth--;
1282
1283
344k
    return true;
1284
344k
}
1285
1286
/* Build an object from the text. */
1287
7.20M
static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1288
7.20M
    cJSON *head = NULL; /* linked list head */
1289
7.20M
    cJSON *current_item = NULL;
1290
1291
7.20M
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1292
2
        return false; /* to deeply nested */
1293
2
    }
1294
7.20M
    input_buffer->depth++;
1295
1296
7.20M
    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
7.20M
    input_buffer->offset++;
1301
7.20M
    buffer_skip_whitespace(input_buffer);
1302
7.20M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) {
1303
6.26M
        goto success; /* empty object */
1304
6.26M
    }
1305
1306
    /* check if we skipped to the end of the buffer */
1307
941k
    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
941k
    input_buffer->offset--;
1314
    /* loop through the comma separated array elements */
1315
1.64M
    do {
1316
        /* allocate next item */
1317
1.64M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1318
1.64M
        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.64M
        if (head == NULL) {
1325
            /* start the linked list */
1326
941k
            current_item = head = new_item;
1327
941k
        } else {
1328
            /* add to the end and advance */
1329
698k
            current_item->next = new_item;
1330
698k
            new_item->prev = current_item;
1331
698k
            current_item = new_item;
1332
698k
        }
1333
1334
1.64M
        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.64M
        input_buffer->offset++;
1340
1.64M
        buffer_skip_whitespace(input_buffer);
1341
1.64M
        if (!parse_string(current_item, input_buffer, out_of_memory)) {
1342
192
            goto fail; /* failed to parse name */
1343
192
        }
1344
1.64M
        buffer_skip_whitespace(input_buffer);
1345
1346
        /* swap valuestring and string, because we parsed the name */
1347
1.64M
        current_item->string = current_item->valuestring;
1348
1.64M
        current_item->valuestring = NULL;
1349
1350
1.64M
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) {
1351
36
            goto fail; /* invalid object */
1352
36
        }
1353
1354
        /* parse the value */
1355
1.64M
        input_buffer->offset++;
1356
1.64M
        buffer_skip_whitespace(input_buffer);
1357
1.64M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1358
7.64k
            goto fail; /* failed to parse value */
1359
7.64k
        }
1360
1.63M
        buffer_skip_whitespace(input_buffer);
1361
1.63M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1362
1363
933k
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) {
1364
17
        goto fail; /* expected end of object */
1365
17
    }
1366
1367
7.20M
success:
1368
7.20M
    input_buffer->depth--;
1369
1370
7.20M
    if (head != NULL) {
1371
933k
        head->prev = current_item;
1372
933k
    }
1373
1374
7.20M
    item->type = cJSON_Object;
1375
7.20M
    item->child = head;
1376
1377
7.20M
    input_buffer->offset++;
1378
7.20M
    return true;
1379
1380
7.88k
fail:
1381
7.88k
    if (head != NULL) {
1382
7.88k
        loader_cJSON_Delete(head);
1383
7.88k
    }
1384
1385
7.88k
    return false;
1386
933k
}
1387
1388
/* Render an object to text. */
1389
6.78M
static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1390
6.78M
    unsigned char *output_pointer = NULL;
1391
6.78M
    size_t length = 0;
1392
6.78M
    cJSON *current_item = item->child;
1393
1394
6.78M
    if (output_buffer == NULL) {
1395
0
        return false;
1396
0
    }
1397
1398
6.78M
    if (output_buffer->depth >= CJSON_NESTING_LIMIT) {
1399
0
        return false; /* nesting is too deep */
1400
0
    }
1401
1402
    /* Compose the output: */
1403
6.78M
    length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */
1404
6.78M
    output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1405
6.78M
    if (output_pointer == NULL) {
1406
0
        return false;
1407
0
    }
1408
1409
6.78M
    *output_pointer++ = '{';
1410
6.78M
    output_buffer->depth++;
1411
6.78M
    if (output_buffer->format) {
1412
6.78M
        *output_pointer++ = '\n';
1413
6.78M
    }
1414
6.78M
    output_buffer->offset += length;
1415
1416
8.30M
    while (current_item) {
1417
1.51M
        if (output_buffer->format) {
1418
1.51M
            size_t i;
1419
1.51M
            output_pointer = ensure(output_buffer, output_buffer->depth, out_of_memory);
1420
1.51M
            if (output_pointer == NULL) {
1421
0
                return false;
1422
0
            }
1423
731M
            for (i = 0; i < output_buffer->depth; i++) {
1424
729M
                *output_pointer++ = '\t';
1425
729M
            }
1426
1.51M
            output_buffer->offset += output_buffer->depth;
1427
1.51M
        }
1428
1429
        /* print key */
1430
1.51M
        if (!print_string_ptr((unsigned char *)current_item->string, output_buffer, out_of_memory)) {
1431
0
            return false;
1432
0
        }
1433
1.51M
        update_offset(output_buffer);
1434
1435
1.51M
        length = (size_t)(output_buffer->format ? 2 : 1);
1436
1.51M
        output_pointer = ensure(output_buffer, length, out_of_memory);
1437
1.51M
        if (output_pointer == NULL) {
1438
0
            return false;
1439
0
        }
1440
1.51M
        *output_pointer++ = ':';
1441
1.51M
        if (output_buffer->format) {
1442
1.51M
            *output_pointer++ = '\t';
1443
1.51M
        }
1444
1.51M
        output_buffer->offset += length;
1445
1446
        /* print value */
1447
1.51M
        if (!print_value(current_item, output_buffer, out_of_memory)) {
1448
0
            return false;
1449
0
        }
1450
1.51M
        update_offset(output_buffer);
1451
1452
        /* print comma if not last */
1453
1.51M
        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
1454
1.51M
        output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1455
1.51M
        if (output_pointer == NULL) {
1456
0
            return false;
1457
0
        }
1458
1.51M
        if (current_item->next) {
1459
671k
            *output_pointer++ = ',';
1460
671k
        }
1461
1462
1.51M
        if (output_buffer->format) {
1463
1.51M
            *output_pointer++ = '\n';
1464
1.51M
        }
1465
1.51M
        *output_pointer = '\0';
1466
1.51M
        output_buffer->offset += length;
1467
1468
1.51M
        current_item = current_item->next;
1469
1.51M
    }
1470
1471
6.78M
    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2, out_of_memory);
1472
6.78M
    if (output_pointer == NULL) {
1473
0
        return false;
1474
0
    }
1475
6.78M
    if (output_buffer->format) {
1476
6.78M
        size_t i;
1477
5.37G
        for (i = 0; i < (output_buffer->depth - 1); i++) {
1478
5.37G
            *output_pointer++ = '\t';
1479
5.37G
        }
1480
6.78M
    }
1481
6.78M
    *output_pointer++ = '}';
1482
6.78M
    *output_pointer = '\0';
1483
6.78M
    output_buffer->depth--;
1484
1485
6.78M
    return true;
1486
6.78M
}
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
}