Coverage Report

Created: 2025-12-31 06:56

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 <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
6.69M
#define true ((cJSON_bool)1)
70
71
#ifdef false
72
#undef false
73
#endif
74
2.77M
#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
657k
CJSON_PUBLIC(char *) loader_cJSON_GetStringValue(const cJSON *const item) {
101
657k
    if (!loader_cJSON_IsString(item)) {
102
220k
        return NULL;
103
220k
    }
104
105
437k
    return item->valuestring;
106
657k
}
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
11.5M
static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) {
123
11.5M
    if ((string1 == NULL) || (string2 == NULL)) {
124
1.54k
        return 1;
125
1.54k
    }
126
127
11.5M
    if (string1 == string2) {
128
0
        return 0;
129
0
    }
130
131
23.1M
    for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) {
132
12.6M
        if (*string1 == '\0') {
133
1.08M
            return 0;
134
1.08M
        }
135
12.6M
    }
136
137
10.4M
    return tolower(*string1) - tolower(*string2);
138
11.5M
}
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
3.37M
static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) {
145
3.37M
    cJSON *node = (cJSON *)loader_calloc(pAllocator, sizeof(cJSON), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
146
3.37M
    if (NULL != node) {
147
3.37M
        node->pAllocator = pAllocator;
148
3.37M
    }
149
3.37M
    return node;
150
3.37M
}
151
152
/* Delete a cJSON structure. */
153
961k
TEST_FUNCTION_EXPORT CJSON_PUBLIC(void) loader_cJSON_Delete(cJSON *item) {
154
961k
    cJSON *next = NULL;
155
4.33M
    while (item != NULL) {
156
3.37M
        next = item->next;
157
3.37M
        if (!(item->type & cJSON_IsReference) && (item->child != NULL)) {
158
693k
            loader_cJSON_Delete(item->child);
159
693k
        }
160
3.37M
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) {
161
2.12M
            loader_free(item->pAllocator, item->valuestring);
162
2.12M
            item->valuestring = NULL;
163
2.12M
        }
164
3.37M
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
165
2.07M
            loader_free(item->pAllocator, item->string);
166
2.07M
            item->string = NULL;
167
2.07M
        }
168
3.37M
        loader_free(item->pAllocator, item);
169
3.37M
        item = next;
170
3.37M
    }
171
961k
}
172
173
/* get the decimal point character of the current locale */
174
182k
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
182k
    return '.';
180
182k
#endif
181
182k
}
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
20.2M
#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
136M
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
195
20.8M
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
196
/* get a pointer to the buffer at the position */
197
93.4M
#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
182k
static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) {
201
182k
    double number = 0;
202
182k
    unsigned char *after_end = NULL;
203
182k
    unsigned char number_c_string[64];
204
182k
    unsigned char decimal_point = get_decimal_point();
205
182k
    size_t i = 0;
206
207
182k
    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
1.02M
    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) {
215
1.02M
        switch (buffer_at_offset(input_buffer)[i]) {
216
68.8k
            case '0':
217
121k
            case '1':
218
309k
            case '2':
219
358k
            case '3':
220
639k
            case '4':
221
665k
            case '5':
222
723k
            case '6':
223
763k
            case '7':
224
803k
            case '8':
225
836k
            case '9':
226
837k
            case '+':
227
841k
            case '-':
228
844k
            case 'e':
229
844k
            case 'E':
230
844k
                number_c_string[i] = buffer_at_offset(input_buffer)[i];
231
844k
                break;
232
233
1.14k
            case '.':
234
1.14k
                number_c_string[i] = decimal_point;
235
1.14k
                break;
236
237
182k
            default:
238
182k
                goto loop_end;
239
1.02M
        }
240
1.02M
    }
241
182k
loop_end:
242
182k
    number_c_string[i] = '\0';
243
244
182k
    number = strtod((const char *)number_c_string, (char **)&after_end);
245
182k
    if (number_c_string == after_end) {
246
102
        return false; /* parse_error */
247
102
    }
248
249
182k
    item->valuedouble = number;
250
251
    /* use saturation in case of overflow */
