/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 | 412k | #define true ((cJSON_bool)1) |
70 | | |
71 | | #ifdef false |
72 | | #undef false |
73 | | #endif |
74 | 166k | #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 | 19.3k | CJSON_PUBLIC(char *) loader_cJSON_GetStringValue(const cJSON *const item) { |
101 | 19.3k | if (!loader_cJSON_IsString(item)) { |
102 | 9.93k | return NULL; |
103 | 9.93k | } |
104 | | |
105 | 9.37k | return item->valuestring; |
106 | 19.3k | } |
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 | 375k | static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) { |
123 | 375k | if ((string1 == NULL) || (string2 == NULL)) { |
124 | 304 | return 1; |
125 | 304 | } |
126 | | |
127 | 375k | if (string1 == string2) { |
128 | 0 | return 0; |
129 | 0 | } |
130 | | |
131 | 854k | for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) { |
132 | 522k | if (*string1 == '\0') { |
133 | 43.5k | return 0; |
134 | 43.5k | } |
135 | 522k | } |
136 | | |
137 | 331k | return tolower(*string1) - tolower(*string2); |
138 | 375k | } |
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 | 262k | static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) { |
145 | 262k | cJSON *node = (cJSON *)loader_calloc(pAllocator, sizeof(cJSON), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); |
146 | 262k | if (NULL != node) { |
147 | 262k | node->pAllocator = pAllocator; |
148 | 262k | } |
149 | 262k | return node; |
150 | 262k | } |
151 | | |
152 | | /* Delete a cJSON structure. */ |
153 | 112k | TEST_FUNCTION_EXPORT CJSON_PUBLIC(void) loader_cJSON_Delete(cJSON *item) { |
154 | 112k | cJSON *next = NULL; |
155 | 375k | while (item != NULL) { |
156 | 262k | next = item->next; |
157 | 262k | if (!(item->type & cJSON_IsReference) && (item->child != NULL)) { |
158 | 48.2k | loader_cJSON_Delete(item->child); |
159 | 48.2k | } |
160 | 262k | if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { |
161 | 123k | loader_free(item->pAllocator, item->valuestring); |
162 | 123k | item->valuestring = NULL; |
163 | 123k | } |
164 | 262k | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { |
165 | 146k | loader_free(item->pAllocator, item->string); |
166 | 146k | item->string = NULL; |
167 | 146k | } |
168 | 262k | loader_free(item->pAllocator, item); |
169 | 262k | item = next; |
170 | 262k | } |
171 | 112k | } |
172 | | |
173 | | /* get the decimal point character of the current locale */ |
174 | 13.1k | 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 | 13.1k | return '.'; |
180 | 13.1k | #endif |
181 | 13.1k | } |
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 | 1.57M | #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 | 14.9M | #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) |
195 | 1.57M | #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) |
196 | | /* get a pointer to the buffer at the position */ |
197 | 9.43M | #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 | 13.1k | static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) { |
201 | 13.1k | double number = 0; |
202 | 13.1k | unsigned char *after_end = NULL; |
203 | 13.1k | unsigned char number_c_string[64]; |
204 | 13.1k | unsigned char decimal_point = get_decimal_point(); |
205 | 13.1k | size_t i = 0; |
206 | | |
207 | 13.1k | 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 | 162k | for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) { |
215 | 162k | switch (buffer_at_offset(input_buffer)[i]) { |
216 | 18.9k | case '0': |
217 | 26.5k | case '1': |
218 | 36.6k | case '2': |
219 | 80.6k | case '3': |
220 | 113k | case '4': |
221 | 117k | case '5': |
222 | 129k | case '6': |
223 | 134k | case '7': |
224 | 139k | case '8': |
225 | 145k | case '9': |
226 | 145k | case '+': |
227 | 148k | case '-': |
228 | 148k | case 'e': |
229 | 148k | case 'E': |
230 | 148k | number_c_string[i] = buffer_at_offset(input_buffer)[i]; |
231 | 148k | break; |
232 | | |
233 | 279 | case '.': |
234 | 279 | number_c_string[i] = decimal_point; |
235 | 279 | break; |
236 | | |
237 | 12.7k | default: |
238 | 12.7k | goto loop_end; |
239 | 162k | } |
240 | 162k | } |
241 | 13.1k | loop_end: |
242 | 13.1k | number_c_string[i] = '\0'; |
243 | | |
244 | 13.1k | number = strtod((const char *)number_c_string, (char **)&after_end); |
245 | 13.1k | if (number_c_string == after_end) { |
246 | 41 | return false; /* parse_error */ |
247 | 41 | } |
248 | | |
249 | 13.1k | item->valuedouble = number; |
250 | | |
251 | | /* use saturation in case of overflow */ |
252 | 13.1k | if (number >= INT_MAX) { |
253 | 1.85k | item->valueint = INT_MAX; |
254 | 11.2k | } else if (number <= (double)INT_MIN) { |
255 | 2.30k | item->valueint = INT_MIN; |
256 | 8.96k | } else { |
257 | 8.96k | item->valueint = (int)number; |
258 | 8.96k | } |
259 | | |
260 | 13.1k | item->type = cJSON_Number; |
261 | | |
262 | 13.1k | input_buffer->offset += (size_t)(after_end - number_c_string); |
263 | 13.1k | return true; |
264 | 13.1k | } |
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 | 30.9k | static unsigned char *ensure(printbuffer *const p, size_t needed, bool *out_of_memory) { |
278 | 30.9k | unsigned char *newbuffer = NULL; |
279 | 30.9k | size_t newsize = 0; |
280 | | |
281 | 30.9k | if ((p == NULL) || (p->buffer == NULL)) { |
282 | 0 | return NULL; |
283 | 0 | } |
284 | | |
285 | 30.9k | if ((p->length > 0) && (p->offset >= p->length)) { |
286 | | /* make sure that offset is valid */ |
287 | 0 | return NULL; |
288 | 0 | } |
289 | | |
290 | 30.9k | if (needed > INT_MAX) { |
291 | | /* sizes bigger than INT_MAX are currently not supported */ |
292 | 0 | return NULL; |
293 | 0 | } |
294 | | |
295 | 30.9k | needed += p->offset + 1; |
296 | 30.9k | if (needed <= p->length) { |
297 | 29.6k | return p->buffer + p->offset; |
298 | 29.6k | } |
299 | | |
300 | 1.29k | if (p->noalloc) { |
301 | 154 | return NULL; |
302 | 154 | } |
303 | | |
304 | | /* calculate new buffer size */ |
305 | 1.13k | 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 | 1.13k | } else { |
313 | 1.13k | newsize = needed * 2; |
314 | 1.13k | } |
315 | | |
316 | 1.13k | newbuffer = (unsigned char *)loader_realloc(p->pAllocator, p->buffer, p->length, newsize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); |
317 | 1.13k | 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 | 1.13k | p->length = newsize; |
327 | 1.13k | p->buffer = newbuffer; |
328 | | |
329 | 1.13k | return newbuffer + p->offset; |
330 | 1.13k | } |
331 | | |
332 | | /* calculate the new length of the string in a printbuffer and update the offset */ |
333 | 18.0k | static void update_offset(printbuffer *const buffer) { |
334 | 18.0k | const unsigned char *buffer_pointer = NULL; |
335 | 18.0k | if ((buffer == NULL) || (buffer->buffer == NULL)) { |
336 | 0 | return; |
337 | 0 | } |
338 | 18.0k | buffer_pointer = buffer->buffer + buffer->offset; |
339 | | |
340 | 18.0k | buffer->offset += strlen((const char *)buffer_pointer); |
341 | 18.0k | } |
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 | 195k | static unsigned parse_hex4(const unsigned char *const input) { |
409 | 195k | unsigned int h = 0; |
410 | 195k | size_t i = 0; |
411 | | |
412 | 614k | for (i = 0; i < 4; i++) { |
413 | | /* parse digit */ |
414 | 568k | if ((input[i] >= '0') && (input[i] <= '9')) { |
415 | 125k | h += (unsigned int)input[i] - '0'; |
416 | 443k | } else if ((input[i] >= 'A') && (input[i] <= 'F')) { |
417 | 200k | h += (unsigned int)10 + input[i] - 'A'; |
418 | 243k | } else if ((input[i] >= 'a') && (input[i] <= 'f')) { |
419 | 93.9k | h += (unsigned int)10 + input[i] - 'a'; |
420 | 93.9k | } else /* invalid */ |
421 | 149k | { |
422 | 149k | return 0; |
423 | 149k | } |
424 | | |
425 | 419k | if (i < 3) { |
426 | | /* shift left to make place for the next nibble */ |
427 | 373k | h = h << 4; |
428 | 373k | } |
429 | 419k | } |
430 | | |
431 | 45.6k | return h; |
432 | 195k | } |
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 | 195k | unsigned char **output_pointer) { |
438 | 195k | long unsigned int codepoint = 0; |
439 | 195k | unsigned int first_code = 0; |
440 | 195k | const unsigned char *first_sequence = input_pointer; |
441 | 195k | unsigned char utf8_length = 0; |
442 | 195k | unsigned char utf8_position = 0; |
443 | 195k | unsigned char sequence_length = 0; |
444 | 195k | unsigned char first_byte_mark = 0; |
445 | | |
446 | 195k | if ((input_end - first_sequence) < 6) { |
447 | | /* input ends unexpectedly */ |
448 | 24 | goto fail; |
449 | 24 | } |
450 | | |
451 | | /* get the first utf16 sequence */ |
452 | 195k | first_code = parse_hex4(first_sequence + 2); |
453 | | |
454 | | /* check that the code is valid */ |
455 | 195k | if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) { |
456 | 55 | goto fail; |
457 | 55 | } |
458 | | |
459 | | /* UTF16 surrogate pair */ |
460 | 194k | if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) { |
461 | 237 | const unsigned char *second_sequence = first_sequence + 6; |
462 | 237 | unsigned int second_code = 0; |
463 | 237 | sequence_length = 12; /* \uXXXX\uXXXX */ |
464 | | |
465 | 237 | if ((input_end - second_sequence) < 6) { |
466 | | /* input ends unexpectedly */ |
467 | 18 | goto fail; |
468 | 18 | } |
469 | | |
470 | 219 | 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 | 163 | second_code = parse_hex4(second_sequence + 2); |
477 | | /* check that the code is valid */ |
478 | 163 | if ((second_code < 0xDC00) || (second_code > 0xDFFF)) { |
479 | | /* invalid second half of the surrogate pair */ |
480 | 62 | goto fail; |
481 | 62 | } |
482 | | |
483 | | /* calculate the unicode codepoint from the surrogate pair */ |
484 | 101 | codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); |
485 | 194k | } else { |
486 | 194k | sequence_length = 6; /* \uXXXX */ |
487 | 194k | codepoint = first_code; |
488 | 194k | } |
489 | | |
490 | | /* encode as UTF-8 |
491 | | * takes at maximum 4 bytes to encode: |
492 | | * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ |
493 | 194k | if (codepoint < 0x80) { |
494 | | /* normal ascii, encoding 0xxxxxxx */ |
495 | 149k | utf8_length = 1; |
496 | 149k | } else if (codepoint < 0x800) { |
497 | | /* two bytes, encoding 110xxxxx 10xxxxxx */ |
498 | 716 | utf8_length = 2; |
499 | 716 | first_byte_mark = 0xC0; /* 11000000 */ |
500 | 44.2k | } else if (codepoint < 0x10000) { |
501 | | /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ |
502 | 44.1k | utf8_length = 3; |
503 | 44.1k | first_byte_mark = 0xE0; /* 11100000 */ |
504 | 44.1k | } else if (codepoint <= 0x10FFFF) { |
505 | | /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ |
506 | 101 | utf8_length = 4; |
507 | 101 | first_byte_mark = 0xF0; /* 11110000 */ |
508 | 101 | } else { |
509 | | /* invalid unicode codepoint */ |
510 | 0 | goto fail; |
511 | 0 | } |
512 | | |
513 | | /* encode as utf8 */ |
514 | 284k | for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) { |
515 | | /* 10xxxxxx */ |
516 | 89.2k | (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); |
517 | 89.2k | codepoint >>= 6; |
518 | 89.2k | } |
519 | | /* encode first byte */ |
520 | 194k | if (utf8_length > 1) { |
521 | 44.9k | (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); |
522 | 149k | } else { |
523 | 149k | (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); |
524 | 149k | } |
525 | | |
526 | 194k | *output_pointer += utf8_length; |
527 | | |
528 | 194k | return sequence_length; |
529 | | |
530 | 215 | fail: |
531 | 215 | return 0; |
532 | 194k | } |
533 | | |
534 | | /* Parse the input text into an unescaped cinput, and populate item. */ |
535 | 271k | static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) { |
536 | 271k | const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; |
537 | 271k | const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; |
538 | 271k | unsigned char *output_pointer = NULL; |
539 | 271k | unsigned char *output = NULL; |
540 | | |
541 | | /* not a string */ |
542 | 271k | if (buffer_at_offset(input_buffer)[0] != '\"') { |
543 | 282 | goto fail; |
544 | 282 | } |
545 | | |
546 | 270k | { |
547 | | /* calculate approximate size of the output (overestimate) */ |
548 | 270k | size_t allocation_length = 0; |
549 | 270k | size_t skipped_bytes = 0; |
550 | 67.2M | while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) { |
551 | | /* is escape sequence */ |
552 | 66.9M | if (input_end[0] == '\\') { |
553 | 845k | 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 | 845k | skipped_bytes++; |
558 | 845k | input_end++; |
559 | 845k | } |
560 | 66.9M | input_end++; |
561 | 66.9M | } |
562 | 270k | if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) { |
563 | 166 | goto fail; /* string ended unexpectedly */ |
564 | 166 | } |
565 | | |
566 | | /* This is at most how much we need for the output */ |
567 | 270k | allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes; |
568 | 270k | output = (unsigned char *)loader_calloc(input_buffer->pAllocator, allocation_length + sizeof(""), |
569 | 270k | VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); |
570 | 270k | if (output == NULL) { |
571 | 0 | *out_of_memory = true; |
572 | 0 | goto fail; /* allocation failure */ |
573 | 0 | } |
574 | 270k | } |
575 | | |
576 | 270k | output_pointer = output; |
577 | | /* loop through the string literal */ |
578 | 63.2M | while (input_pointer < input_end) { |
579 | 62.9M | if (*input_pointer != '\\') { |
580 | 62.4M | *output_pointer++ = *input_pointer++; |
581 | 62.4M | } |
582 | | /* escape sequence */ |
583 | 546k | else { |
584 | 546k | unsigned char sequence_length = 2; |
585 | 546k | if ((input_end - input_pointer) < 1) { |
586 | 0 | goto fail; |
587 | 0 | } |
588 | | |
589 | 546k | switch (input_pointer[1]) { |
590 | 244 | case 'b': |
591 | 244 | *output_pointer++ = '\b'; |
592 | 244 | break; |
593 | 1.38k | case 'f': |
594 | 1.38k | *output_pointer++ = '\f'; |
595 | 1.38k | break; |
596 | 8.94k | case 'n': |
597 | 8.94k | *output_pointer++ = '\n'; |
598 | 8.94k | break; |
599 | 1.15k | case 'r': |
600 | 1.15k | *output_pointer++ = '\r'; |
601 | 1.15k | break; |
602 | 1.17k | case 't': |
603 | 1.17k | *output_pointer++ = '\t'; |
604 | 1.17k | break; |
605 | 2.11k | case '\"': |
606 | 338k | case '\\': |
607 | 338k | case '/': |
608 | 338k | *output_pointer++ = input_pointer[1]; |
609 | 338k | break; |
610 | | |
611 | | /* UTF-16 literal */ |
612 | 195k | case 'u': |
613 | 195k | sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); |
614 | 195k | if (sequence_length == 0) { |
615 | | /* failed to convert UTF16-literal to UTF-8 */ |
616 | 215 | goto fail; |
617 | 215 | } |
618 | 194k | break; |
619 | | |
620 | 194k | default: |
621 | 105 | goto fail; |
622 | 546k | } |
623 | 546k | input_pointer += sequence_length; |
624 | 546k | } |
625 | 62.9M | } |
626 | | |
627 | | /* zero terminate the output */ |
628 | 270k | *output_pointer = '\0'; |
629 | | |
630 | 270k | item->type = cJSON_String; |
631 | 270k | item->valuestring = (char *)output; |
632 | | |
633 | 270k | input_buffer->offset = (size_t)(input_end - input_buffer->content); |
634 | 270k | input_buffer->offset++; |
635 | | |
636 | 270k | return true; |
637 | | |
638 | 768 | fail: |
639 | 768 | if (output != NULL) { |
640 | 320 | loader_free(input_buffer->pAllocator, output); |
641 | 320 | output = NULL; |
642 | 320 | } |
643 | | |
644 | 768 | if (input_pointer != NULL) { |
645 | 768 | input_buffer->offset = (size_t)(input_pointer - input_buffer->content); |
646 | 768 | } |
647 | | |
648 | 768 | return false; |
649 | 270k | } |
650 | | |
651 | | /* Render the cstring provided to an escaped version that can be printed. */ |
652 | 30.9k | static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer, bool *out_of_memory) { |
653 | 30.9k | const unsigned char *input_pointer = NULL; |
654 | 30.9k | unsigned char *output = NULL; |
655 | 30.9k | unsigned char *output_pointer = NULL; |
656 | 30.9k | size_t output_length = 0; |
657 | | /* numbers of additional characters needed for escaping */ |
658 | 30.9k | size_t escape_characters = 0; |
659 | | |
660 | 30.9k | if (output_buffer == NULL) { |
661 | 0 | return false; |
662 | 0 | } |
663 | | |
664 | | /* empty string */ |
665 | 30.9k | 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 | 32.6M | for (input_pointer = input; *input_pointer; input_pointer++) { |
676 | 32.6M | switch (*input_pointer) { |
677 | 32 | case '\"': |
678 | 2.74k | case '\\': |
679 | 5.95k | case '\b': |
680 | 22.8M | case '\f': |
681 | 22.8M | case '\n': |
682 | 22.8M | case '\r': |
683 | 22.8M | case '\t': |
684 | | /* one character escape sequence */ |
685 | 22.8M | escape_characters++; |
686 | 22.8M | break; |
687 | 9.78M | default: |
688 | 9.78M | if (*input_pointer < 32) { |
689 | | /* UTF-16 escape sequence uXXXX */ |
690 | 411k | escape_characters += 5; |
691 | 411k | } |
692 | 9.78M | break; |
693 | 32.6M | } |
694 | 32.6M | } |
695 | 30.9k | output_length = (size_t)(input_pointer - input) + escape_characters; |
696 | | |
697 | 30.9k | output = ensure(output_buffer, output_length + sizeof(""), out_of_memory); |
698 | 30.9k | if (output == NULL) { |
699 | 154 | return false; |
700 | 154 | } |
701 | | |
702 | | /* no characters have to be escaped */ |
703 | 30.8k | if (escape_characters == 0) { |
704 | 26.9k | memcpy(output, input, output_length); |
705 | 26.9k | output[output_length] = '\0'; |
706 | | |
707 | 26.9k | return true; |
708 | 26.9k | } |
709 | | |
710 | 3.84k | output_pointer = output; |
711 | | /* copy the string */ |
712 | 31.8M | for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) { |
713 | 31.8M | if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { |
714 | | /* normal character, copy */ |
715 | 8.60M | *output_pointer = *input_pointer; |
716 | 23.2M | } 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 | 23.2M | switch (*input_pointer) { |
723 | 2.71k | case '\\': |
724 | 2.71k | *output_pointer = '\\'; |
725 | 2.71k | break; |
726 | 32 | case '\"': |
727 | 32 | *output_pointer = '\"'; |
728 | 32 | break; |
729 | 3.20k | case '\b': |
730 | 3.20k | *output_pointer = '\b'; |
731 | 3.20k | break; |
732 | 22.8M | case '\f': |
733 | 22.8M | *output_pointer = '\f'; |
734 | 22.8M | break; |
735 | 1.17k | case '\n': |
736 | 1.17k | *output_pointer = '\n'; |
737 | 1.17k | break; |
738 | 1.14k | case '\r': |
739 | 1.14k | *output_pointer = '\r'; |
740 | 1.14k | break; |
741 | 722 | case '\t': |
742 | 722 | *output_pointer = '\t'; |
743 | 722 | break; |
744 | 407k | default: |
745 | | /* escape and print as unicode codepoint */ |
746 | 407k | snprintf((char *)output_pointer, output_length - (size_t)(output_pointer - output), "u%04x", *input_pointer); |
747 | 407k | output_pointer += 4; |
748 | 407k | break; |
749 | 23.2M | } |
750 | 23.2M | } |
751 | 31.8M | } |
752 | 3.84k | output[output_length] = '\0'; |
753 | | |
754 | 3.84k | return true; |
755 | 3.84k | } |
756 | | |
757 | | /* Invoke print_string_ptr (which is useful) on an item. */ |
758 | 30.9k | static cJSON_bool print_string(const cJSON *const item, printbuffer *const p, bool *out_of_memory) { |
759 | 30.9k | return print_string_ptr((unsigned char *)item->valuestring, p, out_of_memory); |
760 | 30.9k | } |
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 | 860k | static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) { |
772 | 860k | if ((buffer == NULL) || (buffer->content == NULL)) { |
773 | 0 | return NULL; |
774 | 0 | } |
775 | | |
776 | 860k | if (cannot_access_at_index(buffer, 0)) { |
777 | 0 | return buffer; |
778 | 0 | } |
779 | | |
780 | 5.90M | while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { |
781 | 5.04M | buffer->offset++; |
782 | 5.04M | } |
783 | | |
784 | 860k | if (buffer->offset == buffer->length) { |
785 | 3.02k | buffer->offset--; |
786 | 3.02k | } |
787 | | |
788 | 860k | return buffer; |
789 | 860k | } |
790 | | |
791 | | /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ |
792 | 9.63k | static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) { |
793 | 9.63k | if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) { |
794 | 0 | return NULL; |
795 | 0 | } |
796 | | |
797 | 9.63k | if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) { |
798 | 26 | buffer->offset += 3; |
799 | 26 | } |
800 | | |
801 | 9.63k | return buffer; |
802 | 9.63k | } |
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 | 9.63k | const char **return_parse_end, cJSON_bool require_null_terminated, bool *out_of_memory) { |
824 | 9.63k | parse_buffer buffer = {0, 0, 0, 0, 0}; |
825 | 9.63k | cJSON *item = NULL; |
826 | | |
827 | | /* reset error position */ |
828 | 9.63k | global_error.json = NULL; |
829 | 9.63k | global_error.position = 0; |
830 | | |
831 | 9.63k | if (value == NULL || 0 == buffer_length) { |
832 | 0 | goto fail; |
833 | 0 | } |
834 | | |
835 | 9.63k | buffer.content = (const unsigned char *)value; |
836 | 9.63k | buffer.length = buffer_length; |
837 | 9.63k | buffer.offset = 0; |
838 | 9.63k | buffer.pAllocator = pAllocator; |
839 | | |
840 | 9.63k | item = cJSON_New_Item(pAllocator); |
841 | 9.63k | if (item == NULL) /* memory fail */ |
842 | 0 | { |
843 | 0 | *out_of_memory = true; |
844 | 0 | goto fail; |
845 | 0 | } |
846 | | |
847 | 9.63k | if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)), out_of_memory)) { |
848 | | /* parse failure. ep is set. */ |
849 | 4.65k | goto fail; |
850 | 4.65k | } |
851 | | |
852 | | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ |
853 | 4.97k | 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 | 4.97k | if (return_parse_end) { |
860 | 0 | *return_parse_end = (const char *)buffer_at_offset(&buffer); |
861 | 0 | } |
862 | | |
863 | 4.97k | return item; |
864 | | |
865 | 4.65k | fail: |
866 | 4.65k | if (item != NULL) { |
867 | 4.65k | loader_cJSON_Delete(item); |
868 | 4.65k | } |
869 | | |
870 | 4.65k | if (value != NULL) { |
871 | 4.65k | error local_error; |
872 | 4.65k | local_error.json = (const unsigned char *)value; |
873 | 4.65k | local_error.position = 0; |
874 | | |
875 | 4.65k | if (buffer.offset < buffer.length) { |
876 | 4.59k | local_error.position = buffer.offset; |
877 | 4.59k | } else if (buffer.length > 0) { |
878 | 63 | local_error.position = buffer.length - 1; |
879 | 63 | } |
880 | | |
881 | 4.65k | if (return_parse_end != NULL) { |
882 | 0 | *return_parse_end = (const char *)local_error.json + local_error.position; |
883 | 0 | } |
884 | | |
885 | 4.65k | global_error = local_error; |
886 | 4.65k | } |
887 | | |
888 | 4.65k | return NULL; |
889 | 4.97k | } |
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 | 9.63k | bool *out_of_memory) { |
899 | 9.63k | return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, 0, 0, out_of_memory); |
900 | 9.63k | } |
901 | | |
902 | | #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) |
903 | | |
904 | 18.0k | static unsigned char *print(const cJSON *const item, cJSON_bool format, bool *out_of_memory) { |
905 | 18.0k | static const size_t default_buffer_size = 256; |
906 | 18.0k | printbuffer buffer[1]; |
907 | 18.0k | unsigned char *printed = NULL; |
908 | | |
909 | 18.0k | memset(buffer, 0, sizeof(buffer)); |
910 | | |
911 | | /* create buffer */ |
912 | 18.0k | buffer->buffer = (unsigned char *)loader_calloc(item->pAllocator, default_buffer_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); |
913 | 18.0k | buffer->length = default_buffer_size; |
914 | 18.0k | buffer->format = format; |
915 | 18.0k | buffer->pAllocator = item->pAllocator; |
916 | 18.0k | if (buffer->buffer == NULL) { |
917 | 0 | *out_of_memory = true; |
918 | 0 | goto fail; |
919 | 0 | } |
920 | | |
921 | | /* print the value */ |
922 | 18.0k | if (!print_value(item, buffer, out_of_memory)) { |
923 | 0 | goto fail; |
924 | 0 | } |
925 | 18.0k | update_offset(buffer); |
926 | | |
927 | 18.0k | printed = (unsigned char *)loader_realloc(item->pAllocator, buffer->buffer, buffer->length, buffer->offset + 1, |
928 | 18.0k | VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); |
929 | 18.0k | if (printed == NULL) { |
930 | 0 | *out_of_memory = true; |
931 | 0 | goto fail; |
932 | 0 | } |
933 | 18.0k | buffer->buffer = NULL; |
934 | | |
935 | 18.0k | 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 | 18.0k | } |
950 | | |
951 | | /* Render a cJSON item/entity/structure to text. */ |
952 | 18.0k | TEST_FUNCTION_EXPORT CJSON_PUBLIC(char *) loader_cJSON_Print(const cJSON *item, bool *out_of_memory) { |
953 | 18.0k | return (char *)print(item, true, out_of_memory); |
954 | 18.0k | } |
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 | 12.8k | loader_cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { |
990 | 12.8k | printbuffer p = {0, 0, 0, 0, 0, 0, 0}; |
991 | | |
992 | 12.8k | if ((length < 0) || (buffer == NULL)) { |
993 | 0 | return false; |
994 | 0 | } |
995 | | |
996 | 12.8k | p.buffer = (unsigned char *)buffer; |
997 | 12.8k | p.length = (size_t)length; |
998 | 12.8k | p.offset = 0; |
999 | 12.8k | p.noalloc = true; |
1000 | 12.8k | p.format = format; |
1001 | 12.8k | p.pAllocator = item->pAllocator; |
1002 | 12.8k | bool out_of_memory = false; |
1003 | 12.8k | return print_value(item, &p, &out_of_memory); |
1004 | 12.8k | } |
1005 | | |
1006 | | /* Parser core - when encountering text, process appropriately. */ |
1007 | 262k | static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) { |
1008 | 262k | 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 | 262k | if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) { |
1015 | 237 | item->type = cJSON_NULL; |
1016 | 237 | input_buffer->offset += 4; |
1017 | 237 | return true; |
1018 | 237 | } |
1019 | | /* false */ |
1020 | 262k | if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) { |
1021 | 154 | item->type = cJSON_False; |
1022 | 154 | input_buffer->offset += 5; |
1023 | 154 | return true; |
1024 | 154 | } |
1025 | | /* true */ |
1026 | 262k | if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) { |
1027 | 16.9k | item->type = cJSON_True; |
1028 | 16.9k | item->valueint = 1; |
1029 | 16.9k | input_buffer->offset += 4; |
1030 | 16.9k | return true; |
1031 | 16.9k | } |
1032 | | /* string */ |
1033 | 245k | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { |
1034 | 124k | return parse_string(item, input_buffer, out_of_memory); |
1035 | 124k | } |
1036 | | /* number */ |
1037 | 121k | if (can_access_at_index(input_buffer, 0) && |
1038 | 121k | ((buffer_at_offset(input_buffer)[0] == '-') || |
1039 | 121k | ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) { |
1040 | 13.1k | return parse_number(item, input_buffer); |
1041 | 13.1k | } |
1042 | | /* array */ |
1043 | 108k | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) { |
1044 | 69.1k | return parse_array(item, input_buffer, out_of_memory); |
1045 | 69.1k | } |
1046 | | /* object */ |
1047 | 38.8k | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) { |
1048 | 35.5k | return parse_object(item, input_buffer, out_of_memory); |
1049 | 35.5k | } |
1050 | | |
1051 | 3.31k | return false; |
1052 | 38.8k | } |
1053 | | |
1054 | | /* Render a value to text. */ |
1055 | 30.9k | static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) { |
1056 | 30.9k | unsigned char *output = NULL; |
1057 | | |
1058 | 30.9k | if ((item == NULL) || (output_buffer == NULL)) { |
1059 | 0 | return false; |
1060 | 0 | } |
1061 | | |
1062 | 30.9k | 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 | 30.9k | case cJSON_String: |
1106 | 30.9k | 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 | 30.9k | } |
1117 | 30.9k | } |
1118 | | |
1119 | | /* Build an array from input text. */ |
1120 | 69.1k | static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) { |
1121 | 69.1k | cJSON *head = NULL; /* head of the linked list */ |
1122 | 69.1k | cJSON *current_item = NULL; |
1123 | | |
1124 | 69.1k | if (input_buffer->depth >= CJSON_NESTING_LIMIT) { |
1125 | 7 | return false; /* to deeply nested */ |
1126 | 7 | } |
1127 | 69.1k | input_buffer->depth++; |
1128 | | |
1129 | 69.1k | if (buffer_at_offset(input_buffer)[0] != '[') { |
1130 | | /* not an array */ |
1131 | 0 | goto fail; |
1132 | 0 | } |
1133 | | |
1134 | 69.1k | input_buffer->offset++; |
1135 | 69.1k | buffer_skip_whitespace(input_buffer); |
1136 | 69.1k | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) { |
1137 | | /* empty array */ |
1138 | 1.20k | goto success; |
1139 | 1.20k | } |
1140 | | |
1141 | | /* check if we skipped to the end of the buffer */ |
1142 | 67.9k | 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 | 67.9k | input_buffer->offset--; |
1149 | | /* loop through the comma separated array elements */ |
1150 | 106k | do { |
1151 | | /* allocate next item */ |
1152 | 106k | cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator); |
1153 | 106k | 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 | 106k | if (head == NULL) { |
1160 | | /* start the linked list */ |
1161 | 67.9k | current_item = head = new_item; |
1162 | 67.9k | } else { |
1163 | | /* add to the end and advance */ |
1164 | 38.2k | current_item->next = new_item; |
1165 | 38.2k | new_item->prev = current_item; |
1166 | 38.2k | current_item = new_item; |
1167 | 38.2k | } |
1168 | | |
1169 | | /* parse next value */ |
1170 | 106k | input_buffer->offset++; |
1171 | 106k | buffer_skip_whitespace(input_buffer); |
1172 | 106k | if (!parse_value(current_item, input_buffer, out_of_memory)) { |
1173 | 51.9k | goto fail; /* failed to parse value */ |
1174 | 51.9k | } |
1175 | 54.2k | buffer_skip_whitespace(input_buffer); |
1176 | 54.2k | } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); |
1177 | | |
1178 | 16.0k | if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { |
1179 | 304 | goto fail; /* expected end of array */ |
1180 | 304 | } |
1181 | | |
1182 | 16.9k | success: |
1183 | 16.9k | input_buffer->depth--; |
1184 | | |
1185 | 16.9k | if (head != NULL) { |
1186 | 15.6k | head->prev = current_item; |
1187 | 15.6k | } |
1188 | | |
1189 | 16.9k | item->type = cJSON_Array; |
1190 | 16.9k | item->child = head; |
1191 | | |
1192 | 16.9k | input_buffer->offset++; |
1193 | | |
1194 | 16.9k | return true; |
1195 | | |
1196 | 52.2k | fail: |
1197 | 52.2k | if (head != NULL) { |
1198 | 52.2k | loader_cJSON_Delete(head); |
1199 | 52.2k | } |
1200 | | |
1201 | 52.2k | return false; |
1202 | 16.0k | } |
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 | 35.5k | static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) { |
1259 | 35.5k | cJSON *head = NULL; /* linked list head */ |
1260 | 35.5k | cJSON *current_item = NULL; |
1261 | | |
1262 | 35.5k | if (input_buffer->depth >= CJSON_NESTING_LIMIT) { |
1263 | 13 | return false; /* to deeply nested */ |
1264 | 13 | } |
1265 | 35.4k | input_buffer->depth++; |
1266 | | |
1267 | 35.4k | 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 | 35.4k | input_buffer->offset++; |
1272 | 35.4k | buffer_skip_whitespace(input_buffer); |
1273 | 35.4k | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) { |
1274 | 876 | goto success; /* empty object */ |
1275 | 876 | } |
1276 | | |
1277 | | /* check if we skipped to the end of the buffer */ |
1278 | 34.6k | 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 | 34.6k | input_buffer->offset--; |
1285 | | /* loop through the comma separated array elements */ |
1286 | 147k | do { |
1287 | | /* allocate next item */ |
1288 | 147k | cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator); |
1289 | 147k | 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 | 147k | if (head == NULL) { |
1296 | | /* start the linked list */ |
1297 | 34.6k | current_item = head = new_item; |
1298 | 112k | } else { |
1299 | | /* add to the end and advance */ |
1300 | 112k | current_item->next = new_item; |
1301 | 112k | new_item->prev = current_item; |
1302 | 112k | current_item = new_item; |
1303 | 112k | } |
1304 | | |
1305 | 147k | 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 | 147k | input_buffer->offset++; |
1311 | 147k | buffer_skip_whitespace(input_buffer); |
1312 | 147k | if (!parse_string(current_item, input_buffer, out_of_memory)) { |
1313 | 336 | goto fail; /* failed to parse name */ |
1314 | 336 | } |
1315 | 146k | buffer_skip_whitespace(input_buffer); |
1316 | | |
1317 | | /* swap valuestring and string, because we parsed the name */ |
1318 | 146k | current_item->string = current_item->valuestring; |
1319 | 146k | current_item->valuestring = NULL; |
1320 | | |
1321 | 146k | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) { |
1322 | 114 | goto fail; /* invalid object */ |
1323 | 114 | } |
1324 | | |
1325 | | /* parse the value */ |
1326 | 146k | input_buffer->offset++; |
1327 | 146k | buffer_skip_whitespace(input_buffer); |
1328 | 146k | if (!parse_value(current_item, input_buffer, out_of_memory)) { |
1329 | 1.49k | goto fail; /* failed to parse value */ |
1330 | 1.49k | } |
1331 | 145k | buffer_skip_whitespace(input_buffer); |
1332 | 145k | } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); |
1333 | | |
1334 | 32.6k | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) { |
1335 | 93 | goto fail; /* expected end of object */ |
1336 | 93 | } |
1337 | | |
1338 | 33.4k | success: |
1339 | 33.4k | input_buffer->depth--; |
1340 | | |
1341 | 33.4k | if (head != NULL) { |
1342 | 32.5k | head->prev = current_item; |
1343 | 32.5k | } |
1344 | | |
1345 | 33.4k | item->type = cJSON_Object; |
1346 | 33.4k | item->child = head; |
1347 | | |
1348 | 33.4k | input_buffer->offset++; |
1349 | 33.4k | return true; |
1350 | | |
1351 | 2.03k | fail: |
1352 | 2.03k | if (head != NULL) { |
1353 | 2.03k | loader_cJSON_Delete(head); |
1354 | 2.03k | } |
1355 | | |
1356 | 2.03k | return false; |
1357 | 32.6k | } |
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 | 2.54k | CJSON_PUBLIC(int) loader_cJSON_GetArraySize(const cJSON *array) { |
1457 | 2.54k | cJSON *child = NULL; |
1458 | 2.54k | size_t size = 0; |
1459 | | |
1460 | 2.54k | if (array == NULL) { |
1461 | 0 | return 0; |
1462 | 0 | } |
1463 | | |
1464 | 2.54k | child = array->child; |
1465 | | |
1466 | 11.8k | while (child != NULL) { |
1467 | 9.35k | size++; |
1468 | 9.35k | child = child->next; |
1469 | 9.35k | } |
1470 | | |
1471 | | /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ |
1472 | | |
1473 | 2.54k | return (int)size; |
1474 | 2.54k | } |
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 | 85.3k | static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) { |
1501 | 85.3k | cJSON *current_element = NULL; |
1502 | | |
1503 | 85.3k | if ((object == NULL) || (name == NULL)) { |
1504 | 0 | return NULL; |
1505 | 0 | } |
1506 | | |
1507 | 85.3k | current_element = object->child; |
1508 | 85.3k | 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 | 85.3k | } else { |
1513 | 417k | while ((current_element != NULL) && |
1514 | 417k | (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0)) { |
1515 | 332k | current_element = current_element->next; |
1516 | 332k | } |
1517 | 85.3k | } |
1518 | | |
1519 | 85.3k | if ((current_element == NULL) || (current_element->string == NULL)) { |
1520 | 41.7k | return NULL; |
1521 | 41.7k | } |
1522 | | |
1523 | 43.5k | return current_element; |
1524 | 85.3k | } |
1525 | | |
1526 | 85.3k | CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItem(const cJSON *const object, const char *const string) { |
1527 | 85.3k | return get_object_item(object, string, false); |
1528 | 85.3k | } |
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 | 19.3k | CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsString(const cJSON *const item) { |
1670 | 19.3k | if (item == NULL) { |
1671 | 9.88k | return false; |
1672 | 9.88k | } |
1673 | | |
1674 | 9.42k | return (item->type & 0xFF) == cJSON_String; |
1675 | 19.3k | } |
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 | } |