Coverage Report

Created: 2026-05-30 06:40

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
7.45M
#define true ((cJSON_bool)1)
68
69
#ifdef false
70
#undef false
71
#endif
72
1.92M
#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
586k
CJSON_PUBLIC(char *) loader_cJSON_GetStringValue(const cJSON *const item) {
99
586k
    if (!loader_cJSON_IsString(item)) {
100
263k
        return NULL;
101
263k
    }
102
103
323k
    return item->valuestring;
104
586k
}
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
4.16M
static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) {
121
4.16M
    if ((string1 == NULL) || (string2 == NULL)) {
122
339
        return 1;
123
339
    }
124
125
4.16M
    if (string1 == string2) {
126
0
        return 0;
127
0
    }
128
129
9.23M
    for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) {
130
5.82M
        if (*string1 == '\0') {
131
759k
            return 0;
132
759k
        }
133
5.82M
    }
134
135
3.40M
    return tolower(*string1) - tolower(*string2);
136
4.16M
}
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
4.20M
static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) {
143
4.20M
    cJSON *node = (cJSON *)loader_calloc(pAllocator, sizeof(cJSON), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
144
4.20M
    if (NULL != node) {
145
4.20M
        node->pAllocator = pAllocator;
146
4.20M
    }
147
4.20M
    return node;
148
4.20M
}
149
150
/* Delete a cJSON structure. */
151
824k
TEST_FUNCTION_EXPORT CJSON_PUBLIC(void) loader_cJSON_Delete(cJSON *item) {
152
824k
    cJSON *next = NULL;
153
5.03M
    while (item != NULL) {
154
4.20M
        next = item->next;
155
4.20M
        if (!(item->type & cJSON_IsReference) && (item->child != NULL)) {
156
730k
            loader_cJSON_Delete(item->child);
157
730k
        }
158
4.20M
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) {
159
2.38M
            loader_free(item->pAllocator, item->valuestring);
160
2.38M
            item->valuestring = NULL;
161
2.38M
        }
162
4.20M
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
163
1.64M
            loader_free(item->pAllocator, item->string);
164
1.64M
            item->string = NULL;
165
1.64M
        }
166
4.20M
        loader_free(item->pAllocator, item);
167
4.20M
        item = next;
168
4.20M
    }
169
824k
}
170
171
/* get the decimal point character of the current locale */
172
952k
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
952k
    return '.';
178
952k
#endif
179
952k
}
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
25.2M
#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
92.3M
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
193
20.9M
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
194
/* get a pointer to the buffer at the position */
195
75.7M
#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
952k
static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) {
199
952k
    double number = 0;
200
952k
    unsigned char *after_end = NULL;
201
952k
    unsigned char number_c_string[64];
202
952k
    unsigned char decimal_point = get_decimal_point();
203
952k
    size_t i = 0;
204
205
952k
    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
2.71M
    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) {
213
2.71M
        switch (buffer_at_offset(input_buffer)[i]) {
214
134k
            case '0':
215
1.01M
            case '1':
216
1.16M
            case '2':
217
1.24M
            case '3':
218
1.34M
            case '4':
219
1.40M
            case '5':
220
1.47M
            case '6':
221
1.59M
            case '7':
222
1.63M
            case '8':
223
1.71M
            case '9':
224
1.71M
            case '+':
225
1.73M
            case '-':
226
1.74M
            case 'e':
227
1.75M
            case 'E':
228
1.75M
                number_c_string[i] = buffer_at_offset(input_buffer)[i];
229
1.75M
                break;
230
231
16.9k
            case '.':
232
16.9k
                number_c_string[i] = decimal_point;
233
16.9k
                break;
234
235
951k
            default:
236
951k
                goto loop_end;
237
2.71M
        }
238
2.71M
    }
239
952k
loop_end:
240
952k
    number_c_string[i] = '\0';
241
242
952k
    number = strtod((const char *)number_c_string, (char **)&after_end);
243
952k
    if (number_c_string == after_end) {
244
54
        return false; /* parse_error */
245
54
    }
246
247
952k
    item->valuedouble = number;
248
249
    /* use saturation in case of overflow */
