Coverage Report

Created: 2025-07-11 06:48

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