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