Coverage Report

Created: 2025-08-29 06:28

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