oculus1

diff 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
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libovr/Src/OVR_JSON.cpp	Sat Sep 14 16:14:59 2013 +0300
     1.3 @@ -0,0 +1,1056 @@
     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 2012 Oculus VR, Inc. All Rights reserved.
    1.37 +
    1.38 +Use of this software is subject to the terms of the Oculus license
    1.39 +agreement provided at the time of installation or download, or which
    1.40 +otherwise accompanies this software in either electronic or hard copy form.
    1.41 +
    1.42 +************************************************************************************/
    1.43 +
    1.44 +#include <string.h>
    1.45 +#include <stdio.h>
    1.46 +#include <math.h>
    1.47 +#include <stdlib.h>
    1.48 +#include <float.h>
    1.49 +#include <limits.h>
    1.50 +#include <ctype.h>
    1.51 +#include "OVR_JSON.h"
    1.52 +#include "Kernel/OVR_SysFile.h"
    1.53 +#include "Kernel/OVR_Log.h"
    1.54 +
    1.55 +namespace OVR {
    1.56 +
    1.57 +
    1.58 +//-----------------------------------------------------------------------------
    1.59 +// Create a new copy of a string
    1.60 +static char* JSON_strdup(const char* str)
    1.61 +{
    1.62 +    UPInt len  = OVR_strlen(str) + 1;
    1.63 +    char* copy = (char*)OVR_ALLOC(len);
    1.64 +    if (!copy)
    1.65 +        return 0;
    1.66 +    memcpy(copy, str, len);
    1.67 +    return copy;
    1.68 +}
    1.69 +
    1.70 +
    1.71 +//-----------------------------------------------------------------------------
    1.72 +// Render the number from the given item into a string.
    1.73 +static char* PrintNumber(double d)
    1.74 +{
    1.75 +	char *str;
    1.76 +	//double d=item->valuedouble;
    1.77 +    int valueint = (int)d;
    1.78 +	if (fabs(((double)valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
    1.79 +	{
    1.80 +		str=(char*)OVR_ALLOC(21);	// 2^64+1 can be represented in 21 chars.
    1.81 +		if (str)
    1.82 +            OVR_sprintf(str, 21, "%d", valueint);
    1.83 +	}
    1.84 +	else
    1.85 +	{
    1.86 +		str=(char*)OVR_ALLOC(64);	// This is a nice tradeoff.
    1.87 +		if (str)
    1.88 +		{
    1.89 +			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)
    1.90 +                OVR_sprintf(str, 64, "%.0f", d);
    1.91 +			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)
    1.92 +                OVR_sprintf(str, 64, "%e", d);
    1.93 +			else
    1.94 +                OVR_sprintf(str, 64, "%f", d);
    1.95 +		}
    1.96 +	}
    1.97 +	return str;
    1.98 +}
    1.99 +
   1.100 +// Parse the input text into an un-escaped cstring, and populate item.
   1.101 +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
   1.102 +
   1.103 +// Helper to assign error sting and return 0.
   1.104 +const char* AssignError(const char** perror, const char *errorMessage)
   1.105 +{
   1.106 +    if (perror)
   1.107 +        *perror = errorMessage;
   1.108 +    return 0;
   1.109 +}
   1.110 +
   1.111 +//-----------------------------------------------------------------------------
   1.112 +// ***** JSON Node class
   1.113 +
   1.114 +JSON::JSON(JSONItemType itemType)
   1.115 +    : Type(itemType), dValue(0.0)
   1.116 +{
   1.117 +}
   1.118 +
   1.119 +JSON::~JSON()
   1.120 +{
   1.121 +    JSON* child = Children.GetFirst();
   1.122 +    while (!Children.IsNull(child))
   1.123 +    {
   1.124 +        child->RemoveNode();
   1.125 +        child->Release();
   1.126 +        child = Children.GetFirst();
   1.127 +    }
   1.128 +}
   1.129 +
   1.130 +//-----------------------------------------------------------------------------
   1.131 +// Parse the input text to generate a number, and populate the result into item
   1.132 +// Returns the text position after the parsed number
   1.133 +const char* JSON::parseNumber(const char *num)
   1.134 +{
   1.135 +    const char* num_start = num;
   1.136 +    double      n=0, sign=1, scale=0;
   1.137 +    int         subscale     = 0,
   1.138 +                signsubscale = 1;
   1.139 +
   1.140 +	// Could use sscanf for this?
   1.141 +	if (*num=='-') 
   1.142 +        sign=-1,num++;	// Has sign?
   1.143 +	if (*num=='0')
   1.144 +        num++;			// is zero
   1.145 +	
   1.146 +    if (*num>='1' && *num<='9')	
   1.147 +    {
   1.148 +        do
   1.149 +        {   
   1.150 +            n=(n*10.0)+(*num++ -'0');
   1.151 +        }
   1.152 +        while (*num>='0' && *num<='9');	// Number?
   1.153 +    }
   1.154 +
   1.155 +	if (*num=='.' && num[1]>='0' && num[1]<='9')
   1.156 +    {
   1.157 +        num++;
   1.158 +        do
   1.159 +        {
   1.160 +            n=(n*10.0)+(*num++ -'0');
   1.161 +            scale--;
   1.162 +        }
   1.163 +        while (*num>='0' && *num<='9');  // Fractional part?
   1.164 +    }
   1.165 +
   1.166 +	if (*num=='e' || *num=='E')		// Exponent?
   1.167 +	{
   1.168 +        num++;
   1.169 +        if (*num=='+')
   1.170 +            num++;
   1.171 +        else if (*num=='-')
   1.172 +        {
   1.173 +            signsubscale=-1;
   1.174 +            num++;		// With sign?
   1.175 +        }
   1.176 +
   1.177 +		while (*num>='0' && *num<='9')
   1.178 +            subscale=(subscale*10)+(*num++ - '0');	// Number?
   1.179 +	}
   1.180 +
   1.181 +    // Number = +/- number.fraction * 10^+/- exponent
   1.182 +	n = sign*n*pow(10.0,(scale+subscale*signsubscale));
   1.183 +
   1.184 +    // Assign parsed value.
   1.185 +	Type   = JSON_Number;
   1.186 +    dValue = n;
   1.187 +    Value.AssignString(num_start, num - num_start);
   1.188 +    
   1.189 +	return num;
   1.190 +}
   1.191 +
   1.192 +// Parses a hex string up to the specified number of digits.
   1.193 +// Returns the first character after the string.
   1.194 +const char* ParseHex(unsigned* val, unsigned digits, const char* str)
   1.195 +{
   1.196 +    *val = 0;
   1.197 +
   1.198 +    for(unsigned digitCount = 0; digitCount < digits; digitCount++, str++)
   1.199 +    {
   1.200 +        unsigned v = *str;
   1.201 +
   1.202 +        if ((v >= '0') && (v <= '9'))
   1.203 +            v -= '0';
   1.204 +        else if ((v >= 'a') && (v <= 'f'))
   1.205 +            v = 10 + v - 'a';
   1.206 +        else if ((v >= 'A') && (v <= 'F'))
   1.207 +            v = 10 + v - 'A';
   1.208 +        else
   1.209 +            break;
   1.210 +
   1.211 +        *val = *val * 16 + v;
   1.212 +    }
   1.213 +
   1.214 +    return str;
   1.215 +}
   1.216 +
   1.217 +//-----------------------------------------------------------------------------
   1.218 +// Parses the input text into a string item and returns the text position after
   1.219 +// the parsed string
   1.220 +const char* JSON::parseString(const char* str, const char** perror)
   1.221 +{
   1.222 +	const char* ptr = str+1;
   1.223 +    const char* p;
   1.224 +    char*       ptr2;
   1.225 +    char*       out;
   1.226 +    int         len=0;
   1.227 +    unsigned    uc, uc2;
   1.228 +	
   1.229 +    if (*str!='\"')
   1.230 +    {
   1.231 +        return AssignError(perror, "Syntax Error: Missing quote");
   1.232 +    }
   1.233 +	
   1.234 +	while (*ptr!='\"' && *ptr && ++len)
   1.235 +    {   
   1.236 +        if (*ptr++ == '\\') ptr++;	// Skip escaped quotes.
   1.237 +    }
   1.238 +	
   1.239 +    // This is how long we need for the string, roughly.
   1.240 +	out=(char*)OVR_ALLOC(len+1);
   1.241 +	if (!out)
   1.242 +        return 0;
   1.243 +	
   1.244 +	ptr = str+1;
   1.245 +    ptr2= out;
   1.246 +
   1.247 +	while (*ptr!='\"' && *ptr)
   1.248 +	{
   1.249 +		if (*ptr!='\\')
   1.250 +        {
   1.251 +            *ptr2++ = *ptr++;
   1.252 +        }
   1.253 +		else
   1.254 +		{
   1.255 +			ptr++;
   1.256 +			switch (*ptr)
   1.257 +			{
   1.258 +				case 'b': *ptr2++ = '\b';	break;
   1.259 +				case 'f': *ptr2++ = '\f';	break;
   1.260 +				case 'n': *ptr2++ = '\n';	break;
   1.261 +				case 'r': *ptr2++ = '\r';	break;
   1.262 +				case 't': *ptr2++ = '\t';	break;
   1.263 +
   1.264 +                // Transcode utf16 to utf8.
   1.265 +                case 'u':
   1.266 +
   1.267 +                    // Get the unicode char.
   1.268 +                    p = ParseHex(&uc, 4, ptr + 1);
   1.269 +                    if (ptr != p)
   1.270 +                        ptr = p - 1;
   1.271 +
   1.272 +					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)
   1.273 +                        break;	// Check for invalid.
   1.274 +
   1.275 +                    // UTF16 surrogate pairs.
   1.276 +					if (uc>=0xD800 && uc<=0xDBFF)
   1.277 +					{
   1.278 +						if (ptr[1]!='\\' || ptr[2]!='u')
   1.279 +                            break;	// Missing second-half of surrogate.
   1.280 +
   1.281 +                        p= ParseHex(&uc2, 4, ptr + 3);
   1.282 +                        if (ptr != p)
   1.283 +                            ptr = p - 1;
   1.284 +                        
   1.285 +						if (uc2<0xDC00 || uc2>0xDFFF)
   1.286 +                            break;	// Invalid second-half of surrogate.
   1.287 +
   1.288 +						uc = 0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
   1.289 +					}
   1.290 +
   1.291 +					len=4;
   1.292 +                    
   1.293 +                    if (uc<0x80)
   1.294 +                        len=1;
   1.295 +                    else if (uc<0x800)
   1.296 +                        len=2;
   1.297 +                    else if (uc<0x10000)
   1.298 +                        len=3;
   1.299 +                    
   1.300 +                    ptr2+=len;
   1.301 +					
   1.302 +					switch (len)
   1.303 +                    {
   1.304 +						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
   1.305 +						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
   1.306 +						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
   1.307 +						case 1: *--ptr2 = (char)(uc | firstByteMark[len]);
   1.308 +					}
   1.309 +					ptr2+=len;
   1.310 +					break;
   1.311 +
   1.312 +                default:
   1.313 +                    *ptr2++ = *ptr;
   1.314 +                    break;
   1.315 +			}
   1.316 +			ptr++;
   1.317 +		}
   1.318 +	}
   1.319 +
   1.320 +	*ptr2 = 0;
   1.321 +	if (*ptr=='\"')
   1.322 +        ptr++;
   1.323 +	
   1.324 +    // Make a copy of the string 
   1.325 +    Value=out;
   1.326 +    OVR_FREE(out);
   1.327 +	Type=JSON_String;
   1.328 +
   1.329 +	return ptr;
   1.330 +}
   1.331 +
   1.332 +//-----------------------------------------------------------------------------
   1.333 +// Render the string provided to an escaped version that can be printed.
   1.334 +char* PrintString(const char* str)
   1.335 +{
   1.336 +	const char *ptr;
   1.337 +    char *ptr2,*out;
   1.338 +    int len=0;
   1.339 +    unsigned char token;
   1.340 +	
   1.341 +	if (!str)
   1.342 +        return JSON_strdup("");
   1.343 +	ptr=str;
   1.344 +    
   1.345 +    token=*ptr;
   1.346 +    while (token && ++len)\
   1.347 +    {
   1.348 +        if (strchr("\"\\\b\f\n\r\t",token))
   1.349 +            len++;
   1.350 +        else if (token<32) 
   1.351 +            len+=5;
   1.352 +        ptr++;
   1.353 +        token=*ptr;
   1.354 +    }
   1.355 +	
   1.356 +	int buff_size = len+3;
   1.357 +    out=(char*)OVR_ALLOC(buff_size);
   1.358 +	if (!out)
   1.359 +        return 0;
   1.360 +
   1.361 +	ptr2 = out;
   1.362 +    ptr  = str;
   1.363 +	*ptr2++ = '\"';
   1.364 +
   1.365 +	while (*ptr)
   1.366 +	{
   1.367 +		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') 
   1.368 +            *ptr2++=*ptr++;
   1.369 +		else
   1.370 +		{
   1.371 +			*ptr2++='\\';
   1.372 +			switch (token=*ptr++)
   1.373 +			{
   1.374 +				case '\\':	*ptr2++='\\';	break;
   1.375 +				case '\"':	*ptr2++='\"';	break;
   1.376 +				case '\b':	*ptr2++='b';	break;
   1.377 +				case '\f':	*ptr2++='f';	break;
   1.378 +				case '\n':	*ptr2++='n';	break;
   1.379 +				case '\r':	*ptr2++='r';	break;
   1.380 +				case '\t':	*ptr2++='t';	break;
   1.381 +				default: 
   1.382 +                    OVR_sprintf(ptr2, buff_size - (ptr2-out), "u%04x",token);
   1.383 +                    ptr2+=5;
   1.384 +                    break;	// Escape and print.
   1.385 +			}
   1.386 +		}
   1.387 +	}
   1.388 +	*ptr2++='\"';
   1.389 +    *ptr2++=0;
   1.390 +	return out;
   1.391 +}
   1.392 +
   1.393 +//-----------------------------------------------------------------------------
   1.394 +// Utility to jump whitespace and cr/lf
   1.395 +static const char* skip(const char* in)
   1.396 +{
   1.397 +    while (in && *in && (unsigned char)*in<=' ') 
   1.398 +        in++; 
   1.399 +    return in;
   1.400 +}
   1.401 +
   1.402 +//-----------------------------------------------------------------------------
   1.403 +// Parses the supplied buffer of JSON text and returns a JSON object tree
   1.404 +// The returned object must be Released after use
   1.405 +JSON* JSON::Parse(const char* buff, const char** perror)
   1.406 +{
   1.407 +    const char* end = 0;
   1.408 +	JSON*       json = new JSON();
   1.409 +	
   1.410 +	if (!json)
   1.411 +    {
   1.412 +        AssignError(perror, "Error: Failed to allocate memory");
   1.413 +        return 0;
   1.414 +    }
   1.415 + 
   1.416 +	end = json->parseValue(skip(buff), perror);
   1.417 +	if (!end)
   1.418 +    {
   1.419 +        json->Release();
   1.420 +        return NULL;
   1.421 +    }	// parse failure. ep is set.
   1.422 +
   1.423 +    return json;
   1.424 +}
   1.425 +
   1.426 +//-----------------------------------------------------------------------------
   1.427 +// Parser core - when encountering text, process appropriately.
   1.428 +const char* JSON::parseValue(const char* buff, const char** perror)
   1.429 +{
   1.430 +    if (perror)
   1.431 +        *perror = 0;
   1.432 +
   1.433 +	if (!buff)
   1.434 +        return NULL;	// Fail on null.
   1.435 +
   1.436 +	if (!strncmp(buff,"null",4))
   1.437 +    {
   1.438 +        Type = JSON_Null;
   1.439 +        return buff+4;
   1.440 +    }
   1.441 +	if (!strncmp(buff,"false",5))
   1.442 +    { 
   1.443 +        Type   = JSON_Bool;
   1.444 +        Value  = "false";
   1.445 +        dValue = 0;
   1.446 +        return buff+5;
   1.447 +    }
   1.448 +	if (!strncmp(buff,"true",4))
   1.449 +    {
   1.450 +        Type   = JSON_Bool;
   1.451 +        Value  = "true";
   1.452 +        dValue = 1;
   1.453 +        return buff+4;
   1.454 +    }
   1.455 +	if (*buff=='\"')
   1.456 +    {
   1.457 +        return parseString(buff, perror);
   1.458 +    }
   1.459 +	if (*buff=='-' || (*buff>='0' && *buff<='9'))
   1.460 +    { 
   1.461 +        return parseNumber(buff);
   1.462 +    }
   1.463 +	if (*buff=='[')
   1.464 +    { 
   1.465 +        return parseArray(buff, perror);
   1.466 +    }
   1.467 +	if (*buff=='{')
   1.468 +    {
   1.469 +        return parseObject(buff, perror);
   1.470 +    }
   1.471 +
   1.472 +    return AssignError(perror, "Syntax Error: Invalid syntax");
   1.473 +}
   1.474 +
   1.475 +
   1.476 +//-----------------------------------------------------------------------------
   1.477 +// Render a value to text. 
   1.478 +char* JSON::PrintValue(int depth, bool fmt)
   1.479 +{
   1.480 +	char *out=0;
   1.481 +
   1.482 +    switch (Type)
   1.483 +	{
   1.484 +        case JSON_Null:	    out = JSON_strdup("null");	break;
   1.485 +        case JSON_Bool:
   1.486 +            if (dValue == 0)
   1.487 +                out = JSON_strdup("false");
   1.488 +            else
   1.489 +                out = JSON_strdup("true");
   1.490 +            break;
   1.491 +        case JSON_Number:	out = PrintNumber(dValue); break;
   1.492 +        case JSON_String:	out = PrintString(Value); break;
   1.493 +        case JSON_Array:	out = PrintArray(depth, fmt); break;
   1.494 +        case JSON_Object:	out = PrintObject(depth, fmt); break;
   1.495 +        case JSON_None: OVR_ASSERT_LOG(false, ("Bad JSON type.")); break;
   1.496 +	}
   1.497 +	return out;
   1.498 +}
   1.499 +
   1.500 +//-----------------------------------------------------------------------------
   1.501 +// Build an array object from input text and returns the text position after
   1.502 +// the parsed array
   1.503 +const char* JSON::parseArray(const char* buff, const char** perror)
   1.504 +{
   1.505 +	JSON *child;
   1.506 +	if (*buff!='[')
   1.507 +    {
   1.508 +        return AssignError(perror, "Syntax Error: Missing opening bracket");
   1.509 +    }
   1.510 +
   1.511 +	Type=JSON_Array;
   1.512 +	buff=skip(buff+1);
   1.513 +	
   1.514 +    if (*buff==']')
   1.515 +        return buff+1;	// empty array.
   1.516 +
   1.517 +    child = new JSON();
   1.518 +	if (!child)
   1.519 +        return 0;		 // memory fail
   1.520 +    Children.PushBack(child);
   1.521 +	
   1.522 +    buff=skip(child->parseValue(skip(buff), perror));	// skip any spacing, get the buff. 
   1.523 +	if (!buff)
   1.524 +        return 0;
   1.525 +
   1.526 +	while (*buff==',')
   1.527 +	{
   1.528 +		JSON *new_item = new JSON();
   1.529 +		if (!new_item)
   1.530 +            return AssignError(perror, "Error: Failed to allocate memory");
   1.531 +		
   1.532 +        Children.PushBack(new_item);
   1.533 +
   1.534 +		buff=skip(new_item->parseValue(skip(buff+1), perror));
   1.535 +		if (!buff)
   1.536 +            return AssignError(perror, "Error: Failed to allocate memory");
   1.537 +	}
   1.538 +
   1.539 +	if (*buff==']')
   1.540 +        return buff+1;	// end of array
   1.541 +
   1.542 +    return AssignError(perror, "Syntax Error: Missing ending bracket");
   1.543 +}
   1.544 +
   1.545 +//-----------------------------------------------------------------------------
   1.546 +// Render an array to text.  The returned text must be freed
   1.547 +char* JSON::PrintArray(int depth, bool fmt)
   1.548 +{
   1.549 +	char **entries;
   1.550 +	char * out = 0,*ptr,*ret;
   1.551 +    SPInt  len = 5;
   1.552 +	
   1.553 +    bool fail = false;
   1.554 +	
   1.555 +	// How many entries in the array? 
   1.556 +    int numentries = GetItemCount();
   1.557 +	if (!numentries)
   1.558 +	{
   1.559 +		out=(char*)OVR_ALLOC(3);
   1.560 +		if (out)
   1.561 +            OVR_strcpy(out, 3, "[]");
   1.562 +		return out;
   1.563 +	}
   1.564 +	// Allocate an array to hold the values for each
   1.565 +	entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
   1.566 +	if (!entries)
   1.567 +        return 0;
   1.568 +	memset(entries,0,numentries*sizeof(char*));
   1.569 +
   1.570 +	//// Retrieve all the results:
   1.571 +    JSON* child = Children.GetFirst();
   1.572 +    for (int i=0; i<numentries; i++)
   1.573 +	{
   1.574 +		//JSON* child = Children[i];
   1.575 +        ret=child->PrintValue(depth+1, fmt);
   1.576 +		entries[i]=ret;
   1.577 +		if (ret)
   1.578 +            len+=OVR_strlen(ret)+2+(fmt?1:0);
   1.579 +        else
   1.580 +        {
   1.581 +            fail = true;
   1.582 +            break;
   1.583 +        }
   1.584 +        child = Children.GetNext(child);
   1.585 +	}
   1.586 +	
   1.587 +	// If we didn't fail, try to malloc the output string 
   1.588 +	if (!fail)
   1.589 +        out=(char*)OVR_ALLOC(len);
   1.590 +	// If that fails, we fail. 
   1.591 +	if (!out)
   1.592 +        fail = true;
   1.593 +
   1.594 +	// Handle failure.
   1.595 +	if (fail)
   1.596 +	{
   1.597 +		for (int i=0; i<numentries; i++) 
   1.598 +        {
   1.599 +            if (entries[i])
   1.600 +                OVR_FREE(entries[i]);
   1.601 +        }
   1.602 +		OVR_FREE(entries);
   1.603 +		return 0;
   1.604 +	}
   1.605 +	
   1.606 +	// Compose the output array.
   1.607 +	*out='[';
   1.608 +	ptr=out+1;
   1.609 +    *ptr=0;
   1.610 +	for (int i=0; i<numentries; i++)
   1.611 +	{
   1.612 +		OVR_strcpy(ptr, len - (ptr-out), entries[i]);
   1.613 +        ptr+=OVR_strlen(entries[i]);
   1.614 +		if (i!=numentries-1)
   1.615 +        {
   1.616 +            *ptr++=',';
   1.617 +            if (fmt)
   1.618 +                *ptr++=' ';
   1.619 +            *ptr=0;
   1.620 +        }
   1.621 +		OVR_FREE(entries[i]);
   1.622 +	}
   1.623 +	OVR_FREE(entries);
   1.624 +	*ptr++=']';
   1.625 +    *ptr++=0;
   1.626 +	return out;	
   1.627 +}
   1.628 +
   1.629 +//-----------------------------------------------------------------------------
   1.630 +// Build an object from the supplied text and returns the text position after
   1.631 +// the parsed object
   1.632 +const char* JSON::parseObject(const char* buff, const char** perror)
   1.633 +{
   1.634 +	if (*buff!='{')
   1.635 +    {
   1.636 +        return AssignError(perror, "Syntax Error: Missing opening brace");
   1.637 +    }
   1.638 +	
   1.639 +	Type=JSON_Object;
   1.640 +	buff=skip(buff+1);
   1.641 +	if (*buff=='}')
   1.642 +        return buff+1;	// empty array.
   1.643 +	
   1.644 +    JSON* child = new JSON();
   1.645 +    Children.PushBack(child);
   1.646 +
   1.647 +	buff=skip(child->parseString(skip(buff), perror));
   1.648 +	if (!buff) 
   1.649 +        return 0;
   1.650 +	child->Name = child->Value;
   1.651 +    child->Value.Clear();
   1.652 +	
   1.653 +    if (*buff!=':')
   1.654 +    {
   1.655 +        return AssignError(perror, "Syntax Error: Missing colon");
   1.656 +    }
   1.657 +
   1.658 +	buff=skip(child->parseValue(skip(buff+1), perror));	// skip any spacing, get the value.
   1.659 +	if (!buff)
   1.660 +        return 0;
   1.661 +	
   1.662 +	while (*buff==',')
   1.663 +	{
   1.664 +        child = new JSON();
   1.665 +		if (!child)
   1.666 +            return 0; // memory fail
   1.667 +		
   1.668 +        Children.PushBack(child);
   1.669 +
   1.670 +		buff=skip(child->parseString(skip(buff+1), perror));
   1.671 +		if (!buff)
   1.672 +            return 0;
   1.673 +		
   1.674 +        child->Name=child->Value;
   1.675 +        child->Value.Clear();
   1.676 +		
   1.677 +        if (*buff!=':')
   1.678 +        {
   1.679 +            return AssignError(perror, "Syntax Error: Missing colon");
   1.680 +        }	// fail!
   1.681 +		
   1.682 +        // Skip any spacing, get the value.
   1.683 +        buff=skip(child->parseValue(skip(buff+1), perror));
   1.684 +		if (!buff)
   1.685 +            return 0;
   1.686 +	}
   1.687 +	
   1.688 +	if (*buff=='}')
   1.689 +        return buff+1;	// end of array 
   1.690 +	
   1.691 +    return AssignError(perror, "Syntax Error: Missing closing brace");
   1.692 +}
   1.693 +
   1.694 +//-----------------------------------------------------------------------------
   1.695 +// Render an object to text.  The returned string must be freed
   1.696 +char* JSON::PrintObject(int depth, bool fmt)
   1.697 +{
   1.698 +	char** entries = 0, **names = 0;
   1.699 +	char*  out = 0;
   1.700 +    char*  ptr, *ret, *str;
   1.701 +    SPInt  len = 7, i = 0, j;
   1.702 +    bool   fail = false;
   1.703 +	
   1.704 +    // Count the number of entries.
   1.705 +    int numentries = GetItemCount();
   1.706 +    
   1.707 +	// Explicitly handle empty object case
   1.708 +	if (numentries == 0)
   1.709 +	{
   1.710 +		out=(char*)OVR_ALLOC(fmt?depth+3:3);
   1.711 +		if (!out)
   1.712 +            return 0;
   1.713 +		ptr=out;
   1.714 +        *ptr++='{';
   1.715 +		
   1.716 +        if (fmt)
   1.717 +        {
   1.718 +            *ptr++='\n';
   1.719 +            for (i=0;i<depth-1;i++)
   1.720 +                *ptr++='\t';
   1.721 +        }
   1.722 +		*ptr++='}';
   1.723 +        *ptr++=0;
   1.724 +		return out;
   1.725 +	}
   1.726 +	// Allocate space for the names and the objects
   1.727 +	entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
   1.728 +	if (!entries)
   1.729 +        return 0;
   1.730 +	names=(char**)OVR_ALLOC(numentries*sizeof(char*));
   1.731 +	
   1.732 +    if (!names)
   1.733 +    {
   1.734 +        OVR_FREE(entries);
   1.735 +        return 0;
   1.736 +    }
   1.737 +	memset(entries,0,sizeof(char*)*numentries);
   1.738 +	memset(names,0,sizeof(char*)*numentries);
   1.739 +
   1.740 +	// Collect all the results into our arrays:
   1.741 +    depth++;
   1.742 +    if (fmt)
   1.743 +        len+=depth;
   1.744 +
   1.745 +    JSON* child = Children.GetFirst();
   1.746 +    while (!Children.IsNull(child))
   1.747 +	{
   1.748 +		names[i]     = str = PrintString(child->Name);
   1.749 +		entries[i++] = ret = child->PrintValue(depth, fmt);
   1.750 +
   1.751 +		if (str && ret)
   1.752 +        {
   1.753 +            len += OVR_strlen(ret)+OVR_strlen(str)+2+(fmt?2+depth:0);
   1.754 +        }
   1.755 +        else
   1.756 +        {
   1.757 +            fail = true;
   1.758 +            break;
   1.759 +        }
   1.760 +		
   1.761 +        child = Children.GetNext(child);
   1.762 +	}
   1.763 +	
   1.764 +	// Try to allocate the output string
   1.765 +	if (!fail)
   1.766 +        out=(char*)OVR_ALLOC(len);
   1.767 +	if (!out)
   1.768 +        fail=true;
   1.769 +
   1.770 +	// Handle failure
   1.771 +	if (fail)
   1.772 +	{
   1.773 +		for (i=0;i<numentries;i++)
   1.774 +        {
   1.775 +            if (names[i])
   1.776 +                OVR_FREE(names[i]);
   1.777 +            
   1.778 +            if (entries[i])
   1.779 +                OVR_FREE(entries[i]);}
   1.780 +		
   1.781 +        OVR_FREE(names);
   1.782 +        OVR_FREE(entries);
   1.783 +		return 0;
   1.784 +	}
   1.785 +	
   1.786 +	// Compose the output:
   1.787 +	*out = '{';
   1.788 +    ptr  = out+1;
   1.789 +    if (fmt)
   1.790 +        *ptr++='\n';
   1.791 +    *ptr = 0;
   1.792 +	
   1.793 +    for (i=0; i<numentries; i++)
   1.794 +	{
   1.795 +		if (fmt)
   1.796 +        {
   1.797 +            for (j=0; j<depth; j++)
   1.798 +                *ptr++ = '\t';
   1.799 +        }
   1.800 +		OVR_strcpy(ptr, len - (ptr-out), names[i]);
   1.801 +        ptr   += OVR_strlen(names[i]);
   1.802 +		*ptr++ =':';
   1.803 +        
   1.804 +        if (fmt)
   1.805 +            *ptr++='\t';
   1.806 +		
   1.807 +        OVR_strcpy(ptr, len - (ptr-out), entries[i]);
   1.808 +        ptr+=OVR_strlen(entries[i]);
   1.809 +		
   1.810 +        if (i!=numentries-1)
   1.811 +            *ptr++ = ',';
   1.812 +		
   1.813 +        if (fmt)
   1.814 +            *ptr++ = '\n';
   1.815 +        *ptr = 0;
   1.816 +		
   1.817 +        OVR_FREE(names[i]);
   1.818 +        OVR_FREE(entries[i]);
   1.819 +	}
   1.820 +	
   1.821 +	OVR_FREE(names);
   1.822 +    OVR_FREE(entries);
   1.823 +	
   1.824 +    if (fmt)
   1.825 +    {
   1.826 +        for (i=0;i<depth-1;i++)
   1.827 +            *ptr++='\t';
   1.828 +    }
   1.829 +	*ptr++='}';
   1.830 +    *ptr++=0;
   1.831 +	
   1.832 +    return out;	
   1.833 +}
   1.834 +
   1.835 +
   1.836 +
   1.837 +// Returns the number of child items in the object
   1.838 +// Counts the number of items in the object.
   1.839 +unsigned JSON::GetItemCount() const
   1.840 +{
   1.841 +    unsigned count = 0;
   1.842 +    for(const JSON* p = Children.GetFirst(); !Children.IsNull(p); p = p->pNext)
   1.843 +        count++;
   1.844 +    return count;
   1.845 +}
   1.846 +
   1.847 +JSON* JSON::GetItemByIndex(unsigned index)
   1.848 +{
   1.849 +    unsigned i     = 0;
   1.850 +    JSON*    child = 0;
   1.851 +
   1.852 +    if (!Children.IsEmpty())
   1.853 +    {
   1.854 +        child = Children.GetFirst();
   1.855 +
   1.856 +        while (i < index)
   1.857 +        {   
   1.858 +            if (Children.IsNull(child->pNext))
   1.859 +            {
   1.860 +                child = 0;
   1.861 +                break;
   1.862 +            }
   1.863 +            child = child->pNext;
   1.864 +            i++;
   1.865 +        }
   1.866 +    }
   1.867 +  
   1.868 +    return child;
   1.869 +}
   1.870 +
   1.871 +// Returns the child item with the given name or NULL if not found
   1.872 +JSON* JSON::GetItemByName(const char* name)
   1.873 +{
   1.874 +    JSON* child = 0;
   1.875 +
   1.876 +    if (!Children.IsEmpty())
   1.877 +    {
   1.878 +        child = Children.GetFirst();
   1.879 +
   1.880 +        while (OVR_strcmp(child->Name, name) != 0)
   1.881 +        {   
   1.882 +            if (Children.IsNull(child->pNext))
   1.883 +            {
   1.884 +                child = 0;
   1.885 +                break;
   1.886 +            }
   1.887 +            child = child->pNext;
   1.888 +        }
   1.889 +    }
   1.890 +
   1.891 +    return child;
   1.892 +}
   1.893 +
   1.894 +//-----------------------------------------------------------------------------
   1.895 +// Adds a new item to the end of the child list
   1.896 +void JSON::AddItem(const char *string, JSON *item)
   1.897 +{
   1.898 +    if (!item)
   1.899 +        return;
   1.900 + 
   1.901 +    item->Name = string;
   1.902 +    Children.PushBack(item);
   1.903 +}
   1.904 +
   1.905 +/*
   1.906 +
   1.907 +// Removes and frees the items at the given index
   1.908 +void JSON::DeleteItem(unsigned int index)
   1.909 +{
   1.910 +    unsigned int num_items = 0;
   1.911 +    JSON* child = Children.GetFirst();
   1.912 +    while (!Children.IsNull(child) && num_items < index)
   1.913 +    {   
   1.914 +        num_items++;
   1.915 +        child = Children.GetNext(child);
   1.916 +    }
   1.917 +
   1.918 +    if (!Children.IsNull(child))
   1.919 +    
   1.920 +        child->RemoveNode();
   1.921 +        child->Release();
   1.922 +    }
   1.923 +}
   1.924 +
   1.925 +// Replaces and frees the item at the give index with the new item
   1.926 +void JSON::ReplaceItem(unsigned int index, JSON* new_item)
   1.927 +{
   1.928 +    unsigned int num_items = 0;
   1.929 +    JSON* child = Children.GetFirst();
   1.930 +    while (!Children.IsNull(child) && num_items < index)
   1.931 +    {   
   1.932 +        num_items++;
   1.933 +        child = Children.GetNext(child);
   1.934 +    }
   1.935 +
   1.936 +    if (!Children.IsNull(child))
   1.937 +    {
   1.938 +        child->ReplaceNodeWith(new_item);
   1.939 +        child->Release();        
   1.940 +    }
   1.941 +}
   1.942 +*/
   1.943 +
   1.944 +// Helper function to simplify creation of a typed object
   1.945 +JSON* JSON::createHelper(JSONItemType itemType, double dval, const char* strVal)
   1.946 +{
   1.947 +    JSON *item = new JSON(itemType);
   1.948 +    if (item)
   1.949 +    {
   1.950 +        item->dValue = dval;
   1.951 +        if (strVal)
   1.952 +            item->Value = strVal;
   1.953 +    }
   1.954 +    return item;
   1.955 +}
   1.956 +
   1.957 +
   1.958 +//-----------------------------------------------------------------------------
   1.959 +// Adds an element to an array object type
   1.960 +void JSON::AddArrayElement(JSON *item)
   1.961 +{
   1.962 +    if (!item)
   1.963 +        return;
   1.964 +
   1.965 +    Children.PushBack(item);
   1.966 +}
   1.967 +
   1.968 +
   1.969 +// Returns the size of an array
   1.970 +int JSON::GetArraySize()
   1.971 +{
   1.972 +    if (Type == JSON_Array)
   1.973 +        return GetItemCount();
   1.974 +    else
   1.975 +        return 0;
   1.976 +}
   1.977 +
   1.978 +// Returns the number value an the give array index
   1.979 +double JSON::GetArrayNumber(int index)
   1.980 +{
   1.981 +    if (Type == JSON_Array)
   1.982 +    {
   1.983 +        JSON* number = GetItemByIndex(index);
   1.984 +        return number ? number->dValue : 0.0;
   1.985 +    }
   1.986 +    else
   1.987 +    {
   1.988 +        return 0;
   1.989 +    }
   1.990 +}
   1.991 +
   1.992 +// Returns the string value at the given array index
   1.993 +const char* JSON::GetArrayString(int index)
   1.994 +{
   1.995 +    if (Type == JSON_Array)
   1.996 +    {
   1.997 +        JSON* number = GetItemByIndex(index);
   1.998 +        return number ? number->Value : 0;
   1.999 +    }
  1.1000 +    else
  1.1001 +    {
  1.1002 +        return 0;
  1.1003 +    }
  1.1004 +}
  1.1005 +
  1.1006 +//-----------------------------------------------------------------------------
  1.1007 +// Loads and parses the given JSON file pathname and returns a JSON object tree.
  1.1008 +// The returned object must be Released after use.
  1.1009 +JSON* JSON::Load(const char* path, const char** perror)
  1.1010 +{
  1.1011 +    SysFile f;
  1.1012 +    if (!f.Open(path, File::Open_Read, File::Mode_Read))
  1.1013 +    {
  1.1014 +        AssignError(perror, "Failed to open file");
  1.1015 +        return NULL;
  1.1016 +    }
  1.1017 +
  1.1018 +    int    len   = f.GetLength();
  1.1019 +    UByte* buff  = (UByte*)OVR_ALLOC(len);
  1.1020 +    int    bytes = f.Read(buff, len);
  1.1021 +    f.Close();
  1.1022 +
  1.1023 +    if (bytes == 0 || bytes != len)
  1.1024 +    {
  1.1025 +        OVR_FREE(buff);
  1.1026 +        return NULL;
  1.1027 +    }
  1.1028 +
  1.1029 +    JSON* json = JSON::Parse((char*)buff, perror);
  1.1030 +    OVR_FREE(buff);
  1.1031 +    return json;
  1.1032 +}
  1.1033 +
  1.1034 +//-----------------------------------------------------------------------------
  1.1035 +// Serializes the JSON object and writes to the give file path
  1.1036 +bool JSON::Save(const char* path)
  1.1037 +{
  1.1038 +    SysFile f;
  1.1039 +    if (!f.Open(path, File::Open_Write | File::Open_Create | File::Open_Truncate, File::Mode_Write))
  1.1040 +        return false;
  1.1041 +
  1.1042 +    char* text = PrintValue(0, true);
  1.1043 +    if (text)
  1.1044 +    {
  1.1045 +        SPInt len   = OVR_strlen(text);
  1.1046 +        OVR_ASSERT(len < (SPInt)(int)len);
  1.1047 +
  1.1048 +        int   bytes = f.Write((UByte*)text, (int)len);
  1.1049 +        f.Close();
  1.1050 +        OVR_FREE(text);
  1.1051 +        return (bytes == len);
  1.1052 +    }
  1.1053 +    else
  1.1054 +    {
  1.1055 +        return false;
  1.1056 +    }
  1.1057 +}
  1.1058 +
  1.1059 +}