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 43static void *cJSON_malloc(const VkAllocationCallbacks *pAllocator, size_t size) { 44 return loader_calloc(pAllocator, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 45} 46 47static void *cJSON_malloc_instance_scope(const VkAllocationCallbacks *pAllocator, size_t size) { 48 return loader_calloc(pAllocator, size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 49} 50 51static 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. 55static const char *ep; 56 57const char *cJSON_GetErrorPtr(void) { return ep; } 58*/ 59 60static 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. */ 72static 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. */ 82void 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 */ 96static 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 130static 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 140typedef struct { 141 char *buffer; 142 size_t length; 143 size_t offset; 144} printbuffer; 145 146static 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 167static 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. */ 175static 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 211static 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. */ 255static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; 256static 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. */ 348static 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. */ 443static char *print_string(cJSON *item, printbuffer *p) { return print_string_ptr(item->pAllocator, item->valuestring, p); } 444 445/* Declare these prototypes. */ 446static const char *parse_value(cJSON *item, const char *value, bool *out_of_memory); 447static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p); 448static const char *parse_array(cJSON *item, const char *value, bool *out_of_memory); 449static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p); 450static const char *parse_object(cJSON *item, const char *value, bool *out_of_memory); 451static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p); 452 453/* Utility to jump whitespace and cr/lf */ 454static 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. */ 460static 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 */ 490static 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. */ 495char *loader_cJSON_Print(cJSON *item) { return print_value(item, 0, 1, 0); } 496char *loader_cJSON_PrintUnformatted(cJSON *item) { return print_value(item, 0, 0, 0); } 497 498/* Parser core - when encountering text, process appropriately. */ 499static 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. */ 532static 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. */ 594static 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 */ 633static 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. */ 733static 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. */ 788static 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. */ 937int 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} 943cJSON *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} 948cJSON *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 954VkResult 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 1026out: 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 1039VkResult 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 1060VkResult 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} 1075VkResult 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 } 1107out: 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