Coverage Report

Created: 2026-02-14 06:07

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
8.02M
#define true ((cJSON_bool)1)
68
69
#ifdef false
70
#undef false
71
#endif
72
1.92M
#define false ((cJSON_bool)0)
73
74
/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
75
#ifndef isinf
76
#define isinf(d) (isnan((d - d)) && !isnan(d))
77
#endif
78
#ifndef isnan
79
#define isnan(d) (d != d)
80
#endif
81
82
#ifndef NAN
83
#ifdef _WIN32
84
#define NAN sqrt(-1.0)
85
#else
86
#define NAN 0.0 / 0.0
87
#endif
88
#endif
89
90
typedef struct {
91
    const unsigned char *json;
92
    size_t position;
93
} error;
94
static error global_error = {NULL, 0};
95
96
0
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) { return (const char *)(global_error.json + global_error.position); }
97
98
606k
CJSON_PUBLIC(char *) loader_cJSON_GetStringValue(const cJSON *const item) {
99
606k
    if (!loader_cJSON_IsString(item)) {
100
268k
        return NULL;
101
268k
    }
102
103
337k
    return item->valuestring;
104
606k
}
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
3.76M
static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) {
121
3.76M
    if ((string1 == NULL) || (string2 == NULL)) {
122
96
        return 1;
123
96
    }
124
125
3.76M
    if (string1 == string2) {
126
0
        return 0;
127
0
    }
128
129
8.81M
    for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) {
130
5.83M
        if (*string1 == '\0') {
131
776k
            return 0;
132
776k
        }
133
5.83M
    }
134
135
2.98M
    return tolower(*string1) - tolower(*string2);
136
3.76M
}
137
138
/* strlen of character literals resolved at compile time */
139
0
#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
140
141
/* Internal constructor. */
142
4.79M
static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) {
143
4.79M
    cJSON *node = (cJSON *)loader_calloc(pAllocator, sizeof(cJSON), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
144
4.79M
    if (NULL != node) {
145
4.79M
        node->pAllocator = pAllocator;
146
4.79M
    }
147
4.79M
    return node;
148
4.79M
}
149
150
/* Delete a cJSON structure. */
151
823k
TEST_FUNCTION_EXPORT CJSON_PUBLIC(void) loader_cJSON_Delete(cJSON *item) {
152
823k
    cJSON *next = NULL;
153
5.61M
    while (item != NULL) {
154
4.79M
        next = item->next;
155
4.79M
        if (!(item->type & cJSON_IsReference) && (item->child != NULL)) {
156
737k
            loader_cJSON_Delete(item->child);
157
737k
        }
158
4.79M
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) {
159
2.39M
            loader_free(item->pAllocator, item->valuestring);
160
2.39M
            item->valuestring = NULL;
161
2.39M
        }
162
4.79M
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
163
1.70M
            loader_free(item->pAllocator, item->string);
164
1.70M
            item->string = NULL;
165
1.70M
        }
166
4.79M
        loader_free(item->pAllocator, item);
167
4.79M
        item = next;
168
4.79M
    }
169
823k
}
170
171
/* get the decimal point character of the current locale */
172
1.51M
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
1.51M
    return '.';
178
1.51M
#endif
179
1.51M
}
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
28.7M
#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
101M
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
193
22.5M
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
194
/* get a pointer to the buffer at the position */
195
83.9M
#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
1.51M
static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) {
199
1.51M
    double number = 0;
200
1.51M
    unsigned char *after_end = NULL;
201
1.51M
    unsigned char number_c_string[64];
202
1.51M
    unsigned char decimal_point = get_decimal_point();
203
1.51M
    size_t i = 0;
204
205
1.51M
    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.66M
    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) {
213
3.66M
        switch (buffer_at_offset(input_buffer)[i]) {
214
103k
            case '0':
215
1.55M
            case '1':
216
1.71M
            case '2':
217
1.81M
            case '3':
218
1.87M
            case '4':
219
1.91M
            case '5':
220
1.93M
            case '6':
221
1.99M
            case '7':
222
2.04M
            case '8':
223
2.10M
            case '9':
224
2.10M
            case '+':
225
2.11M
            case '-':
226
2.11M
            case 'e':
227
2.12M
            case 'E':
228
2.12M
                number_c_string[i] = buffer_at_offset(input_buffer)[i];
229
2.12M
                break;
230
231
32.7k
            case '.':
232
32.7k
                number_c_string[i] = decimal_point;
233
32.7k
                break;
234
235
1.51M
            default:
236
1.51M
                goto loop_end;
237
3.66M
        }
238
3.66M
    }
239
1.51M
loop_end:
240
1.51M
    number_c_string[i] = '\0';
241
242
1.51M
    number = strtod((const char *)number_c_string, (char **)&after_end);
243
1.51M
    if (number_c_string == after_end) {
244
142
        return false; /* parse_error */
245
142
    }
246
247
1.51M
    item->valuedouble = number;
248
249
    /* use saturation in case of overflow */
250
1.51M
    if (number >= INT_MAX) {
251
6.02k
        item->valueint = INT_MAX;
252
1.50M
    } else if (number <= (double)INT_MIN) {
253
1.10k
        item->valueint = INT_MIN;
254
1.50M
    } else {
255
1.50M
        item->valueint = (int)number;
256
1.50M
    }
257
258
1.51M
    item->type = cJSON_Number;
259
260
1.51M
    input_buffer->offset += (size_t)(after_end - number_c_string);
261
1.51M
    return true;