250
952k
    if (number >= INT_MAX) {
251
16.8k
        item->valueint = INT_MAX;
252
935k
    } else if (number <= (double)INT_MIN) {
253
2.26k
        item->valueint = INT_MIN;
254
932k
    } else {
255
932k
        item->valueint = (int)number;
256
932k
    }
257
258
952k
    item->type = cJSON_Number;
259
260
952k
    input_buffer->offset += (size_t)(after_end - number_c_string);
261
952k
    return true;
262
952k
}
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
843k
static unsigned char *ensure(printbuffer *const p, size_t needed, bool *out_of_memory) {
276
843k
    unsigned char *newbuffer = NULL;
277
843k
    size_t newsize = 0;
278
279
843k
    if ((p == NULL) || (p->buffer == NULL)) {
280
0
        return NULL;
281
0
    }
282
283
843k
    if ((p->length > 0) && (p->offset >= p->length)) {
284
        /* make sure that offset is valid */
285
0
        return NULL;
286
0
    }
287
288
843k
    if (needed > INT_MAX) {
289
        /* sizes bigger than INT_MAX are currently not supported */
290
0
        return NULL;
291
0
    }
292
293
843k
    needed += p->offset + 1;
294
843k
    if (needed <= p->length) {
295
838k
        return p->buffer + p->offset;
296
838k
    }
297
298
5.01k
    if (p->noalloc) {
299
987
        return NULL;
300
987
    }
301
302
    /* calculate new buffer size */
303
4.03k
    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
4.03k
    } else {
311
4.03k
        newsize = needed * 2;
312
4.03k
    }
313
314
4.03k
    newbuffer = (unsigned char *)loader_realloc(p->pAllocator, p->buffer, p->length, newsize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
315
4.03k
    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
4.03k
    p->length = newsize;
325
4.03k
    p->buffer = newbuffer;
326
327
4.03k
    return newbuffer + p->offset;
328
4.03k
}
329
330
/* calculate the new length of the string in a printbuffer and update the offset */
331
527k
static void update_offset(printbuffer *const buffer) {
332
527k
    const unsigned char *buffer_pointer = NULL;
333
527k
    if ((buffer == NULL) || (buffer->buffer == NULL)) {
334
0
        return;
335
0
    }
336
527k
    buffer_pointer = buffer->buffer + buffer->offset;
337
338
527k
    buffer->offset += strlen((const char *)buffer_pointer);
339
527k
}
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
187k
static unsigned parse_hex4(const unsigned char *const input) {
407
187k
    unsigned int h = 0;
408
187k
    size_t i = 0;
409
410
486k
    for (i = 0; i < 4; i++) {
411
        /* parse digit */
412
450k
        if ((input[i] >= '0') && (input[i] <= '9')) {
413
120k
            h += (unsigned int)input[i] - '0';
414
329k
        } else if ((input[i] >= 'A') && (input[i] <= 'F')) {
415
74.2k
            h += (unsigned int)10 + input[i] - 'A';
416
255k
        } else if ((input[i] >= 'a') && (input[i] <= 'f')) {
417
104k
            h += (unsigned int)10 + input[i] - 'a';
418
104k
        } else /* invalid */
419
151k
        {
420
151k
            return 0;
421
151k
        }
422
423
299k
        if (i < 3) {
424
            /* shift left to make place for the next nibble */
425
263k
            h = h << 4;
426
263k
        }
427
299k
    }
428
429
36.2k
    return h;
430
187k
}
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
185k
                                           unsigned char **output_pointer) {
436
185k
    long unsigned int codepoint = 0;
437
185k
    unsigned int first_code = 0;
438
185k
    const unsigned char *first_sequence = input_pointer;
439
185k
    unsigned char utf8_length = 0;
440
185k
    unsigned char utf8_position = 0;
441
185k
    unsigned char sequence_length = 0;
442
185k
    unsigned char first_byte_mark = 0;
443
444
185k
    if ((input_end - first_sequence) < 6) {
445
        /* input ends unexpectedly */
446
5
        goto fail;
447
5
    }
448
449
    /* get the first utf16 sequence */
450
185k
    first_code = parse_hex4(first_sequence + 2);
451
452
    /* check that the code is valid */
453
185k
    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) {
454
43
        goto fail;
455
43
    }
