• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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