252
182k
    if (number >= INT_MAX) {
253
27.1k
        item->valueint = INT_MAX;
254
155k
    } else if (number <= (double)INT_MIN) {
255
534
        item->valueint = INT_MIN;
256
155k
    } else {
257
155k
        item->valueint = (int)number;
258
155k
    }
259
260
182k
    item->type = cJSON_Number;
261
262
182k
    input_buffer->offset += (size_t)(after_end - number_c_string);
263
182k
    return true;
264
182k
}
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
752k
static unsigned char *ensure(printbuffer *const p, size_t needed, bool *out_of_memory) {
278
752k
    unsigned char *newbuffer = NULL;
279
752k
    size_t newsize = 0;
280
281
752k
    if ((p == NULL) || (p->buffer == NULL)) {
282
0
        return NULL;
283
0
    }
284
285
752k
    if ((p->length > 0) && (p->offset >= p->length)) {
286
        /* make sure that offset is valid */
287
0
        return NULL;
288
0
    }
289
290
752k
    if (needed > INT_MAX) {
291
        /* sizes bigger than INT_MAX are currently not supported */
292
0
        return NULL;
293
0
    }
294
295
752k
    needed += p->offset + 1;
296
752k
    if (needed <= p->length) {
297
749k
        return p->buffer + p->offset;
298
749k
    }
299
300
2.98k
    if (p->noalloc) {
301
488
        return NULL;
302
488
    }
303
304
    /* calculate new buffer size */
305
2.49k
    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
2.49k
    } else {
313
2.49k
        newsize = needed * 2;
314
2.49k
    }
315
316
2.49k
    newbuffer = (unsigned char *)loader_realloc(p->pAllocator, p->buffer, p->length, newsize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
317
2.49k
    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
2.49k
    p->length = newsize;
327
2.49k
    p->buffer = newbuffer;
328
329
2.49k
    return newbuffer + p->offset;
330
2.49k
}
331
332
/* calculate the new length of the string in a printbuffer and update the offset */
333
388k
static void update_offset(printbuffer *const buffer) {
334
388k
    const unsigned char *buffer_pointer = NULL;
335
388k
    if ((buffer == NULL) || (buffer->buffer == NULL)) {
336
0
        return;
337
0
    }
338
388k
    buffer_pointer = buffer->buffer + buffer->offset;
339
340
388k
    buffer->offset += strlen((const char *)buffer_pointer);
341
388k
}
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
319k
static unsigned parse_hex4(const unsigned char *const input) {
409
319k
    unsigned int h = 0;
410
319k
    size_t i = 0;
411
412
730k
    for (i = 0; i < 4; i++) {
413
        /* parse digit */
414
689k
        if ((input[i] >= '0') && (input[i] <= '9')) {
415
109k
            h += (unsigned int)input[i] - '0';
416
580k
        } else if ((input[i] >= 'A') && (input[i] <= 'F')) {
417
128k
            h += (unsigned int)10 + input[i] - 'A';
418
451k
        } else if ((input[i] >= 'a') && (input[i] <= 'f')) {
419
173k
            h += (unsigned int)10 + input[i] - 'a';
420
173k
        } else /* invalid */
421
278k
        {
422
278k
            return 0;
423
278k
        }
424
425
411k
        if (i < 3) {
426
            /* shift left to make place for the next nibble */
427
370k
            h = h << 4;
428
370k
        }
429
411k
    }
430
431
41.0k
    return h;
432
319k
}
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
314k
                                           unsigned char **output_pointer) {
438
314k
    long unsigned int codepoint = 0;
439
314k
    unsigned int first_code = 0;
440
314k
    const unsigned char *first_sequence = input_pointer;
441
314k
    unsigned char utf8_length = 0;
442
314k
    unsigned char utf8_position = 0;
443
314k
    unsigned char sequence_length = 0;
444
314k
    unsigned char first_byte_mark = 0;
445
446
314k
    if ((input_end - first_sequence) < 6) {
447
        /* input ends unexpectedly */
448
80
        goto fail;
449
80
    }
450
451
    /* get the first utf16 sequence */
452
314k
    first_code = parse_hex4(first_sequence + 2);
453
454
    /* check that the code is valid */
455
314k
    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) {
456
95
        goto fail;
457
95
    }