262
1.51M
}
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
798k
static unsigned char *ensure(printbuffer *const p, size_t needed, bool *out_of_memory) {
276
798k
    unsigned char *newbuffer = NULL;
277
798k
    size_t newsize = 0;
278
279
798k
    if ((p == NULL) || (p->buffer == NULL)) {
280
0
        return NULL;
281
0
    }
282
283
798k
    if ((p->length > 0) && (p->offset >= p->length)) {
284
        /* make sure that offset is valid */
285
0
        return NULL;
286
0
    }
287
288
798k
    if (needed > INT_MAX) {
289
        /* sizes bigger than INT_MAX are currently not supported */
290
0
        return NULL;
291
0
    }
292
293
798k
    needed += p->offset + 1;
294
798k
    if (needed <= p->length) {
295
793k
        return p->buffer + p->offset;
296
793k
    }
297
298
4.83k
    if (p->noalloc) {
299
808
        return NULL;
300
808
    }
301
302
    /* calculate new buffer size */
303
4.02k
    if (needed > (INT_MAX / 2)) {
304
        /* overflow of int, use INT_MAX if possible */
305
0
        if (needed <= INT_MAX) {
306
0
            newsize = INT_MAX;
307
0
        } else {
308
0
            return NULL;
309
0
        }
310
4.02k
    } else {
311
4.02k
        newsize = needed * 2;
312
4.02k
    }
313
314
4.02k
    newbuffer = (unsigned char *)loader_realloc(p->pAllocator, p->buffer, p->length, newsize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
315
4.02k
    if (newbuffer == NULL) {
316
0
        *out_of_memory = true;
317
0
        loader_free(p->pAllocator, p->buffer);
318
0
        p->length = 0;
319
0
        p->buffer = NULL;
320
321
0
        return NULL;
322
0
    }
323
324
4.02k
    p->length = newsize;
325
4.02k
    p->buffer = newbuffer;
326
327
4.02k
    return newbuffer + p->offset;
328
4.02k
}
329
330
/* calculate the new length of the string in a printbuffer and update the offset */
331
469k
static void update_offset(printbuffer *const buffer) {
332
469k
    const unsigned char *buffer_pointer = NULL;
333
469k
    if ((buffer == NULL) || (buffer->buffer == NULL)) {
334
0
        return;
335
0
    }
336
469k
    buffer_pointer = buffer->buffer + buffer->offset;
337
338
469k
    buffer->offset += strlen((const char *)buffer_pointer);
339
469k
}
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
127k
static unsigned parse_hex4(const unsigned char *const input) {
407
127k
    unsigned int h = 0;
408
127k
    size_t i = 0;
409
410
366k
    for (i = 0; i < 4; i++) {
411
        /* parse digit */
412
334k
        if ((input[i] >= '0') && (input[i] <= '9')) {
413
91.6k
            h += (unsigned int)input[i] - '0';
414
242k
        } else if ((input[i] >= 'A') && (input[i] <= 'F')) {
415
66.2k
            h += (unsigned int)10 + input[i] - 'A';
416
176k
        } else if ((input[i] >= 'a') && (input[i] <= 'f')) {
417
80.6k
            h += (unsigned int)10 + input[i] - 'a';
418
80.6k
        } else /* invalid */
419
95.5k
        {
420
95.5k
            return 0;
421
95.5k
        }
422
423
238k
        if (i < 3) {
424
            /* shift left to make place for the next nibble */
425
206k
            h = h << 4;
426
206k
        }
427
238k
    }
428
429
31.9k
    return h;
430
127k
}
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
125k
                                           unsigned char **output_pointer) {
436
125k
    long unsigned int codepoint = 0;
437
125k
    unsigned int first_code = 0;
438
125k
    const unsigned char *first_sequence = input_pointer;
439
125k
    unsigned char utf8_length = 0;
440
125k
    unsigned char utf8_position = 0;
441
125k
    unsigned char sequence_length = 0;
442
125k
    unsigned char first_byte_mark = 0;
443
444
125k
    if ((input_end - first_sequence) < 6) {
445
        /* input ends unexpectedly */
446
15
        goto fail;
447
15
    }
448
449
    /* get the first utf16 sequence */
450
124k
    first_code = parse_hex4(first_sequence + 2);
451
452
    /* check that the code is valid */
453
124k
    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) {
454
34
        goto fail;
455
34
    }
456
457
    /* UTF16 surrogate pair */
458
124k
    if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) {
459
2.59k
        const unsigned char *second_sequence = first_sequence + 6;
460
2.59k
        unsigned int second_code = 0;
461
2.59k
        sequence_length = 12; /* \uXXXX\uXXXX */
462
463
2.59k
        if ((input_end - second_sequence) < 6) {
464
            /* input ends unexpectedly */
465
33
            goto fail;
466
33
        }
467
468
2.56k
        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) {
469
            /* missing second half of the surrogate pair */
470
73
            goto fail;
471
73
        }
472
473
        /* get the second utf16 sequence */
474
2.49k
        second_code = parse_hex4(second_sequence + 2);
475
        /* check that the code is valid */
476
2.49k
        if ((second_code < 0xDC00) || (second_code > 0xDFFF)) {
477
            /* invalid second half of the surrogate pair */
478
101
            goto fail;
479
101
        }
480
481
        /* calculate the unicode codepoint from the surrogate pair */
482
2.39k
        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
483
122k
    } else {
484
122k
        sequence_length = 6; /* \uXXXX */
485
122k
        codepoint = first_code;
486
122k
    }
487
488
    /* encode as UTF-8
489
     * takes at maximum 4 bytes to encode:
490
     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
491
124k
    if (codepoint < 0x80) {
492
        /* normal ascii, encoding 0xxxxxxx */
493
95.8k
        utf8_length = 1;
494
95.8k
    } else if (codepoint < 0x800) {
495
        /* two bytes, encoding 110xxxxx 10xxxxxx */
496
2.42k
        utf8_length = 2;
497
2.42k
        first_byte_mark = 0xC0; /* 11000000 */
498
26.5k
    } else if (codepoint < 0x10000) {
499
        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
500
24.1k
        utf8_length = 3;
501
24.1k
        first_byte_mark = 0xE0; /* 11100000 */
502
24.1k
    } else if (codepoint <= 0x10FFFF) {
503
        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
504
2.39k
        utf8_length = 4;
505
2.39k
        first_byte_mark = 0xF0; /* 11110000 */
506
2.39k
    } else {
507
        /* invalid unicode codepoint */
508
0
        goto fail;
509
0
    }
510
511
    /* encode as utf8 */
512
182k
    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) {
513
        /* 10xxxxxx */
514
57.8k
        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
515
57.8k
        codepoint >>= 6;
516
57.8k
    }
517
    /* encode first byte */
518
124k
    if (utf8_length > 1) {
519
28.9k
        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
520
95.8k
    } else {
521
95.8k
        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
522
95.8k
    }
523
524
124k
    *output_pointer += utf8_length;
525
526
124k
    return sequence_length;
527
528
256
fail:
529
256
    return 0;
530
124k
}
531
532
/* Parse the input text into an unescaped cinput, and populate item. */
533
4.10M
static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
534
4.10M
    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
535
4.10M
    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
536
4.10M
    unsigned char *output_pointer = NULL;
537
4.10M
    unsigned char *output = NULL;
538
539
    /* not a string */
540
4.10M
    if (buffer_at_offset(input_buffer)[0] != '\"') {
541
242
        goto fail;
542
242
    }
543
544
4.10M
    {
545
        /* calculate approximate size of the output (overestimate) */
546
4.10M
        size_t allocation_length = 0;
547
4.10M
        size_t skipped_bytes = 0;
548
134M
        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) {
549
            /* is escape sequence */
550
130M
            if (input_end[0] == '\\') {
551
218k
                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
218k
                skipped_bytes++;
556
218k
                input_end++;
557
218k
            }
558
130M
            input_end++;
559
130M
        }
560
4.10M
        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) {
561
384
            goto fail; /* string ended unexpectedly */
562
384
        }
563
564
        /* This is at most how much we need for the output */
565
4.10M
        allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
566
4.10M
        output = (unsigned char *)loader_calloc(input_buffer->pAllocator, allocation_length + sizeof(""),
567
4.10M
                                                VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
568
4.10M
        if (output == NULL) {
569
0
            *out_of_memory = true;
570
0
            goto fail; /* allocation failure */
571
0
        }
572
4.10M
    }
573
574
4.10M
    output_pointer = output;
575
    /* loop through the string literal */
