Coverage Report

Created: 2026-01-10 07:02

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