458
459
    /* UTF16 surrogate pair */
460
313k
    if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) {
461
6.12k
        const unsigned char *second_sequence = first_sequence + 6;
462
6.12k
        unsigned int second_code = 0;
463
6.12k
        sequence_length = 12; /* \uXXXX\uXXXX */
464
465
6.12k
        if ((input_end - second_sequence) < 6) {
466
            /* input ends unexpectedly */
467
33
            goto fail;
468
33
        }
469
470
6.08k
        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) {
471
            /* missing second half of the surrogate pair */
472
572
            goto fail;
473
572
        }
474
475
        /* get the second utf16 sequence */
476
5.51k
        second_code = parse_hex4(second_sequence + 2);
477
        /* check that the code is valid */
478
5.51k
        if ((second_code < 0xDC00) || (second_code > 0xDFFF)) {
479
            /* invalid second half of the surrogate pair */
480
189
            goto fail;
481
189
        }
482
483
        /* calculate the unicode codepoint from the surrogate pair */
484
5.32k
        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
485
307k
    } else {
486
307k
        sequence_length = 6; /* \uXXXX */
487
307k
        codepoint = first_code;
488
307k
    }
489
490
    /* encode as UTF-8
491
     * takes at maximum 4 bytes to encode:
492
     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
493
313k
    if (codepoint < 0x80) {
494
        /* normal ascii, encoding 0xxxxxxx */
495
278k
        utf8_length = 1;
496
278k
    } else if (codepoint < 0x800) {
497
        /* two bytes, encoding 110xxxxx 10xxxxxx */
498
354
        utf8_length = 2;
499
354
        first_byte_mark = 0xC0; /* 11000000 */
500
34.2k
    } else if (codepoint < 0x10000) {
501
        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
502
28.9k
        utf8_length = 3;
503
28.9k
        first_byte_mark = 0xE0; /* 11100000 */
504
28.9k
    } else if (codepoint <= 0x10FFFF) {
505
        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
506
5.32k
        utf8_length = 4;
507
5.32k
        first_byte_mark = 0xF0; /* 11110000 */
508
5.32k
    } else {
509
        /* invalid unicode codepoint */
510
0
        goto fail;
511
0
    }
512
513
    /* encode as utf8 */
514
387k
    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) {
515
        /* 10xxxxxx */
516
74.2k
        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
517
74.2k
        codepoint >>= 6;
518
74.2k
    }
519
    /* encode first byte */
520
313k
    if (utf8_length > 1) {
521
34.6k
        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
522
278k
    } else {
523
278k
        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
524
278k
    }
525
526
313k
    *output_pointer += utf8_length;
527
528
313k
    return sequence_length;
529
530
969
fail:
531
969
    return 0;
532
313k
}
533
534
/* Parse the input text into an unescaped cinput, and populate item. */
535
4.20M
static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
536
4.20M
    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
537
4.20M
    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
538
4.20M
    unsigned char *output_pointer = NULL;
539
4.20M
    unsigned char *output = NULL;
540
541
    /* not a string */
542
4.20M
    if (buffer_at_offset(input_buffer)[0] != '\"') {
543
292
        goto fail;
544
292
    }
545
546
4.20M
    {
547
        /* calculate approximate size of the output (overestimate) */
548
4.20M
        size_t allocation_length = 0;
549
4.20M
        size_t skipped_bytes = 0;
550
244M
        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) {
551
            /* is escape sequence */
552
240M
            if (input_end[0] == '\\') {
553
524k
                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
524k
                skipped_bytes++;
558
524k
                input_end++;
559
524k
            }
560
240M
            input_end++;
561
240M
        }
562
4.20M
        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) {
563
237
            goto fail; /* string ended unexpectedly */
564
237
        }
565
566
        /* This is at most how much we need for the output */
567
4.20M
        allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
568
4.20M
        output = (unsigned char *)loader_calloc(input_buffer->pAllocator, allocation_length + sizeof(""),
569
4.20M
                                                VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
570
4.20M
        if (output == NULL) {
571
0
            *out_of_memory = true;
572
0
            goto fail; /* allocation failure */
573
0
        }
574
4.20M
    }