456
457
    /* UTF16 surrogate pair */
458
185k
    if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) {
459
2.24k
        const unsigned char *second_sequence = first_sequence + 6;
460
2.24k
        unsigned int second_code = 0;
461
2.24k
        sequence_length = 12; /* \uXXXX\uXXXX */
462
463
2.24k
        if ((input_end - second_sequence) < 6) {
464
            /* input ends unexpectedly */
465
146
            goto fail;
466
146
        }
467
468
2.09k
        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) {
469
            /* missing second half of the surrogate pair */
470
66
            goto fail;
471
66
        }
472
473
        /* get the second utf16 sequence */
474
2.03k
        second_code = parse_hex4(second_sequence + 2);
475
        /* check that the code is valid */
476
2.03k
        if ((second_code < 0xDC00) || (second_code > 0xDFFF)) {
477
            /* invalid second half of the surrogate pair */
478
436
            goto fail;
479
436
        }
480
481
        /* calculate the unicode codepoint from the surrogate pair */
482
1.59k
        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
483
183k
    } else {
484
183k
        sequence_length = 6; /* \uXXXX */
485
183k
        codepoint = first_code;
486
183k
    }
487
488
    /* encode as UTF-8
489
     * takes at maximum 4 bytes to encode:
490
     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
491
184k
    if (codepoint < 0x80) {
492
        /* normal ascii, encoding 0xxxxxxx */
493
151k
        utf8_length = 1;
494
151k
    } else if (codepoint < 0x800) {
495
        /* two bytes, encoding 110xxxxx 10xxxxxx */
496
1.42k
        utf8_length = 2;
497
1.42k
        first_byte_mark = 0xC0; /* 11000000 */
498
32.1k
    } else if (codepoint < 0x10000) {
499
        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
500
30.5k
        utf8_length = 3;
501
30.5k
        first_byte_mark = 0xE0; /* 11100000 */
502
30.5k
    } else if (codepoint <= 0x10FFFF) {
503
        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
504
1.59k
        utf8_length = 4;
505
1.59k
        first_byte_mark = 0xF0; /* 11110000 */
506
1.59k
    } else {
507
        /* invalid unicode codepoint */
508
0
        goto fail;
509
0
    }
510
511
    /* encode as utf8 */
512
251k
    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) {
513
        /* 10xxxxxx */
514
67.2k
        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
515
67.2k
        codepoint >>= 6;
516
67.2k
    }
517
    /* encode first byte */
518
184k
    if (utf8_length > 1) {
519
33.5k
        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
520
151k
    } else {
521
151k
        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
522
151k
    }
523
524
184k
    *output_pointer += utf8_length;
525
526
184k
    return sequence_length;
527
528
696
fail:
529
696
    return 0;
530
184k
}
531
532
/* Parse the input text into an unescaped cinput, and populate item. */
533
4.02M
static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
534
4.02M
    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
535
4.02M
    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
536
4.02M
    unsigned char *output_pointer = NULL;
537
4.02M
    unsigned char *output = NULL;
538
539
    /* not a string */
540
4.02M
    if (buffer_at_offset(input_buffer)[0] != '\"') {
541
352
        goto fail;
542
352
    }
543
544
4.02M
    {
545
        /* calculate approximate size of the output (overestimate) */
546
4.02M
        size_t allocation_length = 0;
547
4.02M
        size_t skipped_bytes = 0;
548
134M
        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) {
549
            /* is escape sequence */
550
130M
            if (input_end[0] == '\\') {
551
292k
                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
292k
                skipped_bytes++;
556
292k
                input_end++;
557
292k
            }
558
130M
            input_end++;
559
130M
        }
560
4.02M
        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) {
561
184
            goto fail; /* string ended unexpectedly */
562
184
        }
563
564
        /* This is at most how much we need for the output */
565
4.02M
        allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
566
4.02M
        output = (unsigned char *)loader_calloc(input_buffer->pAllocator, allocation_length + sizeof(""),
567
4.02M
                                                VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
568
4.02M
        if (output == NULL) {
569
0
            *out_of_memory = true;
570
0
            goto fail; /* allocation failure */
571
0
        }
572
4.02M
    }