576
126M
    while (input_pointer < input_end) {
577
122M
        if (*input_pointer != '\\') {
578
122M
            *output_pointer++ = *input_pointer++;
579
122M
        }
580
        /* escape sequence */
581
163k
        else {
582
163k
            unsigned char sequence_length = 2;
583
163k
            if ((input_end - input_pointer) < 1) {
584
0
                goto fail;
585
0
            }
586
587
163k
            switch (input_pointer[1]) {
588
640
                case 'b':
589
640
                    *output_pointer++ = '\b';
590
640
                    break;
591
9.52k
                case 'f':
592
9.52k
                    *output_pointer++ = '\f';
593
9.52k
                    break;
594
577
                case 'n':
595
577
                    *output_pointer++ = '\n';
596
577
                    break;
597
1.60k
                case 'r':
598
1.60k
                    *output_pointer++ = '\r';
599
1.60k
                    break;
600
1.16k
                case 't':
601
1.16k
                    *output_pointer++ = '\t';
602
1.16k
                    break;
603
1.77k
                case '\"':
604
24.5k
                case '\\':
605
24.6k
                case '/':
606
24.6k
                    *output_pointer++ = input_pointer[1];
607
24.6k
                    break;
608
609
                /* UTF-16 literal */
610
125k
                case 'u':
611
125k
                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
612
125k
                    if (sequence_length == 0) {
613
                        /* failed to convert UTF16-literal to UTF-8 */
614
256
                        goto fail;
615
256
                    }
616
124k
                    break;
617
618
124k
                default:
619
43
                    goto fail;
620
163k
            }
621
162k
            input_pointer += sequence_length;
622
162k
        }
623
122M
    }
624
625
    /* zero terminate the output */
626
4.10M
    *output_pointer = '\0';
627
628
4.10M
    item->type = cJSON_String;
629
4.10M
    item->valuestring = (char *)output;
630
631
4.10M
    input_buffer->offset = (size_t)(input_end - input_buffer->content);
632
4.10M
    input_buffer->offset++;
633
634
4.10M
    return true;
635
636
925
fail:
637
925
    if (output != NULL) {
638
299
        loader_free(input_buffer->pAllocator, output);
639
299
        output = NULL;
640
299
    }
641
642
925
    if (input_pointer != NULL) {
643
925
        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
644
925
    }
645
646
925
    return false;
647
4.10M
}
648
649
/* Render the cstring provided to an escaped version that can be printed. */
650
798k
static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer, bool *out_of_memory) {
651
798k
    const unsigned char *input_pointer = NULL;
652
798k
    unsigned char *output = NULL;
653
798k
    unsigned char *output_pointer = NULL;
654
798k
    size_t output_length = 0;
655
    /* numbers of additional characters needed for escaping */
656
798k
    size_t escape_characters = 0;
657
658
798k
    if (output_buffer == NULL) {
659
0
        return false;
660
0
    }
661
662
    /* empty string */
663
798k
    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
26.9M
    for (input_pointer = input; *input_pointer; input_pointer++) {
674
26.1M
        switch (*input_pointer) {
675
233
            case '\"':
676
6.43k
            case '\\':
677
27.6k
            case '\b':
678
31.8k
            case '\f':
679
51.9k
            case '\n':
680
55.0k
            case '\r':
681
56.3k
            case '\t':
682
                /* one character escape sequence */
683
56.3k
                escape_characters++;
684
56.3k
                break;
685
26.0M
            default:
686
26.0M
                if (*input_pointer < 32) {
687
                    /* UTF-16 escape sequence uXXXX */
688
20.9M
                    escape_characters += 5;
689
20.9M
                }
690
26.0M
                break;
691
26.1M
        }
692
26.1M
    }
693
798k
    output_length = (size_t)(input_pointer - input) + escape_characters;
694
695
798k
    output = ensure(output_buffer, output_length + sizeof(""), out_of_memory);
696
798k
    if (output == NULL) {
697
808
        return false;
698
808
    }
699
700
    /* no characters have to be escaped */
701
797k
    if (escape_characters == 0) {
702
755k
        memcpy(output, input, output_length);
703
755k
        output[output_length] = '\0';
704
705
755k
        return true;
706
755k
    }
707
708
41.5k
    output_pointer = output;
709
    /* copy the string */
710
22.3M
    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) {
711
22.3M
        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) {
712
            /* normal character, copy */
713
1.49M
            *output_pointer = *input_pointer;
714
20.8M
        } 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
20.8M
            switch (*input_pointer) {
721
6.14k
                case '\\':
722
6.14k
                    *output_pointer = '\\';
723
6.14k
                    break;
724
109
                case '\"':
725
109
                    *output_pointer = '\"';
726
109
                    break;
727
21.2k
                case '\b':
728
21.2k
                    *output_pointer = '\b';
729
21.2k
                    break;
730
3.98k
                case '\f':
731
3.98k
                    *output_pointer = '\f';
732
3.98k
                    break;
733
19.5k
                case '\n':
734
19.5k
                    *output_pointer = '\n';
735
19.5k
                    break;
736
3.07k
                case '\r':
737
3.07k
                    *output_pointer = '\r';
738
3.07k
                    break;
739
1.02k
                case '\t':
740
1.02k
                    *output_pointer = '\t';
741
1.02k
                    break;
742
20.7M
                default:
743
                    /* escape and print as unicode codepoint */
744
20.7M
                    snprintf((char *)output_pointer, output_length - (size_t)(output_pointer - output), "u%04x", *input_pointer);
745
20.7M
                    output_pointer += 4;
746
20.7M
                    break;
747
20.8M
            }
748
20.8M
        }
749
22.3M
    }
750
41.5k
    output[output_length] = '\0';
751
752
41.5k
    return true;
753
41.5k
}
754
755
/* Invoke print_string_ptr (which is useful) on an item. */
756
798k
static cJSON_bool print_string(const cJSON *const item, printbuffer *const p, bool *out_of_memory) {
757
798k
    return print_string_ptr((unsigned char *)item->valuestring, p, out_of_memory);
758
798k
}
759
760
/* Predeclare these prototypes. */
761
static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory);
762
static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory);
763
static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory);
764
static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory);
765
static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory);
766
static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory);
767
768
/* Utility to jump whitespace and cr/lf */
769
13.7M
static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) {
770
13.7M
    if ((buffer == NULL) || (buffer->content == NULL)) {
771
0
        return NULL;
772
0
    }
773
774
13.7M
    if (cannot_access_at_index(buffer, 0)) {
775
0
        return buffer;
776
0
    }
777
778
25.1M
    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) {
779
11.4M
        buffer->offset++;
780
11.4M
    }
781
782
13.7M
    if (buffer->offset == buffer->length) {
783
3.36k
        buffer->offset--;
784
3.36k
    }
785
786
13.7M
    return buffer;
787
13.7M
}
788
789
/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
790
18.9k
static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) {
791
18.9k
    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) {
792
0
        return NULL;
793
0
    }
794
795
18.9k
    if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) {
796
290
        buffer->offset += 3;
797
290
    }
798
799
18.9k
    return buffer;
