oculus1

annotate libovr/Src/OVR_JSON.cpp @ 1:e2f9e4603129

added LibOVR and started a simple vr wrapper.
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 14 Sep 2013 16:14:59 +0300
parents
children
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 }