Coverage Report

Created: 2025-07-18 06:34

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