575
576
4.20M
    output_pointer = output;
577
    /* loop through the string literal */
578
194M
    while (input_pointer < input_end) {
579
190M
        if (*input_pointer != '\\') {
580
189M
            *output_pointer++ = *input_pointer++;
581
189M
        }
582
        /* escape sequence */
583
453k
        else {
584
453k
            unsigned char sequence_length = 2;
585
453k
            if ((input_end - input_pointer) < 1) {
586
0
                goto fail;
587
0
            }
588
589
453k
            switch (input_pointer[1]) {
590
1.41k
                case 'b':
591
1.41k
                    *output_pointer++ = '\b';
592
1.41k
                    break;
593
533
                case 'f':
594
533
                    *output_pointer++ = '\f';
595
533
                    break;
596
36.0k
                case 'n':
597
36.0k
                    *output_pointer++ = '\n';
598
36.0k
                    break;
599
2.67k
                case 'r':
600
2.67k
                    *output_pointer++ = '\r';
601
2.67k
                    break;
602
458
                case 't':
603
458
                    *output_pointer++ = '\t';
604
458
                    break;
605
545
                case '\"':
606
96.0k
                case '\\':
607
98.4k
                case '/':
608
98.4k
                    *output_pointer++ = input_pointer[1];
609
98.4k
                    break;
610
611
                /* UTF-16 literal */
612
314k
                case 'u':
613
314k
                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
614
314k
                    if (sequence_length == 0) {
615
                        /* failed to convert UTF16-literal to UTF-8 */
616
969
                        goto fail;
617
969
                    }
618
313k
                    break;
619
620
313k
                default:
621
179
                    goto fail;
622
453k
            }
623
452k
            input_pointer += sequence_length;
624
452k
        }
625
190M
    }
626
627
    /* zero terminate the output */
628
4.20M
    *output_pointer = '\0';
629
630
4.20M
    item->type = cJSON_String;
631
4.20M
    item->valuestring = (char *)output;
632
633
4.20M
    input_buffer->offset = (size_t)(input_end - input_buffer->content);
634
4.20M
    input_buffer->offset++;
635
636
4.20M
    return true;
637
638
1.67k
fail:
639
1.67k
    if (output != NULL) {
640
1.14k
        loader_free(input_buffer->pAllocator, output);
641
1.14k
        output = NULL;
642
1.14k
    }
643
644
1.67k
    if (input_pointer != NULL) {
645
1.67k
        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
646
1.67k
    }
647
648
1.67k
    return false;
649
4.20M
}
650
651
/* Render the cstring provided to an escaped version that can be printed. */
652
752k
static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer, bool *out_of_memory) {
653
752k
    const unsigned char *input_pointer = NULL;
654
752k
    unsigned char *output = NULL;
655
752k
    unsigned char *output_pointer = NULL;
656
752k
    size_t output_length = 0;
657
    /* numbers of additional characters needed for escaping */
658
752k
    size_t escape_characters = 0;
659
660
752k
    if (output_buffer == NULL) {
661
0
        return false;
662
0
    }
663
664
    /* empty string */
665
752k
    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
64.2M
    for (input_pointer = input; *input_pointer; input_pointer++) {
676
63.4M
        switch (*input_pointer) {
677
109
            case '\"':
678
17.2k
            case '\\':
679
20.6k
            case '\b':
680
455k
            case '\f':
681
459k
            case '\n':
682
529k
            case '\r':
683
540k
            case '\t':
684
                /* one character escape sequence */
685
540k
                escape_characters++;
686
540k
                break;
687
62.9M
            default:
688
62.9M
                if (*input_pointer < 32) {
689
                    /* UTF-16 escape sequence uXXXX */
690
34.2M
                    escape_characters += 5;
691
34.2M
                }
692
62.9M
                break;
693
63.4M
        }
694
63.4M
    }
695
752k
    output_length = (size_t)(input_pointer - input) + escape_characters;
696
697
752k
    output = ensure(output_buffer, output_length + sizeof(""), out_of_memory);
698
752k
    if (output == NULL) {
699
488
        return false;
700
488
    }
701
702
    /* no characters have to be escaped */
703
751k
    if (escape_characters == 0) {
704
574k
        memcpy(output, input, output_length);
705
574k
        output[output_length] = '\0';
706
707
574k
        return true;
708
574k
    }
709
710
177k
    output_pointer = output;
711
    /* copy the string */
712
52.1M
    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) {
713
52.0M
        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) {
714
            /* normal character, copy */
715
17.2M
            *output_pointer = *input_pointer;
716
34.7M
        } 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