573
574
4.02M
    output_pointer = output;
575
    /* loop through the string literal */
576
123M
    while (input_pointer < input_end) {
577
119M
        if (*input_pointer != '\\') {
578
119M
            *output_pointer++ = *input_pointer++;
579
119M
        }
580
        /* escape sequence */
581
222k
        else {
582
222k
            unsigned char sequence_length = 2;
583
222k
            if ((input_end - input_pointer) < 1) {
584
0
                goto fail;
585
0
            }
586
587
222k
            switch (input_pointer[1]) {
588
492
                case 'b':
589
492
                    *output_pointer++ = '\b';
590
492
                    break;
591
13.1k
                case 'f':
592
13.1k
                    *output_pointer++ = '\f';
593
13.1k
                    break;
594
1.05k
                case 'n':
595
1.05k
                    *output_pointer++ = '\n';
596
1.05k
                    break;
597
687
                case 'r':
598
687
                    *output_pointer++ = '\r';
599
687
                    break;
600
1.18k
                case 't':
601
1.18k
                    *output_pointer++ = '\t';
602
1.18k
                    break;
603
1.40k
                case '\"':
604
20.1k
                case '\\':
605
20.2k
                case '/':
606
20.2k
                    *output_pointer++ = input_pointer[1];
607
20.2k
                    break;
608
609
                /* UTF-16 literal */
610
185k
                case 'u':
611
185k
                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
612
185k
                    if (sequence_length == 0) {
613
                        /* failed to convert UTF16-literal to UTF-8 */
614
696
                        goto fail;
615
696
                    }
616
184k
                    break;
617
618
184k
                default:
619
49
                    goto fail;
620
222k
            }
621
221k
            input_pointer += sequence_length;
622
221k
        }
623
119M
    }
624
625
    /* zero terminate the output */
626
4.02M
    *output_pointer = '\0';
627
628
4.02M
    item->type = cJSON_String;
629
4.02M
    item->valuestring = (char *)output;
630
631
4.02M
    input_buffer->offset = (size_t)(input_end - input_buffer->content);
632
4.02M
    input_buffer->offset++;
633
634
4.02M
    return true;
635
636
1.28k
fail:
637
1.28k
    if (output != NULL) {
638
745
        loader_free(input_buffer->pAllocator, output);
639
745
        output = NULL;
640
745
    }
641
642
1.28k
    if (input_pointer != NULL) {
643
1.28k
        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
644
1.28k
    }
645
646
1.28k
    return false;
647
4.02M
}
648
649
/* Render the cstring provided to an escaped version that can be printed. */
650
843k
static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer, bool *out_of_memory) {
651
843k
    const unsigned char *input_pointer = NULL;
652
843k
    unsigned char *output = NULL;
653
843k
    unsigned char *output_pointer = NULL;
654
843k
    size_t output_length = 0;
655
    /* numbers of additional characters needed for escaping */
656
843k
    size_t escape_characters = 0;
657
658
843k
    if (output_buffer == NULL) {
659
0
        return false;
660
0
    }
661
662
    /* empty string */
663
843k
    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
30.6M
    for (input_pointer = input; *input_pointer; input_pointer++) {
674
29.8M
        switch (*input_pointer) {
675
264
            case '\"':
676
9.83k
            case '\\':
677
13.0k
            case '\b':
678
13.8k
            case '\f':
679
32.2k
            case '\n':
680
34.5k
            case '\r':
681
36.1k
            case '\t':
682
                /* one character escape sequence */
683
36.1k
                escape_characters++;
684
36.1k
                break;
685
29.7M
            default:
686
29.7M
                if (*input_pointer < 32) {
687
                    /* UTF-16 escape sequence uXXXX */
688
24.1M
                    escape_characters += 5;
689
24.1M
                }
690
29.7M
                break;
691
29.8M
        }
692
29.8M
    }
693
843k
    output_length = (size_t)(input_pointer - input) + escape_characters;
694
695
843k
    output = ensure(output_buffer, output_length + sizeof(""), out_of_memory);
696
843k
    if (output == NULL) {
697
987
        return false;
698
987
    }
699
700
    /* no characters have to be escaped */
701
842k
    if (escape_characters == 0) {
702
809k
        memcpy(output, input, output_length);
703
809k
        output[output_length] = '\0';
704
705
809k
        return true;
706
809k
    }
707
708
32.6k
    output_pointer = output;
709
    /* copy the string */
710
25.2M
    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) {
711
25.2M
        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) {
712
            /* normal character, copy */
713
1.27M
            *output_pointer = *input_pointer;
714
23.9M
        } 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
