1 /*
2 Copyright (c) 2009 Dave Gamble
3 Copyright (c) 2015-2021 The Khronos Group Inc.
4 Copyright (c) 2015-2021 Valve Corporation
5 Copyright (c) 2015-2021 LunarG, Inc.
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 THE SOFTWARE.
24 */
25
26 /* cJSON */
27 /* JSON parser in C. */
28
29 #include <ctype.h>
30 #include <float.h>
31 #include <limits.h>
32 #include <math.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "cJSON.h"
38
39 #include "allocation.h"
40 #include "loader.h"
41 #include "log.h"
42
cJSON_malloc(const VkAllocationCallbacks * pAllocator,size_t size)43 static void *cJSON_malloc(const VkAllocationCallbacks *pAllocator, size_t size) {
44 return loader_calloc(pAllocator, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
45 }
46
cJSON_malloc_instance_scope(const VkAllocationCallbacks * pAllocator,size_t size)47 static void *cJSON_malloc_instance_scope(const VkAllocationCallbacks *pAllocator, size_t size) {
48 return loader_calloc(pAllocator, size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
49 }
50
cJSON_Free(const VkAllocationCallbacks * pAllocator,void * pMemory)51 static void cJSON_Free(const VkAllocationCallbacks *pAllocator, void *pMemory) { loader_free(pAllocator, pMemory); }
52
53 /*
54 // commented out as it is unused - static error code channel requires external locks to be used.
55 static const char *ep;
56
57 const char *cJSON_GetErrorPtr(void) { return ep; }
58 */
59
cJSON_strdup(const VkAllocationCallbacks * pAllocator,const char * str)60 static char *cJSON_strdup(const VkAllocationCallbacks *pAllocator, const char *str) {
61 size_t len;
62 char *copy;
63
64 len = strlen(str) + 1;
65 copy = (char *)cJSON_malloc(pAllocator, len);
66 if (!copy) return 0;
67 memcpy(copy, str, len);
68 return copy;
69 }
70
71 /* Internal constructor. */
cJSON_New_Item(const VkAllocationCallbacks * pAllocator)72 static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) {
73 cJSON *node = (cJSON *)cJSON_malloc(pAllocator, sizeof(cJSON));
74 if (node) {
75 memset(node, 0, sizeof(cJSON));
76 node->pAllocator = (VkAllocationCallbacks *)pAllocator;
77 }
78 return node;
79 }
80
81 /* Delete a cJSON structure. */
loader_cJSON_Delete(cJSON * c)82 void loader_cJSON_Delete(cJSON *c) {
83 cJSON *next;
84 while (c) {
85 next = c->next;
86 if (!(c->type & cJSON_IsReference) && c->child) loader_cJSON_Delete(c->child);
87 if (!(c->type & cJSON_IsReference) && c->valuestring) cJSON_Free(c->pAllocator, c->valuestring);
88 if (!(c->type & cJSON_StringIsConst) && c->string) cJSON_Free(c->pAllocator, c->string);
89 cJSON_Free(c->pAllocator, c);
90 c = next;
91 }
92 }
93
94 /* Parse the input text to generate a number, and populate the result into item.
95 */
parse_number(cJSON * item,const char * num)96 static const char *parse_number(cJSON *item, const char *num) {
97 double n = 0, sign = 1, scale = 0;
98 int subscale = 0, signsubscale = 1;
99
100 if (*num == '-') sign = -1, num++; /* Has sign? */
101 if (*num == '0') num++; /* is zero */
102 if (*num >= '1' && *num <= '9') do
103 n = (n * 10.0) + (*num++ - '0');
104 while (*num >= '0' && *num <= '9'); /* Number? */
105 if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
106 num++;
107 do n = (n * 10.0) + (*num++ - '0'), scale--;
108 while (*num >= '0' && *num <= '9');
109 } /* Fractional part? */
110 if (*num == 'e' || *num == 'E') /* Exponent? */
111 {
112 num++;
113 if (*num == '+')
114 num++;
115 else if (*num == '-')
116 signsubscale = -1, num++; /* With sign? */
117 while (*num >= '0' && *num <= '9') subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
118 }
119
120 n = sign * n * pow(10.0, (scale + subscale * signsubscale)); /* number = +/-
121 number.fraction *
122 10^+/- exponent */
123
124 item->valuedouble = n;
125 item->valueint = (int)n;
126 item->type = cJSON_Number;
127 return num;
128 }
129
pow2gt(size_t x)130 static size_t pow2gt(size_t x) {
131 --x;
132 x |= x >> 1;
133 x |= x >> 2;
134 x |= x >> 4;
135 x |= x >> 8;
136 x |= x >> 16;
137 return x + 1;
138 }
139
140 typedef struct {
141 char *buffer;
142 size_t length;
143 size_t offset;
144 } printbuffer;
145
ensure(const VkAllocationCallbacks * pAllocator,printbuffer * p,size_t needed)146 static char *ensure(const VkAllocationCallbacks *pAllocator, printbuffer *p, size_t needed) {
147 char *newbuffer;
148 size_t newsize;
149 if (!p || !p->buffer) return 0;
150 needed += p->offset;
151 if (needed <= p->length) return p->buffer + p->offset;
152
153 newsize = pow2gt(needed);
154 newbuffer = (char *)cJSON_malloc(pAllocator, newsize);
155 if (!newbuffer) {
156 cJSON_Free(pAllocator, p->buffer);
157 p->length = 0, p->buffer = 0;
158 return 0;
159 }
160 if (newbuffer) memcpy(newbuffer, p->buffer, p->length);
161 cJSON_Free(pAllocator, p->buffer);
162 p->length = newsize;
163 p->buffer = newbuffer;
164 return newbuffer + p->offset;
165 }
166
cJSON_update(printbuffer * p)167 static size_t cJSON_update(printbuffer *p) {
168 char *str;
169 if (!p || !p->buffer) return 0;
170 str = p->buffer + p->offset;
171 return p->offset + strlen(str);
172 }
173
174 /* Render the number nicely from the given item into a string. */
print_number(cJSON * item,printbuffer * p)175 static char *print_number(cJSON *item, printbuffer *p) {
176 char *str = 0;
177 size_t str_buf_size;
178 double d = item->valuedouble;
179 if (d == 0) {
180 str_buf_size = 2; /* special case for 0. */
181 if (p)
182 str = ensure(item->pAllocator, p, str_buf_size);
183 else
184 str = (char *)cJSON_malloc(item->pAllocator, str_buf_size);
185 if (str) loader_strncpy(str, str_buf_size, "0", 2);
186 } else if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {
187 str_buf_size = 21; /* 2^64+1 can be represented in 21 chars. */
188 if (p)
189 str = ensure(item->pAllocator, p, str_buf_size);
190 else
191 str = (char *)cJSON_malloc(item->pAllocator, str_buf_size);
192 if (str) snprintf(str, str_buf_size, "%d", item->valueint);
193 } else {
194 str_buf_size = 64; /* This is a nice tradeoff. */
195 if (p)
196 str = ensure(item->pAllocator, p, str_buf_size);
197 else
198 str = (char *)cJSON_malloc(item->pAllocator, str_buf_size);
199 if (str) {
200 if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60)
201 snprintf(str, str_buf_size, "%.0f", d);
202 else if (fabs(d) < 1.0e-6 || fabs(d) > 1.0e9)
203 snprintf(str, str_buf_size, "%e", d);
204 else
205 snprintf(str, str_buf_size, "%f", d);
206 }
207 }
208 return str;
209 }
210
parse_hex4(const char * str)211 static unsigned parse_hex4(const char *str) {
212 unsigned h = 0;
213 if (*str >= '0' && *str <= '9')
214 h += (*str) - '0';
215 else if (*str >= 'A' && *str <= 'F')
216 h += 10 + (*str) - 'A';
217 else if (*str >= 'a' && *str <= 'f')
218 h += 10 + (*str) - 'a';
219 else
220 return 0;
221 h = h << 4;
222 str++;
223 if (*str >= '0' && *str <= '9')
224 h += (*str) - '0';
225 else if (*str >= 'A' && *str <= 'F')
226 h += 10 + (*str) - 'A';
227 else if (*str >= 'a' && *str <= 'f')
228 h += 10 + (*str) - 'a';
229 else
230 return 0;
231 h = h << 4;
232 str++;
233 if (*str >= '0' && *str <= '9')
234 h += (*str) - '0';
235 else if (*str >= 'A' && *str <= 'F')
236 h += 10 + (*str) - 'A';
237 else if (*str >= 'a' && *str <= 'f')
238 h += 10 + (*str) - 'a';
239 else
240 return 0;
241 h = h << 4;
242 str++;
243 if (*str >= '0' && *str <= '9')
244 h += (*str) - '0';
245 else if (*str >= 'A' && *str <= 'F')
246 h += 10 + (*str) - 'A';
247 else if (*str >= 'a' && *str <= 'f')
248 h += 10 + (*str) - 'a';
249 else
250 return 0;
251 return h;
252 }
253
254 /* Parse the input text into an unescaped cstring, and populate item. */
255 static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
parse_string(cJSON * item,const char * str,bool * out_of_memory)256 static const char *parse_string(cJSON *item, const char *str, bool *out_of_memory) {
257 const char *ptr = str + 1;
258 char *ptr2;
259 char *out;
260 int len = 0;
261 unsigned uc, uc2;
262 if (*str != '\"') {
263 // ep = str; // commented out as it is unused
264 return 0;
265 } /* not a string! */
266
267 while (*ptr != '\"' && *ptr && ++len)
268 if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
269
270 out = (char *)cJSON_malloc(item->pAllocator, len + 1); /* This is how long we need for the string, roughly. */
271 if (!out) {
272 *out_of_memory = true;
273 return 0;
274 }
275
276 ptr = str + 1;
277 ptr2 = out;
278 while (*ptr != '\"' && *ptr) {
279 if (*ptr != '\\')
280 *ptr2++ = *ptr++;
281 else {
282 ptr++;
283 switch (*ptr) {
284 case 'b':
285 *ptr2++ = '\b';
286 break;
287 case 'f':
288 *ptr2++ = '\f';
289 break;
290 case 'n':
291 *ptr2++ = '\n';
292 break;
293 case 'r':
294 *ptr2++ = '\r';
295 break;
296 case 't':
297 *ptr2++ = '\t';
298 break;
299 case 'u': /* transcode utf16 to utf8. */
300 uc = parse_hex4(ptr + 1);
301 ptr += 4; /* get the unicode char. */
302
303 if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) break; /* check for invalid. */
304
305 if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */
306 {
307 if (ptr[1] != '\\' || ptr[2] != 'u') break; /* missing second-half of surrogate. */
308 uc2 = parse_hex4(ptr + 3);
309 ptr += 6;
310 if (uc2 < 0xDC00 || uc2 > 0xDFFF) break; /* invalid second-half of surrogate. */
311 uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
312 }
313
314 len = 4;
315 if (uc < 0x80)
316 len = 1;
317 else if (uc < 0x800)
318 len = 2;
319 else if (uc < 0x10000)
320 len = 3;
321 ptr2 += len;
322
323 for (size_t i = len; i > 0; i--) {
324 if (i == 1) {
325 *--ptr2 = ((unsigned char)uc | firstByteMark[len]);
326 } else if (i >= 2) {
327 *--ptr2 = ((uc | 0x80) & 0xBF);
328 uc >>= 6;
329 }
330 }
331 ptr2 += len;
332 break;
333 default:
334 *ptr2++ = *ptr;
335 break;
336 }
337 ptr++;
338 }
339 }
340 *ptr2 = 0;
341 if (*ptr == '\"') ptr++;
342 item->valuestring = out;
343 item->type = cJSON_String;
344 return ptr;
345 }
346
347 /* Render the cstring provided to an escaped version that can be printed. */
print_string_ptr(const VkAllocationCallbacks * pAllocator,const char * str,printbuffer * p)348 static char *print_string_ptr(const VkAllocationCallbacks *pAllocator, const char *str, printbuffer *p) {
349 const char *ptr;
350 char *ptr2;
351 char *out;
352 size_t out_buf_size, len = 0, flag = 0;
353 unsigned char token;
354
355 for (ptr = str; *ptr; ptr++) flag |= ((*ptr > 0 && *ptr < 32) || (*ptr == '\"') || (*ptr == '\\')) ? 1 : 0;
356 if (!flag) {
357 len = ptr - str;
358 out_buf_size = len + 1;
359 // out_buf_size = len + 3; // Modified to not put quotes around the string
360 if (p)
361 out = ensure(pAllocator, p, out_buf_size);
362 else
363 out = (char *)cJSON_malloc_instance_scope(pAllocator, out_buf_size);
364 if (!out) return 0;
365 ptr2 = out;
366 // *ptr2++ = '\"'; // Modified to not put quotes around the string
367 loader_strncpy(ptr2, out_buf_size, str, out_buf_size);
368 // ptr2[len] = '\"'; // Modified to not put quotes around the string
369 ptr2[len] = 0; // ptr2[len + 1] = 0; // Modified to not put quotes around the string
370 return out;
371 }
372
373 if (!str) {
374 out_buf_size = 3;
375 if (p)
376 out = ensure(pAllocator, p, out_buf_size);
377 else
378 out = (char *)cJSON_malloc_instance_scope(pAllocator, out_buf_size);
379 if (!out) return 0;
380 loader_strncpy(out, out_buf_size, "\"\"", 3);
381 return out;
382 }
383 ptr = str;
384 token = *ptr;
385 while (token && ++len) {
386 if (strchr("\"\\\b\f\n\r\t", token))
387 len++;
388 else if (token < 32)
389 len += 5;
390 ptr++;
391 token = *ptr;
392 }
393
394 out_buf_size = len + 1;
395 // out_buf_size = len + 3; // Modified to not put quotes around the string
396 if (p)
397 out = ensure(pAllocator, p, out_buf_size);
398 else
399 out = (char *)cJSON_malloc_instance_scope(pAllocator, out_buf_size);
400 if (!out) return 0;
401
402 ptr2 = out;
403 ptr = str;
404 // *ptr2++ = '\"'; // Modified to not put quotes around the string
405 while (*ptr) {
406 if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\')
407 *ptr2++ = *ptr++;
408 else {
409 switch (token = *ptr++) {
410 case '\\':
411 *ptr2++ = '\\';
412 break;
413 case '\"':
414 *ptr2++ = '\"';
415 break;
416 case '\b':
417 *ptr2++ = '\b';
418 break;
419 case '\f':
420 *ptr2++ = '\f';
421 break;
422 case '\n':
423 *ptr2++ = '\n';
424 break;
425 case '\r':
426 *ptr2++ = '\r';
427 break;
428 case '\t':
429 *ptr2++ = '\t';
430 break;
431 default:
432 snprintf(ptr2, out_buf_size - (ptr2 - out), "u%04x", token);
433 ptr2 += 5;
434 break; /* escape and print */
435 }
436 }
437 }
438 // *ptr2++ = '\"'; // Modified to not put quotes around the string
439 *ptr2++ = 0;
440 return out;
441 }
442 /* Invoke print_string_ptr (which is useful) on an item. */
print_string(cJSON * item,printbuffer * p)443 static char *print_string(cJSON *item, printbuffer *p) { return print_string_ptr(item->pAllocator, item->valuestring, p); }
444
445 /* Declare these prototypes. */
446 static const char *parse_value(cJSON *item, const char *value, bool *out_of_memory);
447 static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p);
448 static const char *parse_array(cJSON *item, const char *value, bool *out_of_memory);
449 static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p);
450 static const char *parse_object(cJSON *item, const char *value, bool *out_of_memory);
451 static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p);
452
453 /* Utility to jump whitespace and cr/lf */
skip(const char * in)454 static const char *skip(const char *in) {
455 while (in && *in && (unsigned char)*in <= 32) in++;
456 return in;
457 }
458
459 /* Parse an object - create a new root, and populate. */
cJSON_ParseWithOpts(const VkAllocationCallbacks * pAllocator,const char * value,const char ** return_parse_end,int require_null_terminated,bool * out_of_memory)460 static cJSON *cJSON_ParseWithOpts(const VkAllocationCallbacks *pAllocator, const char *value, const char **return_parse_end,
461 int require_null_terminated, bool *out_of_memory) {
462 const char *end = 0;
463 cJSON *c = cJSON_New_Item(pAllocator);
464 // ep = 0; // commented out as it is unused
465 if (!c) {
466 *out_of_memory = true;
467 return 0; /* memory fail */
468 }
469
470 end = parse_value(c, skip(value), out_of_memory);
471 if (!end) {
472 loader_cJSON_Delete(c);
473 return 0;
474 } /* parse failure. ep is set. */
475
476 /* if we require null-terminated JSON without appended garbage, skip and
477 * then check for a null terminator */
478 if (require_null_terminated) {
479 end = skip(end);
480 if (*end) {
481 loader_cJSON_Delete(c);
482 // ep = end; // commented out as it is unused
483 return 0;
484 }
485 }
486 if (return_parse_end) *return_parse_end = end;
487 return c;
488 }
489 /* Default options for cJSON_Parse */
cJSON_Parse(const VkAllocationCallbacks * pAllocator,const char * value,bool * out_of_memory)490 static cJSON *cJSON_Parse(const VkAllocationCallbacks *pAllocator, const char *value, bool *out_of_memory) {
491 return cJSON_ParseWithOpts(pAllocator, value, 0, 0, out_of_memory);
492 }
493
494 /* Render a cJSON item/entity/structure to text. */
loader_cJSON_Print(cJSON * item)495 char *loader_cJSON_Print(cJSON *item) { return print_value(item, 0, 1, 0); }
loader_cJSON_PrintUnformatted(cJSON * item)496 char *loader_cJSON_PrintUnformatted(cJSON *item) { return print_value(item, 0, 0, 0); }
497
498 /* Parser core - when encountering text, process appropriately. */
parse_value(cJSON * item,const char * value,bool * out_of_memory)499 static const char *parse_value(cJSON *item, const char *value, bool *out_of_memory) {
500 if (!value) return 0; /* Fail on null. */
501 if (!strncmp(value, "null", 4)) {
502 item->type = cJSON_NULL;
503 return value + 4;
504 }
505 if (!strncmp(value, "false", 5)) {
506 item->type = cJSON_False;
507 return value + 5;
508 }
509 if (!strncmp(value, "true", 4)) {
510 item->type = cJSON_True;
511 item->valueint = 1;
512 return value + 4;
513 }
514 if (*value == '\"') {
515 return parse_string(item, value, out_of_memory);
516 }
517 if (*value == '-' || (*value >= '0' && *value <= '9')) {
518 return parse_number(item, value);
519 }
520 if (*value == '[') {
521 return parse_array(item, value, out_of_memory);
522 }
523 if (*value == '{') {
524 return parse_object(item, value, out_of_memory);
525 }
526
527 // ep = value; // commented out as it is unused
528 return 0; /* failure. */
529 }
530
531 /* Render a value to text. */
print_value(cJSON * item,int depth,int fmt,printbuffer * p)532 static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p) {
533 char *out = 0;
534 if (!item) return 0;
535 if (p) {
536 switch ((item->type) & 255) {
537 case cJSON_NULL: {
538 out = ensure(item->pAllocator, p, 5);
539 if (out) loader_strncpy(out, 5, "null", 5);
540 break;
541 }
542 case cJSON_False: {
543 out = ensure(item->pAllocator, p, 6);
544 if (out) loader_strncpy(out, 6, "false", 6);
545 break;
546 }
547 case cJSON_True: {
548 out = ensure(item->pAllocator, p, 5);
549 if (out) loader_strncpy(out, 5, "true", 5);
550 break;
551 }
552 case cJSON_Number:
553 out = print_number(item, p);
554 break;
555 case cJSON_String:
556 out = print_string(item, p);
557 break;
558 case cJSON_Array:
559 out = print_array(item, depth, fmt, p);
560 break;
561 case cJSON_Object:
562 out = print_object(item, depth, fmt, p);
563 break;
564 }
565 } else {
566 switch ((item->type) & 255) {
567 case cJSON_NULL:
568 out = cJSON_strdup(item->pAllocator, "null");
569 break;
570 case cJSON_False:
571 out = cJSON_strdup(item->pAllocator, "false");
572 break;
573 case cJSON_True:
574 out = cJSON_strdup(item->pAllocator, "true");
575 break;
576 case cJSON_Number:
577 out = print_number(item, 0);
578 break;
579 case cJSON_String:
580 out = print_string(item, 0);
581 break;
582 case cJSON_Array:
583 out = print_array(item, depth, fmt, 0);
584 break;
585 case cJSON_Object:
586 out = print_object(item, depth, fmt, 0);
587 break;
588 }
589 }
590 return out;
591 }
592
593 /* Build an array from input text. */
parse_array(cJSON * item,const char * value,bool * out_of_memory)594 static const char *parse_array(cJSON *item, const char *value, bool *out_of_memory) {
595 cJSON *child;
596 if (*value != '[') {
597 // ep = value; // commented out as it is unused
598 return 0;
599 } /* not an array! */
600
601 item->type = cJSON_Array;
602 value = skip(value + 1);
603 if (*value == ']') return value + 1; /* empty array. */
604
605 item->child = child = cJSON_New_Item(item->pAllocator);
606 if (!item->child) {
607 *out_of_memory = true;
608 return 0; /* memory fail */
609 }
610 value = skip(parse_value(child, skip(value), out_of_memory)); /* skip any spacing, get the value. */
611 if (!value) return 0;
612
613 while (*value == ',') {
614 cJSON *new_item;
615 new_item = cJSON_New_Item(item->pAllocator);
616 if (!new_item) {
617 *out_of_memory = true;
618 return 0; /* memory fail */
619 }
620 child->next = new_item;
621 new_item->prev = child;
622 child = new_item;
623 value = skip(parse_value(child, skip(value + 1), out_of_memory));
624 if (!value) return 0; /* memory fail */
625 }
626
627 if (*value == ']') return value + 1; /* end of array */
628 // ep = value; // commented out as it is unused
629 return 0; /* malformed. */
630 }
631
632 /* Render an array to text */
print_array(cJSON * item,int depth,int fmt,printbuffer * p)633 static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p) {
634 char **entries;
635 char *out = 0, *ptr, *ret;
636 size_t len = 5;
637 cJSON *child = item->child;
638 int numentries = 0, fail = 0, j = 0;
639 size_t tmplen = 0, i = 0;
640
641 /* How many entries in the array? */
642 while (child) numentries++, child = child->next;
643 /* Explicitly handle numentries==0 */
644 if (!numentries) {
645 if (p)
646 out = ensure(item->pAllocator, p, 3);
647 else
648 out = (char *)cJSON_malloc(item->pAllocator, 3);
649 if (out) loader_strncpy(out, 3, "[]", 3);
650 return out;
651 }
652
653 if (p) {
654 /* Compose the output array. */
655 i = p->offset;
656 ptr = ensure(item->pAllocator, p, 1);
657 if (!ptr) return 0;
658 *ptr = '[';
659 p->offset++;
660 child = item->child;
661 while (child && !fail) {
662 print_value(child, depth + 1, fmt, p);
663 p->offset = cJSON_update(p);
664 if (child->next) {
665 len = fmt ? 2 : 1;
666 ptr = ensure(item->pAllocator, p, len + 1);
667 if (!ptr) return 0;
668 *ptr++ = ',';
669 if (fmt) *ptr++ = ' ';
670 *ptr = 0;
671 p->offset += len;
672 }
673 child = child->next;
674 }
675 ptr = ensure(item->pAllocator, p, 2);
676 if (!ptr) return 0;
677 *ptr++ = ']';
678 *ptr = 0;
679 out = (p->buffer) + i;
680 } else {
681 /* Allocate an array to hold the values for each */
682 entries = (char **)cJSON_malloc(item->pAllocator, numentries * sizeof(char *));
683 if (!entries) return 0;
684 memset(entries, 0, numentries * sizeof(char *));
685 /* Retrieve all the results: */
686 child = item->child;
687 while (child && !fail) {
688 ret = print_value(child, depth + 1, fmt, 0);
689 entries[i++] = ret;
690 if (ret)
691 len += strlen(ret) + 2 + (fmt ? 1 : 0);
692 else
693 fail = 1;
694 child = child->next;
695 }
696
697 /* If we didn't fail, try to malloc the output string */
698 if (!fail) out = (char *)cJSON_malloc(item->pAllocator, len);
699 /* If that fails, we fail. */
700 if (!out) fail = 1;
701
702 /* Handle failure. */
703 if (fail) {
704 for (j = 0; j < numentries; j++)
705 if (entries[j]) cJSON_Free(item->pAllocator, entries[j]);
706 cJSON_Free(item->pAllocator, entries);
707 return 0;
708 }
709
710 /* Compose the output array. */
711 *out = '[';
712 ptr = out + 1;
713 *ptr = 0;
714 for (j = 0; j < numentries; j++) {
715 tmplen = strlen(entries[j]);
716 memcpy(ptr, entries[j], tmplen);
717 ptr += tmplen;
718 if (j != numentries - 1) {
719 *ptr++ = ',';
720 if (fmt) *ptr++ = ' ';
721 *ptr = 0;
722 }
723 cJSON_Free(item->pAllocator, entries[j]);
724 }
725 cJSON_Free(item->pAllocator, entries);
726 *ptr++ = ']';
727 *ptr++ = 0;
728 }
729 return out;
730 }
731
732 /* Build an object from the text. */
parse_object(cJSON * item,const char * value,bool * out_of_memory)733 static const char *parse_object(cJSON *item, const char *value, bool *out_of_memory) {
734 cJSON *child;
735 if (*value != '{') {
736 // ep = value; // commented out as it is unused
737 return 0;
738 } /* not an object! */
739
740 item->type = cJSON_Object;
741 value = skip(value + 1);
742 if (*value == '}') return value + 1; /* empty array. */
743
744 item->child = child = cJSON_New_Item(item->pAllocator);
745 if (!item->child) {
746 *out_of_memory = true;
747 return 0;
748 }
749 value = skip(parse_string(child, skip(value), out_of_memory));
750 if (!value) return 0;
751 child->string = child->valuestring;
752 child->valuestring = 0;
753 if (*value != ':') {
754 // ep = value; // commented out as it is unused
755 return 0;
756 } /* fail! */
757 value = skip(parse_value(child, skip(value + 1), out_of_memory)); /* skip any spacing, get the value. */
758 if (!value) return 0;
759
760 while (*value == ',') {
761 cJSON *new_item;
762 new_item = cJSON_New_Item(item->pAllocator);
763 if (!new_item) {
764 *out_of_memory = true;
765 return 0; /* memory fail */
766 }
767 child->next = new_item;
768 new_item->prev = child;
769 child = new_item;
770 value = skip(parse_string(child, skip(value + 1), out_of_memory));
771 if (!value) return 0;
772 child->string = child->valuestring;
773 child->valuestring = 0;
774 if (*value != ':') {
775 // ep = value; // commented out as it is unused
776 return 0;
777 } /* fail! */
778 value = skip(parse_value(child, skip(value + 1), out_of_memory)); /* skip any spacing, get the value. */
779 if (!value) return 0;
780 }
781
782 if (*value == '}') return value + 1; /* end of array */
783 // ep = value; // commented out as it is unused
784 return 0; /* malformed. */
785 }
786
787 /* Render an object to text. */
print_object(cJSON * item,int depth,int fmt,printbuffer * p)788 static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p) {
789 char **entries = 0, **names = 0;
790 char *out = 0, *ptr, *ret, *str;
791 int j;
792 cJSON *child = item->child;
793 int numentries = 0, fail = 0, k;
794 size_t tmplen = 0, i = 0, len = 7;
795 /* Count the number of entries. */
796 while (child) numentries++, child = child->next;
797 /* Explicitly handle empty object case */
798 if (!numentries) {
799 if (p)
800 out = ensure(item->pAllocator, p, fmt ? depth + 4 : 3);
801 else
802 out = (char *)cJSON_malloc(item->pAllocator, fmt ? depth + 4 : 3);
803 if (!out) return 0;
804 ptr = out;
805 *ptr++ = '{';
806 if (fmt) {
807 *ptr++ = '\n';
808 for (j = 0; j < depth - 1; j++) *ptr++ = '\t';
809 }
810 *ptr++ = '}';
811 *ptr++ = 0;
812 return out;
813 }
814 if (p) {
815 /* Compose the output: */
816 i = p->offset;
817 len = fmt ? 2 : 1;
818 ptr = ensure(item->pAllocator, p, len + 1);
819 if (!ptr) return 0;
820 *ptr++ = '{';
821 if (fmt) *ptr++ = '\n';
822 *ptr = 0;
823 p->offset += len;
824 child = item->child;
825 depth++;
826 while (child) {
827 if (fmt) {
828 ptr = ensure(item->pAllocator, p, depth);
829 if (!ptr) return 0;
830 for (j = 0; j < depth; j++) *ptr++ = '\t';
831 p->offset += depth;
832 }
833 print_string_ptr(item->pAllocator, child->string, p);
834 p->offset = cJSON_update(p);
835
836 len = fmt ? 2 : 1;
837 ptr = ensure(item->pAllocator, p, len);
838 if (!ptr) return 0;
839 *ptr++ = ':';
840 if (fmt) *ptr++ = '\t';
841 p->offset += len;
842
843 print_value(child, depth, fmt, p);
844 p->offset = cJSON_update(p);
845
846 len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
847 ptr = ensure(item->pAllocator, p, len + 1);
848 if (!ptr) return 0;
849 if (child->next) *ptr++ = ',';
850 if (fmt) *ptr++ = '\n';
851 *ptr = 0;
852 p->offset += len;
853 child = child->next;
854 }
855 ptr = ensure(item->pAllocator, p, fmt ? (depth + 1) : 2);
856 if (!ptr) return 0;
857 if (fmt)
858 for (j = 0; j < depth - 1; j++) *ptr++ = '\t';
859 *ptr++ = '}';
860 *ptr = 0;
861 out = (p->buffer) + i;
862 } else {
863 /* Allocate space for the names and the objects */
864 entries = (char **)cJSON_malloc(item->pAllocator, numentries * sizeof(char *));
865 if (!entries) return 0;
866 names = (char **)cJSON_malloc(item->pAllocator, numentries * sizeof(char *));
867 if (!names) {
868 cJSON_Free(item->pAllocator, entries);
869 return 0;
870 }
871 memset(entries, 0, sizeof(char *) * numentries);
872 memset(names, 0, sizeof(char *) * numentries);
873
874 /* Collect all the results into our arrays: */
875 child = item->child;
876 depth++;
877 if (fmt) len += depth;
878 while (child) {
879 names[i] = str = print_string_ptr(item->pAllocator, child->string, 0);
880 entries[i++] = ret = print_value(child, depth, fmt, 0);
881 if (str && ret)
882 len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
883 else
884 fail = 1;
885 child = child->next;
886 }
887
888 /* Try to allocate the output string */
889 if (!fail) out = (char *)cJSON_malloc(item->pAllocator, len);
890 if (!out) fail = 1;
891
892 /* Handle failure */
893 if (fail) {
894 for (j = 0; j < numentries; j++) {
895 if (names[i]) cJSON_Free(item->pAllocator, names[j]);
896 if (entries[j]) cJSON_Free(item->pAllocator, entries[j]);
897 }
898 cJSON_Free(item->pAllocator, names);
899 cJSON_Free(item->pAllocator, entries);
900 return 0;
901 }
902
903 /* Compose the output: */
904 *out = '{';
905 ptr = out + 1;
906 if (fmt) *ptr++ = '\n';
907 *ptr = 0;
908 for (j = 0; j < numentries; j++) {
909 if (fmt)
910 for (k = 0; k < depth; k++) *ptr++ = '\t';
911 tmplen = strlen(names[j]);
912 memcpy(ptr, names[j], tmplen);
913 ptr += tmplen;
914 *ptr++ = ':';
915 if (fmt) *ptr++ = '\t';
916 size_t entries_size = strlen(entries[j]);
917 loader_strncpy(ptr, len - (ptr - out), entries[j], entries_size);
918 ptr += entries_size;
919 if (j != numentries - 1) *ptr++ = ',';
920 if (fmt) *ptr++ = '\n';
921 *ptr = 0;
922 cJSON_Free(item->pAllocator, names[j]);
923 cJSON_Free(item->pAllocator, entries[j]);
924 }
925
926 cJSON_Free(item->pAllocator, names);
927 cJSON_Free(item->pAllocator, entries);
928 if (fmt)
929 for (j = 0; j < depth - 1; j++) *ptr++ = '\t';
930 *ptr++ = '}';
931 *ptr++ = 0;
932 }
933 return out;
934 }
935
936 /* Get Array size/item / object item. */
loader_cJSON_GetArraySize(cJSON * array)937 int loader_cJSON_GetArraySize(cJSON *array) {
938 cJSON *c = array->child;
939 int i = 0;
940 while (c) i++, c = c->next;
941 return i;
942 }
loader_cJSON_GetArrayItem(cJSON * array,int item)943 cJSON *loader_cJSON_GetArrayItem(cJSON *array, int item) {
944 cJSON *c = array->child;
945 while (c && item > 0) item--, c = c->next;
946 return c;
947 }
loader_cJSON_GetObjectItem(cJSON * object,const char * string)948 cJSON *loader_cJSON_GetObjectItem(cJSON *object, const char *string) {
949 cJSON *c = object->child;
950 while (c && strcmp(c->string, string)) c = c->next;
951 return c;
952 }
953
loader_get_json(const struct loader_instance * inst,const char * filename,cJSON ** json)954 VkResult loader_get_json(const struct loader_instance *inst, const char *filename, cJSON **json) {
955 FILE *file = NULL;
956 char *json_buf = NULL;
957 size_t len;
958 VkResult res = VK_SUCCESS;
959
960 assert(json != NULL);
961
962 *json = NULL;
963
964 #if defined(_WIN32)
965 int filename_utf16_size = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
966 if (filename_utf16_size > 0) {
967 wchar_t *filename_utf16 = (wchar_t *)loader_stack_alloc(filename_utf16_size * sizeof(wchar_t));
968 if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filename_utf16, filename_utf16_size) == filename_utf16_size) {
969 errno_t wfopen_error = _wfopen_s(&file, filename_utf16, L"rb");
970 if (0 != wfopen_error) {
971 loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to open JSON file %s", filename);
972 }
973 }
974 }
975 #elif COMMON_UNIX_PLATFORMS
976 file = fopen(filename, "rb");
977 #else
978 #warning fopen not available on this platform
979 #endif
980
981 if (!file) {
982 loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to open JSON file %s", filename);
983 res = VK_ERROR_INITIALIZATION_FAILED;
984 goto out;
985 }
986 // NOTE: We can't just use fseek(file, 0, SEEK_END) because that isn't guaranteed to be supported on all systems
987 size_t fread_ret_count = 0;
988 do {
989 char buffer[256];
990 fread_ret_count = fread(buffer, 1, 256, file);
991 } while (fread_ret_count == 256 && !feof(file));
992 len = ftell(file);
993 fseek(file, 0, SEEK_SET);
994 json_buf = (char *)loader_instance_heap_calloc(inst, len + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
995 if (json_buf == NULL) {
996 loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
997 "loader_get_json: Failed to allocate space for JSON file %s buffer of length %lu", filename, len);
998 res = VK_ERROR_OUT_OF_HOST_MEMORY;
999 goto out;
1000 }
1001 if (fread(json_buf, sizeof(char), len, file) != len) {
1002 loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to read JSON file %s.", filename);
1003 res = VK_ERROR_INITIALIZATION_FAILED;
1004 goto out;
1005 }
1006 json_buf[len] = '\0';
1007
1008 // Can't be a valid json if the string is of length zero
1009 if (len == 0) {
1010 res = VK_ERROR_INITIALIZATION_FAILED;
1011 goto out;
1012 }
1013 // Parse text from file
1014 bool out_of_memory = false;
1015 *json = cJSON_Parse(inst ? &inst->alloc_callbacks : NULL, json_buf, &out_of_memory);
1016 if (out_of_memory) {
1017 loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Out of Memory error occurred while parsing JSON file %s.",
1018 filename);
1019 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1020 goto out;
1021 } else if (*json == NULL) {
1022 loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Invalid JSON file %s.", filename);
1023 goto out;
1024 }
1025
1026 out:
1027 loader_instance_heap_free(inst, json_buf);
1028 if (NULL != file) {
1029 fclose(file);
1030 }
1031 if (res != VK_SUCCESS && *json != NULL) {
1032 loader_cJSON_Delete(*json);
1033 *json = NULL;
1034 }
1035
1036 return res;
1037 }
1038
loader_parse_json_string_to_existing_str(const struct loader_instance * inst,cJSON * object,const char * key,size_t out_str_len,char * out_string)1039 VkResult loader_parse_json_string_to_existing_str(const struct loader_instance *inst, cJSON *object, const char *key,
1040 size_t out_str_len, char *out_string) {
1041 cJSON *item = loader_cJSON_GetObjectItem(object, key);
1042 if (NULL == item) {
1043 return VK_ERROR_INITIALIZATION_FAILED;
1044 }
1045
1046 char *str = loader_cJSON_Print(item);
1047 if (str == NULL) {
1048 return VK_ERROR_OUT_OF_HOST_MEMORY;
1049 }
1050 if (NULL != out_string) {
1051 loader_strncpy(out_string, out_str_len, str, out_str_len);
1052 if (out_str_len > 0) {
1053 out_string[out_str_len - 1] = '\0';
1054 }
1055 }
1056 loader_instance_heap_free(inst, str);
1057 return VK_SUCCESS;
1058 }
1059
loader_parse_json_string(cJSON * object,const char * key,char ** out_string)1060 VkResult loader_parse_json_string(cJSON *object, const char *key, char **out_string) {
1061 cJSON *item = loader_cJSON_GetObjectItem(object, key);
1062 if (NULL == item) {
1063 return VK_ERROR_INITIALIZATION_FAILED;
1064 }
1065
1066 char *str = loader_cJSON_Print(item);
1067 if (str == NULL) {
1068 return VK_ERROR_OUT_OF_HOST_MEMORY;
1069 }
1070 if (NULL != out_string) {
1071 *out_string = str;
1072 }
1073 return VK_SUCCESS;
1074 }
loader_parse_json_array_of_strings(const struct loader_instance * inst,cJSON * object,const char * key,struct loader_string_list * string_list)1075 VkResult loader_parse_json_array_of_strings(const struct loader_instance *inst, cJSON *object, const char *key,
1076 struct loader_string_list *string_list) {
1077 VkResult res = VK_SUCCESS;
1078 cJSON *item = loader_cJSON_GetObjectItem(object, key);
1079 if (NULL == item) {
1080 return VK_ERROR_INITIALIZATION_FAILED;
1081 }
1082
1083 uint32_t count = loader_cJSON_GetArraySize(item);
1084 if (count == 0) {
1085 return VK_SUCCESS;
1086 }
1087
1088 res = create_string_list(inst, count, string_list);
1089 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
1090 goto out;
1091 }
1092 for (uint32_t i = 0; i < count; i++) {
1093 cJSON *element = loader_cJSON_GetArrayItem(item, i);
1094 if (element == NULL) {
1095 return VK_ERROR_INITIALIZATION_FAILED;
1096 }
1097 char *out_data = loader_cJSON_Print(element);
1098 if (out_data == NULL) {
1099 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1100 goto out;
1101 }
1102 res = append_str_to_string_list(inst, string_list, out_data);
1103 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
1104 goto out;
1105 }
1106 }
1107 out:
1108 if (res == VK_ERROR_OUT_OF_HOST_MEMORY && NULL != string_list->list) {
1109 free_string_list(inst, string_list);
1110 }
1111
1112 return res;
1113 }
1114