800
18.9k
}
801
802
CJSON_PUBLIC(cJSON *)
803
loader_cJSON_ParseWithOpts(const VkAllocationCallbacks *pAllocator, const char *value, const char **return_parse_end,
804
0
                           cJSON_bool require_null_terminated, bool *out_of_memory) {
805
0
    size_t buffer_length;
806
807
0
    if (NULL == value) {
808
0
        return NULL;
809
0
    }
810
811
    /* Adding null character size due to require_null_terminated. */
812
0
    buffer_length = strlen(value) + sizeof("");
813
814
0
    return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, return_parse_end, require_null_terminated,
815
0
                                            out_of_memory);
816
0
}
817
818
/* Parse an object - create a new root, and populate. */
819
CJSON_PUBLIC(cJSON *)
820
loader_cJSON_ParseWithLengthOpts(const VkAllocationCallbacks *pAllocator, const char *value, size_t buffer_length,
821
18.9k
                                 const char **return_parse_end, cJSON_bool require_null_terminated, bool *out_of_memory) {
822
18.9k
    parse_buffer buffer = {0, 0, 0, 0, 0};
823
18.9k
    cJSON *item = NULL;
824
825
    /* reset error position */
826
18.9k
    global_error.json = NULL;
827
18.9k
    global_error.position = 0;
828
829
18.9k
    if (value == NULL || 0 == buffer_length) {
830
0
        goto fail;
831
0
    }
832
833
18.9k
    buffer.content = (const unsigned char *)value;
834
18.9k
    buffer.length = buffer_length;
835
18.9k
    buffer.offset = 0;
836
18.9k
    buffer.pAllocator = pAllocator;
837
838
18.9k
    item = cJSON_New_Item(pAllocator);
839
18.9k
    if (item == NULL) /* memory fail */
840
0
    {
841
0
        *out_of_memory = true;
842
0
        goto fail;
843
0
    }
844
845
18.9k
    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)), out_of_memory)) {
846
        /* parse failure. ep is set. */
847
5.96k
        goto fail;
848
5.96k
    }
849
850
    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
851
12.9k
    if (require_null_terminated) {
852
0
        buffer_skip_whitespace(&buffer);
853
0
        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') {
854
0
            goto fail;
855
0
        }
856
0
    }
857
12.9k
    if (return_parse_end) {
858
0
        *return_parse_end = (const char *)buffer_at_offset(&buffer);
859
0
    }
860
861
12.9k
    return item;
862
863
5.96k
fail:
864
5.96k
    if (item != NULL) {
865
5.96k
        loader_cJSON_Delete(item);
866
5.96k
    }
867
868
5.96k
    if (value != NULL) {
869
5.96k
        error local_error;
870
5.96k
        local_error.json = (const unsigned char *)value;
871
5.96k
        local_error.position = 0;
872
873
5.96k
        if (buffer.offset < buffer.length) {
874
5.79k
            local_error.position = buffer.offset;
875
5.79k
        } else if (buffer.length > 0) {
876
168
            local_error.position = buffer.length - 1;
877
168
        }
878
879
5.96k
        if (return_parse_end != NULL) {
880
0
            *return_parse_end = (const char *)local_error.json + local_error.position;
881
0
        }
882
883
5.96k
        global_error = local_error;
884
5.96k
    }
885
886
5.96k
    return NULL;
887
12.9k
}
888
889
/* Default options for loader_cJSON_Parse */
890
0
CJSON_PUBLIC(cJSON *) loader_cJSON_Parse(const VkAllocationCallbacks *pAllocator, const char *value, bool *out_of_memory) {
891
0
    return loader_cJSON_ParseWithOpts(pAllocator, value, 0, 0, out_of_memory);
892
0
}
893
894
CJSON_PUBLIC(cJSON *)
895
loader_cJSON_ParseWithLength(const VkAllocationCallbacks *pAllocator, const char *value, size_t buffer_length,
896
18.9k
                             bool *out_of_memory) {
897
18.9k
    return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, 0, 0, out_of_memory);
898
18.9k
}
899
900
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
901
902
469k
static unsigned char *print(const cJSON *const item, cJSON_bool format, bool *out_of_memory) {
903
469k
    static const size_t default_buffer_size = 256;
904
469k
    printbuffer buffer[1];
905
469k
    unsigned char *printed = NULL;
906
907
469k
    memset(buffer, 0, sizeof(buffer));
908
909
    /* create buffer */
910
469k
    buffer->buffer = (unsigned char *)loader_calloc(item->pAllocator, default_buffer_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
911
469k
    buffer->length = default_buffer_size;
912
469k
    buffer->format = format;
913
469k
    buffer->pAllocator = item->pAllocator;
914
469k
    if (buffer->buffer == NULL) {
915
0
        *out_of_memory = true;
916
0
        goto fail;
917
0
    }
918
919
    /* print the value */
920
469k
    if (!print_value(item, buffer, out_of_memory)) {
921
0
        goto fail;
922
0
    }
923
469k
    update_offset(buffer);
924
925
469k
    printed = (unsigned char *)loader_realloc(item->pAllocator, buffer->buffer, buffer->length, buffer->offset + 1,
926
469k
                                              VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
927
469k
    if (printed == NULL) {
928
0
        *out_of_memory = true;
929
0
        goto fail;
930
0
    }
931
469k
    buffer->buffer = NULL;
932
933
469k
    return printed;
934
935
0
fail:
936
0
    if (buffer->buffer != NULL) {
937
0
        loader_free(item->pAllocator, buffer->buffer);
938
0
        buffer->buffer = NULL;
939
0
    }
940
941
0
    if (printed != NULL) {
942
0
        loader_free(item->pAllocator, printed);
943
0
        printed = NULL;
944
0
    }
945
946
0
    return NULL;
947
469k
}
948
949
/* Render a cJSON item/entity/structure to text. */
950
469k
TEST_FUNCTION_EXPORT CJSON_PUBLIC(char *) loader_cJSON_Print(const cJSON *item, bool *out_of_memory) {
951
469k
    return (char *)print(item, true, out_of_memory);
952
469k
}
953
954
0
CJSON_PUBLIC(char *) loader_cJSON_PrintUnformatted(const cJSON *item, bool *out_of_memory) {
955
0
    return (char *)print(item, false, out_of_memory);
956
0
}
957
958
CJSON_PUBLIC(char *)
959
0
loader_cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt, bool *out_of_memory) {
960
0
    printbuffer p = {0, 0, 0, 0, 0, 0, 0};
961
962
0
    if (prebuffer < 0) {
963
0
        return NULL;
964
0
    }
965
966
0
    p.buffer = (unsigned char *)loader_alloc(item->pAllocator, (size_t)prebuffer, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
967
0
    if (!p.buffer) {
968
0
        return NULL;
969
0
    }
970
971
0
    p.length = (size_t)prebuffer;
972
0
    p.offset = 0;
973
0
    p.noalloc = false;
974
0
    p.format = fmt;
975
0
    p.pAllocator = item->pAllocator;
976
977
0
    if (!print_value(item, &p, out_of_memory)) {
978
0
        loader_free(item->pAllocator, p.buffer);
979
0
        p.buffer = NULL;
980
0
        return NULL;
981
0
    }
982
983
0
    return (char *)p.buffer;
984
0
}
985
986
CJSON_PUBLIC(cJSON_bool)
987
328k
loader_cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) {
988
328k
    printbuffer p = {0, 0, 0, 0, 0, 0, 0};
989
990
328k
    if ((length < 0) || (buffer == NULL)) {
991
0
        return false;
992
0
    }
993
994
328k
    p.buffer = (unsigned char *)buffer;
995
328k
    p.length = (size_t)length;
996
328k
    p.offset = 0;
997
328k
    p.noalloc = true;
998
328k
    p.format = format;
999
328k
    p.pAllocator = item->pAllocator;
1000
328k
    bool out_of_memory = false;
1001
328k
    return print_value(item, &p, &out_of_memory);
1002
328k
}
1003
1004
/* Parser core - when encountering text, process appropriately. */
1005
4.79M
static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1006
4.79M
    if ((input_buffer == NULL) || (input_buffer->content == NULL)) {
1007
0
        return false; /* no input */
1008
0
    }
1009
1010
    /* parse the different types of values */
1011
    /* null */
1012
4.79M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) {
1013
394
        item->type = cJSON_NULL;
1014
394
        input_buffer->offset += 4;
1015
394
        return true;
1016
394
    }