23.9M
            switch (*input_pointer) {
721
9.56k
                case '\\':
722
9.56k
                    *output_pointer = '\\';
723
9.56k
                    break;
724
264
                case '\"':
725
264
                    *output_pointer = '\"';
726
264
                    break;
727
3.23k
                case '\b':
728
3.23k
                    *output_pointer = '\b';
729
3.23k
                    break;
730
813
                case '\f':
731
813
                    *output_pointer = '\f';
732
813
                    break;
733
14.3k
                case '\n':
734
14.3k
                    *output_pointer = '\n';
735
14.3k
                    break;
736
2.34k
                case '\r':
737
2.34k
                    *output_pointer = '\r';
738
2.34k
                    break;
739
1.32k
                case '\t':
740
1.32k
                    *output_pointer = '\t';
741
1.32k
                    break;
742
23.9M
                default:
743
                    /* escape and print as unicode codepoint */
744
23.9M
                    snprintf((char *)output_pointer, output_length - (size_t)(output_pointer - output), "u%04x", *input_pointer);
745
23.9M
                    output_pointer += 4;
746
23.9M
                    break;
747
23.9M
            }
748
23.9M
        }
749
25.2M
    }
750
32.6k
    output[output_length] = '\0';
751
752
32.6k
    return true;
753
32.6k
}
754
755
/* Invoke print_string_ptr (which is useful) on an item. */
756
843k
static cJSON_bool print_string(const cJSON *const item, printbuffer *const p, bool *out_of_memory) {
757
843k
    return print_string_ptr((unsigned char *)item->valuestring, p, out_of_memory);
758
843k
}
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
12.4M
static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) {
770
12.4M
    if ((buffer == NULL) || (buffer->content == NULL)) {
771
0
        return NULL;
772
0
    }
773
774
12.4M
    if (cannot_access_at_index(buffer, 0)) {
775
0
        return buffer;
776
0
    }
777
778
23.3M
    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) {
779
10.9M
        buffer->offset++;
780
10.9M
    }
781
782
12.4M
    if (buffer->offset == buffer->length) {
783
3.97k
        buffer->offset--;
784
3.97k
    }
785
786
12.4M
    return buffer;
787
12.4M
}
788
789
/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
790
20.9k
static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) {
791
20.9k
    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) {
792
0
        return NULL;
793
0
    }
794
795
20.9k
    if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) {
796
338
        buffer->offset += 3;
797
338
    }
798
799
20.9k
    return buffer;
800
20.9k
}
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
20.9k
                                 const char **return_parse_end, cJSON_bool require_null_terminated, bool *out_of_memory) {
822
20.9k
    parse_buffer buffer = {0, 0, 0, 0, 0};
823
20.9k
    cJSON *item = NULL;
824
825
    /* reset error position */
826
    // global_error.json = NULL;
827
    // global_error.position = 0;
828
829
20.9k
    if (value == NULL || 0 == buffer_length) {
830
0
        goto fail;
831
0
    }
832
833
20.9k
    buffer.content = (const unsigned char *)value;
834
20.9k
    buffer.length = buffer_length;
835
20.9k
    buffer.offset = 0;
836
20.9k
    buffer.pAllocator = pAllocator;
837
838
20.9k
    item = cJSON_New_Item(pAllocator);
839
20.9k
    if (item == NULL) /* memory fail */
840
0
    {
841
0
        *out_of_memory = true;
842
0
        goto fail;
843
0
    }
844
845
20.9k
    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)), out_of_memory)) {
846
        /* parse failure. ep is set. */
847
7.14k
        goto fail;
848
7.14k
    }