34.7M
            switch (*input_pointer) {
723
17.0k
                case '\\':
724
17.0k
                    *output_pointer = '\\';
725
17.0k
                    break;
726
109
                case '\"':
727
109
                    *output_pointer = '\"';
728
109
                    break;
729
3.39k
                case '\b':
730
3.39k
                    *output_pointer = '\b';
731
3.39k
                    break;
732
434k
                case '\f':
733
434k
                    *output_pointer = '\f';
734
434k
                    break;
735
3.73k
                case '\n':
736
3.73k
                    *output_pointer = '\n';
737
3.73k
                    break;
738
70.4k
                case '\r':
739
70.4k
                    *output_pointer = '\r';
740
70.4k
                    break;
741
9.93k
                case '\t':
742
9.93k
                    *output_pointer = '\t';
743
9.93k
                    break;
744
34.2M
                default:
745
                    /* escape and print as unicode codepoint */
746
34.2M
                    snprintf((char *)output_pointer, output_length - (size_t)(output_pointer - output), "u%04x", *input_pointer);
747
34.2M
                    output_pointer += 4;
748
34.2M
                    break;
749
34.7M
            }
750
34.7M
        }
751
52.0M
    }
752
177k
    output[output_length] = '\0';
753
754
177k
    return true;
755
177k
}
756
757
/* Invoke print_string_ptr (which is useful) on an item. */
758
752k
static cJSON_bool print_string(const cJSON *const item, printbuffer *const p, bool *out_of_memory) {
759
752k
    return print_string_ptr((unsigned char *)item->valuestring, p, out_of_memory);
760
752k
}
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
11.5M
static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) {
772
11.5M
    if ((buffer == NULL) || (buffer->content == NULL)) {
773
0
        return NULL;
774
0
    }
775
776
11.5M
    if (cannot_access_at_index(buffer, 0)) {
777
0
        return buffer;
778
0
    }
779
780
48.7M
    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) {
781
37.2M
        buffer->offset++;
782
37.2M
    }
783
784
11.5M
    if (buffer->offset == buffer->length) {
785
5.28k
        buffer->offset--;
786
5.28k
    }
787
788
11.5M
    return buffer;
789
11.5M
}
790
791
/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
792
21.8k
static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) {
793
21.8k
    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) {
794
0
        return NULL;
795
0
    }
796
797
21.8k
    if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) {
798
107
        buffer->offset += 3;
799
107
    }
800
801
21.8k
    return buffer;
802
21.8k
}
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.8k
                                 const char **return_parse_end, cJSON_bool require_null_terminated, bool *out_of_memory) {
824
21.8k
    parse_buffer buffer = {0, 0, 0, 0, 0};
825
21.8k
    cJSON *item = NULL;
826
827
    /* reset error position */
828
21.8k
    global_error.json = NULL;
829
21.8k
    global_error.position = 0;
830
831
21.8k
    if (value == NULL || 0 == buffer_length) {
832
0
        goto fail;
833
0
    }
834
835
21.8k
    buffer.content = (const unsigned char *)value;
836
21.8k
    buffer.length = buffer_length;
837
21.8k
    buffer.offset = 0;
838
21.8k
    buffer.pAllocator = pAllocator;
839
840
21.8k
    item = cJSON_New_Item(pAllocator);
841
21.8k
    if (item == NULL) /* memory fail */
842
0
    {
843
0
        *out_of_memory = true;
844
0
        goto fail;
845
0
    }
846
847
21.8k
    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)), out_of_memory)) {
848
        /* parse failure. ep is set. */
849
8.45k
        goto fail;
850
8.45k
    }
851
852
    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
853
13.4k
    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
