rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 PublicHeader: None
|
nuclear@0
|
4 Filename : OVR_JSON.h
|
nuclear@0
|
5 Content : JSON format reader and writer
|
nuclear@0
|
6 Created : April 9, 2013
|
nuclear@0
|
7 Author : Brant Lewis
|
nuclear@0
|
8 Notes :
|
nuclear@0
|
9 The code is a derivative of the cJSON library written by Dave Gamble and subject
|
nuclear@0
|
10 to the following permissive copyright.
|
nuclear@0
|
11
|
nuclear@0
|
12 Copyright (c) 2009 Dave Gamble
|
nuclear@0
|
13
|
nuclear@0
|
14 Permission is hereby granted, free of charge, to any person obtaining a copy
|
nuclear@0
|
15 of this software and associated documentation files (the "Software"), to deal
|
nuclear@0
|
16 in the Software without restriction, including without limitation the rights
|
nuclear@0
|
17 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
nuclear@0
|
18 copies of the Software, and to permit persons to whom the Software is
|
nuclear@0
|
19 furnished to do so, subject to the following conditions:
|
nuclear@0
|
20
|
nuclear@0
|
21 The above copyright notice and this permission notice shall be included in
|
nuclear@0
|
22 all copies or substantial portions of the Software.
|
nuclear@0
|
23
|
nuclear@0
|
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
nuclear@0
|
25 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
nuclear@0
|
26 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
nuclear@0
|
27 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
nuclear@0
|
28 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
nuclear@0
|
29 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
nuclear@0
|
30 THE SOFTWARE.
|
nuclear@0
|
31
|
nuclear@0
|
32
|
nuclear@0
|
33 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
34
|
nuclear@0
|
35 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
36 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
37 which is provided at the time of installation or download, or which
|
nuclear@0
|
38 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
39
|
nuclear@0
|
40 You may obtain a copy of the License at
|
nuclear@0
|
41
|
nuclear@0
|
42 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
43
|
nuclear@0
|
44 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
45 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
46 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
47 See the License for the specific language governing permissions and
|
nuclear@0
|
48 limitations under the License.
|
nuclear@0
|
49
|
nuclear@0
|
50 ************************************************************************************/
|
nuclear@0
|
51
|
nuclear@0
|
52 #include <string.h>
|
nuclear@0
|
53 #include <stdio.h>
|
nuclear@0
|
54 #include <math.h>
|
nuclear@0
|
55 #include <stdlib.h>
|
nuclear@0
|
56 #include <float.h>
|
nuclear@0
|
57 #include <limits.h>
|
nuclear@0
|
58 #include <ctype.h>
|
nuclear@0
|
59 #include "OVR_JSON.h"
|
nuclear@0
|
60 #include "Kernel/OVR_SysFile.h"
|
nuclear@0
|
61 #include "Kernel/OVR_Log.h"
|
nuclear@0
|
62
|
nuclear@0
|
63 #ifdef OVR_OS_LINUX
|
nuclear@0
|
64 #include <locale.h>
|
nuclear@0
|
65 #endif
|
nuclear@0
|
66
|
nuclear@0
|
67 namespace OVR {
|
nuclear@0
|
68
|
nuclear@0
|
69
|
nuclear@0
|
70 //-----------------------------------------------------------------------------
|
nuclear@0
|
71 // Create a new copy of a string
|
nuclear@0
|
72 static char* JSON_strdup(const char* str)
|
nuclear@0
|
73 {
|
nuclear@0
|
74 size_t len = OVR_strlen(str) + 1;
|
nuclear@0
|
75 char* copy = (char*)OVR_ALLOC(len);
|
nuclear@0
|
76 if (!copy)
|
nuclear@0
|
77 return 0;
|
nuclear@0
|
78 memcpy(copy, str, len);
|
nuclear@0
|
79 return copy;
|
nuclear@0
|
80 }
|
nuclear@0
|
81
|
nuclear@0
|
82
|
nuclear@0
|
83 //-----------------------------------------------------------------------------
|
nuclear@0
|
84 // Render the number from the given item into a string.
|
nuclear@0
|
85 static char* PrintInt(int valueint)
|
nuclear@0
|
86 {
|
nuclear@0
|
87 char *str;
|
nuclear@0
|
88 str = (char*)OVR_ALLOC(21); // 2^64+1 can be represented in 21 chars.
|
nuclear@0
|
89 if (str)
|
nuclear@0
|
90 {
|
nuclear@0
|
91 OVR_sprintf(str, 21, "%d", valueint);
|
nuclear@0
|
92 }
|
nuclear@0
|
93 return str;
|
nuclear@0
|
94 }
|
nuclear@0
|
95
|
nuclear@0
|
96
|
nuclear@0
|
97 //-----------------------------------------------------------------------------
|
nuclear@0
|
98 // Render the number from the given item into a string.
|
nuclear@0
|
99 static char* PrintNumber(double d)
|
nuclear@0
|
100 {
|
nuclear@0
|
101 char *str;
|
nuclear@0
|
102 int valueint = (int)d;
|
nuclear@0
|
103 if (fabs(((double)valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
|
nuclear@0
|
104 {
|
nuclear@0
|
105 return PrintInt(valueint);
|
nuclear@0
|
106 }
|
nuclear@0
|
107 else
|
nuclear@0
|
108 {
|
nuclear@0
|
109 str=(char*)OVR_ALLOC(64); // This is a nice tradeoff.
|
nuclear@0
|
110 if (str)
|
nuclear@0
|
111 {
|
nuclear@0
|
112 if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)
|
nuclear@0
|
113 OVR_sprintf(str, 64, "%.0f", d);
|
nuclear@0
|
114 else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)
|
nuclear@0
|
115 OVR_sprintf(str, 64, "%e", d);
|
nuclear@0
|
116 else
|
nuclear@0
|
117 OVR_sprintf(str, 64, "%f", d);
|
nuclear@0
|
118 }
|
nuclear@0
|
119 }
|
nuclear@0
|
120 return str;
|
nuclear@0
|
121 }
|
nuclear@0
|
122
|
nuclear@0
|
123
|
nuclear@0
|
124 // Parse the input text into an un-escaped cstring, and populate item.
|
nuclear@0
|
125 static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
nuclear@0
|
126
|
nuclear@0
|
127 // Helper to assign error sting and return 0.
|
nuclear@0
|
128 const char* AssignError(const char** perror, const char *errorMessage)
|
nuclear@0
|
129 {
|
nuclear@0
|
130 if (perror)
|
nuclear@0
|
131 *perror = errorMessage;
|
nuclear@0
|
132 return 0;
|
nuclear@0
|
133 }
|
nuclear@0
|
134
|
nuclear@0
|
135 //-----------------------------------------------------------------------------
|
nuclear@0
|
136 // ***** JSON Node class
|
nuclear@0
|
137
|
nuclear@0
|
138 JSON::JSON(JSONItemType itemType) :
|
nuclear@0
|
139 Type(itemType), dValue(0.)
|
nuclear@0
|
140 {
|
nuclear@0
|
141 }
|
nuclear@0
|
142
|
nuclear@0
|
143 JSON::~JSON()
|
nuclear@0
|
144 {
|
nuclear@0
|
145 JSON* child = Children.GetFirst();
|
nuclear@0
|
146 while (!Children.IsNull(child))
|
nuclear@0
|
147 {
|
nuclear@0
|
148 child->RemoveNode();
|
nuclear@0
|
149 child->Release();
|
nuclear@0
|
150 child = Children.GetFirst();
|
nuclear@0
|
151 }
|
nuclear@0
|
152 }
|
nuclear@0
|
153
|
nuclear@0
|
154 //-----------------------------------------------------------------------------
|
nuclear@0
|
155 // Parse the input text to generate a number, and populate the result into item
|
nuclear@0
|
156 // Returns the text position after the parsed number
|
nuclear@0
|
157 const char* JSON::parseNumber(const char *num)
|
nuclear@0
|
158 {
|
nuclear@0
|
159 const char* num_start = num;
|
nuclear@0
|
160 double n=0, scale=0;
|
nuclear@0
|
161 int subscale = 0,
|
nuclear@0
|
162 signsubscale = 1;
|
nuclear@0
|
163 bool positiveSign = true;
|
nuclear@0
|
164 char localeSeparator = '.';
|
nuclear@0
|
165
|
nuclear@0
|
166 #ifdef OVR_OS_LINUX
|
nuclear@0
|
167 // We should switch to a locale aware parsing function, such as atof. We
|
nuclear@0
|
168 // will probably want to go farther and enforce the 'C' locale on all JSON
|
nuclear@0
|
169 // output/input.
|
nuclear@0
|
170 struct lconv* localeConv = localeconv();
|
nuclear@0
|
171 localeSeparator = localeConv->decimal_point[0];
|
nuclear@0
|
172 #endif
|
nuclear@0
|
173
|
nuclear@0
|
174 // Could use sscanf for this?
|
nuclear@0
|
175 if (*num == '-')
|
nuclear@0
|
176 {
|
nuclear@0
|
177 positiveSign = false;
|
nuclear@0
|
178 num++; // Has sign?
|
nuclear@0
|
179 }
|
nuclear@0
|
180 if (*num == '0')
|
nuclear@0
|
181 {
|
nuclear@0
|
182 num++; // is zero
|
nuclear@0
|
183 }
|
nuclear@0
|
184
|
nuclear@0
|
185 if (*num>='1' && *num<='9')
|
nuclear@0
|
186 {
|
nuclear@0
|
187 do
|
nuclear@0
|
188 {
|
nuclear@0
|
189 n = (n*10.0) + (*num++ - '0');
|
nuclear@0
|
190 }
|
nuclear@0
|
191 while (*num>='0' && *num<='9'); // Number?
|
nuclear@0
|
192 }
|
nuclear@0
|
193
|
nuclear@0
|
194 if ((*num=='.' || *num==localeSeparator) && num[1]>='0' && num[1]<='9')
|
nuclear@0
|
195 {
|
nuclear@0
|
196 num++;
|
nuclear@0
|
197 do
|
nuclear@0
|
198 {
|
nuclear@0
|
199 n=(n*10.0)+(*num++ -'0');
|
nuclear@0
|
200 scale--;
|
nuclear@0
|
201 }
|
nuclear@0
|
202 while (*num>='0' && *num<='9'); // Fractional part?
|
nuclear@0
|
203 }
|
nuclear@0
|
204
|
nuclear@0
|
205 if (*num=='e' || *num=='E') // Exponent?
|
nuclear@0
|
206 {
|
nuclear@0
|
207 num++;
|
nuclear@0
|
208 if (*num == '+')
|
nuclear@0
|
209 {
|
nuclear@0
|
210 num++;
|
nuclear@0
|
211 }
|
nuclear@0
|
212 else if (*num=='-')
|
nuclear@0
|
213 {
|
nuclear@0
|
214 signsubscale=-1;
|
nuclear@0
|
215 num++; // With sign?
|
nuclear@0
|
216 }
|
nuclear@0
|
217
|
nuclear@0
|
218 while (*num >= '0' && *num <= '9')
|
nuclear@0
|
219 {
|
nuclear@0
|
220 subscale = (subscale * 10) + (*num++ - '0'); // Number?
|
nuclear@0
|
221 }
|
nuclear@0
|
222 }
|
nuclear@0
|
223
|
nuclear@0
|
224 // Number = +/- number.fraction * 10^+/- exponent
|
nuclear@0
|
225 n *= pow(10.0, (scale + subscale*signsubscale));
|
nuclear@0
|
226
|
nuclear@0
|
227 if (!positiveSign)
|
nuclear@0
|
228 {
|
nuclear@0
|
229 n = -n;
|
nuclear@0
|
230 }
|
nuclear@0
|
231
|
nuclear@0
|
232 // Assign parsed value.
|
nuclear@0
|
233 Type = JSON_Number;
|
nuclear@0
|
234 dValue = n;
|
nuclear@0
|
235 Value.AssignString(num_start, num - num_start);
|
nuclear@0
|
236
|
nuclear@0
|
237 return num;
|
nuclear@0
|
238 }
|
nuclear@0
|
239
|
nuclear@0
|
240 // Parses a hex string up to the specified number of digits.
|
nuclear@0
|
241 // Returns the first character after the string.
|
nuclear@0
|
242 const char* ParseHex(unsigned* val, unsigned digits, const char* str)
|
nuclear@0
|
243 {
|
nuclear@0
|
244 *val = 0;
|
nuclear@0
|
245
|
nuclear@0
|
246 for(unsigned digitCount = 0; digitCount < digits; digitCount++, str++)
|
nuclear@0
|
247 {
|
nuclear@0
|
248 unsigned v = *str;
|
nuclear@0
|
249
|
nuclear@0
|
250 if ((v >= '0') && (v <= '9'))
|
nuclear@0
|
251 v -= '0';
|
nuclear@0
|
252 else if ((v >= 'a') && (v <= 'f'))
|
nuclear@0
|
253 v = 10 + v - 'a';
|
nuclear@0
|
254 else if ((v >= 'A') && (v <= 'F'))
|
nuclear@0
|
255 v = 10 + v - 'A';
|
nuclear@0
|
256 else
|
nuclear@0
|
257 break;
|
nuclear@0
|
258
|
nuclear@0
|
259 *val = *val * 16 + v;
|
nuclear@0
|
260 }
|
nuclear@0
|
261
|
nuclear@0
|
262 return str;
|
nuclear@0
|
263 }
|
nuclear@0
|
264
|
nuclear@0
|
265 //-----------------------------------------------------------------------------
|
nuclear@0
|
266 // Parses the input text into a string item and returns the text position after
|
nuclear@0
|
267 // the parsed string
|
nuclear@0
|
268 const char* JSON::parseString(const char* str, const char** perror)
|
nuclear@0
|
269 {
|
nuclear@0
|
270 const char* ptr = str+1;
|
nuclear@0
|
271 const char* p;
|
nuclear@0
|
272 char* ptr2;
|
nuclear@0
|
273 char* out;
|
nuclear@0
|
274 int len=0;
|
nuclear@0
|
275 unsigned uc, uc2;
|
nuclear@0
|
276
|
nuclear@0
|
277 if (*str!='\"')
|
nuclear@0
|
278 {
|
nuclear@0
|
279 return AssignError(perror, "Syntax Error: Missing quote");
|
nuclear@0
|
280 }
|
nuclear@0
|
281
|
nuclear@0
|
282 while (*ptr!='\"' && *ptr && ++len)
|
nuclear@0
|
283 {
|
nuclear@0
|
284 if (*ptr++ == '\\') ptr++; // Skip escaped quotes.
|
nuclear@0
|
285 }
|
nuclear@0
|
286
|
nuclear@0
|
287 // This is how long we need for the string, roughly.
|
nuclear@0
|
288 out=(char*)OVR_ALLOC(len+1);
|
nuclear@0
|
289 if (!out)
|
nuclear@0
|
290 return 0;
|
nuclear@0
|
291
|
nuclear@0
|
292 ptr = str+1;
|
nuclear@0
|
293 ptr2= out;
|
nuclear@0
|
294
|
nuclear@0
|
295 while (*ptr!='\"' && *ptr)
|
nuclear@0
|
296 {
|
nuclear@0
|
297 if (*ptr!='\\')
|
nuclear@0
|
298 {
|
nuclear@0
|
299 *ptr2++ = *ptr++;
|
nuclear@0
|
300 }
|
nuclear@0
|
301 else
|
nuclear@0
|
302 {
|
nuclear@0
|
303 ptr++;
|
nuclear@0
|
304 switch (*ptr)
|
nuclear@0
|
305 {
|
nuclear@0
|
306 case 'b': *ptr2++ = '\b'; break;
|
nuclear@0
|
307 case 'f': *ptr2++ = '\f'; break;
|
nuclear@0
|
308 case 'n': *ptr2++ = '\n'; break;
|
nuclear@0
|
309 case 'r': *ptr2++ = '\r'; break;
|
nuclear@0
|
310 case 't': *ptr2++ = '\t'; break;
|
nuclear@0
|
311
|
nuclear@0
|
312 // Transcode utf16 to utf8.
|
nuclear@0
|
313 case 'u':
|
nuclear@0
|
314
|
nuclear@0
|
315 // Get the unicode char.
|
nuclear@0
|
316 p = ParseHex(&uc, 4, ptr + 1);
|
nuclear@0
|
317 if (ptr != p)
|
nuclear@0
|
318 ptr = p - 1;
|
nuclear@0
|
319
|
nuclear@0
|
320 if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)
|
nuclear@0
|
321 break; // Check for invalid.
|
nuclear@0
|
322
|
nuclear@0
|
323 // UTF16 surrogate pairs.
|
nuclear@0
|
324 if (uc>=0xD800 && uc<=0xDBFF)
|
nuclear@0
|
325 {
|
nuclear@0
|
326 if (ptr[1]!='\\' || ptr[2]!='u')
|
nuclear@0
|
327 break; // Missing second-half of surrogate.
|
nuclear@0
|
328
|
nuclear@0
|
329 p= ParseHex(&uc2, 4, ptr + 3);
|
nuclear@0
|
330 if (ptr != p)
|
nuclear@0
|
331 ptr = p - 1;
|
nuclear@0
|
332
|
nuclear@0
|
333 if (uc2<0xDC00 || uc2>0xDFFF)
|
nuclear@0
|
334 break; // Invalid second-half of surrogate.
|
nuclear@0
|
335
|
nuclear@0
|
336 uc = 0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
|
nuclear@0
|
337 }
|
nuclear@0
|
338
|
nuclear@0
|
339 len=4;
|
nuclear@0
|
340
|
nuclear@0
|
341 if (uc<0x80)
|
nuclear@0
|
342 len=1;
|
nuclear@0
|
343 else if (uc<0x800)
|
nuclear@0
|
344 len=2;
|
nuclear@0
|
345 else if (uc<0x10000)
|
nuclear@0
|
346 len=3;
|
nuclear@0
|
347
|
nuclear@0
|
348 ptr2+=len;
|
nuclear@0
|
349
|
nuclear@0
|
350 switch (len)
|
nuclear@0
|
351 {
|
nuclear@0
|
352 case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
nuclear@0
|
353 //no break, fall through
|
nuclear@0
|
354 case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
nuclear@0
|
355 //no break
|
nuclear@0
|
356 case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
nuclear@0
|
357 //no break
|
nuclear@0
|
358 case 1: *--ptr2 = (char)(uc | firstByteMark[len]);
|
nuclear@0
|
359 //no break
|
nuclear@0
|
360 }
|
nuclear@0
|
361 ptr2+=len;
|
nuclear@0
|
362 break;
|
nuclear@0
|
363
|
nuclear@0
|
364 default:
|
nuclear@0
|
365 *ptr2++ = *ptr;
|
nuclear@0
|
366 break;
|
nuclear@0
|
367 }
|
nuclear@0
|
368 ptr++;
|
nuclear@0
|
369 }
|
nuclear@0
|
370 }
|
nuclear@0
|
371
|
nuclear@0
|
372 *ptr2 = 0;
|
nuclear@0
|
373 if (*ptr=='\"')
|
nuclear@0
|
374 ptr++;
|
nuclear@0
|
375
|
nuclear@0
|
376 // Make a copy of the string
|
nuclear@0
|
377 Value=out;
|
nuclear@0
|
378 OVR_FREE(out);
|
nuclear@0
|
379 Type=JSON_String;
|
nuclear@0
|
380
|
nuclear@0
|
381 return ptr;
|
nuclear@0
|
382 }
|
nuclear@0
|
383
|
nuclear@0
|
384 //-----------------------------------------------------------------------------
|
nuclear@0
|
385 // Render the string provided to an escaped version that can be printed.
|
nuclear@0
|
386 char* PrintString(const char* str)
|
nuclear@0
|
387 {
|
nuclear@0
|
388 const char *ptr;
|
nuclear@0
|
389 char *ptr2,*out;
|
nuclear@0
|
390 int len=0;
|
nuclear@0
|
391 unsigned char token;
|
nuclear@0
|
392
|
nuclear@0
|
393 if (!str)
|
nuclear@0
|
394 return JSON_strdup("");
|
nuclear@0
|
395 ptr=str;
|
nuclear@0
|
396
|
nuclear@0
|
397 token=*ptr;
|
nuclear@0
|
398 while (token && ++len)\
|
nuclear@0
|
399 {
|
nuclear@0
|
400 if (strchr("\"\\\b\f\n\r\t",token))
|
nuclear@0
|
401 len++;
|
nuclear@0
|
402 else if (token<32)
|
nuclear@0
|
403 len+=5;
|
nuclear@0
|
404 ptr++;
|
nuclear@0
|
405 token=*ptr;
|
nuclear@0
|
406 }
|
nuclear@0
|
407
|
nuclear@0
|
408 int buff_size = len+3;
|
nuclear@0
|
409 out=(char*)OVR_ALLOC(buff_size);
|
nuclear@0
|
410 if (!out)
|
nuclear@0
|
411 return 0;
|
nuclear@0
|
412
|
nuclear@0
|
413 ptr2 = out;
|
nuclear@0
|
414 ptr = str;
|
nuclear@0
|
415 *ptr2++ = '\"';
|
nuclear@0
|
416
|
nuclear@0
|
417 while (*ptr)
|
nuclear@0
|
418 {
|
nuclear@0
|
419 if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\')
|
nuclear@0
|
420 *ptr2++=*ptr++;
|
nuclear@0
|
421 else
|
nuclear@0
|
422 {
|
nuclear@0
|
423 *ptr2++='\\';
|
nuclear@0
|
424 switch (token=*ptr++)
|
nuclear@0
|
425 {
|
nuclear@0
|
426 case '\\': *ptr2++='\\'; break;
|
nuclear@0
|
427 case '\"': *ptr2++='\"'; break;
|
nuclear@0
|
428 case '\b': *ptr2++='b'; break;
|
nuclear@0
|
429 case '\f': *ptr2++='f'; break;
|
nuclear@0
|
430 case '\n': *ptr2++='n'; break;
|
nuclear@0
|
431 case '\r': *ptr2++='r'; break;
|
nuclear@0
|
432 case '\t': *ptr2++='t'; break;
|
nuclear@0
|
433 default:
|
nuclear@0
|
434 OVR_sprintf(ptr2, buff_size - (ptr2-out), "u%04x",token);
|
nuclear@0
|
435 ptr2+=5;
|
nuclear@0
|
436 break; // Escape and print.
|
nuclear@0
|
437 }
|
nuclear@0
|
438 }
|
nuclear@0
|
439 }
|
nuclear@0
|
440 *ptr2++='\"';
|
nuclear@0
|
441 *ptr2++=0;
|
nuclear@0
|
442 return out;
|
nuclear@0
|
443 }
|
nuclear@0
|
444
|
nuclear@0
|
445 //-----------------------------------------------------------------------------
|
nuclear@0
|
446 // Utility to jump whitespace and cr/lf
|
nuclear@0
|
447 static const char* skip(const char* in)
|
nuclear@0
|
448 {
|
nuclear@0
|
449 while (in && *in && (unsigned char)*in<=' ')
|
nuclear@0
|
450 in++;
|
nuclear@0
|
451 return in;
|
nuclear@0
|
452 }
|
nuclear@0
|
453
|
nuclear@0
|
454 //-----------------------------------------------------------------------------
|
nuclear@0
|
455 // Parses the supplied buffer of JSON text and returns a JSON object tree
|
nuclear@0
|
456 // The returned object must be Released after use
|
nuclear@0
|
457 JSON* JSON::Parse(const char* buff, const char** perror)
|
nuclear@0
|
458 {
|
nuclear@0
|
459 const char* end = 0;
|
nuclear@0
|
460 JSON* json = new JSON();
|
nuclear@0
|
461
|
nuclear@0
|
462 if (!json)
|
nuclear@0
|
463 {
|
nuclear@0
|
464 AssignError(perror, "Error: Failed to allocate memory");
|
nuclear@0
|
465 return 0;
|
nuclear@0
|
466 }
|
nuclear@0
|
467
|
nuclear@0
|
468 end = json->parseValue(skip(buff), perror);
|
nuclear@0
|
469 if (!end)
|
nuclear@0
|
470 {
|
nuclear@0
|
471 json->Release();
|
nuclear@0
|
472 return NULL;
|
nuclear@0
|
473 } // parse failure. ep is set.
|
nuclear@0
|
474
|
nuclear@0
|
475 return json;
|
nuclear@0
|
476 }
|
nuclear@0
|
477
|
nuclear@0
|
478 //-----------------------------------------------------------------------------
|
nuclear@0
|
479 // This version works for buffers that are not null terminated strings.
|
nuclear@0
|
480 JSON* JSON::ParseBuffer(const char *buff, int len, const char** perror)
|
nuclear@0
|
481 {
|
nuclear@0
|
482 // Our JSON parser does not support length-based parsing,
|
nuclear@0
|
483 // so ensure it is null-terminated.
|
nuclear@0
|
484 char *termStr = new char[len + 1];
|
nuclear@0
|
485 memcpy(termStr, buff, len);
|
nuclear@0
|
486 termStr[len] = '\0';
|
nuclear@0
|
487
|
nuclear@0
|
488 JSON *objJson = Parse(termStr, perror);
|
nuclear@0
|
489
|
nuclear@0
|
490 delete[]termStr;
|
nuclear@0
|
491
|
nuclear@0
|
492 return objJson;
|
nuclear@0
|
493 }
|
nuclear@0
|
494
|
nuclear@0
|
495 //-----------------------------------------------------------------------------
|
nuclear@0
|
496 // Parser core - when encountering text, process appropriately.
|
nuclear@0
|
497 const char* JSON::parseValue(const char* buff, const char** perror)
|
nuclear@0
|
498 {
|
nuclear@0
|
499 if (perror)
|
nuclear@0
|
500 *perror = 0;
|
nuclear@0
|
501
|
nuclear@0
|
502 if (!buff)
|
nuclear@0
|
503 return NULL; // Fail on null.
|
nuclear@0
|
504
|
nuclear@0
|
505 if (!strncmp(buff,"null",4))
|
nuclear@0
|
506 {
|
nuclear@0
|
507 Type = JSON_Null;
|
nuclear@0
|
508 return buff+4;
|
nuclear@0
|
509 }
|
nuclear@0
|
510 if (!strncmp(buff,"false",5))
|
nuclear@0
|
511 {
|
nuclear@0
|
512 Type = JSON_Bool;
|
nuclear@0
|
513 Value = "false";
|
nuclear@0
|
514 dValue = 0.;
|
nuclear@0
|
515 return buff+5;
|
nuclear@0
|
516 }
|
nuclear@0
|
517 if (!strncmp(buff,"true",4))
|
nuclear@0
|
518 {
|
nuclear@0
|
519 Type = JSON_Bool;
|
nuclear@0
|
520 Value = "true";
|
nuclear@0
|
521 dValue = 1.;
|
nuclear@0
|
522 return buff + 4;
|
nuclear@0
|
523 }
|
nuclear@0
|
524 if (*buff=='\"')
|
nuclear@0
|
525 {
|
nuclear@0
|
526 return parseString(buff, perror);
|
nuclear@0
|
527 }
|
nuclear@0
|
528 if (*buff=='-' || (*buff>='0' && *buff<='9'))
|
nuclear@0
|
529 {
|
nuclear@0
|
530 return parseNumber(buff);
|
nuclear@0
|
531 }
|
nuclear@0
|
532 if (*buff=='[')
|
nuclear@0
|
533 {
|
nuclear@0
|
534 return parseArray(buff, perror);
|
nuclear@0
|
535 }
|
nuclear@0
|
536 if (*buff=='{')
|
nuclear@0
|
537 {
|
nuclear@0
|
538 return parseObject(buff, perror);
|
nuclear@0
|
539 }
|
nuclear@0
|
540
|
nuclear@0
|
541 return AssignError(perror, "Syntax Error: Invalid syntax");
|
nuclear@0
|
542 }
|
nuclear@0
|
543
|
nuclear@0
|
544
|
nuclear@0
|
545 //-----------------------------------------------------------------------------
|
nuclear@0
|
546 // Render a value to text.
|
nuclear@0
|
547 char* JSON::PrintValue(int depth, bool fmt)
|
nuclear@0
|
548 {
|
nuclear@0
|
549 char *out=0;
|
nuclear@0
|
550
|
nuclear@0
|
551 switch (Type)
|
nuclear@0
|
552 {
|
nuclear@0
|
553 case JSON_Null: out = JSON_strdup("null"); break;
|
nuclear@0
|
554 case JSON_Bool:
|
nuclear@0
|
555 if ((int)dValue == 0)
|
nuclear@0
|
556 out = JSON_strdup("false");
|
nuclear@0
|
557 else
|
nuclear@0
|
558 out = JSON_strdup("true");
|
nuclear@0
|
559 break;
|
nuclear@0
|
560 case JSON_Number: out = PrintNumber(dValue); break;
|
nuclear@0
|
561 case JSON_String: out = PrintString(Value); break;
|
nuclear@0
|
562 case JSON_Array: out = PrintArray(depth, fmt); break;
|
nuclear@0
|
563 case JSON_Object: out = PrintObject(depth, fmt); break;
|
nuclear@0
|
564 case JSON_None: OVR_ASSERT_LOG(false, ("Bad JSON type.")); break;
|
nuclear@0
|
565 }
|
nuclear@0
|
566 return out;
|
nuclear@0
|
567 }
|
nuclear@0
|
568
|
nuclear@0
|
569 //-----------------------------------------------------------------------------
|
nuclear@0
|
570 // Build an array object from input text and returns the text position after
|
nuclear@0
|
571 // the parsed array
|
nuclear@0
|
572 const char* JSON::parseArray(const char* buff, const char** perror)
|
nuclear@0
|
573 {
|
nuclear@0
|
574 JSON *child;
|
nuclear@0
|
575 if (*buff!='[')
|
nuclear@0
|
576 {
|
nuclear@0
|
577 return AssignError(perror, "Syntax Error: Missing opening bracket");
|
nuclear@0
|
578 }
|
nuclear@0
|
579
|
nuclear@0
|
580 Type=JSON_Array;
|
nuclear@0
|
581 buff=skip(buff+1);
|
nuclear@0
|
582
|
nuclear@0
|
583 if (*buff==']')
|
nuclear@0
|
584 return buff+1; // empty array.
|
nuclear@0
|
585
|
nuclear@0
|
586 child = new JSON();
|
nuclear@0
|
587 if (!child)
|
nuclear@0
|
588 return 0; // memory fail
|
nuclear@0
|
589 Children.PushBack(child);
|
nuclear@0
|
590
|
nuclear@0
|
591 buff=skip(child->parseValue(skip(buff), perror)); // skip any spacing, get the buff.
|
nuclear@0
|
592 if (!buff)
|
nuclear@0
|
593 return 0;
|
nuclear@0
|
594
|
nuclear@0
|
595 while (*buff==',')
|
nuclear@0
|
596 {
|
nuclear@0
|
597 JSON *new_item = new JSON();
|
nuclear@0
|
598 if (!new_item)
|
nuclear@0
|
599 return AssignError(perror, "Error: Failed to allocate memory");
|
nuclear@0
|
600
|
nuclear@0
|
601 Children.PushBack(new_item);
|
nuclear@0
|
602
|
nuclear@0
|
603 buff=skip(new_item->parseValue(skip(buff+1), perror));
|
nuclear@0
|
604 if (!buff)
|
nuclear@0
|
605 return AssignError(perror, "Error: Failed to allocate memory");
|
nuclear@0
|
606 }
|
nuclear@0
|
607
|
nuclear@0
|
608 if (*buff==']')
|
nuclear@0
|
609 return buff+1; // end of array
|
nuclear@0
|
610
|
nuclear@0
|
611 return AssignError(perror, "Syntax Error: Missing ending bracket");
|
nuclear@0
|
612 }
|
nuclear@0
|
613
|
nuclear@0
|
614 //-----------------------------------------------------------------------------
|
nuclear@0
|
615 // Render an array to text. The returned text must be freed
|
nuclear@0
|
616 char* JSON::PrintArray(int depth, bool fmt)
|
nuclear@0
|
617 {
|
nuclear@0
|
618 char ** entries;
|
nuclear@0
|
619 char * out = 0, *ptr,*ret;
|
nuclear@0
|
620 intptr_t len = 5;
|
nuclear@0
|
621
|
nuclear@0
|
622 bool fail = false;
|
nuclear@0
|
623
|
nuclear@0
|
624 // How many entries in the array?
|
nuclear@0
|
625 int numentries = GetItemCount();
|
nuclear@0
|
626 if (!numentries)
|
nuclear@0
|
627 {
|
nuclear@0
|
628 out=(char*)OVR_ALLOC(3);
|
nuclear@0
|
629 if (out)
|
nuclear@0
|
630 OVR_strcpy(out, 3, "[]");
|
nuclear@0
|
631 return out;
|
nuclear@0
|
632 }
|
nuclear@0
|
633 // Allocate an array to hold the values for each
|
nuclear@0
|
634 entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
|
nuclear@0
|
635 if (!entries)
|
nuclear@0
|
636 return 0;
|
nuclear@0
|
637 memset(entries,0,numentries*sizeof(char*));
|
nuclear@0
|
638
|
nuclear@0
|
639 //// Retrieve all the results:
|
nuclear@0
|
640 JSON* child = Children.GetFirst();
|
nuclear@0
|
641 for (int i=0; i<numentries; i++)
|
nuclear@0
|
642 {
|
nuclear@0
|
643 //JSON* child = Children[i];
|
nuclear@0
|
644 ret=child->PrintValue(depth+1, fmt);
|
nuclear@0
|
645 entries[i]=ret;
|
nuclear@0
|
646 if (ret)
|
nuclear@0
|
647 len+=OVR_strlen(ret)+2+(fmt?1:0);
|
nuclear@0
|
648 else
|
nuclear@0
|
649 {
|
nuclear@0
|
650 fail = true;
|
nuclear@0
|
651 break;
|
nuclear@0
|
652 }
|
nuclear@0
|
653 child = Children.GetNext(child);
|
nuclear@0
|
654 }
|
nuclear@0
|
655
|
nuclear@0
|
656 // If we didn't fail, try to malloc the output string
|
nuclear@0
|
657 if (!fail)
|
nuclear@0
|
658 out=(char*)OVR_ALLOC(len);
|
nuclear@0
|
659 // If that fails, we fail.
|
nuclear@0
|
660 if (!out)
|
nuclear@0
|
661 fail = true;
|
nuclear@0
|
662
|
nuclear@0
|
663 // Handle failure.
|
nuclear@0
|
664 if (fail)
|
nuclear@0
|
665 {
|
nuclear@0
|
666 for (int i=0; i<numentries; i++)
|
nuclear@0
|
667 {
|
nuclear@0
|
668 if (entries[i])
|
nuclear@0
|
669 OVR_FREE(entries[i]);
|
nuclear@0
|
670 }
|
nuclear@0
|
671 OVR_FREE(entries);
|
nuclear@0
|
672 return 0;
|
nuclear@0
|
673 }
|
nuclear@0
|
674
|
nuclear@0
|
675 // Compose the output array.
|
nuclear@0
|
676 *out='[';
|
nuclear@0
|
677 ptr=out+1;
|
nuclear@0
|
678 *ptr=0;
|
nuclear@0
|
679 for (int i=0; i<numentries; i++)
|
nuclear@0
|
680 {
|
nuclear@0
|
681 OVR_strcpy(ptr, len - (ptr-out), entries[i]);
|
nuclear@0
|
682 ptr+=OVR_strlen(entries[i]);
|
nuclear@0
|
683 if (i!=numentries-1)
|
nuclear@0
|
684 {
|
nuclear@0
|
685 *ptr++=',';
|
nuclear@0
|
686 if (fmt)
|
nuclear@0
|
687 *ptr++=' ';
|
nuclear@0
|
688 *ptr=0;
|
nuclear@0
|
689 }
|
nuclear@0
|
690 OVR_FREE(entries[i]);
|
nuclear@0
|
691 }
|
nuclear@0
|
692 OVR_FREE(entries);
|
nuclear@0
|
693 *ptr++=']';
|
nuclear@0
|
694 *ptr++=0;
|
nuclear@0
|
695 return out;
|
nuclear@0
|
696 }
|
nuclear@0
|
697
|
nuclear@0
|
698 //-----------------------------------------------------------------------------
|
nuclear@0
|
699 // Build an object from the supplied text and returns the text position after
|
nuclear@0
|
700 // the parsed object
|
nuclear@0
|
701 const char* JSON::parseObject(const char* buff, const char** perror)
|
nuclear@0
|
702 {
|
nuclear@0
|
703 if (*buff!='{')
|
nuclear@0
|
704 {
|
nuclear@0
|
705 return AssignError(perror, "Syntax Error: Missing opening brace");
|
nuclear@0
|
706 }
|
nuclear@0
|
707
|
nuclear@0
|
708 Type=JSON_Object;
|
nuclear@0
|
709 buff=skip(buff+1);
|
nuclear@0
|
710 if (*buff=='}')
|
nuclear@0
|
711 return buff+1; // empty array.
|
nuclear@0
|
712
|
nuclear@0
|
713 JSON* child = new JSON();
|
nuclear@0
|
714 Children.PushBack(child);
|
nuclear@0
|
715
|
nuclear@0
|
716 buff=skip(child->parseString(skip(buff), perror));
|
nuclear@0
|
717 if (!buff)
|
nuclear@0
|
718 return 0;
|
nuclear@0
|
719 child->Name = child->Value;
|
nuclear@0
|
720 child->Value.Clear();
|
nuclear@0
|
721
|
nuclear@0
|
722 if (*buff!=':')
|
nuclear@0
|
723 {
|
nuclear@0
|
724 return AssignError(perror, "Syntax Error: Missing colon");
|
nuclear@0
|
725 }
|
nuclear@0
|
726
|
nuclear@0
|
727 buff=skip(child->parseValue(skip(buff+1), perror)); // skip any spacing, get the value.
|
nuclear@0
|
728 if (!buff)
|
nuclear@0
|
729 return 0;
|
nuclear@0
|
730
|
nuclear@0
|
731 while (*buff==',')
|
nuclear@0
|
732 {
|
nuclear@0
|
733 child = new JSON();
|
nuclear@0
|
734 if (!child)
|
nuclear@0
|
735 return 0; // memory fail
|
nuclear@0
|
736
|
nuclear@0
|
737 Children.PushBack(child);
|
nuclear@0
|
738
|
nuclear@0
|
739 buff=skip(child->parseString(skip(buff+1), perror));
|
nuclear@0
|
740 if (!buff)
|
nuclear@0
|
741 return 0;
|
nuclear@0
|
742
|
nuclear@0
|
743 child->Name=child->Value;
|
nuclear@0
|
744 child->Value.Clear();
|
nuclear@0
|
745
|
nuclear@0
|
746 if (*buff!=':')
|
nuclear@0
|
747 {
|
nuclear@0
|
748 return AssignError(perror, "Syntax Error: Missing colon");
|
nuclear@0
|
749 } // fail!
|
nuclear@0
|
750
|
nuclear@0
|
751 // Skip any spacing, get the value.
|
nuclear@0
|
752 buff=skip(child->parseValue(skip(buff+1), perror));
|
nuclear@0
|
753 if (!buff)
|
nuclear@0
|
754 return 0;
|
nuclear@0
|
755 }
|
nuclear@0
|
756
|
nuclear@0
|
757 if (*buff=='}')
|
nuclear@0
|
758 return buff+1; // end of array
|
nuclear@0
|
759
|
nuclear@0
|
760 return AssignError(perror, "Syntax Error: Missing closing brace");
|
nuclear@0
|
761 }
|
nuclear@0
|
762
|
nuclear@0
|
763 //-----------------------------------------------------------------------------
|
nuclear@0
|
764 // Render an object to text. The returned string must be freed
|
nuclear@0
|
765 char* JSON::PrintObject(int depth, bool fmt)
|
nuclear@0
|
766 {
|
nuclear@0
|
767 char** entries = 0, **names = 0;
|
nuclear@0
|
768 char* out = 0;
|
nuclear@0
|
769 char* ptr, *ret, *str;
|
nuclear@0
|
770 intptr_t len = 7, i = 0, j;
|
nuclear@0
|
771 bool fail = false;
|
nuclear@0
|
772
|
nuclear@0
|
773 // Count the number of entries.
|
nuclear@0
|
774 int numentries = GetItemCount();
|
nuclear@0
|
775
|
nuclear@0
|
776 // Explicitly handle empty object case
|
nuclear@0
|
777 if (numentries == 0)
|
nuclear@0
|
778 {
|
nuclear@0
|
779 out=(char*)OVR_ALLOC(fmt?depth+4:4);
|
nuclear@0
|
780 if (!out)
|
nuclear@0
|
781 return 0;
|
nuclear@0
|
782 ptr=out;
|
nuclear@0
|
783 *ptr++='{';
|
nuclear@0
|
784
|
nuclear@0
|
785 if (fmt)
|
nuclear@0
|
786 {
|
nuclear@0
|
787 *ptr++='\n';
|
nuclear@0
|
788 for (i=0;i<depth-1;i++)
|
nuclear@0
|
789 *ptr++='\t';
|
nuclear@0
|
790 }
|
nuclear@0
|
791 *ptr++='}';
|
nuclear@0
|
792 *ptr++=0;
|
nuclear@0
|
793 return out;
|
nuclear@0
|
794 }
|
nuclear@0
|
795 // Allocate space for the names and the objects
|
nuclear@0
|
796 entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
|
nuclear@0
|
797 if (!entries)
|
nuclear@0
|
798 return 0;
|
nuclear@0
|
799 names=(char**)OVR_ALLOC(numentries*sizeof(char*));
|
nuclear@0
|
800
|
nuclear@0
|
801 if (!names)
|
nuclear@0
|
802 {
|
nuclear@0
|
803 OVR_FREE(entries);
|
nuclear@0
|
804 return 0;
|
nuclear@0
|
805 }
|
nuclear@0
|
806 memset(entries,0,sizeof(char*)*numentries);
|
nuclear@0
|
807 memset(names,0,sizeof(char*)*numentries);
|
nuclear@0
|
808
|
nuclear@0
|
809 // Collect all the results into our arrays:
|
nuclear@0
|
810 depth++;
|
nuclear@0
|
811 if (fmt)
|
nuclear@0
|
812 len+=depth;
|
nuclear@0
|
813
|
nuclear@0
|
814 JSON* child = Children.GetFirst();
|
nuclear@0
|
815 while (!Children.IsNull(child))
|
nuclear@0
|
816 {
|
nuclear@0
|
817 names[i] = str = PrintString(child->Name);
|
nuclear@0
|
818 entries[i++] = ret = child->PrintValue(depth, fmt);
|
nuclear@0
|
819
|
nuclear@0
|
820 if (str && ret)
|
nuclear@0
|
821 {
|
nuclear@0
|
822 len += OVR_strlen(ret)+OVR_strlen(str)+2+(fmt?3+depth:0);
|
nuclear@0
|
823 }
|
nuclear@0
|
824 else
|
nuclear@0
|
825 {
|
nuclear@0
|
826 fail = true;
|
nuclear@0
|
827 break;
|
nuclear@0
|
828 }
|
nuclear@0
|
829
|
nuclear@0
|
830 child = Children.GetNext(child);
|
nuclear@0
|
831 }
|
nuclear@0
|
832
|
nuclear@0
|
833 // Try to allocate the output string
|
nuclear@0
|
834 if (!fail)
|
nuclear@0
|
835 out=(char*)OVR_ALLOC(len);
|
nuclear@0
|
836 if (!out)
|
nuclear@0
|
837 fail=true;
|
nuclear@0
|
838
|
nuclear@0
|
839 // Handle failure
|
nuclear@0
|
840 if (fail)
|
nuclear@0
|
841 {
|
nuclear@0
|
842 for (i=0;i<numentries;i++)
|
nuclear@0
|
843 {
|
nuclear@0
|
844 if (names[i])
|
nuclear@0
|
845 OVR_FREE(names[i]);
|
nuclear@0
|
846
|
nuclear@0
|
847 if (entries[i])
|
nuclear@0
|
848 OVR_FREE(entries[i]);}
|
nuclear@0
|
849
|
nuclear@0
|
850 OVR_FREE(names);
|
nuclear@0
|
851 OVR_FREE(entries);
|
nuclear@0
|
852 return 0;
|
nuclear@0
|
853 }
|
nuclear@0
|
854
|
nuclear@0
|
855 // Compose the output:
|
nuclear@0
|
856 *out = '{';
|
nuclear@0
|
857 ptr = out+1;
|
nuclear@0
|
858 if (fmt)
|
nuclear@0
|
859 {
|
nuclear@0
|
860 #ifdef OVR_OS_WIN32
|
nuclear@0
|
861 *ptr++ = '\r';
|
nuclear@0
|
862 #endif
|
nuclear@0
|
863 *ptr++ = '\n';
|
nuclear@0
|
864 }
|
nuclear@0
|
865 *ptr = 0;
|
nuclear@0
|
866
|
nuclear@0
|
867 for (i=0; i<numentries; i++)
|
nuclear@0
|
868 {
|
nuclear@0
|
869 if (fmt)
|
nuclear@0
|
870 {
|
nuclear@0
|
871 for (j = 0; j < depth; j++)
|
nuclear@0
|
872 {
|
nuclear@0
|
873 *ptr++ = '\t';
|
nuclear@0
|
874 }
|
nuclear@0
|
875 }
|
nuclear@0
|
876 OVR_strcpy(ptr, len - (ptr-out), names[i]);
|
nuclear@0
|
877 ptr += OVR_strlen(names[i]);
|
nuclear@0
|
878 *ptr++ =':';
|
nuclear@0
|
879
|
nuclear@0
|
880 if (fmt)
|
nuclear@0
|
881 {
|
nuclear@0
|
882 *ptr++ = '\t';
|
nuclear@0
|
883 }
|
nuclear@0
|
884
|
nuclear@0
|
885 OVR_strcpy(ptr, len - (ptr-out), entries[i]);
|
nuclear@0
|
886 ptr+=OVR_strlen(entries[i]);
|
nuclear@0
|
887
|
nuclear@0
|
888 if (i != numentries - 1)
|
nuclear@0
|
889 {
|
nuclear@0
|
890 *ptr++ = ',';
|
nuclear@0
|
891 }
|
nuclear@0
|
892
|
nuclear@0
|
893 if (fmt)
|
nuclear@0
|
894 {
|
nuclear@0
|
895 #ifdef OVR_OS_WIN32
|
nuclear@0
|
896 *ptr++ = '\r';
|
nuclear@0
|
897 #endif
|
nuclear@0
|
898 *ptr++ = '\n';
|
nuclear@0
|
899 }
|
nuclear@0
|
900 *ptr = 0;
|
nuclear@0
|
901
|
nuclear@0
|
902 OVR_FREE(names[i]);
|
nuclear@0
|
903 OVR_FREE(entries[i]);
|
nuclear@0
|
904 }
|
nuclear@0
|
905
|
nuclear@0
|
906 OVR_FREE(names);
|
nuclear@0
|
907 OVR_FREE(entries);
|
nuclear@0
|
908
|
nuclear@0
|
909 if (fmt)
|
nuclear@0
|
910 {
|
nuclear@0
|
911 for (i = 0; i < depth - 1; i++)
|
nuclear@0
|
912 {
|
nuclear@0
|
913 *ptr++ = '\t';
|
nuclear@0
|
914 }
|
nuclear@0
|
915 }
|
nuclear@0
|
916 *ptr++='}';
|
nuclear@0
|
917 *ptr++=0;
|
nuclear@0
|
918
|
nuclear@0
|
919 return out;
|
nuclear@0
|
920 }
|
nuclear@0
|
921
|
nuclear@0
|
922
|
nuclear@0
|
923
|
nuclear@0
|
924 // Returns the number of child items in the object
|
nuclear@0
|
925 // Counts the number of items in the object.
|
nuclear@0
|
926 unsigned JSON::GetItemCount() const
|
nuclear@0
|
927 {
|
nuclear@0
|
928 unsigned count = 0;
|
nuclear@0
|
929 for (const JSON* p = Children.GetFirst(); !Children.IsNull(p); p = p->pNext)
|
nuclear@0
|
930 {
|
nuclear@0
|
931 count++;
|
nuclear@0
|
932 }
|
nuclear@0
|
933 return count;
|
nuclear@0
|
934 }
|
nuclear@0
|
935
|
nuclear@0
|
936 JSON* JSON::GetItemByIndex(unsigned index)
|
nuclear@0
|
937 {
|
nuclear@0
|
938 unsigned i = 0;
|
nuclear@0
|
939 JSON* child = 0;
|
nuclear@0
|
940
|
nuclear@0
|
941 if (!Children.IsEmpty())
|
nuclear@0
|
942 {
|
nuclear@0
|
943 child = Children.GetFirst();
|
nuclear@0
|
944
|
nuclear@0
|
945 while (i < index)
|
nuclear@0
|
946 {
|
nuclear@0
|
947 if (Children.IsNull(child->pNext))
|
nuclear@0
|
948 {
|
nuclear@0
|
949 child = 0;
|
nuclear@0
|
950 break;
|
nuclear@0
|
951 }
|
nuclear@0
|
952 child = child->pNext;
|
nuclear@0
|
953 i++;
|
nuclear@0
|
954 }
|
nuclear@0
|
955 }
|
nuclear@0
|
956
|
nuclear@0
|
957 return child;
|
nuclear@0
|
958 }
|
nuclear@0
|
959
|
nuclear@0
|
960 // Returns the child item with the given name or NULL if not found
|
nuclear@0
|
961 JSON* JSON::GetItemByName(const char* name)
|
nuclear@0
|
962 {
|
nuclear@0
|
963 JSON* child = 0;
|
nuclear@0
|
964
|
nuclear@0
|
965 if (!Children.IsEmpty())
|
nuclear@0
|
966 {
|
nuclear@0
|
967 child = Children.GetFirst();
|
nuclear@0
|
968
|
nuclear@0
|
969 while (OVR_strcmp(child->Name, name) != 0)
|
nuclear@0
|
970 {
|
nuclear@0
|
971 if (Children.IsNull(child->pNext))
|
nuclear@0
|
972 {
|
nuclear@0
|
973 child = 0;
|
nuclear@0
|
974 break;
|
nuclear@0
|
975 }
|
nuclear@0
|
976 child = child->pNext;
|
nuclear@0
|
977 }
|
nuclear@0
|
978 }
|
nuclear@0
|
979
|
nuclear@0
|
980 return child;
|
nuclear@0
|
981 }
|
nuclear@0
|
982
|
nuclear@0
|
983 //-----------------------------------------------------------------------------
|
nuclear@0
|
984 // Adds a new item to the end of the child list
|
nuclear@0
|
985 void JSON::AddItem(const char *string, JSON *item)
|
nuclear@0
|
986 {
|
nuclear@0
|
987 if (item)
|
nuclear@0
|
988 {
|
nuclear@0
|
989 item->Name = string;
|
nuclear@0
|
990 Children.PushBack(item);
|
nuclear@0
|
991 }
|
nuclear@0
|
992 }
|
nuclear@0
|
993
|
nuclear@0
|
994 /*
|
nuclear@0
|
995
|
nuclear@0
|
996 // Removes and frees the items at the given index
|
nuclear@0
|
997 void JSON::DeleteItem(unsigned int index)
|
nuclear@0
|
998 {
|
nuclear@0
|
999 unsigned int num_items = 0;
|
nuclear@0
|
1000 JSON* child = Children.GetFirst();
|
nuclear@0
|
1001 while (!Children.IsNull(child) && num_items < index)
|
nuclear@0
|
1002 {
|
nuclear@0
|
1003 num_items++;
|
nuclear@0
|
1004 child = Children.GetNext(child);
|
nuclear@0
|
1005 }
|
nuclear@0
|
1006
|
nuclear@0
|
1007 if (!Children.IsNull(child))
|
nuclear@0
|
1008
|
nuclear@0
|
1009 child->RemoveNode();
|
nuclear@0
|
1010 child->Release();
|
nuclear@0
|
1011 }
|
nuclear@0
|
1012 }
|
nuclear@0
|
1013
|
nuclear@0
|
1014 // Replaces and frees the item at the give index with the new item
|
nuclear@0
|
1015 void JSON::ReplaceItem(unsigned int index, JSON* new_item)
|
nuclear@0
|
1016 {
|
nuclear@0
|
1017 unsigned int num_items = 0;
|
nuclear@0
|
1018 JSON* child = Children.GetFirst();
|
nuclear@0
|
1019 while (!Children.IsNull(child) && num_items < index)
|
nuclear@0
|
1020 {
|
nuclear@0
|
1021 num_items++;
|
nuclear@0
|
1022 child = Children.GetNext(child);
|
nuclear@0
|
1023 }
|
nuclear@0
|
1024
|
nuclear@0
|
1025 if (!Children.IsNull(child))
|
nuclear@0
|
1026 {
|
nuclear@0
|
1027 child->ReplaceNodeWith(new_item);
|
nuclear@0
|
1028 child->Release();
|
nuclear@0
|
1029 }
|
nuclear@0
|
1030 }
|
nuclear@0
|
1031 */
|
nuclear@0
|
1032
|
nuclear@0
|
1033 // Removes and frees the last child item
|
nuclear@0
|
1034 void JSON::RemoveLast()
|
nuclear@0
|
1035 {
|
nuclear@0
|
1036 JSON* child = Children.GetLast();
|
nuclear@0
|
1037 if (!Children.IsNull(child))
|
nuclear@0
|
1038 {
|
nuclear@0
|
1039 child->RemoveNode();
|
nuclear@0
|
1040 child->Release();
|
nuclear@0
|
1041 }
|
nuclear@0
|
1042 }
|
nuclear@0
|
1043
|
nuclear@0
|
1044 JSON* JSON::CreateBool(bool b)
|
nuclear@0
|
1045 {
|
nuclear@0
|
1046 JSON *item = new JSON(JSON_Bool);
|
nuclear@0
|
1047 if (item)
|
nuclear@0
|
1048 {
|
nuclear@0
|
1049 item->dValue = b ? 1. : 0.;
|
nuclear@0
|
1050 item->Value = b ? "true" : "false";
|
nuclear@0
|
1051 }
|
nuclear@0
|
1052 return item;
|
nuclear@0
|
1053 }
|
nuclear@0
|
1054
|
nuclear@0
|
1055 JSON* JSON::CreateNumber(double num)
|
nuclear@0
|
1056 {
|
nuclear@0
|
1057 JSON *item = new JSON(JSON_Number);
|
nuclear@0
|
1058 if (item)
|
nuclear@0
|
1059 {
|
nuclear@0
|
1060 item->dValue = num;
|
nuclear@0
|
1061 }
|
nuclear@0
|
1062 return item;
|
nuclear@0
|
1063 }
|
nuclear@0
|
1064
|
nuclear@0
|
1065 JSON* JSON::CreateInt(int num)
|
nuclear@0
|
1066 {
|
nuclear@0
|
1067 JSON *item = new JSON(JSON_Number);
|
nuclear@0
|
1068 if (item)
|
nuclear@0
|
1069 {
|
nuclear@0
|
1070 item->dValue = num;
|
nuclear@0
|
1071 }
|
nuclear@0
|
1072 return item;
|
nuclear@0
|
1073 }
|
nuclear@0
|
1074
|
nuclear@0
|
1075 JSON* JSON::CreateString(const char *s)
|
nuclear@0
|
1076 {
|
nuclear@0
|
1077 JSON *item = new JSON(JSON_String);
|
nuclear@0
|
1078 if (item && s)
|
nuclear@0
|
1079 {
|
nuclear@0
|
1080 item->Value = s;
|
nuclear@0
|
1081 }
|
nuclear@0
|
1082 return item;
|
nuclear@0
|
1083 }
|
nuclear@0
|
1084
|
nuclear@0
|
1085
|
nuclear@0
|
1086 //-----------------------------------------------------------------------------
|
nuclear@0
|
1087 // Get elements by name
|
nuclear@0
|
1088 double JSON::GetNumberByName(const char *name, double defValue)
|
nuclear@0
|
1089 {
|
nuclear@0
|
1090 JSON* item = GetItemByName(name);
|
nuclear@0
|
1091 if (!item || item->Type != JSON_Number)
|
nuclear@0
|
1092 {
|
nuclear@0
|
1093 return defValue;
|
nuclear@0
|
1094 }
|
nuclear@0
|
1095 else
|
nuclear@0
|
1096 {
|
nuclear@0
|
1097 return item->dValue;
|
nuclear@0
|
1098 }
|
nuclear@0
|
1099 }
|
nuclear@0
|
1100
|
nuclear@0
|
1101 int JSON::GetIntByName(const char *name, int defValue)
|
nuclear@0
|
1102 {
|
nuclear@0
|
1103 JSON* item = GetItemByName(name);
|
nuclear@0
|
1104 if (!item || item->Type != JSON_Number)
|
nuclear@0
|
1105 {
|
nuclear@0
|
1106 return defValue;
|
nuclear@0
|
1107 }
|
nuclear@0
|
1108 else
|
nuclear@0
|
1109 {
|
nuclear@0
|
1110 return (int)item->dValue;
|
nuclear@0
|
1111 }
|
nuclear@0
|
1112 }
|
nuclear@0
|
1113
|
nuclear@0
|
1114 bool JSON::GetBoolByName(const char *name, bool defValue)
|
nuclear@0
|
1115 {
|
nuclear@0
|
1116 JSON* item = GetItemByName(name);
|
nuclear@0
|
1117 if (!item || item->Type != JSON_Bool)
|
nuclear@0
|
1118 {
|
nuclear@0
|
1119 return defValue;
|
nuclear@0
|
1120 }
|
nuclear@0
|
1121 else
|
nuclear@0
|
1122 {
|
nuclear@0
|
1123 return (int)item->dValue != 0;
|
nuclear@0
|
1124 }
|
nuclear@0
|
1125 }
|
nuclear@0
|
1126
|
nuclear@0
|
1127 String JSON::GetStringByName(const char *name, const String &defValue)
|
nuclear@0
|
1128 {
|
nuclear@0
|
1129 JSON* item = GetItemByName(name);
|
nuclear@0
|
1130 if (!item || item->Type != JSON_String)
|
nuclear@0
|
1131 {
|
nuclear@0
|
1132 return defValue;
|
nuclear@0
|
1133 }
|
nuclear@0
|
1134 else
|
nuclear@0
|
1135 {
|
nuclear@0
|
1136 return item->Value;
|
nuclear@0
|
1137 }
|
nuclear@0
|
1138 }
|
nuclear@0
|
1139
|
nuclear@0
|
1140 //-----------------------------------------------------------------------------
|
nuclear@0
|
1141 // Adds an element to an array object type
|
nuclear@0
|
1142 void JSON::AddArrayElement(JSON *item)
|
nuclear@0
|
1143 {
|
nuclear@0
|
1144 if (item)
|
nuclear@0
|
1145 {
|
nuclear@0
|
1146 Children.PushBack(item);
|
nuclear@0
|
1147 }
|
nuclear@0
|
1148 }
|
nuclear@0
|
1149
|
nuclear@0
|
1150 // Inserts an element into a valid array position
|
nuclear@0
|
1151 void JSON::InsertArrayElement(int index, JSON *item)
|
nuclear@0
|
1152 {
|
nuclear@0
|
1153 if (!item)
|
nuclear@0
|
1154 {
|
nuclear@0
|
1155 return;
|
nuclear@0
|
1156 }
|
nuclear@0
|
1157
|
nuclear@0
|
1158 if (index == 0)
|
nuclear@0
|
1159 {
|
nuclear@0
|
1160 Children.PushFront(item);
|
nuclear@0
|
1161 return;
|
nuclear@0
|
1162 }
|
nuclear@0
|
1163
|
nuclear@0
|
1164 JSON* iter = Children.GetFirst();
|
nuclear@0
|
1165 int i=0;
|
nuclear@0
|
1166 while (iter && i<index)
|
nuclear@0
|
1167 {
|
nuclear@0
|
1168 iter = Children.GetNext(iter);
|
nuclear@0
|
1169 i++;
|
nuclear@0
|
1170 }
|
nuclear@0
|
1171
|
nuclear@0
|
1172 if (iter)
|
nuclear@0
|
1173 iter->InsertNodeBefore(item);
|
nuclear@0
|
1174 else
|
nuclear@0
|
1175 Children.PushBack(item);
|
nuclear@0
|
1176 }
|
nuclear@0
|
1177
|
nuclear@0
|
1178 // Returns the size of an array
|
nuclear@0
|
1179 int JSON::GetArraySize()
|
nuclear@0
|
1180 {
|
nuclear@0
|
1181 if (Type == JSON_Array)
|
nuclear@0
|
1182 {
|
nuclear@0
|
1183 return GetItemCount();
|
nuclear@0
|
1184 }
|
nuclear@0
|
1185
|
nuclear@0
|
1186 return 0;
|
nuclear@0
|
1187 }
|
nuclear@0
|
1188
|
nuclear@0
|
1189 // Returns the number value an the give array index
|
nuclear@0
|
1190 double JSON::GetArrayNumber(int index)
|
nuclear@0
|
1191 {
|
nuclear@0
|
1192 if (Type == JSON_Array)
|
nuclear@0
|
1193 {
|
nuclear@0
|
1194 JSON* number = GetItemByIndex(index);
|
nuclear@0
|
1195 return number ? number->dValue : 0.0;
|
nuclear@0
|
1196 }
|
nuclear@0
|
1197
|
nuclear@0
|
1198 return 0;
|
nuclear@0
|
1199 }
|
nuclear@0
|
1200
|
nuclear@0
|
1201 // Returns the string value at the given array index
|
nuclear@0
|
1202 const char* JSON::GetArrayString(int index)
|
nuclear@0
|
1203 {
|
nuclear@0
|
1204 if (Type == JSON_Array)
|
nuclear@0
|
1205 {
|
nuclear@0
|
1206 JSON* number = GetItemByIndex(index);
|
nuclear@0
|
1207 return number ? number->Value : 0;
|
nuclear@0
|
1208 }
|
nuclear@0
|
1209
|
nuclear@0
|
1210 return 0;
|
nuclear@0
|
1211 }
|
nuclear@0
|
1212
|
nuclear@0
|
1213 JSON* JSON::Copy()
|
nuclear@0
|
1214 {
|
nuclear@0
|
1215 JSON* copy = new JSON(Type);
|
nuclear@0
|
1216 copy->Name = Name;
|
nuclear@0
|
1217 copy->Value = Value;
|
nuclear@0
|
1218 copy->dValue = dValue;
|
nuclear@0
|
1219
|
nuclear@0
|
1220 JSON* child = Children.GetFirst();
|
nuclear@0
|
1221 while (!Children.IsNull(child))
|
nuclear@0
|
1222 {
|
nuclear@0
|
1223 copy->Children.PushBack(child->Copy());
|
nuclear@0
|
1224 child = Children.GetNext(child);
|
nuclear@0
|
1225 }
|
nuclear@0
|
1226
|
nuclear@0
|
1227 return copy;
|
nuclear@0
|
1228 }
|
nuclear@0
|
1229
|
nuclear@0
|
1230 //-----------------------------------------------------------------------------
|
nuclear@0
|
1231 // Loads and parses the given JSON file pathname and returns a JSON object tree.
|
nuclear@0
|
1232 // The returned object must be Released after use.
|
nuclear@0
|
1233 JSON* JSON::Load(const char* path, const char** perror)
|
nuclear@0
|
1234 {
|
nuclear@0
|
1235 SysFile f;
|
nuclear@0
|
1236 if (!f.Open(path, File::Open_Read, File::Mode_Read))
|
nuclear@0
|
1237 {
|
nuclear@0
|
1238 AssignError(perror, "Failed to open file");
|
nuclear@0
|
1239 return NULL;
|
nuclear@0
|
1240 }
|
nuclear@0
|
1241
|
nuclear@0
|
1242 int len = f.GetLength();
|
nuclear@0
|
1243 uint8_t* buff = (uint8_t*)OVR_ALLOC(len + 1);
|
nuclear@0
|
1244 int bytes = f.Read(buff, len);
|
nuclear@0
|
1245 f.Close();
|
nuclear@0
|
1246
|
nuclear@0
|
1247 if (bytes == 0 || bytes != len)
|
nuclear@0
|
1248 {
|
nuclear@0
|
1249 OVR_FREE(buff);
|
nuclear@0
|
1250 return NULL;
|
nuclear@0
|
1251 }
|
nuclear@0
|
1252
|
nuclear@0
|
1253 // Ensure the result is null-terminated since Parse() expects null-terminated input.
|
nuclear@0
|
1254 buff[len] = '\0';
|
nuclear@0
|
1255
|
nuclear@0
|
1256 JSON* json = JSON::Parse((char*)buff, perror);
|
nuclear@0
|
1257 OVR_FREE(buff);
|
nuclear@0
|
1258 return json;
|
nuclear@0
|
1259 }
|
nuclear@0
|
1260
|
nuclear@0
|
1261 //-----------------------------------------------------------------------------
|
nuclear@0
|
1262 // Serializes the JSON object and writes to the give file path
|
nuclear@0
|
1263 bool JSON::Save(const char* path)
|
nuclear@0
|
1264 {
|
nuclear@0
|
1265 SysFile f;
|
nuclear@0
|
1266 if (!f.Open(path, File::Open_Write | File::Open_Create | File::Open_Truncate, File::Mode_Write))
|
nuclear@0
|
1267 return false;
|
nuclear@0
|
1268
|
nuclear@0
|
1269 char* text = PrintValue(0, true);
|
nuclear@0
|
1270 if (text)
|
nuclear@0
|
1271 {
|
nuclear@0
|
1272 intptr_t len = OVR_strlen(text);
|
nuclear@0
|
1273 OVR_ASSERT(len <= (intptr_t)(int)len);
|
nuclear@0
|
1274
|
nuclear@0
|
1275 int bytes = f.Write((uint8_t*)text, (int)len);
|
nuclear@0
|
1276 f.Close();
|
nuclear@0
|
1277 OVR_FREE(text);
|
nuclear@0
|
1278 return (bytes == len);
|
nuclear@0
|
1279 }
|
nuclear@0
|
1280 else
|
nuclear@0
|
1281 {
|
nuclear@0
|
1282 return false;
|
nuclear@0
|
1283 }
|
nuclear@0
|
1284 }
|
nuclear@0
|
1285
|
nuclear@0
|
1286
|
nuclear@0
|
1287 } // namespace OVR
|