ovr_sdk

diff LibOVR/Src/OVR_JSON.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/LibOVR/Src/OVR_JSON.cpp	Wed Jan 14 06:51:16 2015 +0200
     1.3 @@ -0,0 +1,1287 @@
     1.4 +/************************************************************************************
     1.5 +
     1.6 +PublicHeader:   None
     1.7 +Filename    :   OVR_JSON.h
     1.8 +Content     :   JSON format reader and writer
     1.9 +Created     :   April 9, 2013
    1.10 +Author      :   Brant Lewis
    1.11 +Notes       :
    1.12 +  The code is a derivative of the cJSON library written by Dave Gamble and subject 
    1.13 +  to the following permissive copyright.
    1.14 +
    1.15 +  Copyright (c) 2009 Dave Gamble
    1.16 + 
    1.17 +  Permission is hereby granted, free of charge, to any person obtaining a copy
    1.18 +  of this software and associated documentation files (the "Software"), to deal
    1.19 +  in the Software without restriction, including without limitation the rights
    1.20 +  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    1.21 +  copies of the Software, and to permit persons to whom the Software is
    1.22 +  furnished to do so, subject to the following conditions:
    1.23 + 
    1.24 +  The above copyright notice and this permission notice shall be included in
    1.25 +  all copies or substantial portions of the Software.
    1.26 + 
    1.27 +  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    1.28 +  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    1.29 +  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    1.30 +  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    1.31 +  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    1.32 +  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    1.33 +  THE SOFTWARE.
    1.34 +
    1.35 +
    1.36 +Copyright   :   Copyright 2014 Oculus VR, LLC All Rights reserved.
    1.37 +
    1.38 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 
    1.39 +you may not use the Oculus VR Rift SDK except in compliance with the License, 
    1.40 +which is provided at the time of installation or download, or which 
    1.41 +otherwise accompanies this software in either electronic or hard copy form.
    1.42 +
    1.43 +You may obtain a copy of the License at
    1.44 +
    1.45 +http://www.oculusvr.com/licenses/LICENSE-3.2 
    1.46 +
    1.47 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 
    1.48 +distributed under the License is distributed on an "AS IS" BASIS,
    1.49 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.50 +See the License for the specific language governing permissions and
    1.51 +limitations under the License.
    1.52 +
    1.53 +************************************************************************************/
    1.54 +
    1.55 +#include <string.h>
    1.56 +#include <stdio.h>
    1.57 +#include <math.h>
    1.58 +#include <stdlib.h>
    1.59 +#include <float.h>
    1.60 +#include <limits.h>
    1.61 +#include <ctype.h>
    1.62 +#include "OVR_JSON.h"
    1.63 +#include "Kernel/OVR_SysFile.h"
    1.64 +#include "Kernel/OVR_Log.h"
    1.65 +
    1.66 +#ifdef OVR_OS_LINUX
    1.67 +#include <locale.h>
    1.68 +#endif
    1.69 +
    1.70 +namespace OVR {
    1.71 +
    1.72 +
    1.73 +//-----------------------------------------------------------------------------
    1.74 +// Create a new copy of a string
    1.75 +static char* JSON_strdup(const char* str)
    1.76 +{
    1.77 +    size_t len  = OVR_strlen(str) + 1;
    1.78 +    char* copy = (char*)OVR_ALLOC(len);
    1.79 +    if (!copy)
    1.80 +        return 0;
    1.81 +    memcpy(copy, str, len);
    1.82 +    return copy;
    1.83 +}
    1.84 +
    1.85 +
    1.86 +//-----------------------------------------------------------------------------
    1.87 +// Render the number from the given item into a string.
    1.88 +static char* PrintInt(int valueint)
    1.89 +{
    1.90 +    char *str;
    1.91 +    str = (char*)OVR_ALLOC(21);	// 2^64+1 can be represented in 21 chars.
    1.92 +    if (str)
    1.93 +    {
    1.94 +        OVR_sprintf(str, 21, "%d", valueint);
    1.95 +    }
    1.96 +    return str;
    1.97 +}
    1.98 +
    1.99 +
   1.100 +//-----------------------------------------------------------------------------
   1.101 +// Render the number from the given item into a string.
   1.102 +static char* PrintNumber(double d)
   1.103 +{
   1.104 +    char *str;
   1.105 +    int valueint = (int)d;
   1.106 +	if (fabs(((double)valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
   1.107 +	{
   1.108 +        return PrintInt(valueint);
   1.109 +	}
   1.110 +	else
   1.111 +	{
   1.112 +		str=(char*)OVR_ALLOC(64);	// This is a nice tradeoff.
   1.113 +		if (str)
   1.114 +		{
   1.115 +			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)
   1.116 +                OVR_sprintf(str, 64, "%.0f", d);
   1.117 +			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)
   1.118 +                OVR_sprintf(str, 64, "%e", d);
   1.119 +			else
   1.120 +                OVR_sprintf(str, 64, "%f", d);
   1.121 +		}
   1.122 +	}
   1.123 +	return str;
   1.124 +}
   1.125 +
   1.126 +
   1.127 +// Parse the input text into an un-escaped cstring, and populate item.
   1.128 +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
   1.129 +
   1.130 +// Helper to assign error sting and return 0.
   1.131 +const char* AssignError(const char** perror, const char *errorMessage)
   1.132 +{
   1.133 +    if (perror)
   1.134 +        *perror = errorMessage;
   1.135 +    return 0;
   1.136 +}
   1.137 +
   1.138 +//-----------------------------------------------------------------------------
   1.139 +// ***** JSON Node class
   1.140 +
   1.141 +JSON::JSON(JSONItemType itemType) :
   1.142 +    Type(itemType), dValue(0.)
   1.143 +{
   1.144 +}
   1.145 +
   1.146 +JSON::~JSON()
   1.147 +{
   1.148 +    JSON* child = Children.GetFirst();
   1.149 +    while (!Children.IsNull(child))
   1.150 +    {
   1.151 +        child->RemoveNode();
   1.152 +        child->Release();
   1.153 +        child = Children.GetFirst();
   1.154 +    }
   1.155 +}
   1.156 +
   1.157 +//-----------------------------------------------------------------------------
   1.158 +// Parse the input text to generate a number, and populate the result into item
   1.159 +// Returns the text position after the parsed number
   1.160 +const char* JSON::parseNumber(const char *num)
   1.161 +{
   1.162 +    const char* num_start = num;
   1.163 +    double      n=0, scale=0;
   1.164 +    int         subscale     = 0,
   1.165 +                signsubscale = 1;
   1.166 +    bool positiveSign = true;
   1.167 +    char localeSeparator = '.';
   1.168 +
   1.169 +#ifdef OVR_OS_LINUX
   1.170 +    // We should switch to a locale aware parsing function, such as atof. We
   1.171 +    // will probably want to go farther and enforce the 'C' locale on all JSON
   1.172 +    // output/input.
   1.173 +    struct lconv* localeConv = localeconv();
   1.174 +    localeSeparator = localeConv->decimal_point[0];
   1.175 +#endif
   1.176 +
   1.177 +    // Could use sscanf for this?
   1.178 +    if (*num == '-')
   1.179 +    {
   1.180 +        positiveSign = false;
   1.181 +        num++;	// Has sign?
   1.182 +    }
   1.183 +    if (*num == '0')
   1.184 +    {
   1.185 +        num++;			// is zero
   1.186 +    }
   1.187 +
   1.188 +    if (*num>='1' && *num<='9')	
   1.189 +    {
   1.190 +        do
   1.191 +        {
   1.192 +            n = (n*10.0) + (*num++ - '0');
   1.193 +        }
   1.194 +        while (*num>='0' && *num<='9');	// Number?
   1.195 +    }
   1.196 +
   1.197 +    if ((*num=='.' || *num==localeSeparator) && num[1]>='0' && num[1]<='9')
   1.198 +    {
   1.199 +        num++;
   1.200 +        do
   1.201 +        {
   1.202 +            n=(n*10.0)+(*num++ -'0');
   1.203 +            scale--;
   1.204 +        }
   1.205 +        while (*num>='0' && *num<='9');  // Fractional part?
   1.206 +    }
   1.207 +
   1.208 +	if (*num=='e' || *num=='E')		// Exponent?
   1.209 +	{
   1.210 +        num++;
   1.211 +        if (*num == '+')
   1.212 +        {
   1.213 +            num++;
   1.214 +        }
   1.215 +        else if (*num=='-')
   1.216 +        {
   1.217 +            signsubscale=-1;
   1.218 +            num++;		// With sign?
   1.219 +        }
   1.220 +
   1.221 +        while (*num >= '0' && *num <= '9')
   1.222 +        {
   1.223 +            subscale = (subscale * 10) + (*num++ - '0');	// Number?
   1.224 +        }
   1.225 +	}
   1.226 +
   1.227 +    // Number = +/- number.fraction * 10^+/- exponent
   1.228 +    n *= pow(10.0, (scale + subscale*signsubscale));
   1.229 +
   1.230 +    if (!positiveSign)
   1.231 +    {
   1.232 +        n = -n;
   1.233 +    }
   1.234 +
   1.235 +    // Assign parsed value.
   1.236 +    Type = JSON_Number;
   1.237 +    dValue = n;
   1.238 +    Value.AssignString(num_start, num - num_start);
   1.239 +
   1.240 +	return num;
   1.241 +}
   1.242 +
   1.243 +// Parses a hex string up to the specified number of digits.
   1.244 +// Returns the first character after the string.
   1.245 +const char* ParseHex(unsigned* val, unsigned digits, const char* str)
   1.246 +{
   1.247 +    *val = 0;
   1.248 +
   1.249 +    for(unsigned digitCount = 0; digitCount < digits; digitCount++, str++)
   1.250 +    {
   1.251 +        unsigned v = *str;
   1.252 +
   1.253 +        if ((v >= '0') && (v <= '9'))
   1.254 +            v -= '0';
   1.255 +        else if ((v >= 'a') && (v <= 'f'))
   1.256 +            v = 10 + v - 'a';
   1.257 +        else if ((v >= 'A') && (v <= 'F'))
   1.258 +            v = 10 + v - 'A';
   1.259 +        else
   1.260 +            break;
   1.261 +
   1.262 +        *val = *val * 16 + v;
   1.263 +    }
   1.264 +
   1.265 +    return str;
   1.266 +}
   1.267 +
   1.268 +//-----------------------------------------------------------------------------
   1.269 +// Parses the input text into a string item and returns the text position after
   1.270 +// the parsed string
   1.271 +const char* JSON::parseString(const char* str, const char** perror)
   1.272 +{
   1.273 +	const char* ptr = str+1;
   1.274 +    const char* p;
   1.275 +    char*       ptr2;
   1.276 +    char*       out;
   1.277 +    int         len=0;
   1.278 +    unsigned    uc, uc2;
   1.279 +	
   1.280 +    if (*str!='\"')
   1.281 +    {
   1.282 +        return AssignError(perror, "Syntax Error: Missing quote");
   1.283 +    }
   1.284 +	
   1.285 +	while (*ptr!='\"' && *ptr && ++len)
   1.286 +    {   
   1.287 +        if (*ptr++ == '\\') ptr++;	// Skip escaped quotes.
   1.288 +    }
   1.289 +	
   1.290 +    // This is how long we need for the string, roughly.
   1.291 +	out=(char*)OVR_ALLOC(len+1);
   1.292 +	if (!out)
   1.293 +        return 0;
   1.294 +	
   1.295 +	ptr = str+1;
   1.296 +    ptr2= out;
   1.297 +
   1.298 +	while (*ptr!='\"' && *ptr)
   1.299 +	{
   1.300 +		if (*ptr!='\\')
   1.301 +        {
   1.302 +            *ptr2++ = *ptr++;
   1.303 +        }
   1.304 +		else
   1.305 +		{
   1.306 +			ptr++;
   1.307 +			switch (*ptr)
   1.308 +			{
   1.309 +				case 'b': *ptr2++ = '\b';	break;
   1.310 +				case 'f': *ptr2++ = '\f';	break;
   1.311 +				case 'n': *ptr2++ = '\n';	break;
   1.312 +				case 'r': *ptr2++ = '\r';	break;
   1.313 +				case 't': *ptr2++ = '\t';	break;
   1.314 +
   1.315 +                // Transcode utf16 to utf8.
   1.316 +                case 'u':
   1.317 +
   1.318 +                    // Get the unicode char.
   1.319 +                    p = ParseHex(&uc, 4, ptr + 1);
   1.320 +                    if (ptr != p)
   1.321 +                        ptr = p - 1;
   1.322 +
   1.323 +					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)
   1.324 +                        break;	// Check for invalid.
   1.325 +
   1.326 +                    // UTF16 surrogate pairs.
   1.327 +					if (uc>=0xD800 && uc<=0xDBFF)
   1.328 +					{
   1.329 +						if (ptr[1]!='\\' || ptr[2]!='u')
   1.330 +                            break;	// Missing second-half of surrogate.
   1.331 +
   1.332 +                        p= ParseHex(&uc2, 4, ptr + 3);
   1.333 +                        if (ptr != p)
   1.334 +                            ptr = p - 1;
   1.335 +                        
   1.336 +						if (uc2<0xDC00 || uc2>0xDFFF)
   1.337 +                            break;	// Invalid second-half of surrogate.
   1.338 +
   1.339 +						uc = 0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
   1.340 +					}
   1.341 +
   1.342 +					len=4;
   1.343 +                    
   1.344 +                    if (uc<0x80)
   1.345 +                        len=1;
   1.346 +                    else if (uc<0x800)
   1.347 +                        len=2;
   1.348 +                    else if (uc<0x10000)
   1.349 +                        len=3;
   1.350 +                    
   1.351 +                    ptr2+=len;
   1.352 +					
   1.353 +					switch (len)
   1.354 +                    {
   1.355 +						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
   1.356 +							//no break, fall through
   1.357 +						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
   1.358 +							//no break
   1.359 +						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
   1.360 +							//no break
   1.361 +						case 1: *--ptr2 = (char)(uc | firstByteMark[len]);
   1.362 +							//no break
   1.363 +					}
   1.364 +					ptr2+=len;
   1.365 +					break;
   1.366 +
   1.367 +                default:
   1.368 +                    *ptr2++ = *ptr;
   1.369 +                    break;
   1.370 +			}
   1.371 +			ptr++;
   1.372 +		}
   1.373 +	}
   1.374 +
   1.375 +	*ptr2 = 0;
   1.376 +	if (*ptr=='\"')
   1.377 +        ptr++;
   1.378 +	
   1.379 +    // Make a copy of the string 
   1.380 +    Value=out;
   1.381 +    OVR_FREE(out);
   1.382 +	Type=JSON_String;
   1.383 +
   1.384 +	return ptr;
   1.385 +}
   1.386 +
   1.387 +//-----------------------------------------------------------------------------
   1.388 +// Render the string provided to an escaped version that can be printed.
   1.389 +char* PrintString(const char* str)
   1.390 +{
   1.391 +	const char *ptr;
   1.392 +    char *ptr2,*out;
   1.393 +    int len=0;
   1.394 +    unsigned char token;
   1.395 +	
   1.396 +	if (!str)
   1.397 +        return JSON_strdup("");
   1.398 +	ptr=str;
   1.399 +    
   1.400 +    token=*ptr;
   1.401 +    while (token && ++len)\
   1.402 +    {
   1.403 +        if (strchr("\"\\\b\f\n\r\t",token))
   1.404 +            len++;
   1.405 +        else if (token<32) 
   1.406 +            len+=5;
   1.407 +        ptr++;
   1.408 +        token=*ptr;
   1.409 +    }
   1.410 +	
   1.411 +	int buff_size = len+3;
   1.412 +    out=(char*)OVR_ALLOC(buff_size);
   1.413 +	if (!out)
   1.414 +        return 0;
   1.415 +
   1.416 +	ptr2 = out;
   1.417 +    ptr  = str;
   1.418 +	*ptr2++ = '\"';
   1.419 +
   1.420 +	while (*ptr)
   1.421 +	{
   1.422 +		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') 
   1.423 +            *ptr2++=*ptr++;
   1.424 +		else
   1.425 +		{
   1.426 +			*ptr2++='\\';
   1.427 +			switch (token=*ptr++)
   1.428 +			{
   1.429 +				case '\\':	*ptr2++='\\';	break;
   1.430 +				case '\"':	*ptr2++='\"';	break;
   1.431 +				case '\b':	*ptr2++='b';	break;
   1.432 +				case '\f':	*ptr2++='f';	break;
   1.433 +				case '\n':	*ptr2++='n';	break;
   1.434 +				case '\r':	*ptr2++='r';	break;
   1.435 +				case '\t':	*ptr2++='t';	break;
   1.436 +				default: 
   1.437 +                    OVR_sprintf(ptr2, buff_size - (ptr2-out), "u%04x",token);
   1.438 +                    ptr2+=5;
   1.439 +                    break;	// Escape and print.
   1.440 +			}
   1.441 +		}
   1.442 +	}
   1.443 +	*ptr2++='\"';
   1.444 +    *ptr2++=0;
   1.445 +	return out;
   1.446 +}
   1.447 +
   1.448 +//-----------------------------------------------------------------------------
   1.449 +// Utility to jump whitespace and cr/lf
   1.450 +static const char* skip(const char* in)
   1.451 +{
   1.452 +    while (in && *in && (unsigned char)*in<=' ') 
   1.453 +        in++; 
   1.454 +    return in;
   1.455 +}
   1.456 +
   1.457 +//-----------------------------------------------------------------------------
   1.458 +// Parses the supplied buffer of JSON text and returns a JSON object tree
   1.459 +// The returned object must be Released after use
   1.460 +JSON* JSON::Parse(const char* buff, const char** perror)
   1.461 +{
   1.462 +    const char* end = 0;
   1.463 +	JSON*       json = new JSON();
   1.464 +	
   1.465 +	if (!json)
   1.466 +    {
   1.467 +        AssignError(perror, "Error: Failed to allocate memory");
   1.468 +        return 0;
   1.469 +    }
   1.470 + 
   1.471 +	end = json->parseValue(skip(buff), perror);
   1.472 +	if (!end)
   1.473 +    {
   1.474 +        json->Release();
   1.475 +        return NULL;
   1.476 +    }	// parse failure. ep is set.
   1.477 +
   1.478 +    return json;
   1.479 +}
   1.480 +
   1.481 +//-----------------------------------------------------------------------------
   1.482 +// This version works for buffers that are not null terminated strings.
   1.483 +JSON* JSON::ParseBuffer(const char *buff, int len, const char** perror)
   1.484 +{
   1.485 +	// Our JSON parser does not support length-based parsing,
   1.486 +	// so ensure it is null-terminated.
   1.487 +	char *termStr = new char[len + 1];
   1.488 +	memcpy(termStr, buff, len);
   1.489 +	termStr[len] = '\0';
   1.490 +
   1.491 +	JSON *objJson = Parse(termStr, perror);
   1.492 +
   1.493 +	delete[]termStr;
   1.494 +
   1.495 +	return objJson;
   1.496 +}
   1.497 +
   1.498 +//-----------------------------------------------------------------------------
   1.499 +// Parser core - when encountering text, process appropriately.
   1.500 +const char* JSON::parseValue(const char* buff, const char** perror)
   1.501 +{
   1.502 +    if (perror)
   1.503 +        *perror = 0;
   1.504 +
   1.505 +	if (!buff)
   1.506 +        return NULL;	// Fail on null.
   1.507 +
   1.508 +	if (!strncmp(buff,"null",4))
   1.509 +    {
   1.510 +        Type = JSON_Null;
   1.511 +        return buff+4;
   1.512 +    }
   1.513 +	if (!strncmp(buff,"false",5))
   1.514 +    { 
   1.515 +        Type   = JSON_Bool;
   1.516 +        Value  = "false";
   1.517 +        dValue = 0.;
   1.518 +        return buff+5;
   1.519 +    }
   1.520 +	if (!strncmp(buff,"true",4))
   1.521 +    {
   1.522 +        Type   = JSON_Bool;
   1.523 +        Value  = "true";
   1.524 +        dValue = 1.;
   1.525 +        return buff + 4;
   1.526 +    }
   1.527 +	if (*buff=='\"')
   1.528 +    {
   1.529 +        return parseString(buff, perror);
   1.530 +    }
   1.531 +	if (*buff=='-' || (*buff>='0' && *buff<='9'))
   1.532 +    { 
   1.533 +        return parseNumber(buff);
   1.534 +    }
   1.535 +	if (*buff=='[')
   1.536 +    { 
   1.537 +        return parseArray(buff, perror);
   1.538 +    }
   1.539 +	if (*buff=='{')
   1.540 +    {
   1.541 +        return parseObject(buff, perror);
   1.542 +    }
   1.543 +
   1.544 +    return AssignError(perror, "Syntax Error: Invalid syntax");
   1.545 +}
   1.546 +
   1.547 +
   1.548 +//-----------------------------------------------------------------------------
   1.549 +// Render a value to text. 
   1.550 +char* JSON::PrintValue(int depth, bool fmt)
   1.551 +{
   1.552 +	char *out=0;
   1.553 +
   1.554 +    switch (Type)
   1.555 +	{
   1.556 +        case JSON_Null:	    out = JSON_strdup("null");	break;
   1.557 +        case JSON_Bool:
   1.558 +            if ((int)dValue == 0)
   1.559 +                out = JSON_strdup("false");
   1.560 +            else
   1.561 +                out = JSON_strdup("true");
   1.562 +            break;
   1.563 +        case JSON_Number:	out = PrintNumber(dValue); break;
   1.564 +        case JSON_String:	out = PrintString(Value); break;
   1.565 +        case JSON_Array:	out = PrintArray(depth, fmt); break;
   1.566 +        case JSON_Object:	out = PrintObject(depth, fmt); break;
   1.567 +        case JSON_None: OVR_ASSERT_LOG(false, ("Bad JSON type.")); break;
   1.568 +	}
   1.569 +	return out;
   1.570 +}
   1.571 +
   1.572 +//-----------------------------------------------------------------------------
   1.573 +// Build an array object from input text and returns the text position after
   1.574 +// the parsed array
   1.575 +const char* JSON::parseArray(const char* buff, const char** perror)
   1.576 +{
   1.577 +	JSON *child;
   1.578 +	if (*buff!='[')
   1.579 +    {
   1.580 +        return AssignError(perror, "Syntax Error: Missing opening bracket");
   1.581 +    }
   1.582 +
   1.583 +	Type=JSON_Array;
   1.584 +	buff=skip(buff+1);
   1.585 +	
   1.586 +    if (*buff==']')
   1.587 +        return buff+1;	// empty array.
   1.588 +
   1.589 +    child = new JSON();
   1.590 +	if (!child)
   1.591 +        return 0;		 // memory fail
   1.592 +    Children.PushBack(child);
   1.593 +	
   1.594 +    buff=skip(child->parseValue(skip(buff), perror));	// skip any spacing, get the buff. 
   1.595 +	if (!buff)
   1.596 +        return 0;
   1.597 +
   1.598 +	while (*buff==',')
   1.599 +	{
   1.600 +		JSON *new_item = new JSON();
   1.601 +		if (!new_item)
   1.602 +            return AssignError(perror, "Error: Failed to allocate memory");
   1.603 +		
   1.604 +        Children.PushBack(new_item);
   1.605 +
   1.606 +		buff=skip(new_item->parseValue(skip(buff+1), perror));
   1.607 +		if (!buff)
   1.608 +            return AssignError(perror, "Error: Failed to allocate memory");
   1.609 +	}
   1.610 +
   1.611 +	if (*buff==']')
   1.612 +        return buff+1;	// end of array
   1.613 +
   1.614 +    return AssignError(perror, "Syntax Error: Missing ending bracket");
   1.615 +}
   1.616 +
   1.617 +//-----------------------------------------------------------------------------
   1.618 +// Render an array to text.  The returned text must be freed
   1.619 +char* JSON::PrintArray(int depth, bool fmt)
   1.620 +{
   1.621 +	char **  entries;
   1.622 +	char *   out = 0, *ptr,*ret;
   1.623 +    intptr_t len = 5;
   1.624 +	
   1.625 +    bool fail = false;
   1.626 +	
   1.627 +	// How many entries in the array? 
   1.628 +    int numentries = GetItemCount();
   1.629 +	if (!numentries)
   1.630 +	{
   1.631 +		out=(char*)OVR_ALLOC(3);
   1.632 +		if (out)
   1.633 +            OVR_strcpy(out, 3, "[]");
   1.634 +		return out;
   1.635 +	}
   1.636 +	// Allocate an array to hold the values for each
   1.637 +	entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
   1.638 +	if (!entries)
   1.639 +        return 0;
   1.640 +	memset(entries,0,numentries*sizeof(char*));
   1.641 +
   1.642 +	//// Retrieve all the results:
   1.643 +    JSON* child = Children.GetFirst();
   1.644 +    for (int i=0; i<numentries; i++)
   1.645 +	{
   1.646 +		//JSON* child = Children[i];
   1.647 +        ret=child->PrintValue(depth+1, fmt);
   1.648 +		entries[i]=ret;
   1.649 +		if (ret)
   1.650 +            len+=OVR_strlen(ret)+2+(fmt?1:0);
   1.651 +        else
   1.652 +        {
   1.653 +            fail = true;
   1.654 +            break;
   1.655 +        }
   1.656 +        child = Children.GetNext(child);
   1.657 +	}
   1.658 +	
   1.659 +	// If we didn't fail, try to malloc the output string 
   1.660 +	if (!fail)
   1.661 +        out=(char*)OVR_ALLOC(len);
   1.662 +	// If that fails, we fail. 
   1.663 +	if (!out)
   1.664 +        fail = true;
   1.665 +
   1.666 +	// Handle failure.
   1.667 +	if (fail)
   1.668 +	{
   1.669 +		for (int i=0; i<numentries; i++) 
   1.670 +        {
   1.671 +            if (entries[i])
   1.672 +                OVR_FREE(entries[i]);
   1.673 +        }
   1.674 +		OVR_FREE(entries);
   1.675 +		return 0;
   1.676 +	}
   1.677 +	
   1.678 +	// Compose the output array.
   1.679 +	*out='[';
   1.680 +	ptr=out+1;
   1.681 +    *ptr=0;
   1.682 +	for (int i=0; i<numentries; i++)
   1.683 +	{
   1.684 +		OVR_strcpy(ptr, len - (ptr-out), entries[i]);
   1.685 +        ptr+=OVR_strlen(entries[i]);
   1.686 +		if (i!=numentries-1)
   1.687 +        {
   1.688 +            *ptr++=',';
   1.689 +            if (fmt)
   1.690 +                *ptr++=' ';
   1.691 +            *ptr=0;
   1.692 +        }
   1.693 +		OVR_FREE(entries[i]);
   1.694 +	}
   1.695 +	OVR_FREE(entries);
   1.696 +	*ptr++=']';
   1.697 +    *ptr++=0;
   1.698 +	return out;	
   1.699 +}
   1.700 +
   1.701 +//-----------------------------------------------------------------------------
   1.702 +// Build an object from the supplied text and returns the text position after
   1.703 +// the parsed object
   1.704 +const char* JSON::parseObject(const char* buff, const char** perror)
   1.705 +{
   1.706 +	if (*buff!='{')
   1.707 +    {
   1.708 +        return AssignError(perror, "Syntax Error: Missing opening brace");
   1.709 +    }
   1.710 +	
   1.711 +	Type=JSON_Object;
   1.712 +	buff=skip(buff+1);
   1.713 +	if (*buff=='}')
   1.714 +        return buff+1;	// empty array.
   1.715 +	
   1.716 +    JSON* child = new JSON();
   1.717 +    Children.PushBack(child);
   1.718 +
   1.719 +	buff=skip(child->parseString(skip(buff), perror));
   1.720 +	if (!buff) 
   1.721 +        return 0;
   1.722 +	child->Name = child->Value;
   1.723 +    child->Value.Clear();
   1.724 +	
   1.725 +    if (*buff!=':')
   1.726 +    {
   1.727 +        return AssignError(perror, "Syntax Error: Missing colon");
   1.728 +    }
   1.729 +
   1.730 +	buff=skip(child->parseValue(skip(buff+1), perror));	// skip any spacing, get the value.
   1.731 +	if (!buff)
   1.732 +        return 0;
   1.733 +	
   1.734 +	while (*buff==',')
   1.735 +	{
   1.736 +        child = new JSON();
   1.737 +		if (!child)
   1.738 +            return 0; // memory fail
   1.739 +		
   1.740 +        Children.PushBack(child);
   1.741 +
   1.742 +		buff=skip(child->parseString(skip(buff+1), perror));
   1.743 +		if (!buff)
   1.744 +            return 0;
   1.745 +		
   1.746 +        child->Name=child->Value;
   1.747 +        child->Value.Clear();
   1.748 +		
   1.749 +        if (*buff!=':')
   1.750 +        {
   1.751 +            return AssignError(perror, "Syntax Error: Missing colon");
   1.752 +        }	// fail!
   1.753 +		
   1.754 +        // Skip any spacing, get the value.
   1.755 +        buff=skip(child->parseValue(skip(buff+1), perror));
   1.756 +		if (!buff)
   1.757 +            return 0;
   1.758 +	}
   1.759 +	
   1.760 +	if (*buff=='}')
   1.761 +        return buff+1;	// end of array 
   1.762 +	
   1.763 +    return AssignError(perror, "Syntax Error: Missing closing brace");
   1.764 +}
   1.765 +
   1.766 +//-----------------------------------------------------------------------------
   1.767 +// Render an object to text.  The returned string must be freed
   1.768 +char* JSON::PrintObject(int depth, bool fmt)
   1.769 +{
   1.770 +	char**   entries = 0, **names = 0;
   1.771 +	char*    out = 0;
   1.772 +    char*    ptr, *ret, *str;
   1.773 +    intptr_t len = 7, i = 0, j;
   1.774 +    bool     fail = false;
   1.775 +	
   1.776 +    // Count the number of entries.
   1.777 +    int numentries = GetItemCount();
   1.778 +    
   1.779 +	// Explicitly handle empty object case
   1.780 +	if (numentries == 0)
   1.781 +	{
   1.782 +		out=(char*)OVR_ALLOC(fmt?depth+4:4);
   1.783 +		if (!out)
   1.784 +            return 0;
   1.785 +		ptr=out;
   1.786 +        *ptr++='{';
   1.787 +		
   1.788 +        if (fmt)
   1.789 +        {
   1.790 +            *ptr++='\n';
   1.791 +            for (i=0;i<depth-1;i++)
   1.792 +                *ptr++='\t';
   1.793 +        }
   1.794 +		*ptr++='}';
   1.795 +        *ptr++=0;
   1.796 +		return out;
   1.797 +	}
   1.798 +	// Allocate space for the names and the objects
   1.799 +	entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
   1.800 +	if (!entries)
   1.801 +        return 0;
   1.802 +	names=(char**)OVR_ALLOC(numentries*sizeof(char*));
   1.803 +	
   1.804 +    if (!names)
   1.805 +    {
   1.806 +        OVR_FREE(entries);
   1.807 +        return 0;
   1.808 +    }
   1.809 +	memset(entries,0,sizeof(char*)*numentries);
   1.810 +	memset(names,0,sizeof(char*)*numentries);
   1.811 +
   1.812 +	// Collect all the results into our arrays:
   1.813 +    depth++;
   1.814 +    if (fmt)
   1.815 +        len+=depth;
   1.816 +
   1.817 +    JSON* child = Children.GetFirst();
   1.818 +    while (!Children.IsNull(child))
   1.819 +	{
   1.820 +		names[i]     = str = PrintString(child->Name);
   1.821 +		entries[i++] = ret = child->PrintValue(depth, fmt);
   1.822 +
   1.823 +		if (str && ret)
   1.824 +        {
   1.825 +            len += OVR_strlen(ret)+OVR_strlen(str)+2+(fmt?3+depth:0);
   1.826 +        }
   1.827 +        else
   1.828 +        {
   1.829 +            fail = true;
   1.830 +            break;
   1.831 +        }
   1.832 +		
   1.833 +        child = Children.GetNext(child);
   1.834 +	}
   1.835 +	
   1.836 +	// Try to allocate the output string
   1.837 +	if (!fail)
   1.838 +        out=(char*)OVR_ALLOC(len);
   1.839 +	if (!out)
   1.840 +        fail=true;
   1.841 +
   1.842 +	// Handle failure
   1.843 +	if (fail)
   1.844 +	{
   1.845 +		for (i=0;i<numentries;i++)
   1.846 +        {
   1.847 +            if (names[i])
   1.848 +                OVR_FREE(names[i]);
   1.849 +            
   1.850 +            if (entries[i])
   1.851 +                OVR_FREE(entries[i]);}
   1.852 +		
   1.853 +        OVR_FREE(names);
   1.854 +        OVR_FREE(entries);
   1.855 +		return 0;
   1.856 +	}
   1.857 +	
   1.858 +	// Compose the output:
   1.859 +	*out = '{';
   1.860 +    ptr  = out+1;
   1.861 +    if (fmt)
   1.862 +    {
   1.863 +#ifdef OVR_OS_WIN32
   1.864 +        *ptr++ = '\r';
   1.865 +#endif
   1.866 +        *ptr++ = '\n';
   1.867 +    }
   1.868 +    *ptr = 0;
   1.869 +	
   1.870 +    for (i=0; i<numentries; i++)
   1.871 +	{
   1.872 +		if (fmt)
   1.873 +        {
   1.874 +            for (j = 0; j < depth; j++)
   1.875 +            {
   1.876 +                *ptr++ = '\t';
   1.877 +            }
   1.878 +        }
   1.879 +		OVR_strcpy(ptr, len - (ptr-out), names[i]);
   1.880 +        ptr   += OVR_strlen(names[i]);
   1.881 +		*ptr++ =':';
   1.882 +        
   1.883 +        if (fmt)
   1.884 +        {
   1.885 +            *ptr++ = '\t';
   1.886 +        }
   1.887 +		
   1.888 +        OVR_strcpy(ptr, len - (ptr-out), entries[i]);
   1.889 +        ptr+=OVR_strlen(entries[i]);
   1.890 +		
   1.891 +        if (i != numentries - 1)
   1.892 +        {
   1.893 +            *ptr++ = ',';
   1.894 +        }
   1.895 +		
   1.896 +        if (fmt)
   1.897 +        {
   1.898 +#ifdef OVR_OS_WIN32
   1.899 +            *ptr++ = '\r';
   1.900 +#endif
   1.901 +            *ptr++ = '\n';
   1.902 +        }
   1.903 +        *ptr = 0;
   1.904 +		
   1.905 +        OVR_FREE(names[i]);
   1.906 +        OVR_FREE(entries[i]);
   1.907 +	}
   1.908 +	
   1.909 +	OVR_FREE(names);
   1.910 +    OVR_FREE(entries);
   1.911 +	
   1.912 +    if (fmt)
   1.913 +    {
   1.914 +        for (i = 0; i < depth - 1; i++)
   1.915 +        {
   1.916 +            *ptr++ = '\t';
   1.917 +        }
   1.918 +    }
   1.919 +	*ptr++='}';
   1.920 +    *ptr++=0;
   1.921 +	
   1.922 +    return out;	
   1.923 +}
   1.924 +
   1.925 +
   1.926 +
   1.927 +// Returns the number of child items in the object
   1.928 +// Counts the number of items in the object.
   1.929 +unsigned JSON::GetItemCount() const
   1.930 +{
   1.931 +    unsigned count = 0;
   1.932 +    for (const JSON* p = Children.GetFirst(); !Children.IsNull(p); p = p->pNext)
   1.933 +    {
   1.934 +        count++;
   1.935 +    }
   1.936 +    return count;
   1.937 +}
   1.938 +
   1.939 +JSON* JSON::GetItemByIndex(unsigned index)
   1.940 +{
   1.941 +    unsigned i     = 0;
   1.942 +    JSON*    child = 0;
   1.943 +
   1.944 +    if (!Children.IsEmpty())
   1.945 +    {
   1.946 +        child = Children.GetFirst();
   1.947 +
   1.948 +        while (i < index)
   1.949 +        {   
   1.950 +            if (Children.IsNull(child->pNext))
   1.951 +            {
   1.952 +                child = 0;
   1.953 +                break;
   1.954 +            }
   1.955 +            child = child->pNext;
   1.956 +            i++;
   1.957 +        }
   1.958 +    }
   1.959 +  
   1.960 +    return child;
   1.961 +}
   1.962 +
   1.963 +// Returns the child item with the given name or NULL if not found
   1.964 +JSON* JSON::GetItemByName(const char* name)
   1.965 +{
   1.966 +    JSON* child = 0;
   1.967 +
   1.968 +    if (!Children.IsEmpty())
   1.969 +    {
   1.970 +        child = Children.GetFirst();
   1.971 +
   1.972 +        while (OVR_strcmp(child->Name, name) != 0)
   1.973 +        {   
   1.974 +            if (Children.IsNull(child->pNext))
   1.975 +            {
   1.976 +                child = 0;
   1.977 +                break;
   1.978 +            }
   1.979 +            child = child->pNext;
   1.980 +        }
   1.981 +    }
   1.982 +
   1.983 +    return child;
   1.984 +}
   1.985 +
   1.986 +//-----------------------------------------------------------------------------
   1.987 +// Adds a new item to the end of the child list
   1.988 +void JSON::AddItem(const char *string, JSON *item)
   1.989 +{
   1.990 +    if (item)
   1.991 +    {
   1.992 +        item->Name = string;
   1.993 +        Children.PushBack(item);
   1.994 +    }
   1.995 +}
   1.996 +
   1.997 +/*
   1.998 +
   1.999 +// Removes and frees the items at the given index
  1.1000 +void JSON::DeleteItem(unsigned int index)
  1.1001 +{
  1.1002 +    unsigned int num_items = 0;
  1.1003 +    JSON* child = Children.GetFirst();
  1.1004 +    while (!Children.IsNull(child) && num_items < index)
  1.1005 +    {   
  1.1006 +        num_items++;
  1.1007 +        child = Children.GetNext(child);
  1.1008 +    }
  1.1009 +
  1.1010 +    if (!Children.IsNull(child))
  1.1011 +    
  1.1012 +        child->RemoveNode();
  1.1013 +        child->Release();
  1.1014 +    }
  1.1015 +}
  1.1016 +
  1.1017 +// Replaces and frees the item at the give index with the new item
  1.1018 +void JSON::ReplaceItem(unsigned int index, JSON* new_item)
  1.1019 +{
  1.1020 +    unsigned int num_items = 0;
  1.1021 +    JSON* child = Children.GetFirst();
  1.1022 +    while (!Children.IsNull(child) && num_items < index)
  1.1023 +    {   
  1.1024 +        num_items++;
  1.1025 +        child = Children.GetNext(child);
  1.1026 +    }
  1.1027 +
  1.1028 +    if (!Children.IsNull(child))
  1.1029 +    {
  1.1030 +        child->ReplaceNodeWith(new_item);
  1.1031 +        child->Release();        
  1.1032 +    }
  1.1033 +}
  1.1034 +*/
  1.1035 +
  1.1036 +// Removes and frees the last child item
  1.1037 +void JSON::RemoveLast()
  1.1038 +{
  1.1039 +    JSON* child = Children.GetLast();
  1.1040 +    if (!Children.IsNull(child))
  1.1041 +    {
  1.1042 +        child->RemoveNode();
  1.1043 +        child->Release();
  1.1044 +    }
  1.1045 +}
  1.1046 +
  1.1047 +JSON* JSON::CreateBool(bool b)
  1.1048 +{
  1.1049 +    JSON *item = new JSON(JSON_Bool);
  1.1050 +    if (item)
  1.1051 +    {
  1.1052 +        item->dValue = b ? 1. : 0.;
  1.1053 +        item->Value = b ? "true" : "false";
  1.1054 +    }
  1.1055 +    return item;
  1.1056 +}
  1.1057 +
  1.1058 +JSON* JSON::CreateNumber(double num)
  1.1059 +{
  1.1060 +    JSON *item = new JSON(JSON_Number);
  1.1061 +    if (item)
  1.1062 +    {
  1.1063 +        item->dValue = num;
  1.1064 +    }
  1.1065 +    return item;
  1.1066 +}
  1.1067 +
  1.1068 +JSON* JSON::CreateInt(int num)
  1.1069 +{
  1.1070 +    JSON *item = new JSON(JSON_Number);
  1.1071 +    if (item)
  1.1072 +    {
  1.1073 +        item->dValue = num;
  1.1074 +    }
  1.1075 +    return item;
  1.1076 +}
  1.1077 +
  1.1078 +JSON* JSON::CreateString(const char *s)
  1.1079 +{
  1.1080 +    JSON *item = new JSON(JSON_String);
  1.1081 +    if (item && s)
  1.1082 +    {
  1.1083 +        item->Value = s;
  1.1084 +    }
  1.1085 +    return item;
  1.1086 +}
  1.1087 +
  1.1088 +
  1.1089 +//-----------------------------------------------------------------------------
  1.1090 +// Get elements by name
  1.1091 +double JSON::GetNumberByName(const char *name, double defValue)
  1.1092 +{
  1.1093 +	JSON* item = GetItemByName(name);
  1.1094 +	if (!item || item->Type != JSON_Number)
  1.1095 +    {
  1.1096 +		return defValue;
  1.1097 +	}
  1.1098 +	else
  1.1099 +    {
  1.1100 +		return item->dValue;
  1.1101 +	}
  1.1102 +}
  1.1103 +
  1.1104 +int JSON::GetIntByName(const char *name, int defValue)
  1.1105 +{
  1.1106 +	JSON* item = GetItemByName(name);
  1.1107 +	if (!item || item->Type != JSON_Number)
  1.1108 +    {
  1.1109 +		return defValue;
  1.1110 +	}
  1.1111 +	else
  1.1112 +    {
  1.1113 +		return (int)item->dValue;
  1.1114 +	}
  1.1115 +}
  1.1116 +
  1.1117 +bool JSON::GetBoolByName(const char *name, bool defValue)
  1.1118 +{
  1.1119 +	JSON* item = GetItemByName(name);
  1.1120 +	if (!item || item->Type != JSON_Bool)
  1.1121 +    {
  1.1122 +		return defValue;
  1.1123 +	}
  1.1124 +	else
  1.1125 +    {
  1.1126 +		return (int)item->dValue != 0;
  1.1127 +	}
  1.1128 +}
  1.1129 +
  1.1130 +String JSON::GetStringByName(const char *name, const String &defValue)
  1.1131 +{
  1.1132 +	JSON* item = GetItemByName(name);
  1.1133 +	if (!item || item->Type != JSON_String)
  1.1134 +    {
  1.1135 +		return defValue;
  1.1136 +	}
  1.1137 +	else
  1.1138 +    {
  1.1139 +		return item->Value;
  1.1140 +	}
  1.1141 +}
  1.1142 +
  1.1143 +//-----------------------------------------------------------------------------
  1.1144 +// Adds an element to an array object type
  1.1145 +void JSON::AddArrayElement(JSON *item)
  1.1146 +{
  1.1147 +    if (item)
  1.1148 +    {
  1.1149 +        Children.PushBack(item);
  1.1150 +    }
  1.1151 +}
  1.1152 +
  1.1153 +// Inserts an element into a valid array position
  1.1154 +void JSON::InsertArrayElement(int index, JSON *item)
  1.1155 +{
  1.1156 +    if (!item)
  1.1157 +    {
  1.1158 +        return;
  1.1159 +    }
  1.1160 +
  1.1161 +    if (index == 0)
  1.1162 +    {
  1.1163 +        Children.PushFront(item);
  1.1164 +        return;
  1.1165 +    }
  1.1166 +
  1.1167 +    JSON* iter = Children.GetFirst();
  1.1168 +    int i=0;
  1.1169 +    while (iter && i<index)
  1.1170 +    {
  1.1171 +        iter = Children.GetNext(iter);
  1.1172 +        i++;
  1.1173 +    }
  1.1174 +
  1.1175 +    if (iter)
  1.1176 +        iter->InsertNodeBefore(item);
  1.1177 +    else
  1.1178 +        Children.PushBack(item);
  1.1179 +}
  1.1180 +
  1.1181 +// Returns the size of an array
  1.1182 +int JSON::GetArraySize()
  1.1183 +{
  1.1184 +    if (Type == JSON_Array)
  1.1185 +    {
  1.1186 +        return GetItemCount();
  1.1187 +    }
  1.1188 +
  1.1189 +    return 0;
  1.1190 +}
  1.1191 +
  1.1192 +// Returns the number value an the give array index
  1.1193 +double JSON::GetArrayNumber(int index)
  1.1194 +{
  1.1195 +    if (Type == JSON_Array)
  1.1196 +    {
  1.1197 +        JSON* number = GetItemByIndex(index);
  1.1198 +        return number ? number->dValue : 0.0;
  1.1199 +    }
  1.1200 +
  1.1201 +    return 0;
  1.1202 +}
  1.1203 +
  1.1204 +// Returns the string value at the given array index
  1.1205 +const char* JSON::GetArrayString(int index)
  1.1206 +{
  1.1207 +    if (Type == JSON_Array)
  1.1208 +    {
  1.1209 +        JSON* number = GetItemByIndex(index);
  1.1210 +        return number ? number->Value : 0;
  1.1211 +    }
  1.1212 +
  1.1213 +    return 0;
  1.1214 +}
  1.1215 +
  1.1216 +JSON* JSON::Copy()
  1.1217 +{
  1.1218 +    JSON* copy = new JSON(Type);
  1.1219 +    copy->Name = Name;
  1.1220 +    copy->Value = Value;
  1.1221 +    copy->dValue = dValue;
  1.1222 +
  1.1223 +    JSON* child = Children.GetFirst();
  1.1224 +    while (!Children.IsNull(child))
  1.1225 +    {
  1.1226 +        copy->Children.PushBack(child->Copy());
  1.1227 +        child = Children.GetNext(child);
  1.1228 +    }
  1.1229 +
  1.1230 +    return copy;
  1.1231 +}
  1.1232 +
  1.1233 +//-----------------------------------------------------------------------------
  1.1234 +// Loads and parses the given JSON file pathname and returns a JSON object tree.
  1.1235 +// The returned object must be Released after use.
  1.1236 +JSON* JSON::Load(const char* path, const char** perror)
  1.1237 +{
  1.1238 +    SysFile f;
  1.1239 +    if (!f.Open(path, File::Open_Read, File::Mode_Read))
  1.1240 +    {
  1.1241 +        AssignError(perror, "Failed to open file");
  1.1242 +        return NULL;
  1.1243 +    }
  1.1244 +
  1.1245 +    int    len   = f.GetLength();
  1.1246 +    uint8_t* buff  = (uint8_t*)OVR_ALLOC(len + 1);
  1.1247 +    int    bytes = f.Read(buff, len);
  1.1248 +    f.Close();
  1.1249 +
  1.1250 +    if (bytes == 0 || bytes != len)
  1.1251 +    {
  1.1252 +        OVR_FREE(buff);
  1.1253 +        return NULL;
  1.1254 +    }
  1.1255 +
  1.1256 +	// Ensure the result is null-terminated since Parse() expects null-terminated input.
  1.1257 +	buff[len] = '\0';
  1.1258 +
  1.1259 +    JSON* json = JSON::Parse((char*)buff, perror);
  1.1260 +    OVR_FREE(buff);
  1.1261 +    return json;
  1.1262 +}
  1.1263 +
  1.1264 +//-----------------------------------------------------------------------------
  1.1265 +// Serializes the JSON object and writes to the give file path
  1.1266 +bool JSON::Save(const char* path)
  1.1267 +{
  1.1268 +    SysFile f;
  1.1269 +    if (!f.Open(path, File::Open_Write | File::Open_Create | File::Open_Truncate, File::Mode_Write))
  1.1270 +        return false;
  1.1271 +
  1.1272 +    char* text = PrintValue(0, true);
  1.1273 +    if (text)
  1.1274 +    {
  1.1275 +        intptr_t len   = OVR_strlen(text);
  1.1276 +        OVR_ASSERT(len <= (intptr_t)(int)len);
  1.1277 +
  1.1278 +        int   bytes = f.Write((uint8_t*)text, (int)len);
  1.1279 +        f.Close();
  1.1280 +        OVR_FREE(text);
  1.1281 +        return (bytes == len);
  1.1282 +    }
  1.1283 +    else
  1.1284 +    {
  1.1285 +        return false;
  1.1286 +    }
  1.1287 +}
  1.1288 +
  1.1289 +
  1.1290 +} // namespace OVR