13.4k
    if (return_parse_end) {
860
0
        *return_parse_end = (const char *)buffer_at_offset(&buffer);
861
0
    }
862
863
13.4k
    return item;
864
865
8.45k
fail:
866
8.45k
    if (item != NULL) {
867
8.45k
        loader_cJSON_Delete(item);
868
8.45k
    }
869
870
8.45k
    if (value != NULL) {
871
8.45k
        error local_error;
872
8.45k
        local_error.json = (const unsigned char *)value;
873
8.45k
        local_error.position = 0;
874
875
8.45k
        if (buffer.offset < buffer.length) {
876
8.24k
            local_error.position = buffer.offset;
877
8.24k
        } else if (buffer.length > 0) {
878
212
            local_error.position = buffer.length - 1;
879
212
        }
880
881
8.45k
        if (return_parse_end != NULL) {
882
0
            *return_parse_end = (const char *)local_error.json + local_error.position;
883
0
        }
884
885
8.45k
        global_error = local_error;
886
8.45k
    }
887
888
8.45k
    return NULL;
889
13.4k
}
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.8k
                             bool *out_of_memory) {
899
21.8k
    return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, 0, 0, out_of_memory);
900
21.8k
}
901
902
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
903
904
388k
static unsigned char *print(const cJSON *const item, cJSON_bool format, bool *out_of_memory) {
905
388k
    static const size_t default_buffer_size = 256;
906
388k
    printbuffer buffer[1];
907
388k
    unsigned char *printed = NULL;
908
909
388k
    memset(buffer, 0, sizeof(buffer));
910
911
    /* create buffer */
912
388k
    buffer->buffer = (unsigned char *)loader_calloc(item->pAllocator, default_buffer_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
913
388k
    buffer->length = default_buffer_size;
914
388k
    buffer->format = format;
915
388k
    buffer->pAllocator = item->pAllocator;
916
388k
    if (buffer->buffer == NULL) {
917
0
        *out_of_memory = true;
918
0
        goto fail;
919
0
    }
920
921
    /* print the value */
922
388k
    if (!print_value(item, buffer, out_of_memory)) {
923
0
        goto fail;
924
0
    }
925
388k
    update_offset(buffer);
926
927
388k
    printed = (unsigned char *)loader_realloc(item->pAllocator, buffer->buffer, buffer->length, buffer->offset + 1,
928
388k
                                              VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
929
388k
    if (printed == NULL) {
930
0
        *out_of_memory = true;
931
0
        goto fail;
932
0
    }
933
388k
    buffer->buffer = NULL;
934
935
388k
    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
388k
}
950
951
/* Render a cJSON item/entity/structure to text. */
952
388k
TEST_FUNCTION_EXPORT CJSON_PUBLIC(char *) loader_cJSON_Print(const cJSON *item, bool *out_of_memory) {
953
388k
    return (char *)print(item, true, out_of_memory);
954
388k
}
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
363k
loader_cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) {
990
363k
    printbuffer p = {0, 0, 0, 0, 0, 0, 0};
991
992
363k
    if ((length < 0) || (buffer == NULL)) {
993
0
        return false;
994
0
    }
995
996
363k
    p.buffer = (unsigned char *)buffer;
997
363k
    p.length = (size_t)length;
998
363k
    p.offset = 0;
999
363k
    p.noalloc = true;
1000
363k
    p.format = format;
1001
363k
    p.pAllocator = item->pAllocator;
1002
363k
    bool out_of_memory = false;
1003
363k
    return print_value(item, &p, &out_of_memory);
1004
363k
}
1005
1006
/* Parser core - when encountering text, process appropriately. */
1007
3.37M
static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1008
3.37M
    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
3.37M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) {
1015
509
        item->type = cJSON_NULL;
1016
509
        input_buffer->offset += 4;
1017
509
        return true;
1018
509
    }
1019
    /* false */
1020
3.37M
    if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) {
1021
231
        item->type = cJSON_False;
1022
231
        input_buffer->offset += 5;
1023
231
        return true;
1024
231
    }
1025
    /* true */