1017
    /* false */
1018
4.79M
    if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) {
1019
256
        item->type = cJSON_False;
1020
256
        input_buffer->offset += 5;
1021
256
        return true;
1022
256
    }
1023
    /* true */
1024
4.79M
    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) {
1025
47.1k
        item->type = cJSON_True;
1026
47.1k
        item->valueint = 1;
1027
47.1k
        input_buffer->offset += 4;
1028
47.1k
        return true;
1029
47.1k
    }
1030
    /* string */
1031
4.74M
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) {
1032
2.39M
        return parse_string(item, input_buffer, out_of_memory);
1033
2.39M
    }
1034
    /* number */
1035
2.34M
    if (can_access_at_index(input_buffer, 0) &&
1036
2.34M
        ((buffer_at_offset(input_buffer)[0] == '-') ||
1037
2.34M
         ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) {
1038
1.51M
        return parse_number(item, input_buffer);
1039
1.51M
    }
1040
    /* array */
1041
838k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) {
1042
134k
        return parse_array(item, input_buffer, out_of_memory);
1043
134k
    }
1044
    /* object */
1045
703k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) {
1046
699k
        return parse_object(item, input_buffer, out_of_memory);
1047
699k
    }
1048
1049
4.48k
    return false;
1050
703k
}
1051
1052
/* Render a value to text. */
1053
798k
static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1054
798k
    unsigned char *output = NULL;
1055
1056
798k
    if ((item == NULL) || (output_buffer == NULL)) {
1057
0
        return false;
1058
0
    }
1059
1060
798k
    switch ((item->type) & 0xFF) {
1061
0
        case cJSON_NULL:
1062
0
            output = ensure(output_buffer, 5, out_of_memory);
1063
0
            if (output == NULL) {
1064
0
                return false;
1065
0
            }
1066
0
            strcpy((char *)output, "null");
1067
0
            return true;
1068
1069
0
        case cJSON_False:
1070
0
            output = ensure(output_buffer, 6, out_of_memory);
1071
0
            if (output == NULL) {
1072
0
                return false;
1073
0
            }
1074
0
            strcpy((char *)output, "false");
1075
0
            return true;
1076
1077
0
        case cJSON_True:
1078
0
            output = ensure(output_buffer, 5, out_of_memory);
1079
0
            if (output == NULL) {
1080
0
                return false;
1081
0
            }
1082
0
            strcpy((char *)output, "true");
1083
0
            return true;
1084
1085
0
        case cJSON_Number:
1086
0
            return print_number(item, output_buffer, out_of_memory);
1087
1088
0
        case cJSON_Raw: {
1089
0
            size_t raw_length = 0;
1090
0
            if (item->valuestring == NULL) {
1091
0
                return false;
1092
0
            }
1093
1094
0
            raw_length = strlen(item->valuestring) + sizeof("");
1095
0
            output = ensure(output_buffer, raw_length, out_of_memory);
1096
0
            if (output == NULL) {
1097
0
                return false;
1098
0
            }
1099
0
            memcpy(output, item->valuestring, raw_length);
1100
0
            return true;
1101
0
        }
1102
1103
798k
        case cJSON_String:
1104
798k
            return print_string(item, output_buffer, out_of_memory);
1105
1106
0
        case cJSON_Array:
1107
0
            return print_array(item, output_buffer, out_of_memory);
1108
1109
0
        case cJSON_Object:
1110
0
            return print_object(item, output_buffer, out_of_memory);
1111
1112
0
        default:
1113
0
            return false;
1114
798k
    }
1115
798k
}
1116
1117
/* Build an array from input text. */
1118
134k
static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1119
134k
    cJSON *head = NULL; /* head of the linked list */
1120
134k
    cJSON *current_item = NULL;
1121
1122
134k
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1123
2
        return false; /* to deeply nested */
1124
2
    }
1125
134k
    input_buffer->depth++;
1126
1127
134k
    if (buffer_at_offset(input_buffer)[0] != '[') {
1128
        /* not an array */
1129
0
        goto fail;
1130
0
    }
1131
1132
134k
    input_buffer->offset++;
1133
134k
    buffer_skip_whitespace(input_buffer);
1134
134k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) {
1135
        /* empty array */
1136
20.8k
        goto success;
1137
20.8k
    }
1138
1139
    /* check if we skipped to the end of the buffer */
1140
113k
    if (cannot_access_at_index(input_buffer, 0)) {
1141
0
        input_buffer->offset--;
1142
0
        goto fail;
1143
0
    }
1144
1145
    /* step back to character in front of the first element */
1146
113k
    input_buffer->offset--;
1147
    /* loop through the comma separated array elements */
1148
3.06M
    do {
1149
        /* allocate next item */
1150
3.06M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1151
3.06M
        if (new_item == NULL) {
1152
0
            *out_of_memory = true;
1153
0
            goto fail; /* allocation failure */
1154
0
        }
1155
1156
        /* attach next item to list */
1157
3.06M
        if (head == NULL) {
1158
            /* start the linked list */
1159
113k
            current_item = head = new_item;
1160
2.95M
        } else {
1161
            /* add to the end and advance */
1162
2.95M
            current_item->next = new_item;
1163
2.95M
            new_item->prev = current_item;
1164
2.95M
            current_item = new_item;
1165
2.95M
        }
1166
1167
        /* parse next value */
1168
3.06M
        input_buffer->offset++;
1169
3.06M
        buffer_skip_whitespace(input_buffer);
1170
3.06M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1171
63.6k
            goto fail; /* failed to parse value */
1172
63.6k
        }
1173
3.00M
        buffer_skip_whitespace(input_buffer);
1174
3.00M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1175
1176
49.9k
    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') {
