Coverage Report

Created: 2026-02-26 06:46

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