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