1026
3.37M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) {
1027
99.3k
        item->type = cJSON_True;
1028
99.3k
        item->valueint = 1;
1029
99.3k
        input_buffer->offset += 4;
1030
99.3k
        return true;
1031
99.3k
    }
1032
    /* string */
1033
3.27M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) {
1034
2.12M
        return parse_string(item, input_buffer, out_of_memory);
1035
2.12M
    }
1036
    /* number */
1037
1.14M
    if (can_access_at_index(input_buffer, 0) &&
1038
1.14M
        ((buffer_at_offset(input_buffer)[0] == '-') ||
1039
1.14M
         ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) {
1040
182k
        return parse_number(item, input_buffer);
1041
182k
    }
1042
    /* array */
1043
960k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) {
1044
568k
        return parse_array(item, input_buffer, out_of_memory);
1045
568k
    }
1046
    /* object */
1047
391k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) {
1048
385k
        return parse_object(item, input_buffer, out_of_memory);
1049
385k
    }
1050
1051
5.92k
    return false;
1052
391k
}
1053
1054
/* Render a value to text. */
1055
752k
static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1056
752k
    unsigned char *output = NULL;
1057
1058
752k
    if ((item == NULL) || (output_buffer == NULL)) {
1059
0
        return false;
1060
0
    }
1061
1062
752k
    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
752k
        case cJSON_String:
1106
752k
            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
752k
    }
1117
752k
}
1118
1119
/* Build an array from input text. */
1120
568k
static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1121
568k
    cJSON *head = NULL; /* head of the linked list */
1122
568k
    cJSON *current_item = NULL;
1123
1124
568k
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1125
143
        return false; /* to deeply nested */
1126
143
    }
1127
568k
    input_buffer->depth++;
1128
1129
568k
    if (buffer_at_offset(input_buffer)[0] != '[') {
1130
        /* not an array */
1131
0
        goto fail;
1132
0
    }
1133
1134
568k
    input_buffer->offset++;
1135
568k
    buffer_skip_whitespace(input_buffer);
1136
568k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) {
1137
        /* empty array */
1138
6.91k
        goto success;
1139
6.91k
    }
1140
1141
    /* check if we skipped to the end of the buffer */
1142
561k
    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
561k
    input_buffer->offset--;
1149
    /* loop through the comma separated array elements */
1150
1.27M
    do {
1151
        /* allocate next item */
1152
1.27M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1153
1.27M
        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
1.27M
        if (head == NULL) {
1160
            /* start the linked list */
1161
561k
            current_item = head = new_item;
1162
716k
        } else {
1163
            /* add to the end and advance */
1164
716k
            current_item->next = new_item;
1165
716k
            new_item->prev = current_item;
1166
716k
            current_item = new_item;
1167
716k
        }
1168
1169
        /* parse next value */
1170
1.27M
        input_buffer->offset++;
1171
1.27M
        buffer_skip_whitespace(input_buffer);
1172
1.27M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1173
243k
            goto fail; /* failed to parse value */
1174
243k
        }
1175
1.03M
        buffer_skip_whitespace(input_buffer);
1176
1.03M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1177
1178
318k
    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') {
1179
332
        goto fail; /* expected end of array */
1180
332
    }
1181
1182
324k
success:
1183
324k
    input_buffer->depth--;
1184
1185
324k
    if (head != NULL) {
1186
317k
        head->prev = current_item;
1187
317k
    }
1188
1189
324k
    item->type = cJSON_Array;
1190
324k
    item->child = head;
1191
1192
324k
    input_buffer->offset++;
1193
1194
324k
    return true;
1195
1196
243k
fail:
1197
243k
    if (head != NULL) {
1198
243k
        loader_cJSON_Delete(head);
1199
243k
    }
1200
1201
243k
    return false;
1202
318k
}
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
385k
static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1259
385k
    cJSON *head = NULL; /* linked list head */
1260
385k
    cJSON *current_item = NULL;
1261
1262
385k
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1263
64
        return false; /* to deeply nested */
1264
64
    }
1265
385k
    input_buffer->depth++;
1266
1267
385k
    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
385k
    input_buffer->offset++;
1272
385k
    buffer_skip_whitespace(input_buffer);
1273
385k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) {
1274
7.87k
        goto success; /* empty object */
1275
7.87k
    }