1177
290
        goto fail; /* expected end of array */
1178
290
    }
1179
1180
70.4k
success:
1181
70.4k
    input_buffer->depth--;
1182
1183
70.4k
    if (head != NULL) {
1184
49.6k
        head->prev = current_item;
1185
49.6k
    }
1186
1187
70.4k
    item->type = cJSON_Array;
1188
70.4k
    item->child = head;
1189
1190
70.4k
    input_buffer->offset++;
1191
1192
70.4k
    return true;
1193
1194
63.9k
fail:
1195
63.9k
    if (head != NULL) {
1196
63.9k
        loader_cJSON_Delete(head);
1197
63.9k
    }
1198
1199
63.9k
    return false;
1200
49.9k
}
1201
1202
/* Render an array to text */
1203
0
static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1204
0
    unsigned char *output_pointer = NULL;
1205
0
    size_t length = 0;
1206
0
    cJSON *current_element = item->child;
1207
1208
0
    if (output_buffer == NULL) {
1209
0
        return false;
1210
0
    }
1211
1212
    /* Compose the output array. */
1213
    /* opening square bracket */
1214
0
    output_pointer = ensure(output_buffer, 1, out_of_memory);
1215
0
    if (output_pointer == NULL) {
1216
0
        return false;
1217
0
    }
1218
1219
0
    *output_pointer = '[';
1220
0
    output_buffer->offset++;
1221
0
    output_buffer->depth++;
1222
1223
0
    while (current_element != NULL) {
1224
0
        if (!print_value(current_element, output_buffer, out_of_memory)) {
1225
0
            return false;
1226
0
        }
1227
0
        update_offset(output_buffer);
1228
0
        if (current_element->next) {
1229
0
            length = (size_t)(output_buffer->format ? 2 : 1);
1230
0
            output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1231
0
            if (output_pointer == NULL) {
1232
0
                return false;
1233
0
            }
1234
0
            *output_pointer++ = ',';
1235
0
            if (output_buffer->format) {
1236
0
                *output_pointer++ = ' ';
1237
0
            }
1238
0
            *output_pointer = '\0';
1239
0
            output_buffer->offset += length;
1240
0
        }
1241
0
        current_element = current_element->next;
1242
0
    }
1243
1244
0
    output_pointer = ensure(output_buffer, 2, out_of_memory);
1245
0
    if (output_pointer == NULL) {
1246
0
        return false;
1247
0
    }
1248
0
    *output_pointer++ = ']';
1249
0
    *output_pointer = '\0';
1250
0
    output_buffer->depth--;
1251
1252
0
    return true;
1253
0
}
1254
1255
/* Build an object from the text. */
1256
699k
static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1257
699k
    cJSON *head = NULL; /* linked list head */
1258
699k
    cJSON *current_item = NULL;
1259
1260
699k
    if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1261
3
        return false; /* to deeply nested */
1262
3
    }
1263
699k
    input_buffer->depth++;
1264
1265
699k
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) {
1266
0
        goto fail; /* not an object */
1267
0
    }
1268
1269
699k
    input_buffer->offset++;
1270
699k
    buffer_skip_whitespace(input_buffer);
1271
699k
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) {
1272
8.55k
        goto success; /* empty object */
1273
8.55k
    }
1274
1275
    /* check if we skipped to the end of the buffer */
1276
690k
    if (cannot_access_at_index(input_buffer, 0)) {
1277
0
        input_buffer->offset--;
1278
0
        goto fail;
1279
0
    }
1280
1281
    /* step back to character in front of the first element */
1282
690k
    input_buffer->offset--;
1283
    /* loop through the comma separated array elements */
1284
1.70M
    do {
1285
        /* allocate next item */
1286
1.70M
        cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1287
1.70M
        if (new_item == NULL) {
1288
0
            *out_of_memory = true;
1289
0
            goto fail; /* allocation failure */
1290
0
        }
1291
1292
        /* attach next item to list */
1293
1.70M
        if (head == NULL) {
1294
            /* start the linked list */
1295
690k
            current_item = head = new_item;
1296
1.01M
        } else {
1297
            /* add to the end and advance */
1298
1.01M
            current_item->next = new_item;
1299
1.01M
            new_item->prev = current_item;
1300
1.01M
            current_item = new_item;
1301
1.01M
        }
1302
1303
1.70M
        if (cannot_access_at_index(input_buffer, 1)) {
1304
0
            goto fail; /* nothing comes after the comma */
1305
0
        }
1306
1307
        /* parse the name of the child */
1308
1.70M
        input_buffer->offset++;
1309
1.70M
        buffer_skip_whitespace(input_buffer);
1310
1.70M
        if (!parse_string(current_item, input_buffer, out_of_memory)) {
1311
285
            goto fail; /* failed to parse name */
1312
285
        }
1313
1.70M
        buffer_skip_whitespace(input_buffer);
1314
1315
        /* swap valuestring and string, because we parsed the name */
1316
1.70M
        current_item->string = current_item->valuestring;
1317
1.70M
        current_item->valuestring = NULL;
1318
1319
1.70M
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) {
1320
60
            goto fail; /* invalid object */
1321
60
        }
1322
1323
        /* parse the value */
1324
1.70M
        input_buffer->offset++;
1325
1.70M
        buffer_skip_whitespace(input_buffer);
1326
1.70M
        if (!parse_value(current_item, input_buffer, out_of_memory)) {
1327
2.61k
            goto fail; /* failed to parse value */
1328
2.61k
        }
1329
1.70M
        buffer_skip_whitespace(input_buffer);
1330
1.70M
    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1331
1332
687k
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) {
1333
56
        goto fail; /* expected end of object */
1334
56
    }
1335
1336
696k
success:
1337
696k
    input_buffer->depth--;
1338
1339
696k
    if (head != NULL) {
1340
687k
        head->prev = current_item;
1341
687k
    }
1342
1343
696k
    item->type = cJSON_Object;
1344
696k
    item->child = head;
1345
1346
696k
    input_buffer->offset++;
1347
696k
    return true;
1348
1349
3.01k
fail:
1350
3.01k
    if (head != NULL) {
1351
3.01k
        loader_cJSON_Delete(head);
1352
3.01k
    }
1353
1354
3.01k
    return false;
1355
687k
}
1356
1357
/* Render an object to text. */
1358
0
static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1359
0
    unsigned char *output_pointer = NULL;
1360
0
    size_t length = 0;
1361
0
    cJSON *current_item = item->child;
1362
1363
0
    if (output_buffer == NULL) {
1364
0
        return false;
1365
0
    }
1366
1367
    /* Compose the output: */
1368
0
    length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */
1369
0
    output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1370
0
    if (output_pointer == NULL) {
1371
0
        return false;
1372
0
    }
1373
1374
0
    *output_pointer++ = '{';
1375
0
    output_buffer->depth++;
1376
0
    if (output_buffer->format) {
1377
0
        *output_pointer++ = '\n';
1378
0
    }
1379
0
    output_buffer->offset += length;
