/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 | 12.8M | #define true ((cJSON_bool)1) |
70 | | |
71 | | #ifdef false |
72 | | #undef false |
73 | | #endif |
74 | 3.25M | #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 | 715k | CJSON_PUBLIC(char *) loader_cJSON_GetStringValue(const cJSON *const item) { |
101 | 715k | if (!loader_cJSON_IsString(item)) { |
102 | 613k | return NULL; |
103 | 613k | } |
104 | | |
105 | 102k | return item->valuestring; |
106 | 715k | } |
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 | 4.41M | static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) { |
123 | 4.41M | if ((string1 == NULL) || (string2 == NULL)) { |
124 | 37 | return 1; |
125 | 37 | } |
126 | | |
127 | 4.41M | if (string1 == string2) { |
128 | 0 | return 0; |
129 | 0 | } |
130 | | |
131 | 10.6M | for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) { |
132 | 7.17M | if (*string1 == '\0') { |
133 | 926k | return 0; |
134 | 926k | } |
135 | 7.17M | } |
136 | | |
137 | 3.48M | return tolower(*string1) - tolower(*string2); |
138 | 4.41M | } |
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.32M | static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) { |
145 | 8.32M | cJSON *node = (cJSON *)loader_calloc(pAllocator, sizeof(cJSON), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); |
146 | 8.32M | if (NULL != node) { |
147 | 8.32M | node->pAllocator = pAllocator; |
148 | 8.32M | } |
149 | 8.32M | return node; |
150 | 8.32M | } |
151 | | |
152 | | /* Delete a cJSON structure. */ |
153 | 2.06M | TEST_FUNCTION_EXPORT CJSON_PUBLIC(void) loader_cJSON_Delete(cJSON *item) { |
154 | 2.06M | cJSON *next = NULL; |
155 | 10.3M | while (item != NULL) { |
156 | 8.32M | next = item->next; |
157 | 8.32M | if (!(item->type & cJSON_IsReference) && (item->child != NULL)) { |
158 | 1.94M | loader_cJSON_Delete(item->child); |
159 | 1.94M | } |
160 | 8.32M | if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { |
161 | 2.88M | loader_free(item->pAllocator, item->valuestring); |
162 | 2.88M | item->valuestring = NULL; |
163 | 2.88M | } |
164 | 8.32M | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { |
165 | 2.50M | loader_free(item->pAllocator, item->string); |
166 | 2.50M | item->string = NULL; |
167 | 2.50M | } |
168 | 8.32M | loader_free(item->pAllocator, item); |
169 | 8.32M | item = next; |
170 | 8.32M | } |
171 | 2.06M | } |
172 | | |
173 | | /* get the decimal point character of the current locale */ |
174 | 3.30M | 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 | 3.30M | return '.'; |
180 | 3.30M | #endif |
181 | 3.30M | } |
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 | 49.9M | #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 | 174M | #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) |
195 | 40.8M | #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 | 3.30M | static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) { |
201 | 3.30M | double number = 0; |
202 | 3.30M | unsigned char *after_end = NULL; |
203 | 3.30M | unsigned char number_c_string[64]; |
204 | 3.30M | unsigned char decimal_point = get_decimal_point(); |
205 | 3.30M | size_t i = 0; |
206 | | |
207 | 3.30M | 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 | 8.25M | for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) { |
215 | 8.25M | switch (buffer_at_offset(input_buffer)[i]) { |
216 | 212k | case '0': |
217 | 3.45M | case '1': |
218 | 3.79M | case '2': |
219 | 4.00M | case '3': |
220 | 4.19M | case '4': |
221 | 4.31M | case '5': |
222 | 4.41M | case '6': |
223 | 4.57M | case '7': |
224 | 4.68M | case '8': |
225 | 4.84M | case '9': |
226 | 4.84M | case '+': |
227 | 4.86M | case '-': |
228 | 4.88M | case 'e': |
229 | 4.89M | case 'E': |
230 | 4.89M | number_c_string[i] = buffer_at_offset(input_buffer)[i]; |
231 | 4.89M | break; |
232 | | |
233 | 61.9k | case '.': |
234 | 61.9k | number_c_string[i] = decimal_point; |
235 | 61.9k | break; |
236 | | |
237 | 3.30M | default: |
238 | 3.30M | goto loop_end; |
239 | 8.25M | } |
240 | 8.25M | } |
241 | 3.30M | loop_end: |
242 | 3.30M | number_c_string[i] = '\0'; |
243 | | |
244 | 3.30M | number = strtod((const char *)number_c_string, (char **)&after_end); |
245 | 3.30M | if (number_c_string == after_end) { |
246 | 75 | return false; /* parse_error */ |
247 | 75 | } |
248 | | |
249 | 3.30M | item->valuedouble = number; |
250 | | |
251 | | /* use saturation in case of overflow */ |
252 | 3.30M | if (number >= INT_MAX) { |
253 | 24.0k | item->valueint = INT_MAX; |
254 | 3.28M | } else if (number <= (double)INT_MIN) { |
255 | 1.09k | item->valueint = INT_MIN; |
256 | 3.28M | } else { |
257 | 3.28M | item->valueint = (int)number; |
258 | 3.28M | } |
259 | | |
260 | 3.30M | item->type = cJSON_Number; |
261 | | |
262 | 3.30M | input_buffer->offset += (size_t)(after_end - number_c_string); |
263 | 3.30M | return true; |
264 | 3.30M | } |
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 | 1.05M | static unsigned char *ensure(printbuffer *const p, size_t needed, bool *out_of_memory) { |
278 | 1.05M | unsigned char *newbuffer = NULL; |
279 | 1.05M | size_t newsize = 0; |
280 | | |
281 | 1.05M | if ((p == NULL) || (p->buffer == NULL)) { |
282 | 0 | return NULL; |
283 | 0 | } |
284 | | |
285 | 1.05M | if ((p->length > 0) && (p->offset >= p->length)) { |
286 | | /* make sure that offset is valid */ |
287 | 0 | return NULL; |
288 | 0 | } |
289 | | |
290 | 1.05M | if (needed > INT_MAX) { |
291 | | /* sizes bigger than INT_MAX are currently not supported */ |
292 | 0 | return NULL; |
293 | 0 | } |
294 | | |
295 | 1.05M | needed += p->offset + 1; |
296 | 1.05M | if (needed <= p->length) { |
297 | 1.04M | return p->buffer + p->offset; |
298 | 1.04M | } |
299 | | |
300 | 6.62k | if (p->noalloc) { |
301 | 1.92k | return NULL; |
302 | 1.92k | } |
303 | | |
304 | | /* calculate new buffer size */ |
305 | 4.70k | 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 | 4.70k | } else { |
313 | 4.70k | newsize = needed * 2; |
314 | 4.70k | } |
315 | | |
316 | 4.70k | newbuffer = (unsigned char *)loader_realloc(p->pAllocator, p->buffer, p->length, newsize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); |
317 | 4.70k | 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 | 4.70k | p->length = newsize; |
327 | 4.70k | p->buffer = newbuffer; |
328 | | |
329 | 4.70k | return newbuffer + p->offset; |
330 | 4.70k | } |
331 | | |
332 | | /* calculate the new length of the string in a printbuffer and update the offset */ |
333 | 357k | static void update_offset(printbuffer *const buffer) { |
334 | 357k | const unsigned char *buffer_pointer = NULL; |
335 | 357k | if ((buffer == NULL) || (buffer->buffer == NULL)) { |
336 | 0 | return; |
337 | 0 | } |
338 | 357k | buffer_pointer = buffer->buffer + buffer->offset; |
339 | | |
340 | 357k | buffer->offset += strlen((const char *)buffer_pointer); |
341 | 357k | } |
342 | | |
343 | | /* securely comparison of floating-point variables */ |
344 | 0 | static cJSON_bool compare_double(double a, double b) { |
345 | 0 | double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); |
346 | 0 | return (fabs(a - b) <= maxVal * DBL_EPSILON); |
347 | 0 | } |
348 | | |
349 | | /* Render the number nicely from the given item into a string. */ |
350 | 0 | static cJSON_bool print_number(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) { |
351 | 0 | unsigned char *output_pointer = NULL; |
352 | 0 | double d = item->valuedouble; |
353 | 0 | int length = 0; |
354 | 0 | size_t i = 0; |
355 | 0 | unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ |
356 | 0 | unsigned char decimal_point = get_decimal_point(); |
357 | 0 | double test = 0.0; |
358 | |
|
359 | 0 | if (output_buffer == NULL) { |
360 | 0 | return false; |
361 | 0 | } |
362 | | |
363 | | /* This checks for NaN and Infinity */ |
364 | 0 | if (isnan(d) || isinf(d)) { |
365 | 0 | length = snprintf((char *)number_buffer, 26, "null"); |
366 | 0 | } else if (d == (double)item->valueint) { |
367 | 0 | length = snprintf((char *)number_buffer, 26, "%d", item->valueint); |
368 | 0 | } else { |
369 | | /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ |
370 | 0 | length = snprintf((char *)number_buffer, 26, "%1.15g", d); |
371 | | |
372 | | /* Check whether the original double can be recovered */ |
373 | 0 | if ((sscanf((char *)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) { |
374 | | /* If not, print with 17 decimal places of precision */ |
375 | 0 | length = snprintf((char *)number_buffer, 26, "%1.17g", d); |
376 | 0 | } |
377 | 0 | } |
378 | | |
379 | | /* snprintf failed or buffer overrun occurred */ |
380 | 0 | if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { |
381 | 0 | return false; |
382 | 0 | } |
383 | | |
384 | | /* reserve appropriate space in the output */ |
385 | 0 | output_pointer = ensure(output_buffer, (size_t)length + sizeof(""), out_of_memory); |
386 | 0 | if (output_pointer == NULL) { |
387 | 0 | return false; |
388 | 0 | } |
389 | | |
390 | | /* copy the printed number to the output and replace locale |
391 | | * dependent decimal point with '.' */ |
392 | 0 | for (i = 0; i < ((size_t)length); i++) { |
393 | 0 | if (number_buffer[i] == decimal_point) { |
394 | 0 | output_pointer[i] = '.'; |
395 | 0 | continue; |
396 | 0 | } |
397 | | |
398 | 0 | output_pointer[i] = number_buffer[i]; |
399 | 0 | } |
400 | 0 | output_pointer[i] = '\0'; |
401 | |
|
402 | 0 | output_buffer->offset += (size_t)length; |
403 | |
|
404 | 0 | return true; |
405 | 0 | } |
406 | | |
407 | | /* parse 4 digit hexadecimal number */ |
408 | 130k | static unsigned parse_hex4(const unsigned char *const input) { |
409 | 130k | unsigned int h = 0; |
410 | 130k | size_t i = 0; |
411 | | |
412 | 448k | for (i = 0; i < 4; i++) { |
413 | | /* parse digit */ |
414 | 399k | if ((input[i] >= '0') && (input[i] <= '9')) { |
415 | 121k | h += (unsigned int)input[i] - '0'; |
416 | 277k | } else if ((input[i] >= 'A') && (input[i] <= 'F')) { |
417 | 98.5k | h += (unsigned int)10 + input[i] - 'A'; |
418 | 178k | } else if ((input[i] >= 'a') && (input[i] <= 'f')) { |
419 | 97.4k | h += (unsigned int)10 + input[i] - 'a'; |
420 | 97.4k | } else /* invalid */ |
421 | 81.4k | { |
422 | 81.4k | return 0; |
423 | 81.4k | } |
424 | | |
425 | 317k | if (i < 3) { |
426 | | /* shift left to make place for the next nibble */ |
427 | 268k | h = h << 4; |
428 | 268k | } |
429 | 317k | } |
430 | | |
431 | 49.2k | return h; |
432 | 130k | } |
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 | 125k | unsigned char **output_pointer) { |
438 | 125k | long unsigned int codepoint = 0; |
439 | 125k | unsigned int first_code = 0; |
440 | 125k | const unsigned char *first_sequence = input_pointer; |
441 | 125k | unsigned char utf8_length = 0; |
442 | 125k | unsigned char utf8_position = 0; |
443 | 125k | unsigned char sequence_length = 0; |
444 | 125k | unsigned char first_byte_mark = 0; |
445 | | |
446 | 125k | if ((input_end - first_sequence) < 6) { |
447 | | /* input ends unexpectedly */ |
448 | 20 | goto fail; |
449 | 20 | } |
450 | | |
451 | | /* get the first utf16 sequence */ |
452 | 125k | first_code = parse_hex4(first_sequence + 2); |
453 | | |
454 | | /* check that the code is valid */ |
455 | 125k | if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) { |
456 | 44 | goto fail; |
457 | 44 | } |
458 | | |
459 | | /* UTF16 surrogate pair */ |
460 | 125k | if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) { |
461 | 5.39k | const unsigned char *second_sequence = first_sequence + 6; |
462 | 5.39k | unsigned int second_code = 0; |
463 | 5.39k | sequence_length = 12; /* \uXXXX\uXXXX */ |
464 | | |
465 | 5.39k | if ((input_end - second_sequence) < 6) { |
466 | | /* input ends unexpectedly */ |
467 | 41 | goto fail; |
468 | 41 | } |
469 | | |
470 | 5.35k | if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) { |
471 | | /* missing second half of the surrogate pair */ |
472 | 56 | goto fail; |
473 | 56 | } |
474 | | |
475 | | /* get the second utf16 sequence */ |
476 | 5.29k | second_code = parse_hex4(second_sequence + 2); |
477 | | /* check that the code is valid */ |
478 | 5.29k | if ((second_code < 0xDC00) || (second_code > 0xDFFF)) { |
479 | | /* invalid second half of the surrogate pair */ |
480 | 97 | goto fail; |
481 | 97 | } |
482 | | |
483 | | /* calculate the unicode codepoint from the surrogate pair */ |
484 | 5.19k | codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); |
485 | 120k | } else { |
486 | 120k | sequence_length = 6; /* \uXXXX */ |
487 | 120k | codepoint = first_code; |
488 | 120k | } |
489 | | |
490 | | /* encode as UTF-8 |
491 | | * takes at maximum 4 bytes to encode: |
492 | | * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ |
493 | 125k | if (codepoint < 0x80) { |
494 | | /* normal ascii, encoding 0xxxxxxx */ |
495 | 81.8k | utf8_length = 1; |
496 | 81.8k | } else if (codepoint < 0x800) { |
497 | | /* two bytes, encoding 110xxxxx 10xxxxxx */ |
498 | 4.56k | utf8_length = 2; |
499 | 4.56k | first_byte_mark = 0xC0; /* 11000000 */ |
500 | 38.8k | } else if (codepoint < 0x10000) { |
501 | | /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ |
502 | 33.6k | utf8_length = 3; |
503 | 33.6k | first_byte_mark = 0xE0; /* 11100000 */ |
504 | 33.6k | } else if (codepoint <= 0x10FFFF) { |
505 | | /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ |
506 | 5.19k | utf8_length = 4; |
507 | 5.19k | first_byte_mark = 0xF0; /* 11110000 */ |
508 | 5.19k | } else { |
509 | | /* invalid unicode codepoint */ |
510 | 0 | goto fail; |
511 | 0 | } |
512 | | |
513 | | /* encode as utf8 */ |
514 | 212k | for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) { |
515 | | /* 10xxxxxx */ |
516 | 87.4k | (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); |
517 | 87.4k | codepoint >>= 6; |
518 | 87.4k | } |
519 | | /* encode first byte */ |
520 | 125k | if (utf8_length > 1) { |
521 | 43.4k | (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); |
522 | 81.8k | } else { |
523 | 81.8k | (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); |
524 | 81.8k | } |
525 | | |
526 | 125k | *output_pointer += utf8_length; |
527 | | |
528 | 125k | return sequence_length; |
529 | | |
530 | 258 | fail: |
531 | 258 | return 0; |
532 | 125k | } |
533 | | |
534 | | /* Parse the input text into an unescaped cinput, and populate item. */ |
535 | 5.39M | static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) { |
536 | 5.39M | const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; |
537 | 5.39M | const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; |
538 | 5.39M | unsigned char *output_pointer = NULL; |
539 | 5.39M | unsigned char *output = NULL; |
540 | | |
541 | | /* not a string */ |
542 | 5.39M | if (buffer_at_offset(input_buffer)[0] != '\"') { |
543 | 222 | goto fail; |
544 | 222 | } |
545 | | |
546 | 5.39M | { |
547 | | /* calculate approximate size of the output (overestimate) */ |
548 | 5.39M | size_t allocation_length = 0; |
549 | 5.39M | size_t skipped_bytes = 0; |
550 | 108M | while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) { |
551 | | /* is escape sequence */ |
552 | 103M | if (input_end[0] == '\\') { |
553 | 231k | 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 | 231k | skipped_bytes++; |
558 | 231k | input_end++; |
559 | 231k | } |
560 | 103M | input_end++; |
561 | 103M | } |
562 | 5.39M | if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) { |
563 | 161 | goto fail; /* string ended unexpectedly */ |
564 | 161 | } |
565 | | |
566 | | /* This is at most how much we need for the output */ |
567 | 5.39M | allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes; |
568 | 5.39M | output = (unsigned char *)loader_calloc(input_buffer->pAllocator, allocation_length + sizeof(""), |
569 | 5.39M | VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); |
570 | 5.39M | if (output == NULL) { |
571 | 0 | *out_of_memory = true; |
572 | 0 | goto fail; /* allocation failure */ |
573 | 0 | } |
574 | 5.39M | } |
575 | | |
576 | 5.39M | output_pointer = output; |
577 | | /* loop through the string literal */ |
578 | 103M | while (input_pointer < input_end) { |
579 | 98.4M | if (*input_pointer != '\\') { |
580 | 98.3M | *output_pointer++ = *input_pointer++; |
581 | 98.3M | } |
582 | | /* escape sequence */ |
583 | 167k | else { |
584 | 167k | unsigned char sequence_length = 2; |
585 | 167k | if ((input_end - input_pointer) < 1) { |
586 | 0 | goto fail; |
587 | 0 | } |
588 | | |
589 | 167k | switch (input_pointer[1]) { |
590 | 1.06k | case 'b': |
591 | 1.06k | *output_pointer++ = '\b'; |
592 | 1.06k | break; |
593 | 11.4k | case 'f': |
594 | 11.4k | *output_pointer++ = '\f'; |
595 | 11.4k | break; |
596 | 2.34k | case 'n': |
597 | 2.34k | *output_pointer++ = '\n'; |
598 | 2.34k | break; |
599 | 4.71k | case 'r': |
600 | 4.71k | *output_pointer++ = '\r'; |
601 | 4.71k | break; |
602 | 495 | case 't': |
603 | 495 | *output_pointer++ = '\t'; |
604 | 495 | break; |
605 | 4.81k | case '\"': |
606 | 20.9k | case '\\': |
607 | 21.6k | case '/': |
608 | 21.6k | *output_pointer++ = input_pointer[1]; |
609 | 21.6k | break; |
610 | | |
611 | | /* UTF-16 literal */ |
612 | 125k | case 'u': |
613 | 125k | sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); |
614 | 125k | if (sequence_length == 0) { |
615 | | /* failed to convert UTF16-literal to UTF-8 */ |
616 | 258 | goto fail; |
617 | 258 | } |
618 | 125k | break; |
619 | | |
620 | 125k | default: |
621 | 99 | goto fail; |
622 | 167k | } |
623 | 167k | input_pointer += sequence_length; |
624 | 167k | } |
625 | 98.4M | } |
626 | | |
627 | | /* zero terminate the output */ |
628 | 5.39M | *output_pointer = '\0'; |
629 | | |
630 | 5.39M | item->type = cJSON_String; |
631 | 5.39M | item->valuestring = (char *)output; |
632 | | |
633 | 5.39M | input_buffer->offset = (size_t)(input_end - input_buffer->content); |
634 | 5.39M | input_buffer->offset++; |
635 | | |
636 | 5.39M | return true; |
637 | | |
638 | 740 | fail: |
639 | 740 | if (output != NULL) { |
640 | 357 | loader_free(input_buffer->pAllocator, output); |
641 | 357 | output = NULL; |
642 | 357 | } |
643 | | |
644 | 740 | if (input_pointer != NULL) { |
645 | 740 | input_buffer->offset = (size_t)(input_pointer - input_buffer->content); |
646 | 740 | } |
647 | | |
648 | 740 | return false; |
649 | 5.39M | } |
650 | | |
651 | | /* Render the cstring provided to an escaped version that can be printed. */ |
652 | 1.05M | static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer, bool *out_of_memory) { |
653 | 1.05M | const unsigned char *input_pointer = NULL; |
654 | 1.05M | unsigned char *output = NULL; |
655 | 1.05M | unsigned char *output_pointer = NULL; |
656 | 1.05M | size_t output_length = 0; |
657 | | /* numbers of additional characters needed for escaping */ |
658 | 1.05M | size_t escape_characters = 0; |
659 | | |
660 | 1.05M | if (output_buffer == NULL) { |
661 | 0 | return false; |
662 | 0 | } |
663 | | |
664 | | /* empty string */ |
665 | 1.05M | 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 | 26.9M | for (input_pointer = input; *input_pointer; input_pointer++) { |
676 | 25.9M | switch (*input_pointer) { |
677 | 306 | case '\"': |
678 | 4.89k | case '\\': |
679 | 14.1k | case '\b': |
680 | 145k | case '\f': |
681 | 299k | case '\n': |
682 | 303k | case '\r': |
683 | 328k | case '\t': |
684 | | /* one character escape sequence */ |
685 | 328k | escape_characters++; |
686 | 328k | break; |
687 | 25.5M | default: |
688 | 25.5M | if (*input_pointer < 32) { |
689 | | /* UTF-16 escape sequence uXXXX */ |
690 | 15.7M | escape_characters += 5; |
691 | 15.7M | } |
692 | 25.5M | break; |
693 | 25.9M | } |
694 | 25.9M | } |
695 | 1.05M | output_length = (size_t)(input_pointer - input) + escape_characters; |
696 | | |
697 | 1.05M | output = ensure(output_buffer, output_length + sizeof(""), out_of_memory); |
698 | 1.05M | if (output == NULL) { |
699 | 1.92k | return false; |
700 | 1.92k | } |
701 | | |
702 | | /* no characters have to be escaped */ |
703 | 1.05M | if (escape_characters == 0) { |
704 | 999k | memcpy(output, input, output_length); |
705 | 999k | output[output_length] = '\0'; |
706 | | |
707 | 999k | return true; |
708 | 999k | } |
709 | | |
710 | 50.3k | output_pointer = output; |
711 | | /* copy the string */ |
712 | 18.4M | for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) { |
713 | 18.3M | if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { |
714 | | /* normal character, copy */ |
715 | 2.47M | *output_pointer = *input_pointer; |
716 | 15.8M | } 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 | 15.8M | switch (*input_pointer) { |
723 | 4.58k | case '\\': |
724 | 4.58k | *output_pointer = '\\'; |
725 | 4.58k | break; |
726 | 306 | case '\"': |
727 | 306 | *output_pointer = '\"'; |
728 | 306 | break; |
729 | 9.22k | case '\b': |
730 | 9.22k | *output_pointer = '\b'; |
731 | 9.22k | break; |
732 | 129k | case '\f': |
733 | 129k | *output_pointer = '\f'; |
734 | 129k | break; |
735 | 95.8k | case '\n': |
736 | 95.8k | *output_pointer = '\n'; |
737 | 95.8k | break; |
738 | 4.21k | case '\r': |
739 | 4.21k | *output_pointer = '\r'; |
740 | 4.21k | break; |
741 | 21.8k | case '\t': |
742 | 21.8k | *output_pointer = '\t'; |
743 | 21.8k | break; |
744 | 15.6M | default: |
745 | | /* escape and print as unicode codepoint */ |
746 | 15.6M | snprintf((char *)output_pointer, output_length - (size_t)(output_pointer - output), "u%04x", *input_pointer); |
747 | 15.6M | output_pointer += 4; |
748 | 15.6M | break; |
749 | 15.8M | } |
750 | 15.8M | } |
751 | 18.3M | } |
752 | 50.3k | output[output_length] = '\0'; |
753 | | |
754 | 50.3k | return true; |
755 | 50.3k | } |
756 | | |
757 | | /* Invoke print_string_ptr (which is useful) on an item. */ |
758 | 1.05M | static cJSON_bool print_string(const cJSON *const item, printbuffer *const p, bool *out_of_memory) { |
759 | 1.05M | return print_string_ptr((unsigned char *)item->valuestring, p, out_of_memory); |
760 | 1.05M | } |
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 | 23.6M | static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) { |
772 | 23.6M | if ((buffer == NULL) || (buffer->content == NULL)) { |
773 | 0 | return NULL; |
774 | 0 | } |
775 | | |
776 | 23.6M | if (cannot_access_at_index(buffer, 0)) { |
777 | 0 | return buffer; |
778 | 0 | } |
779 | | |
780 | 37.8M | while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { |
781 | 14.2M | buffer->offset++; |
782 | 14.2M | } |
783 | | |
784 | 23.6M | if (buffer->offset == buffer->length) { |
785 | 2.27k | buffer->offset--; |
786 | 2.27k | } |
787 | | |
788 | 23.6M | return buffer; |
789 | 23.6M | } |
790 | | |
791 | | /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ |
792 | 17.2k | static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) { |
793 | 17.2k | if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) { |
794 | 0 | return NULL; |
795 | 0 | } |
796 | | |
797 | 17.2k | if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) { |
798 | 92 | buffer->offset += 3; |
799 | 92 | } |
800 | | |
801 | 17.2k | return buffer; |
802 | 17.2k | } |
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 | 17.2k | const char **return_parse_end, cJSON_bool require_null_terminated, bool *out_of_memory) { |
824 | 17.2k | parse_buffer buffer = {0, 0, 0, 0, 0}; |
825 | 17.2k | cJSON *item = NULL; |
826 | | |
827 | | /* reset error position */ |
828 | 17.2k | global_error.json = NULL; |
829 | 17.2k | global_error.position = 0; |
830 | | |
831 | 17.2k | if (value == NULL || 0 == buffer_length) { |
832 | 0 | goto fail; |
833 | 0 | } |
834 | | |
835 | 17.2k | buffer.content = (const unsigned char *)value; |
836 | 17.2k | buffer.length = buffer_length; |
837 | 17.2k | buffer.offset = 0; |
838 | 17.2k | buffer.pAllocator = pAllocator; |
839 | | |
840 | 17.2k | item = cJSON_New_Item(pAllocator); |
841 | 17.2k | if (item == NULL) /* memory fail */ |
842 | 0 | { |
843 | 0 | *out_of_memory = true; |
844 | 0 | goto fail; |
845 | 0 | } |
846 | | |
847 | 17.2k | if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)), out_of_memory)) { |
848 | | /* parse failure. ep is set. */ |
849 | 4.50k | goto fail; |
850 | 4.50k | } |
851 | | |
852 | | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ |
853 | 12.7k | 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 | 12.7k | if (return_parse_end) { |
860 | 0 | *return_parse_end = (const char *)buffer_at_offset(&buffer); |
861 | 0 | } |
862 | | |
863 | 12.7k | return item; |
864 | | |
865 | 4.50k | fail: |
866 | 4.50k | if (item != NULL) { |
867 | 4.50k | loader_cJSON_Delete(item); |
868 | 4.50k | } |
869 | | |
870 | 4.50k | if (value != NULL) { |
871 | 4.50k | error local_error; |
872 | 4.50k | local_error.json = (const unsigned char *)value; |
873 | 4.50k | local_error.position = 0; |
874 | | |
875 | 4.50k | if (buffer.offset < buffer.length) { |
876 | 4.36k | local_error.position = buffer.offset; |
877 | 4.36k | } else if (buffer.length > 0) { |
878 | 144 | local_error.position = buffer.length - 1; |
879 | 144 | } |
880 | | |
881 | 4.50k | if (return_parse_end != NULL) { |
882 | 0 | *return_parse_end = (const char *)local_error.json + local_error.position; |
883 | 0 | } |
884 | | |
885 | 4.50k | global_error = local_error; |
886 | 4.50k | } |
887 | | |
888 | 4.50k | return NULL; |
889 | 12.7k | } |
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 | 17.2k | bool *out_of_memory) { |
899 | 17.2k | return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, 0, 0, out_of_memory); |
900 | 17.2k | } |
901 | | |
902 | | #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) |
903 | | |
904 | 357k | static unsigned char *print(const cJSON *const item, cJSON_bool format, bool *out_of_memory) { |
905 | 357k | static const size_t default_buffer_size = 256; |
906 | 357k | printbuffer buffer[1]; |
907 | 357k | unsigned char *printed = NULL; |
908 | | |
909 | 357k | memset(buffer, 0, sizeof(buffer)); |
910 | | |
911 | | /* create buffer */ |
912 | 357k | buffer->buffer = (unsigned char *)loader_calloc(item->pAllocator, default_buffer_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); |
913 | 357k | buffer->length = default_buffer_size; |
914 | 357k | buffer->format = format; |
915 | 357k | buffer->pAllocator = item->pAllocator; |
916 | 357k | if (buffer->buffer == NULL) { |
917 | 0 | *out_of_memory = true; |
918 | 0 | goto fail; |
919 | 0 | } |
920 | | |
921 | | /* print the value */ |
922 | 357k | if (!print_value(item, buffer, out_of_memory)) { |
923 | 0 | goto fail; |
924 | 0 | } |
925 | 357k | update_offset(buffer); |
926 | | |
927 | 357k | printed = (unsigned char *)loader_realloc(item->pAllocator, buffer->buffer, buffer->length, buffer->offset + 1, |
928 | 357k | VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); |
929 | 357k | if (printed == NULL) { |
930 | 0 | *out_of_memory = true; |
931 | 0 | goto fail; |
932 | 0 | } |
933 | 357k | buffer->buffer = NULL; |
934 | | |
935 | 357k | 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 | 357k | } |
950 | | |
951 | | /* Render a cJSON item/entity/structure to text. */ |
952 | 357k | TEST_FUNCTION_EXPORT CJSON_PUBLIC(char *) loader_cJSON_Print(const cJSON *item, bool *out_of_memory) { |
953 | 357k | return (char *)print(item, true, out_of_memory); |
954 | 357k | } |
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 | 694k | loader_cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { |
990 | 694k | printbuffer p = {0, 0, 0, 0, 0, 0, 0}; |
991 | | |
992 | 694k | if ((length < 0) || (buffer == NULL)) { |
993 | 0 | return false; |
994 | 0 | } |
995 | | |
996 | 694k | p.buffer = (unsigned char *)buffer; |
997 | 694k | p.length = (size_t)length; |
998 | 694k | p.offset = 0; |
999 | 694k | p.noalloc = true; |
1000 | 694k | p.format = format; |
1001 | 694k | p.pAllocator = item->pAllocator; |
1002 | 694k | bool out_of_memory = false; |
1003 | 694k | return print_value(item, &p, &out_of_memory); |
1004 | 694k | } |
1005 | | |
1006 | | /* Parser core - when encountering text, process appropriately. */ |
1007 | 8.32M | static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) { |
1008 | 8.32M | 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.32M | if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) { |
1015 | 751 | item->type = cJSON_NULL; |
1016 | 751 | input_buffer->offset += 4; |
1017 | 751 | return true; |
1018 | 751 | } |
1019 | | /* false */ |
1020 | 8.32M | if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) { |
1021 | 459 | item->type = cJSON_False; |
1022 | 459 | input_buffer->offset += 5; |
1023 | 459 | return true; |
1024 | 459 | } |
1025 | | /* true */ |
1026 | 8.32M | if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) { |
1027 | 11.4k | item->type = cJSON_True; |
1028 | 11.4k | item->valueint = 1; |
1029 | 11.4k | input_buffer->offset += 4; |
1030 | 11.4k | return true; |
1031 | 11.4k | } |
1032 | | /* string */ |
1033 | 8.31M | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { |
1034 | 2.88M | return parse_string(item, input_buffer, out_of_memory); |
1035 | 2.88M | } |
1036 | | /* number */ |
1037 | 5.42M | if (can_access_at_index(input_buffer, 0) && |
1038 | 5.42M | ((buffer_at_offset(input_buffer)[0] == '-') || |
1039 | 5.42M | ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) { |
1040 | 3.30M | return parse_number(item, input_buffer); |
1041 | 3.30M | } |
1042 | | /* array */ |
1043 | 2.12M | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) { |
1044 | 242k | return parse_array(item, input_buffer, out_of_memory); |
1045 | 242k | } |
1046 | | /* object */ |
1047 | 1.87M | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) { |
1048 | 1.87M | return parse_object(item, input_buffer, out_of_memory); |
1049 | 1.87M | } |
1050 | | |
1051 | 3.22k | return false; |
1052 | 1.87M | } |
1053 | | |
1054 | | /* Render a value to text. */ |
1055 | 1.05M | static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) { |
1056 | 1.05M | unsigned char *output = NULL; |
1057 | | |
1058 | 1.05M | if ((item == NULL) || (output_buffer == NULL)) { |
1059 | 0 | return false; |
1060 | 0 | } |
1061 | | |
1062 | 1.05M | switch ((item->type) & 0xFF) { |
1063 | 0 | case cJSON_NULL: |
1064 | 0 | output = ensure(output_buffer, 5, out_of_memory); |
1065 | 0 | if (output == NULL) { |
1066 | 0 | return false; |
1067 | 0 | } |
1068 | 0 | strcpy((char *)output, "null"); |
1069 | 0 | return true; |
1070 | | |
1071 | 0 | case cJSON_False: |
1072 | 0 | output = ensure(output_buffer, 6, out_of_memory); |
1073 | 0 | if (output == NULL) { |
1074 | 0 | return false; |
1075 | 0 | } |
1076 | 0 | strcpy((char *)output, "false"); |
1077 | 0 | return true; |
1078 | | |
1079 | 0 | case cJSON_True: |
1080 | 0 | output = ensure(output_buffer, 5, out_of_memory); |
1081 | 0 | if (output == NULL) { |
1082 | 0 | return false; |
1083 | 0 | } |
1084 | 0 | strcpy((char *)output, "true"); |
1085 | 0 | return true; |
1086 | | |
1087 | 0 | case cJSON_Number: |
1088 | 0 | return print_number(item, output_buffer, out_of_memory); |
1089 | | |
1090 | 0 | case cJSON_Raw: { |
1091 | 0 | size_t raw_length = 0; |
1092 | 0 | if (item->valuestring == NULL) { |
1093 | 0 | return false; |
1094 | 0 | } |
1095 | | |
1096 | 0 | raw_length = strlen(item->valuestring) + sizeof(""); |
1097 | 0 | output = ensure(output_buffer, raw_length, out_of_memory); |
1098 | 0 | if (output == NULL) { |
1099 | 0 | return false; |
1100 | 0 | } |
1101 | 0 | memcpy(output, item->valuestring, raw_length); |
1102 | 0 | return true; |
1103 | 0 | } |
1104 | | |
1105 | 1.05M | case cJSON_String: |
1106 | 1.05M | return print_string(item, output_buffer, out_of_memory); |
1107 | | |
1108 | 0 | case cJSON_Array: |
1109 | 0 | return print_array(item, output_buffer, out_of_memory); |
1110 | | |
1111 | 0 | case cJSON_Object: |
1112 | 0 | return print_object(item, output_buffer, out_of_memory); |
1113 | | |
1114 | 0 | default: |
1115 | 0 | return false; |
1116 | 1.05M | } |
1117 | 1.05M | } |
1118 | | |
1119 | | /* Build an array from input text. */ |
1120 | 242k | static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) { |
1121 | 242k | cJSON *head = NULL; /* head of the linked list */ |
1122 | 242k | cJSON *current_item = NULL; |
1123 | | |
1124 | 242k | if (input_buffer->depth >= CJSON_NESTING_LIMIT) { |
1125 | 3 | return false; /* to deeply nested */ |
1126 | 3 | } |
1127 | 242k | input_buffer->depth++; |
1128 | | |
1129 | 242k | if (buffer_at_offset(input_buffer)[0] != '[') { |
1130 | | /* not an array */ |
1131 | 0 | goto fail; |
1132 | 0 | } |
1133 | | |
1134 | 242k | input_buffer->offset++; |
1135 | 242k | buffer_skip_whitespace(input_buffer); |
1136 | 242k | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) { |
1137 | | /* empty array */ |
1138 | 54.1k | goto success; |
1139 | 54.1k | } |
1140 | | |
1141 | | /* check if we skipped to the end of the buffer */ |
1142 | 188k | 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 | 188k | input_buffer->offset--; |
1149 | | /* loop through the comma separated array elements */ |
1150 | 5.80M | do { |
1151 | | /* allocate next item */ |
1152 | 5.80M | cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator); |
1153 | 5.80M | 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 | 5.80M | if (head == NULL) { |
1160 | | /* start the linked list */ |
1161 | 188k | current_item = head = new_item; |
1162 | 5.61M | } else { |
1163 | | /* add to the end and advance */ |
1164 | 5.61M | current_item->next = new_item; |
1165 | 5.61M | new_item->prev = current_item; |
1166 | 5.61M | current_item = new_item; |
1167 | 5.61M | } |
1168 | | |
1169 | | /* parse next value */ |
1170 | 5.80M | input_buffer->offset++; |
1171 | 5.80M | buffer_skip_whitespace(input_buffer); |
1172 | 5.80M | if (!parse_value(current_item, input_buffer, out_of_memory)) { |
1173 | 96.8k | goto fail; /* failed to parse value */ |
1174 | 96.8k | } |
1175 | 5.71M | buffer_skip_whitespace(input_buffer); |
1176 | 5.71M | } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); |
1177 | | |
1178 | 91.4k | if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { |
1179 | 312 | goto fail; /* expected end of array */ |
1180 | 312 | } |
1181 | | |
1182 | 145k | success: |
1183 | 145k | input_buffer->depth--; |
1184 | | |
1185 | 145k | if (head != NULL) { |
1186 | 91.1k | head->prev = current_item; |
1187 | 91.1k | } |
1188 | | |
1189 | 145k | item->type = cJSON_Array; |
1190 | 145k | item->child = head; |
1191 | | |
1192 | 145k | input_buffer->offset++; |
1193 | | |
1194 | 145k | return true; |
1195 | | |
1196 | 97.2k | fail: |
1197 | 97.2k | if (head != NULL) { |
1198 | 97.2k | loader_cJSON_Delete(head); |
1199 | 97.2k | } |
1200 | | |
1201 | 97.2k | return false; |
1202 | 91.4k | } |
1203 | | |
1204 | | /* Render an array to text */ |
1205 | 0 | static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) { |
1206 | 0 | unsigned char *output_pointer = NULL; |
1207 | 0 | size_t length = 0; |
1208 | 0 | cJSON *current_element = item->child; |
1209 | |
|
1210 | 0 | if (output_buffer == NULL) { |
1211 | 0 | return false; |
1212 | 0 | } |
1213 | | |
1214 | | /* Compose the output array. */ |
1215 | | /* opening square bracket */ |
1216 | 0 | output_pointer = ensure(output_buffer, 1, out_of_memory); |
1217 | 0 | if (output_pointer == NULL) { |
1218 | 0 | return false; |
1219 | 0 | } |
1220 | | |
1221 | 0 | *output_pointer = '['; |
1222 | 0 | output_buffer->offset++; |
1223 | 0 | output_buffer->depth++; |
1224 | |
|
1225 | 0 | while (current_element != NULL) { |
1226 | 0 | if (!print_value(current_element, output_buffer, out_of_memory)) { |
1227 | 0 | return false; |
1228 | 0 | } |
1229 | 0 | update_offset(output_buffer); |
1230 | 0 | if (current_element->next) { |
1231 | 0 | length = (size_t)(output_buffer->format ? 2 : 1); |
1232 | 0 | output_pointer = ensure(output_buffer, length + 1, out_of_memory); |
1233 | 0 | if (output_pointer == NULL) { |
1234 | 0 | return false; |
1235 | 0 | } |
1236 | 0 | *output_pointer++ = ','; |
1237 | 0 | if (output_buffer->format) { |
1238 | 0 | *output_pointer++ = ' '; |
1239 | 0 | } |
1240 | 0 | *output_pointer = '\0'; |
1241 | 0 | output_buffer->offset += length; |
1242 | 0 | } |
1243 | 0 | current_element = current_element->next; |
1244 | 0 | } |
1245 | | |
1246 | 0 | output_pointer = ensure(output_buffer, 2, out_of_memory); |
1247 | 0 | if (output_pointer == NULL) { |
1248 | 0 | return false; |
1249 | 0 | } |
1250 | 0 | *output_pointer++ = ']'; |
1251 | 0 | *output_pointer = '\0'; |
1252 | 0 | output_buffer->depth--; |
1253 | |
|
1254 | 0 | return true; |
1255 | 0 | } |
1256 | | |
1257 | | /* Build an object from the text. */ |
1258 | 1.87M | static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) { |
1259 | 1.87M | cJSON *head = NULL; /* linked list head */ |
1260 | 1.87M | cJSON *current_item = NULL; |
1261 | | |
1262 | 1.87M | if (input_buffer->depth >= CJSON_NESTING_LIMIT) { |
1263 | 8 | return false; /* to deeply nested */ |
1264 | 8 | } |
1265 | 1.87M | input_buffer->depth++; |
1266 | | |
1267 | 1.87M | 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 | 1.87M | input_buffer->offset++; |
1272 | 1.87M | buffer_skip_whitespace(input_buffer); |
1273 | 1.87M | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) { |
1274 | 13.6k | goto success; /* empty object */ |
1275 | 13.6k | } |
1276 | | |
1277 | | /* check if we skipped to the end of the buffer */ |
1278 | 1.86M | 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 | 1.86M | input_buffer->offset--; |
1285 | | /* loop through the comma separated array elements */ |
1286 | 2.50M | do { |
1287 | | /* allocate next item */ |
1288 | 2.50M | cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator); |
1289 | 2.50M | 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 | 2.50M | if (head == NULL) { |
1296 | | /* start the linked list */ |
1297 | 1.86M | current_item = head = new_item; |
1298 | 1.86M | } else { |
1299 | | /* add to the end and advance */ |
1300 | 641k | current_item->next = new_item; |
1301 | 641k | new_item->prev = current_item; |
1302 | 641k | current_item = new_item; |
1303 | 641k | } |
1304 | | |
1305 | 2.50M | 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 | 2.50M | input_buffer->offset++; |
1311 | 2.50M | buffer_skip_whitespace(input_buffer); |
1312 | 2.50M | if (!parse_string(current_item, input_buffer, out_of_memory)) { |
1313 | 287 | goto fail; /* failed to parse name */ |
1314 | 287 | } |
1315 | 2.50M | buffer_skip_whitespace(input_buffer); |
1316 | | |
1317 | | /* swap valuestring and string, because we parsed the name */ |
1318 | 2.50M | current_item->string = current_item->valuestring; |
1319 | 2.50M | current_item->valuestring = NULL; |
1320 | | |
1321 | 2.50M | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) { |
1322 | 84 | goto fail; /* invalid object */ |
1323 | 84 | } |
1324 | | |
1325 | | /* parse the value */ |
1326 | 2.50M | input_buffer->offset++; |
1327 | 2.50M | buffer_skip_whitespace(input_buffer); |
1328 | 2.50M | if (!parse_value(current_item, input_buffer, out_of_memory)) { |
1329 | 2.62k | goto fail; /* failed to parse value */ |
1330 | 2.62k | } |
1331 | 2.50M | buffer_skip_whitespace(input_buffer); |
1332 | 2.50M | } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); |
1333 | | |
1334 | 1.85M | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) { |
1335 | 55 | goto fail; /* expected end of object */ |
1336 | 55 | } |
1337 | | |
1338 | 1.87M | success: |
1339 | 1.87M | input_buffer->depth--; |
1340 | | |
1341 | 1.87M | if (head != NULL) { |
1342 | 1.85M | head->prev = current_item; |
1343 | 1.85M | } |
1344 | | |
1345 | 1.87M | item->type = cJSON_Object; |
1346 | 1.87M | item->child = head; |
1347 | | |
1348 | 1.87M | input_buffer->offset++; |
1349 | 1.87M | return true; |
1350 | | |
1351 | 3.04k | fail: |
1352 | 3.04k | if (head != NULL) { |
1353 | 3.04k | loader_cJSON_Delete(head); |
1354 | 3.04k | } |
1355 | | |
1356 | 3.04k | return false; |
1357 | 1.85M | } |
1358 | | |
1359 | | /* Render an object to text. */ |
1360 | 0 | static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) { |
1361 | 0 | unsigned char *output_pointer = NULL; |
1362 | 0 | size_t length = 0; |
1363 | 0 | cJSON *current_item = item->child; |
1364 | |
|
1365 | 0 | if (output_buffer == NULL) { |
1366 | 0 | return false; |
1367 | 0 | } |
1368 | | |
1369 | | /* Compose the output: */ |
1370 | 0 | length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */ |
1371 | 0 | output_pointer = ensure(output_buffer, length + 1, out_of_memory); |
1372 | 0 | if (output_pointer == NULL) { |
1373 | 0 | return false; |
1374 | 0 | } |
1375 | | |
1376 | 0 | *output_pointer++ = '{'; |
1377 | 0 | output_buffer->depth++; |
1378 | 0 | if (output_buffer->format) { |
1379 | 0 | *output_pointer++ = '\n'; |
1380 | 0 | } |
1381 | 0 | output_buffer->offset += length; |
1382 | |
|
1383 | 0 | while (current_item) { |
1384 | 0 | if (output_buffer->format) { |
1385 | 0 | size_t i; |
1386 | 0 | output_pointer = ensure(output_buffer, output_buffer->depth, out_of_memory); |
1387 | 0 | if (output_pointer == NULL) { |
1388 | 0 | return false; |
1389 | 0 | } |
1390 | 0 | for (i = 0; i < output_buffer->depth; i++) { |
1391 | 0 | *output_pointer++ = '\t'; |
1392 | 0 | } |
1393 | 0 | output_buffer->offset += output_buffer->depth; |
1394 | 0 | } |
1395 | | |
1396 | | /* print key */ |
1397 | 0 | if (!print_string_ptr((unsigned char *)current_item->string, output_buffer, out_of_memory)) { |
1398 | 0 | return false; |
1399 | 0 | } |
1400 | 0 | update_offset(output_buffer); |
1401 | |
|
1402 | 0 | length = (size_t)(output_buffer->format ? 2 : 1); |
1403 | 0 | output_pointer = ensure(output_buffer, length, out_of_memory); |
1404 | 0 | if (output_pointer == NULL) { |
1405 | 0 | return false; |
1406 | 0 | } |
1407 | 0 | *output_pointer++ = ':'; |
1408 | 0 | if (output_buffer->format) { |
1409 | 0 | *output_pointer++ = '\t'; |
1410 | 0 | } |
1411 | 0 | output_buffer->offset += length; |
1412 | | |
1413 | | /* print value */ |
1414 | 0 | if (!print_value(current_item, output_buffer, out_of_memory)) { |
1415 | 0 | return false; |
1416 | 0 | } |
1417 | 0 | update_offset(output_buffer); |
1418 | | |
1419 | | /* print comma if not last */ |
1420 | 0 | length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); |
1421 | 0 | output_pointer = ensure(output_buffer, length + 1, out_of_memory); |
1422 | 0 | if (output_pointer == NULL) { |
1423 | 0 | return false; |
1424 | 0 | } |
1425 | 0 | if (current_item->next) { |
1426 | 0 | *output_pointer++ = ','; |
1427 | 0 | } |
1428 | |
|
1429 | 0 | if (output_buffer->format) { |
1430 | 0 | *output_pointer++ = '\n'; |
1431 | 0 | } |
1432 | 0 | *output_pointer = '\0'; |
1433 | 0 | output_buffer->offset += length; |
1434 | |
|
1435 | 0 | current_item = current_item->next; |
1436 | 0 | } |
1437 | | |
1438 | 0 | output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2, out_of_memory); |
1439 | 0 | if (output_pointer == NULL) { |
1440 | 0 | return false; |
1441 | 0 | } |
1442 | 0 | if (output_buffer->format) { |
1443 | 0 | size_t i; |
1444 | 0 | for (i = 0; i < (output_buffer->depth - 1); i++) { |
1445 | 0 | *output_pointer++ = '\t'; |
1446 | 0 | } |
1447 | 0 | } |
1448 | 0 | *output_pointer++ = '}'; |
1449 | 0 | *output_pointer = '\0'; |
1450 | 0 | output_buffer->depth--; |
1451 | |
|
1452 | 0 | return true; |
1453 | 0 | } |
1454 | | |
1455 | | /* Get Array size/item / object item. */ |
1456 | 25.7k | CJSON_PUBLIC(int) loader_cJSON_GetArraySize(const cJSON *array) { |
1457 | 25.7k | cJSON *child = NULL; |
1458 | 25.7k | size_t size = 0; |
1459 | | |
1460 | 25.7k | if (array == NULL) { |
1461 | 0 | return 0; |
1462 | 0 | } |
1463 | | |
1464 | 25.7k | child = array->child; |
1465 | | |
1466 | 1.35M | while (child != NULL) { |
1467 | 1.33M | size++; |
1468 | 1.33M | child = child->next; |
1469 | 1.33M | } |
1470 | | |
1471 | | /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ |
1472 | | |
1473 | 25.7k | return (int)size; |
1474 | 25.7k | } |
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 | 1.84M | static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) { |
1501 | 1.84M | cJSON *current_element = NULL; |
1502 | | |
1503 | 1.84M | if ((object == NULL) || (name == NULL)) { |
1504 | 0 | return NULL; |
1505 | 0 | } |
1506 | | |
1507 | 1.84M | current_element = object->child; |
1508 | 1.84M | 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 | 1.84M | } else { |
1513 | 5.32M | while ((current_element != NULL) && |
1514 | 5.32M | (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0)) { |
1515 | 3.48M | current_element = current_element->next; |
1516 | 3.48M | } |
1517 | 1.84M | } |
1518 | | |
1519 | 1.84M | if ((current_element == NULL) || (current_element->string == NULL)) { |
1520 | 915k | return NULL; |
1521 | 915k | } |
1522 | | |
1523 | 926k | return current_element; |
1524 | 1.84M | } |
1525 | | |
1526 | 1.84M | CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItem(const cJSON *const object, const char *const string) { |
1527 | 1.84M | return get_object_item(object, string, false); |
1528 | 1.84M | } |
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 | 715k | CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsString(const cJSON *const item) { |
1670 | 715k | if (item == NULL) { |
1671 | 613k | return false; |
1672 | 613k | } |
1673 | | |
1674 | 102k | return (item->type & 0xFF) == cJSON_String; |
1675 | 715k | } |
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 | } |