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