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