1276
1277
    /* check if we skipped to the end of the buffer */
1278
377k
    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
377k
    input_buffer->offset--;
1285
    /* loop through the comma separated array elements */
1286
2.07M
    do {
1287
        /* allocate next item */
1288
2.07M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1289
2.07M
        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.07M
        if (head == NULL) {
1296
            /* start the linked list */
1297
377k
            current_item = head = new_item;
1298
1.69M
        } else {
1299
            /* add to the end and advance */
1300
1.69M
            current_item->next = new_item;
1301
1.69M
            new_item->prev = current_item;
1302
1.69M
            current_item = new_item;
1303
1.69M
        }
1304
1305
2.07M
        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.07M
        input_buffer->offset++;
1311
2.07M
        buffer_skip_whitespace(input_buffer);
1312
2.07M
        if (!parse_string(current_item, input_buffer, out_of_memory)) {
1313
850
            goto fail; /* failed to parse name */
1314
850
        }
1315
2.07M
        buffer_skip_whitespace(input_buffer);
1316
1317
        /* swap valuestring and string, because we parsed the name */
1318
2.07M
        current_item->string = current_item->valuestring;
1319
2.07M
        current_item->valuestring = NULL;
1320
1321
2.07M
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) {
1322
97
            goto fail; /* invalid object */
1323
97
        }
1324
1325
        /* parse the value */
1326
2.07M
        input_buffer->offset++;
1327
2.07M
        buffer_skip_whitespace(input_buffer);
1328
2.07M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1329
1.23k
            goto fail; /* failed to parse value */
1330
1.23k
        }
1331
2.07M
        buffer_skip_whitespace(input_buffer);
1332
2.07M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1333
1334
375k
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) {
1335
111
        goto fail; /* expected end of object */
1336
111
    }
1337
1338
383k
success:
1339
383k
    input_buffer->depth--;
1340
1341
383k
    if (head != NULL) {
1342
375k
        head->prev = current_item;
1343
375k
    }
1344
1345
383k
    item->type = cJSON_Object;
1346
383k
    item->child = head;
1347
1348
383k
    input_buffer->offset++;
1349
383k
    return true;
1350
1351
2.28k
fail:
1352
2.28k
    if (head != NULL) {
1353
2.28k
        loader_cJSON_Delete(head);
1354
2.28k
    }
1355
1356
2.28k
    return false;
1357
375k
}
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
108k
CJSON_PUBLIC(int) loader_cJSON_GetArraySize(const cJSON *array) {
1457
108k
    cJSON *child = NULL;
1458
108k
    size_t size = 0;
1459
1460
108k
    if (array == NULL) {
1461
0
        return 0;
1462
0
    }
1463
1464
108k
    child = array->child;
1465
1466
490k
    while (child != NULL) {
1467
381k
        size++;
1468
381k
        child = child->next;
1469
381k
    }
1470
1471
    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1472
1473
108k
    return (int)size;
1474
108k
}
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
1.93M
static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) {
1501
1.93M
    cJSON *current_element = NULL;
1502
1503
1.93M
    if ((object == NULL) || (name == NULL)) {
1504
0
        return NULL;
1505
0
    }
1506
1507
1.93M
    current_element = object->child;
1508
1.93M
    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
1.93M
    } else {
1513
12.4M
        while ((current_element != NULL) &&
1514
11.5M
               (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0)) {
1515
10.4M
            current_element = current_element->next;
1516
10.4M
        }
1517
1.93M
    }
1518
1519
1.93M
    if ((current_element == NULL) || (current_element->string == NULL)) {
1520
851k
        return NULL;
1521
851k
    }
1522
1523
1.08M
    return current_element;
1524
1.93M
}
1525
1526
1.93M
CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItem(const cJSON *const object, const char *const string) {
1527
1.93M
    return get_object_item(object, string, false);
1528
1.93M
}
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
657k
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsString(const cJSON *const item) {
1670
657k
    if (item == NULL) {
1671
219k
        return false;
1672
219k
    }
1673
1674
437k
    return (item->type & 0xFF) == cJSON_String;
1675
657k
}
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
}