Coverage Report

Created: 2026-08-11 06:34

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