849
850
    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
851
13.8k
    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
13.8k
    if (return_parse_end) {
858
0
        *return_parse_end = (const char *)buffer_at_offset(&buffer);
859
0
    }
860
861
13.8k
    return item;
862
863
7.14k
fail:
864
7.14k
    if (item != NULL) {
865
7.14k
        loader_cJSON_Delete(item);
866
7.14k
    }
867
868
7.14k
    if (value != NULL) {
869
7.14k
        error local_error;
870
7.14k
        local_error.json = (const unsigned char *)value;
871
7.14k
        local_error.position = 0;
872
873
7.14k
        if (buffer.offset < buffer.length) {
874
6.87k
            local_error.position = buffer.offset;
875
6.87k
        } else if (buffer.length > 0) {
876
273
            local_error.position = buffer.length - 1;
877
273
        }
878
879
7.14k
        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
7.14k
    }
885
886
7.14k
    return NULL;
887
13.8k
}
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
20.9k
                             bool *out_of_memory) {
897
20.9k
    return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, 0, 0, out_of_memory);
898
20.9k
}
899
900
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
901
902
527k
static unsigned char *print(const cJSON *const item, cJSON_bool format, bool *out_of_memory) {
903
527k
    static const size_t default_buffer_size = 256;
904
527k
    printbuffer buffer[1];
905
527k
    unsigned char *printed = NULL;
906
907
527k
    memset(buffer, 0, sizeof(buffer));
908
909
    /* create buffer */
910
527k
    buffer->buffer = (unsigned char *)loader_calloc(item->pAllocator, default_buffer_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
911
527k
    buffer->length = default_buffer_size;
912
527k
    buffer->format = format;
913
527k
    buffer->pAllocator = item->pAllocator;
914
527k
    if (buffer->buffer == NULL) {
915
0
        *out_of_memory = true;
916
0
        goto fail;
917
0
    }
918
919
    /* print the value */
920
527k
    if (!print_value(item, buffer, out_of_memory)) {
921
0
        goto fail;
922
0
    }
923
527k
    update_offset(buffer);
924
925
527k
    printed = (unsigned char *)loader_realloc(item->pAllocator, buffer->buffer, buffer->length, buffer->offset + 1,
926
527k
                                              VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
927
527k
    if (printed == NULL) {
928
0
        *out_of_memory = true;
929
0
        goto fail;
930
0
    }
931
527k
    buffer->buffer = NULL;
932
933
527k
    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
527k
}
948
949
/* Render a cJSON item/entity/structure to text. */
950
527k
TEST_FUNCTION_EXPORT CJSON_PUBLIC(char *) loader_cJSON_Print(const cJSON *item, bool *out_of_memory) {
951
527k
    return (char *)print(item, true, out_of_memory);
952
527k
}
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
315k
loader_cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) {
988
315k
    printbuffer p = {0, 0, 0, 0, 0, 0, 0};
989
990
315k
    if ((length < 0) || (buffer == NULL)) {
991
0
        return false;
992
0
    }
993
994
315k
    p.buffer = (unsigned char *)buffer;
995
315k
    p.length = (size_t)length;
996
315k
    p.offset = 0;
997
315k
    p.noalloc = true;
998
315k
    p.format = format;
999
315k
    p.pAllocator = item->pAllocator;
1000
315k
    bool out_of_memory = false;
1001
315k
    return print_value(item, &p, &out_of_memory);
1002
315k
}
1003
1004
/* Parser core - when encountering text, process appropriately. */
1005
4.20M
static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1006
4.20M
    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
4.20M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) {
1013
810
        item->type = cJSON_NULL;
1014
810
        input_buffer->offset += 4;
1015
810
        return true;
1016
810
    }
1017
    /* false */
1018
4.20M
    if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) {
1019
244
        item->type = cJSON_False;
1020
244
        input_buffer->offset += 5;
1021
244
        return true;
1022
244
    }
1023
    /* true */
1024
4.20M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) {
1025
32.8k
        item->type = cJSON_True;
1026
32.8k
        item->valueint = 1;
1027
32.8k
        input_buffer->offset += 4;
1028
32.8k
        return true;
1029
32.8k
    }
