Coverage Report

Created: 2025-08-11 06:16

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