1380
1381
0
    while (current_item) {
1382
0
        if (output_buffer->format) {
1383
0
            size_t i;
1384
0
            output_pointer = ensure(output_buffer, output_buffer->depth, out_of_memory);
1385
0
            if (output_pointer == NULL) {
1386
0
                return false;
1387
0
            }
1388
0
            for (i = 0; i < output_buffer->depth; i++) {
1389
0
                *output_pointer++ = '\t';
1390
0
            }
1391
0
            output_buffer->offset += output_buffer->depth;
1392
0
        }
1393
1394
        /* print key */
1395
0
        if (!print_string_ptr((unsigned char *)current_item->string, output_buffer, out_of_memory)) {
1396
0
            return false;
1397
0
        }
1398
0
        update_offset(output_buffer);
1399
1400
0
        length = (size_t)(output_buffer->format ? 2 : 1);
1401
0
        output_pointer = ensure(output_buffer, length, out_of_memory);
1402
0
        if (output_pointer == NULL) {
1403
0
            return false;
1404
0
        }
1405
0
        *output_pointer++ = ':';
1406
0
        if (output_buffer->format) {
1407
0
            *output_pointer++ = '\t';
1408
0
        }
1409
0
        output_buffer->offset += length;
1410
1411
        /* print value */
1412
0
        if (!print_value(current_item, output_buffer, out_of_memory)) {
1413
0
            return false;
1414
0
        }
1415
0
        update_offset(output_buffer);
1416
1417
        /* print comma if not last */
1418
0
        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
1419
0
        output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1420
0
        if (output_pointer == NULL) {
1421
0
            return false;
1422
0
        }
1423
0
        if (current_item->next) {
1424
0
            *output_pointer++ = ',';
1425
0
        }
1426
1427
0
        if (output_buffer->format) {
1428
0
            *output_pointer++ = '\n';
1429
0
        }
1430
0
        *output_pointer = '\0';
1431
0
        output_buffer->offset += length;
1432
1433
0
        current_item = current_item->next;
1434
0
    }
1435
1436
0
    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2, out_of_memory);
1437
0
    if (output_pointer == NULL) {
1438
0
        return false;
1439
0
    }
1440
0
    if (output_buffer->format) {
1441
0
        size_t i;
1442
0
        for (i = 0; i < (output_buffer->depth - 1); i++) {
1443
0
            *output_pointer++ = '\t';
1444
0
        }
1445
0
    }
1446
0
    *output_pointer++ = '}';
1447
0
    *output_pointer = '\0';
1448
0
    output_buffer->depth--;
1449
1450
0
    return true;
1451
0
}
1452
1453
/* Get Array size/item / object item. */
1454
11.3k
CJSON_PUBLIC(int) loader_cJSON_GetArraySize(const cJSON *array) {
1455
11.3k
    cJSON *child = NULL;
1456
11.3k
    size_t size = 0;
1457
1458
11.3k
    if (array == NULL) {
1459
0
        return 0;
1460
0
    }
1461
1462
11.3k
    child = array->child;
1463
1464
679k
    while (child != NULL) {
1465
668k
        size++;
1466
668k
        child = child->next;
1467
668k
    }
1468
1469
    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1470
1471
11.3k
    return (int)size;
1472
11.3k
}
1473
1474
0
static cJSON *get_array_item(const cJSON *array, size_t index) {
1475
0
    cJSON *current_child = NULL;
1476
1477
0
    if (array == NULL) {
1478
0
        return NULL;
1479
0
    }
1480
1481
0
    current_child = array->child;
1482
0
    while ((current_child != NULL) && (index > 0)) {
1483
0
        index--;
1484
0
        current_child = current_child->next;
1485
0
    }
1486
1487
0
    return current_child;
1488
0
}
1489
1490
0
CJSON_PUBLIC(cJSON *) loader_cJSON_GetArrayItem(const cJSON *array, int index) {
1491
0
    if (index < 0) {
1492
0
        return NULL;
1493
0
    }
1494
1495
0
    return get_array_item(array, (size_t)index);
1496
0
}
1497
1498
1.25M
static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) {
1499
1.25M
    cJSON *current_element = NULL;
1500
1501
1.25M
    if ((object == NULL) || (name == NULL)) {
1502
0
        return NULL;
1503
0
    }
1504
1505
1.25M
    current_element = object->child;
1506
1.25M
    if (case_sensitive) {
1507
0
        while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) {
1508
0
            current_element = current_element->next;
1509
0
        }
1510
1.25M
    } else {
1511
4.24M
        while ((current_element != NULL) &&
1512
3.76M
               (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0)) {
1513
2.98M
            current_element = current_element->next;
1514
2.98M
        }
1515
1.25M
    }
1516
1517
1.25M
    if ((current_element == NULL) || (current_element->string == NULL)) {
1518
481k
        return NULL;
1519
481k
    }
1520
1521
776k
    return current_element;
1522
1.25M
}
1523
1524
1.25M
CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItem(const cJSON *const object, const char *const string) {
1525
1.25M
    return get_object_item(object, string, false);
1526
1.25M
}
1527
1528
0
CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItemCaseSensitive(const cJSON *const object, const char *const string) {
1529
0
    return get_object_item(object, string, true);
1530
0
}
1531
1532
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_HasObjectItem(const cJSON *object, const char *string) {
1533
0
    return loader_cJSON_GetObjectItem(object, string) ? 1 : 0;
1534
0
}
1535
1536
0
static void skip_oneline_comment(char **input) {
1537
0
    *input += static_strlen("//");
1538
1539
0
    for (; (*input)[0] != '\0'; ++(*input)) {
1540
0
        if ((*input)[0] == '\n') {
1541
0
            *input += static_strlen("\n");
1542
0
            return;
1543
0
        }
1544
0
    }
1545
0
}
1546
1547
0
static void skip_multiline_comment(char **input) {
1548
0
    *input += static_strlen("/*");
1549
1550
0
    for (; (*input)[0] != '\0'; ++(*input)) {
1551
0
        if (((*input)[0] == '*') && ((*input)[1] == '/')) {
1552
0
            *input += static_strlen("*/");
1553
0
            return;
1554
0
        }
1555
0
    }
1556
0
}
1557
1558
0
static void minify_string(char **input, char **output) {
1559
0
    (*output)[0] = (*input)[0];
1560
0
    *input += static_strlen("\"");
1561
0
    *output += static_strlen("\"");
1562
1563
0
    for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
1564
0
        (*output)[0] = (*input)[0];
1565
1566
0
        if ((*input)[0] == '\"') {
1567
0
            (*output)[0] = '\"';
1568
0
            *input += static_strlen("\"");
1569
0
            *output += static_strlen("\"");
1570
0
            return;
1571
0
        } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
1572
0
            (*output)[1] = (*input)[1];
1573
0
            *input += static_strlen("\"");
1574
0
            *output += static_strlen("\"");
1575
0
        }
1576
0
    }