1030
    /* string */
1031
4.17M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) {
1032
2.38M
        return parse_string(item, input_buffer, out_of_memory);
1033
2.38M
    }
1034
    /* number */
1035
1.79M
    if (can_access_at_index(input_buffer, 0) &&
1036
1.79M
        ((buffer_at_offset(input_buffer)[0] == '-') ||
1037
1.77M
         ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) {
1038
952k
        return parse_number(item, input_buffer);
1039
952k
    }
1040
    /* array */
1041
839k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) {
1042
150k
        return parse_array(item, input_buffer, out_of_memory);
1043
150k
    }
1044
    /* object */
1045
688k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) {
1046
682k
        return parse_object(item, input_buffer, out_of_memory);
1047
682k
    }
1048
1049
5.37k
    return false;
1050
688k
}
1051
1052
/* Render a value to text. */
1053
843k
static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1054
843k
    unsigned char *output = NULL;
1055
1056
843k
    if ((item == NULL) || (output_buffer == NULL)) {
1057
0
        return false;
1058
0
    }
1059
1060
843k
    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
843k
        case cJSON_String:
1104
843k
            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
843k
    }
1115
843k
}
1116
1117
/* Build an array from input text. */
1118
150k
static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1119
150k
    cJSON *head = NULL; /* head of the linked list */
1120
150k
    cJSON *current_item = NULL;
1121
1122
150k
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1123
4
        return false; /* to deeply nested */
1124
4
    }
1125
150k
    input_buffer->depth++;
1126
1127
150k
    if (buffer_at_offset(input_buffer)[0] != '[') {
1128
        /* not an array */
1129
0
        goto fail;
1130
0
    }
1131
1132
150k
    input_buffer->offset++;
1133
150k
    buffer_skip_whitespace(input_buffer);
1134
150k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) {
1135
        /* empty array */
1136
22.8k
        goto success;
1137
22.8k
    }
1138
1139
    /* check if we skipped to the end of the buffer */
1140
127k
    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
127k
    input_buffer->offset--;
1147
    /* loop through the comma separated array elements */
1148
2.54M
    do {
1149
        /* allocate next item */
1150
2.54M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1151
2.54M
        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.54M
        if (head == NULL) {
1158
            /* start the linked list */
1159
127k
            current_item = head = new_item;
1160
2.41M
        } else {
1161
            /* add to the end and advance */
1162
2.41M
            current_item->next = new_item;
1163
2.41M
            new_item->prev = current_item;
1164
2.41M
            current_item = new_item;
1165
2.41M
        }
1166
1167
        /* parse next value */
1168
2.54M
        input_buffer->offset++;
1169
2.54M
        buffer_skip_whitespace(input_buffer);
1170
2.54M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1171
69.6k
            goto fail; /* failed to parse value */
1172
69.6k
        }
1173
2.47M
        buffer_skip_whitespace(input_buffer);
1174
2.47M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1175
1176
58.3k
    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') {
1177
314
        goto fail; /* expected end of array */
1178
314
    }
1179
1180
80.9k
success:
1181
80.9k
    input_buffer->depth--;
1182
1183
80.9k
    if (head != NULL) {
1184
58.0k
        head->prev = current_item;
1185
58.0k
    }
1186
1187
80.9k
    item->type = cJSON_Array;
1188
80.9k
    item->child = head;
1189
1190
80.9k
    input_buffer->offset++;
1191
1192
80.9k
    return true;
1193
1194
69.9k
fail:
1195
69.9k
    if (head != NULL) {
1196
69.9k
        loader_cJSON_Delete(head);
1197
69.9k
    }
1198
1199
69.9k
    return false;
1200
58.3k
}
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
682k
static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1257
682k
    cJSON *head = NULL; /* linked list head */
1258
682k
    cJSON *current_item = NULL;
1259
1260
682k
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1261
5
        return false; /* to deeply nested */
1262
5
    }
1263
682k
    input_buffer->depth++;
1264
1265
682k
    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
682k
    input_buffer->offset++;
1270
682k
    buffer_skip_whitespace(input_buffer);
1271
682k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) {
1272
7.45k
        goto success; /* empty object */
1273
7.45k
    }
