aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/OVR_JSON.cpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-06-19 17:03:28 +0200
committerSven Gothel <[email protected]>2014-06-19 17:03:28 +0200
commitd9a584844a60542519d813b5dc1a62428f14a0ae (patch)
tree942c10a5ebcd0aab65e9d6facb59778468f39d3b /LibOVR/Src/OVR_JSON.cpp
Add OculusSDK 0.3.2 Linux Source Code w/o Samples, docs or binaries (libs or tools)
Diffstat (limited to 'LibOVR/Src/OVR_JSON.cpp')
-rw-r--r--LibOVR/Src/OVR_JSON.cpp1185
1 files changed, 1185 insertions, 0 deletions
diff --git a/LibOVR/Src/OVR_JSON.cpp b/LibOVR/Src/OVR_JSON.cpp
new file mode 100644
index 0000000..262a0d9
--- /dev/null
+++ b/LibOVR/Src/OVR_JSON.cpp
@@ -0,0 +1,1185 @@
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_JSON.h
+Content : JSON format reader and writer
+Created : April 9, 2013
+Author : Brant Lewis
+Notes :
+ The code is a derivative of the cJSON library written by Dave Gamble and subject
+ to the following permissive copyright.
+
+ Copyright (c) 2009 Dave Gamble
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+
+Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.1
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include "OVR_JSON.h"
+#include "Kernel/OVR_SysFile.h"
+#include "Kernel/OVR_Log.h"
+
+namespace OVR {
+
+
+//-----------------------------------------------------------------------------
+// Create a new copy of a string
+static char* JSON_strdup(const char* str)
+{
+ UPInt len = OVR_strlen(str) + 1;
+ char* copy = (char*)OVR_ALLOC(len);
+ if (!copy)
+ return 0;
+ memcpy(copy, str, len);
+ return copy;
+}
+
+
+//-----------------------------------------------------------------------------
+// Render the number from the given item into a string.
+static char* PrintNumber(double d)
+{
+ char *str;
+ //double d=item->valuedouble;
+ int valueint = (int)d;
+ if (fabs(((double)valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
+ {
+ str=(char*)OVR_ALLOC(21); // 2^64+1 can be represented in 21 chars.
+ if (str)
+ OVR_sprintf(str, 21, "%d", valueint);
+ }
+ else
+ {
+ str=(char*)OVR_ALLOC(64); // This is a nice tradeoff.
+ if (str)
+ {
+ if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)
+ OVR_sprintf(str, 64, "%.0f", d);
+ else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)
+ OVR_sprintf(str, 64, "%e", d);
+ else
+ OVR_sprintf(str, 64, "%f", d);
+ }
+ }
+ return str;
+}
+
+// Parse the input text into an un-escaped cstring, and populate item.
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+// Helper to assign error sting and return 0.
+const char* AssignError(const char** perror, const char *errorMessage)
+{
+ if (perror)
+ *perror = errorMessage;
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// ***** JSON Node class
+
+JSON::JSON(JSONItemType itemType)
+ : Type(itemType), dValue(0.0)
+{
+}
+
+JSON::~JSON()
+{
+ JSON* child = Children.GetFirst();
+ while (!Children.IsNull(child))
+ {
+ child->RemoveNode();
+ child->Release();
+ child = Children.GetFirst();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Parse the input text to generate a number, and populate the result into item
+// Returns the text position after the parsed number
+const char* JSON::parseNumber(const char *num)
+{
+ const char* num_start = num;
+ double n=0, sign=1, scale=0;
+ int subscale = 0,
+ signsubscale = 1;
+
+ // Could use sscanf for this?
+ if (*num=='-')
+ sign=-1,num++; // Has sign?
+ if (*num=='0')
+ num++; // is zero
+
+ if (*num>='1' && *num<='9')
+ {
+ do
+ {
+ n=(n*10.0)+(*num++ -'0');
+ }
+ while (*num>='0' && *num<='9'); // Number?
+ }
+
+ if (*num=='.' && num[1]>='0' && num[1]<='9')
+ {
+ num++;
+ do
+ {
+ n=(n*10.0)+(*num++ -'0');
+ scale--;
+ }
+ while (*num>='0' && *num<='9'); // Fractional part?
+ }
+
+ if (*num=='e' || *num=='E') // Exponent?
+ {
+ num++;
+ if (*num=='+')
+ num++;
+ else if (*num=='-')
+ {
+ signsubscale=-1;
+ num++; // With sign?
+ }
+
+ while (*num>='0' && *num<='9')
+ subscale=(subscale*10)+(*num++ - '0'); // Number?
+ }
+
+ // Number = +/- number.fraction * 10^+/- exponent
+ n = sign*n*pow(10.0,(scale+subscale*signsubscale));
+
+ // Assign parsed value.
+ Type = JSON_Number;
+ dValue = n;
+ Value.AssignString(num_start, num - num_start);
+
+ return num;
+}
+
+// Parses a hex string up to the specified number of digits.
+// Returns the first character after the string.
+const char* ParseHex(unsigned* val, unsigned digits, const char* str)
+{
+ *val = 0;
+
+ for(unsigned digitCount = 0; digitCount < digits; digitCount++, str++)
+ {
+ unsigned v = *str;
+
+ if ((v >= '0') && (v <= '9'))
+ v -= '0';
+ else if ((v >= 'a') && (v <= 'f'))
+ v = 10 + v - 'a';
+ else if ((v >= 'A') && (v <= 'F'))
+ v = 10 + v - 'A';
+ else
+ break;
+
+ *val = *val * 16 + v;
+ }
+
+ return str;
+}
+
+//-----------------------------------------------------------------------------
+// Parses the input text into a string item and returns the text position after
+// the parsed string
+const char* JSON::parseString(const char* str, const char** perror)
+{
+ const char* ptr = str+1;
+ const char* p;
+ char* ptr2;
+ char* out;
+ int len=0;
+ unsigned uc, uc2;
+
+ if (*str!='\"')
+ {
+ return AssignError(perror, "Syntax Error: Missing quote");
+ }
+
+ while (*ptr!='\"' && *ptr && ++len)
+ {
+ if (*ptr++ == '\\') ptr++; // Skip escaped quotes.
+ }
+
+ // This is how long we need for the string, roughly.
+ out=(char*)OVR_ALLOC(len+1);
+ if (!out)
+ return 0;
+
+ ptr = str+1;
+ ptr2= out;
+
+ while (*ptr!='\"' && *ptr)
+ {
+ if (*ptr!='\\')
+ {
+ *ptr2++ = *ptr++;
+ }
+ else
+ {
+ ptr++;
+ switch (*ptr)
+ {
+ case 'b': *ptr2++ = '\b'; break;
+ case 'f': *ptr2++ = '\f'; break;
+ case 'n': *ptr2++ = '\n'; break;
+ case 'r': *ptr2++ = '\r'; break;
+ case 't': *ptr2++ = '\t'; break;
+
+ // Transcode utf16 to utf8.
+ case 'u':
+
+ // Get the unicode char.
+ p = ParseHex(&uc, 4, ptr + 1);
+ if (ptr != p)
+ ptr = p - 1;
+
+ if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)
+ break; // Check for invalid.
+
+ // UTF16 surrogate pairs.
+ if (uc>=0xD800 && uc<=0xDBFF)
+ {
+ if (ptr[1]!='\\' || ptr[2]!='u')
+ break; // Missing second-half of surrogate.
+
+ p= ParseHex(&uc2, 4, ptr + 3);
+ if (ptr != p)
+ ptr = p - 1;
+
+ if (uc2<0xDC00 || uc2>0xDFFF)
+ break; // Invalid second-half of surrogate.
+
+ uc = 0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
+ }
+
+ len=4;
+
+ if (uc<0x80)
+ len=1;
+ else if (uc<0x800)
+ len=2;
+ else if (uc<0x10000)
+ len=3;
+
+ ptr2+=len;
+
+ switch (len)
+ {
+ case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 1: *--ptr2 = (char)(uc | firstByteMark[len]);
+ }
+ ptr2+=len;
+ break;
+
+ default:
+ *ptr2++ = *ptr;
+ break;
+ }
+ ptr++;
+ }
+ }
+
+ *ptr2 = 0;
+ if (*ptr=='\"')
+ ptr++;
+
+ // Make a copy of the string
+ Value=out;
+ OVR_FREE(out);
+ Type=JSON_String;
+
+ return ptr;
+}
+
+//-----------------------------------------------------------------------------
+// Render the string provided to an escaped version that can be printed.
+char* PrintString(const char* str)
+{
+ const char *ptr;
+ char *ptr2,*out;
+ int len=0;
+ unsigned char token;
+
+ if (!str)
+ return JSON_strdup("");
+ ptr=str;
+
+ token=*ptr;
+ while (token && ++len)\
+ {
+ if (strchr("\"\\\b\f\n\r\t",token))
+ len++;
+ else if (token<32)
+ len+=5;
+ ptr++;
+ token=*ptr;
+ }
+
+ int buff_size = len+3;
+ out=(char*)OVR_ALLOC(buff_size);
+ if (!out)
+ return 0;
+
+ ptr2 = out;
+ ptr = str;
+ *ptr2++ = '\"';
+
+ while (*ptr)
+ {
+ if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\')
+ *ptr2++=*ptr++;
+ else
+ {
+ *ptr2++='\\';
+ switch (token=*ptr++)
+ {
+ case '\\': *ptr2++='\\'; break;
+ case '\"': *ptr2++='\"'; break;
+ case '\b': *ptr2++='b'; break;
+ case '\f': *ptr2++='f'; break;
+ case '\n': *ptr2++='n'; break;
+ case '\r': *ptr2++='r'; break;
+ case '\t': *ptr2++='t'; break;
+ default:
+ OVR_sprintf(ptr2, buff_size - (ptr2-out), "u%04x",token);
+ ptr2+=5;
+ break; // Escape and print.
+ }
+ }
+ }
+ *ptr2++='\"';
+ *ptr2++=0;
+ return out;
+}
+
+//-----------------------------------------------------------------------------
+// Utility to jump whitespace and cr/lf
+static const char* skip(const char* in)
+{
+ while (in && *in && (unsigned char)*in<=' ')
+ in++;
+ return in;
+}
+
+//-----------------------------------------------------------------------------
+// Parses the supplied buffer of JSON text and returns a JSON object tree
+// The returned object must be Released after use
+JSON* JSON::Parse(const char* buff, const char** perror)
+{
+ const char* end = 0;
+ JSON* json = new JSON();
+
+ if (!json)
+ {
+ AssignError(perror, "Error: Failed to allocate memory");
+ return 0;
+ }
+
+ end = json->parseValue(skip(buff), perror);
+ if (!end)
+ {
+ json->Release();
+ return NULL;
+ } // parse failure. ep is set.
+
+ return json;
+}
+
+//-----------------------------------------------------------------------------
+// This version works for buffers that are not null terminated strings.
+JSON* JSON::ParseBuffer(const char *buff, int len, const char** perror)
+{
+ // Our JSON parser does not support length-based parsing,
+ // so ensure it is null-terminated.
+ char *termStr = new char[len + 1];
+ memcpy(termStr, buff, len);
+ termStr[len] = '\0';
+
+ JSON *objJson = Parse(termStr, perror);
+
+ delete[]termStr;
+
+ return objJson;
+}
+
+//-----------------------------------------------------------------------------
+// Parser core - when encountering text, process appropriately.
+const char* JSON::parseValue(const char* buff, const char** perror)
+{
+ if (perror)
+ *perror = 0;
+
+ if (!buff)
+ return NULL; // Fail on null.
+
+ if (!strncmp(buff,"null",4))
+ {
+ Type = JSON_Null;
+ return buff+4;
+ }
+ if (!strncmp(buff,"false",5))
+ {
+ Type = JSON_Bool;
+ Value = "false";
+ dValue = 0;
+ return buff+5;
+ }
+ if (!strncmp(buff,"true",4))
+ {
+ Type = JSON_Bool;
+ Value = "true";
+ dValue = 1;
+ return buff+4;
+ }
+ if (*buff=='\"')
+ {
+ return parseString(buff, perror);
+ }
+ if (*buff=='-' || (*buff>='0' && *buff<='9'))
+ {
+ return parseNumber(buff);
+ }
+ if (*buff=='[')
+ {
+ return parseArray(buff, perror);
+ }
+ if (*buff=='{')
+ {
+ return parseObject(buff, perror);
+ }
+
+ return AssignError(perror, "Syntax Error: Invalid syntax");
+}
+
+
+//-----------------------------------------------------------------------------
+// Render a value to text.
+char* JSON::PrintValue(int depth, bool fmt)
+{
+ char *out=0;
+
+ switch (Type)
+ {
+ case JSON_Null: out = JSON_strdup("null"); break;
+ case JSON_Bool:
+ if (dValue == 0)
+ out = JSON_strdup("false");
+ else
+ out = JSON_strdup("true");
+ break;
+ case JSON_Number: out = PrintNumber(dValue); break;
+ case JSON_String: out = PrintString(Value); break;
+ case JSON_Array: out = PrintArray(depth, fmt); break;
+ case JSON_Object: out = PrintObject(depth, fmt); break;
+ case JSON_None: OVR_ASSERT_LOG(false, ("Bad JSON type.")); break;
+ }
+ return out;
+}
+
+//-----------------------------------------------------------------------------
+// Build an array object from input text and returns the text position after
+// the parsed array
+const char* JSON::parseArray(const char* buff, const char** perror)
+{
+ JSON *child;
+ if (*buff!='[')
+ {
+ return AssignError(perror, "Syntax Error: Missing opening bracket");
+ }
+
+ Type=JSON_Array;
+ buff=skip(buff+1);
+
+ if (*buff==']')
+ return buff+1; // empty array.
+
+ child = new JSON();
+ if (!child)
+ return 0; // memory fail
+ Children.PushBack(child);
+
+ buff=skip(child->parseValue(skip(buff), perror)); // skip any spacing, get the buff.
+ if (!buff)
+ return 0;
+
+ while (*buff==',')
+ {
+ JSON *new_item = new JSON();
+ if (!new_item)
+ return AssignError(perror, "Error: Failed to allocate memory");
+
+ Children.PushBack(new_item);
+
+ buff=skip(new_item->parseValue(skip(buff+1), perror));
+ if (!buff)
+ return AssignError(perror, "Error: Failed to allocate memory");
+ }
+
+ if (*buff==']')
+ return buff+1; // end of array
+
+ return AssignError(perror, "Syntax Error: Missing ending bracket");
+}
+
+//-----------------------------------------------------------------------------
+// Render an array to text. The returned text must be freed
+char* JSON::PrintArray(int depth, bool fmt)
+{
+ char **entries;
+ char * out = 0,*ptr,*ret;
+ SPInt len = 5;
+
+ bool fail = false;
+
+ // How many entries in the array?
+ int numentries = GetItemCount();
+ if (!numentries)
+ {
+ out=(char*)OVR_ALLOC(3);
+ if (out)
+ OVR_strcpy(out, 3, "[]");
+ return out;
+ }
+ // Allocate an array to hold the values for each
+ entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
+ if (!entries)
+ return 0;
+ memset(entries,0,numentries*sizeof(char*));
+
+ //// Retrieve all the results:
+ JSON* child = Children.GetFirst();
+ for (int i=0; i<numentries; i++)
+ {
+ //JSON* child = Children[i];
+ ret=child->PrintValue(depth+1, fmt);
+ entries[i]=ret;
+ if (ret)
+ len+=OVR_strlen(ret)+2+(fmt?1:0);
+ else
+ {
+ fail = true;
+ break;
+ }
+ child = Children.GetNext(child);
+ }
+
+ // If we didn't fail, try to malloc the output string
+ if (!fail)
+ out=(char*)OVR_ALLOC(len);
+ // If that fails, we fail.
+ if (!out)
+ fail = true;
+
+ // Handle failure.
+ if (fail)
+ {
+ for (int i=0; i<numentries; i++)
+ {
+ if (entries[i])
+ OVR_FREE(entries[i]);
+ }
+ OVR_FREE(entries);
+ return 0;
+ }
+
+ // Compose the output array.
+ *out='[';
+ ptr=out+1;
+ *ptr=0;
+ for (int i=0; i<numentries; i++)
+ {
+ OVR_strcpy(ptr, len - (ptr-out), entries[i]);
+ ptr+=OVR_strlen(entries[i]);
+ if (i!=numentries-1)
+ {
+ *ptr++=',';
+ if (fmt)
+ *ptr++=' ';
+ *ptr=0;
+ }
+ OVR_FREE(entries[i]);
+ }
+ OVR_FREE(entries);
+ *ptr++=']';
+ *ptr++=0;
+ return out;
+}
+
+//-----------------------------------------------------------------------------
+// Build an object from the supplied text and returns the text position after
+// the parsed object
+const char* JSON::parseObject(const char* buff, const char** perror)
+{
+ if (*buff!='{')
+ {
+ return AssignError(perror, "Syntax Error: Missing opening brace");
+ }
+
+ Type=JSON_Object;
+ buff=skip(buff+1);
+ if (*buff=='}')
+ return buff+1; // empty array.
+
+ JSON* child = new JSON();
+ Children.PushBack(child);
+
+ buff=skip(child->parseString(skip(buff), perror));
+ if (!buff)
+ return 0;
+ child->Name = child->Value;
+ child->Value.Clear();
+
+ if (*buff!=':')
+ {
+ return AssignError(perror, "Syntax Error: Missing colon");
+ }
+
+ buff=skip(child->parseValue(skip(buff+1), perror)); // skip any spacing, get the value.
+ if (!buff)
+ return 0;
+
+ while (*buff==',')
+ {
+ child = new JSON();
+ if (!child)
+ return 0; // memory fail
+
+ Children.PushBack(child);
+
+ buff=skip(child->parseString(skip(buff+1), perror));
+ if (!buff)
+ return 0;
+
+ child->Name=child->Value;
+ child->Value.Clear();
+
+ if (*buff!=':')
+ {
+ return AssignError(perror, "Syntax Error: Missing colon");
+ } // fail!
+
+ // Skip any spacing, get the value.
+ buff=skip(child->parseValue(skip(buff+1), perror));
+ if (!buff)
+ return 0;
+ }
+
+ if (*buff=='}')
+ return buff+1; // end of array
+
+ return AssignError(perror, "Syntax Error: Missing closing brace");
+}
+
+//-----------------------------------------------------------------------------
+// Render an object to text. The returned string must be freed
+char* JSON::PrintObject(int depth, bool fmt)
+{
+ char** entries = 0, **names = 0;
+ char* out = 0;
+ char* ptr, *ret, *str;
+ SPInt len = 7, i = 0, j;
+ bool fail = false;
+
+ // Count the number of entries.
+ int numentries = GetItemCount();
+
+ // Explicitly handle empty object case
+ if (numentries == 0)
+ {
+ out=(char*)OVR_ALLOC(fmt?depth+3:3);
+ if (!out)
+ return 0;
+ ptr=out;
+ *ptr++='{';
+
+ if (fmt)
+ {
+ *ptr++='\n';
+ for (i=0;i<depth-1;i++)
+ *ptr++='\t';
+ }
+ *ptr++='}';
+ *ptr++=0;
+ return out;
+ }
+ // Allocate space for the names and the objects
+ entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
+ if (!entries)
+ return 0;
+ names=(char**)OVR_ALLOC(numentries*sizeof(char*));
+
+ if (!names)
+ {
+ OVR_FREE(entries);
+ return 0;
+ }
+ memset(entries,0,sizeof(char*)*numentries);
+ memset(names,0,sizeof(char*)*numentries);
+
+ // Collect all the results into our arrays:
+ depth++;
+ if (fmt)
+ len+=depth;
+
+ JSON* child = Children.GetFirst();
+ while (!Children.IsNull(child))
+ {
+ names[i] = str = PrintString(child->Name);
+ entries[i++] = ret = child->PrintValue(depth, fmt);
+
+ if (str && ret)
+ {
+ len += OVR_strlen(ret)+OVR_strlen(str)+2+(fmt?2+depth:0);
+ }
+ else
+ {
+ fail = true;
+ break;
+ }
+
+ child = Children.GetNext(child);
+ }
+
+ // Try to allocate the output string
+ if (!fail)
+ out=(char*)OVR_ALLOC(len);
+ if (!out)
+ fail=true;
+
+ // Handle failure
+ if (fail)
+ {
+ for (i=0;i<numentries;i++)
+ {
+ if (names[i])
+ OVR_FREE(names[i]);
+
+ if (entries[i])
+ OVR_FREE(entries[i]);}
+
+ OVR_FREE(names);
+ OVR_FREE(entries);
+ return 0;
+ }
+
+ // Compose the output:
+ *out = '{';
+ ptr = out+1;
+ if (fmt)
+ *ptr++='\n';
+ *ptr = 0;
+
+ for (i=0; i<numentries; i++)
+ {
+ if (fmt)
+ {
+ for (j=0; j<depth; j++)
+ *ptr++ = '\t';
+ }
+ OVR_strcpy(ptr, len - (ptr-out), names[i]);
+ ptr += OVR_strlen(names[i]);
+ *ptr++ =':';
+
+ if (fmt)
+ *ptr++='\t';
+
+ OVR_strcpy(ptr, len - (ptr-out), entries[i]);
+ ptr+=OVR_strlen(entries[i]);
+
+ if (i!=numentries-1)
+ *ptr++ = ',';
+
+ if (fmt)
+ *ptr++ = '\n';
+ *ptr = 0;
+
+ OVR_FREE(names[i]);
+ OVR_FREE(entries[i]);
+ }
+
+ OVR_FREE(names);
+ OVR_FREE(entries);
+
+ if (fmt)
+ {
+ for (i=0;i<depth-1;i++)
+ *ptr++='\t';
+ }
+ *ptr++='}';
+ *ptr++=0;
+
+ return out;
+}
+
+
+
+// Returns the number of child items in the object
+// Counts the number of items in the object.
+unsigned JSON::GetItemCount() const
+{
+ unsigned count = 0;
+ for(const JSON* p = Children.GetFirst(); !Children.IsNull(p); p = p->pNext)
+ count++;
+ return count;
+}
+
+JSON* JSON::GetItemByIndex(unsigned index)
+{
+ unsigned i = 0;
+ JSON* child = 0;
+
+ if (!Children.IsEmpty())
+ {
+ child = Children.GetFirst();
+
+ while (i < index)
+ {
+ if (Children.IsNull(child->pNext))
+ {
+ child = 0;
+ break;
+ }
+ child = child->pNext;
+ i++;
+ }
+ }
+
+ return child;
+}
+
+// Returns the child item with the given name or NULL if not found
+JSON* JSON::GetItemByName(const char* name)
+{
+ JSON* child = 0;
+
+ if (!Children.IsEmpty())
+ {
+ child = Children.GetFirst();
+
+ while (OVR_strcmp(child->Name, name) != 0)
+ {
+ if (Children.IsNull(child->pNext))
+ {
+ child = 0;
+ break;
+ }
+ child = child->pNext;
+ }
+ }
+
+ return child;
+}
+
+//-----------------------------------------------------------------------------
+// Adds a new item to the end of the child list
+void JSON::AddItem(const char *string, JSON *item)
+{
+ if (!item)
+ return;
+
+ item->Name = string;
+ Children.PushBack(item);
+}
+
+/*
+
+// Removes and frees the items at the given index
+void JSON::DeleteItem(unsigned int index)
+{
+ unsigned int num_items = 0;
+ JSON* child = Children.GetFirst();
+ while (!Children.IsNull(child) && num_items < index)
+ {
+ num_items++;
+ child = Children.GetNext(child);
+ }
+
+ if (!Children.IsNull(child))
+
+ child->RemoveNode();
+ child->Release();
+ }
+}
+
+// Replaces and frees the item at the give index with the new item
+void JSON::ReplaceItem(unsigned int index, JSON* new_item)
+{
+ unsigned int num_items = 0;
+ JSON* child = Children.GetFirst();
+ while (!Children.IsNull(child) && num_items < index)
+ {
+ num_items++;
+ child = Children.GetNext(child);
+ }
+
+ if (!Children.IsNull(child))
+ {
+ child->ReplaceNodeWith(new_item);
+ child->Release();
+ }
+}
+*/
+
+// Removes and frees the last child item
+void JSON::RemoveLast()
+{
+ JSON* child = Children.GetLast();
+ if (!Children.IsNull(child))
+ {
+ child->RemoveNode();
+ child->Release();
+ }
+}
+
+// Helper function to simplify creation of a typed object
+JSON* JSON::createHelper(JSONItemType itemType, double dval, const char* strVal)
+{
+ JSON *item = new JSON(itemType);
+ if (item)
+ {
+ item->dValue = dval;
+ if (strVal)
+ item->Value = strVal;
+ }
+ return item;
+}
+
+//-----------------------------------------------------------------------------
+// Get elements by name
+double JSON::GetNumberByName(const char *name, double defValue)
+{
+ JSON* item = GetItemByName(name);
+ if (!item || item->Type != JSON_Number) {
+ return defValue;
+ }
+ else {
+ return item->dValue;
+ }
+}
+
+int JSON::GetIntByName(const char *name, int defValue)
+{
+ JSON* item = GetItemByName(name);
+ if (!item || item->Type != JSON_Number) {
+ return defValue;
+ }
+ else {
+ return (int)item->dValue;
+ }
+}
+
+bool JSON::GetBoolByName(const char *name, bool defValue)
+{
+ JSON* item = GetItemByName(name);
+ if (!item || item->Type != JSON_Bool) {
+ return defValue;
+ }
+ else {
+ return (int)item->dValue != 0;
+ }
+}
+
+String JSON::GetStringByName(const char *name, const String &defValue)
+{
+ JSON* item = GetItemByName(name);
+ if (!item || item->Type != JSON_String) {
+ return defValue;
+ }
+ else {
+ return item->Value;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Adds an element to an array object type
+void JSON::AddArrayElement(JSON *item)
+{
+ if (!item)
+ return;
+
+ Children.PushBack(item);
+}
+
+// Inserts an element into a valid array position
+void JSON::InsertArrayElement(int index, JSON *item)
+{
+ if (!item)
+ return;
+
+ if (index == 0)
+ {
+ Children.PushFront(item);
+ return;
+ }
+
+ JSON* iter = Children.GetFirst();
+ int i=0;
+ while (iter && i<index)
+ {
+ iter = Children.GetNext(iter);
+ i++;
+ }
+
+ if (iter)
+ iter->InsertNodeBefore(item);
+ else
+ Children.PushBack(item);
+}
+
+// Returns the size of an array
+int JSON::GetArraySize()
+{
+ if (Type == JSON_Array)
+ return GetItemCount();
+ else
+ return 0;
+}
+
+// Returns the number value an the give array index
+double JSON::GetArrayNumber(int index)
+{
+ if (Type == JSON_Array)
+ {
+ JSON* number = GetItemByIndex(index);
+ return number ? number->dValue : 0.0;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Returns the string value at the given array index
+const char* JSON::GetArrayString(int index)
+{
+ if (Type == JSON_Array)
+ {
+ JSON* number = GetItemByIndex(index);
+ return number ? number->Value : 0;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+JSON* JSON::Copy()
+{
+ JSON* copy = new JSON(Type);
+ copy->Name = Name;
+ copy->Value = Value;
+ copy->dValue = dValue;
+
+ JSON* child = Children.GetFirst();
+ while (!Children.IsNull(child))
+ {
+ copy->Children.PushBack(child->Copy());
+ child = Children.GetNext(child);
+ }
+
+ return copy;
+}
+
+//-----------------------------------------------------------------------------
+// Loads and parses the given JSON file pathname and returns a JSON object tree.
+// The returned object must be Released after use.
+JSON* JSON::Load(const char* path, const char** perror)
+{
+ SysFile f;
+ if (!f.Open(path, File::Open_Read, File::Mode_Read))
+ {
+ AssignError(perror, "Failed to open file");
+ return NULL;
+ }
+
+ int len = f.GetLength();
+ UByte* buff = (UByte*)OVR_ALLOC(len + 1);
+ int bytes = f.Read(buff, len);
+ f.Close();
+
+ if (bytes == 0 || bytes != len)
+ {
+ OVR_FREE(buff);
+ return NULL;
+ }
+
+ // Ensure the result is null-terminated since Parse() expects null-terminated input.
+ buff[len] = '\0';
+
+ JSON* json = JSON::Parse((char*)buff, perror);
+ OVR_FREE(buff);
+ return json;
+}
+
+//-----------------------------------------------------------------------------
+// Serializes the JSON object and writes to the give file path
+bool JSON::Save(const char* path)
+{
+ SysFile f;
+ if (!f.Open(path, File::Open_Write | File::Open_Create | File::Open_Truncate, File::Mode_Write))
+ return false;
+
+ char* text = PrintValue(0, true);
+ if (text)
+ {
+ SPInt len = OVR_strlen(text);
+ OVR_ASSERT(len <= (SPInt)(int)len);
+
+ int bytes = f.Write((UByte*)text, (int)len);
+ f.Close();
+ OVR_FREE(text);
+ return (bytes == len);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+}