1577
0
}
1578
1579
0
CJSON_PUBLIC(void) loader_cJSON_Minify(char *json) {
1580
0
    char *into = json;
1581
1582
0
    if (json == NULL) {
1583
0
        return;
1584
0
    }
1585
1586
0
    while (json[0] != '\0') {
1587
0
        switch (json[0]) {
1588
0
            case ' ':
1589
0
            case '\t':
1590
0
            case '\r':
1591
0
            case '\n':
1592
0
                json++;
1593
0
                break;
1594
1595
0
            case '/':
1596
0
                if (json[1] == '/') {
1597
0
                    skip_oneline_comment(&json);
1598
0
                } else if (json[1] == '*') {
1599
0
                    skip_multiline_comment(&json);
1600
0
                } else {
1601
0
                    json++;
1602
0
                }
1603
0
                break;
1604
1605
0
            case '\"':
1606
0
                minify_string(&json, (char **)&into);
1607
0
                break;
1608
1609
0
            default:
1610
0
                into[0] = json[0];
1611
0
                json++;
1612
0
                into++;
1613
0
        }
1614
0
    }
1615
1616
    /* and null-terminate. */
1617
0
    *into = '\0';
1618
0
}
1619
1620
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsInvalid(const cJSON *const item) {
1621
0
    if (item == NULL) {
1622
0
        return false;
1623
0
    }
1624
1625
0
    return (item->type & 0xFF) == cJSON_Invalid;
1626
0
}
1627
1628
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsFalse(const cJSON *const item) {
1629
0
    if (item == NULL) {
1630
0
        return false;
1631
0
    }
1632
1633
0
    return (item->type & 0xFF) == cJSON_False;
1634
0
}
1635
1636
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsTrue(const cJSON *const item) {
1637
0
    if (item == NULL) {
1638
0
        return false;
1639
0
    }
1640
1641
0
    return (item->type & 0xff) == cJSON_True;
1642
0
}
1643
1644
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsBool(const cJSON *const item) {
1645
0
    if (item == NULL) {
1646
0
        return false;
1647
0
    }
1648
1649
0
    return (item->type & (cJSON_True | cJSON_False)) != 0;
1650
0
}
1651
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsNull(const cJSON *const item) {
1652
0
    if (item == NULL) {
1653
0
        return false;
1654
0
    }
1655
1656
0
    return (item->type & 0xFF) == cJSON_NULL;
1657
0
}
1658
1659
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsNumber(const cJSON *const item) {
1660
0
    if (item == NULL) {
1661
0
        return false;
1662
0
    }
1663
1664
0
    return (item->type & 0xFF) == cJSON_Number;
1665
0
}
1666
1667
606k
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsString(const cJSON *const item) {
1668
606k
    if (item == NULL) {
1669
268k
        return false;
1670
268k
    }
1671
1672
338k
    return (item->type & 0xFF) == cJSON_String;
1673
606k
}
1674
1675
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsArray(const cJSON *const item) {
1676
0
    if (item == NULL) {
1677
0
        return false;
1678
0
    }
1679
1680
0
    return (item->type & 0xFF) == cJSON_Array;
1681
0
}
1682
1683
0
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON *const item) {
1684
0
    if (item == NULL) {
1685
0
        return false;
1686
0
    }
1687
1688
0
    return (item->type & 0xFF) == cJSON_Object;
1689
0
}
1690
1691
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsRaw(const cJSON *const item) {
1692
0
    if (item == NULL) {
1693
0
        return false;
1694
0
    }
1695
1696
0
    return (item->type & 0xFF) == cJSON_Raw;
1697
0
}
1698
1699
0
CJSON_PUBLIC(cJSON_bool) loader_cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive) {
1700
0
    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) {
1701
0
        return false;
1702
0
    }
1703
1704
    /* check if type is valid */
1705
0
    switch (a->type & 0xFF) {
1706
0
        case cJSON_False:
1707
0
        case cJSON_True:
1708
0
        case cJSON_NULL:
1709
0
        case cJSON_Number:
1710
0
        case cJSON_String:
1711
0
        case cJSON_Raw:
1712
0
        case cJSON_Array:
1713
0
        case cJSON_Object:
1714
0
            break;
1715
1716
0
        default:
1717
0
            return false;
1718
0
    }
1719
1720
    /* identical objects are equal */
1721
0
    if (a == b) {
1722
0
        return true;
1723
0
    }
1724
1725
0
    switch (a->type & 0xFF) {
1726
        /* in these cases and equal type is enough */
1727
0
        case cJSON_False:
1728
0
        case cJSON_True:
1729
0
        case cJSON_NULL:
1730
0
            return true;
1731
1732
0
        case cJSON_Number:
1733
0
            if (compare_double(a->valuedouble, b->valuedouble)) {
1734
0
                return true;
1735
0
            }
1736
0
            return false;
1737
1738
0
        case cJSON_String:
1739
0
        case cJSON_Raw:
1740
0
            if ((a->valuestring == NULL) || (b->valuestring == NULL)) {
1741
0
                return false;
1742
0
            }
1743
0
            if (strcmp(a->valuestring, b->valuestring) == 0) {
1744
0
                return true;
1745
0
            }
1746
1747
0
            return false;
1748
1749
0
        case cJSON_Array: {
1750
0
            cJSON *a_element = a->child;
1751
0
            cJSON *b_element = b->child;
1752
1753
0
            for (; (a_element != NULL) && (b_element != NULL);) {
1754
0
                if (!loader_cJSON_Compare(a_element, b_element, case_sensitive)) {
1755
0
                    return false;
1756
0
                }
1757
1758
0
                a_element = a_element->next;
1759
0
                b_element = b_element->next;
1760
0
            }
1761
1762
            /* one of the arrays is longer than the other */
1763
0
            if (a_element != b_element) {
1764
0
                return false;
1765
0
            }
1766
1767
0
            return true;
1768
0
        }
1769
1770
0
        case cJSON_Object: {
1771
0
            cJSON *a_element = NULL;
1772
0
            cJSON *b_element = NULL;
1773
0
            cJSON_ArrayForEach(a_element, a) {
1774
                /* TODO This has O(n^2) runtime, which is horrible! */
1775
0
                b_element = get_object_item(b, a_element->string, case_sensitive);
1776
0
                if (b_element == NULL) {
1777
0
                    return false;
1778
0
                }
1779
1780
0
                if (!loader_cJSON_Compare(a_element, b_element, case_sensitive)) {
1781
0
                    return false;
1782
0
                }
1783
0
            }
1784
1785
            /* doing this twice, once on a and b to prevent true comparison if a subset of b
1786
             * TODO: Do this the proper way, this is just a fix for now */
1787
0
            cJSON_ArrayForEach(b_element, b) {
1788
0
                a_element = get_object_item(a, b_element->string, case_sensitive);
1789
0
                if (a_element == NULL) {
1790
0
                    return false;
1791
0
                }
1792
1793
0
                if (!loader_cJSON_Compare(b_element, a_element, case_sensitive)) {
1794
0
                    return false;
1795
0
                }
1796
0
            }
1797
1798
0
            return true;
1799
0
        }
1800
1801
0
        default:
1802
0
            return false;
1803
0
    }
1804
0
}