1274
1275
    /* check if we skipped to the end of the buffer */
1276
675k
    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
675k
    input_buffer->offset--;
1283
    /* loop through the comma separated array elements */
1284
1.64M
    do {
1285
        /* allocate next item */
1286
1.64M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1287
1.64M
        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.64M
        if (head == NULL) {
1294
            /* start the linked list */
1295
675k
            current_item = head = new_item;
1296
967k
        } else {
1297
            /* add to the end and advance */
1298
967k
            current_item->next = new_item;
1299
967k
            new_item->prev = current_item;
1300
967k
            current_item = new_item;
1301
967k
        }
1302
1303
1.64M
        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.64M
        input_buffer->offset++;
1309
1.64M
        buffer_skip_whitespace(input_buffer);
1310
1.64M
        if (!parse_string(current_item, input_buffer, out_of_memory)) {
1311
510
            goto fail; /* failed to parse name */
1312
510
        }
1313
1.64M
        buffer_skip_whitespace(input_buffer);
1314
1315
        /* swap valuestring and string, because we parsed the name */
1316
1.64M
        current_item->string = current_item->valuestring;
1317
1.64M
        current_item->valuestring = NULL;
1318
1319
1.64M
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) {
1320
67
            goto fail; /* invalid object */
1321
67
        }
1322
1323
        /* parse the value */
1324
1.64M
        input_buffer->offset++;
1325
1.64M
        buffer_skip_whitespace(input_buffer);
1326
1.64M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1327
2.00k
            goto fail; /* failed to parse value */
1328
2.00k
        }
1329
1.63M
        buffer_skip_whitespace(input_buffer);
1330
1.63M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1331
1332
672k
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) {
1333
50
        goto fail; /* expected end of object */
1334
50
    }
1335
1336
680k
success:
1337
680k
    input_buffer->depth--;
1338
1339
680k
    if (head != NULL) {
1340
672k
        head->prev = current_item;
1341
672k
    }
1342
1343
680k
    item->type = cJSON_Object;
1344
680k
    item->child = head;
1345
1346
680k
    input_buffer->offset++;
1347
680k
    return true;
1348
1349
2.62k
fail:
1350
2.62k
    if (head != NULL) {
1351
2.62k
        loader_cJSON_Delete(head);
1352
2.62k
    }
1353
1354
2.62k
    return false;
1355
672k
}
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
11.5k
CJSON_PUBLIC(int) loader_cJSON_GetArraySize(const cJSON *array) {
1455
11.5k
    cJSON *child = NULL;
1456
11.5k
    size_t size = 0;
1457
1458
11.5k
    if (array == NULL) {
1459
0
        return 0;
1460
0
    }
1461
1462
11.5k
    child = array->child;
1463
1464
788k
    while (child != NULL) {
1465
777k
        size++;
1466
777k
        child = child->next;
1467
777k
    }
1468
1469
    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1470
1471
11.5k
    return (int)size;
1472
11.5k
}
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
1.27M
static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) {
1499
1.27M
    cJSON *current_element = NULL;
1500
1501
1.27M
    if ((object == NULL) || (name == NULL)) {
1502
0
        return NULL;
1503
0
    }
1504
1505
1.27M
    current_element = object->child;
1506
1.27M
    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
1.27M
    } else {
1511
4.67M
        while ((current_element != NULL) &&
1512
4.16M
               (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0)) {
1513
3.40M
            current_element = current_element->next;
1514
3.40M
        }
1515
1.27M
    }
1516
1517
1.27M
    if ((current_element == NULL) || (current_element->string == NULL)) {
1518
511k
        return NULL;
1519
511k
    }
1520
1521
759k
    return current_element;
1522
1.27M
}
1523
1524
1.27M
CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItem(const cJSON *const object, const char *const string) {
1525
1.27M
    return get_object_item(object, string, false);
1526
1.27M
}
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
586k
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsString(const cJSON *const item) {
1668
586k
    if (item == NULL) {
1669
262k
        return false;
1670
262k
    }
1671
1672
324k
    return (item->type & 0xFF) == cJSON_String;
1673
586k
}
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
}