diff options
Diffstat (limited to 'ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_JSON.cpp')
-rw-r--r-- | ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_JSON.cpp | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_JSON.cpp b/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_JSON.cpp new file mode 100644 index 0000000..b52b75f --- /dev/null +++ b/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_JSON.cpp @@ -0,0 +1,1202 @@ +/************************************************************************************ + +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 (c) Facebook Technologies, LLC and its affiliates. All rights reserved. + +Licensed under the Oculus Master SDK License Version 1.0 (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 + +https://developer.oculus.com/licenses/oculusmastersdk-1.0 + +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 "OVR_JSON.h" +#include <ctype.h> +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "OVR_SysFile.h" + +namespace OVR { + +//----------------------------------------------------------------------------- +// Create a new copy of a string +static char* JSON_strdup(const char* str) { + size_t 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* PrintInt(int valueint) { + char* str; + str = (char*)OVR_ALLOC(21); // 2^64+1 can be represented in 21 chars. + if (str) { + snprintf(str, 21, "%d", valueint); + } + return str; +} + +//----------------------------------------------------------------------------- +// Render the number from the given item into a string. +static char* PrintNumber(double d) { + char* str; + int valueint = (int)d; + + if ((fabs(((double)valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) { + return PrintInt(valueint); + } else { + const size_t kCapacity = 64; + + str = (char*)OVR_ALLOC(kCapacity); // This is a nice tradeoff. + if (str) { + // The JSON Standard, section 7.8.3, specifies that decimals are always expressed with '.' and + // not some locale-specific decimal such as ',' or ' '. However, since we are using the C + // standard + // library below to write a floating point number, we need to make sure that it's writing a + // '.' + // and not something else. We can't change the locale (even temporarily) here, as it will + // affect + // the whole process by default. That are compiler-specific ways to change this per-thread, + // but + // below we implement the simple solution of simply fixing the decimal after the string was + // written. + + if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) { + // Write integral values with no decimals + snprintf(str, kCapacity, "%.0f", d); + } else if ((fabs(d) < 1.0) || (fabs(d) > 1.0e9)) { + // Write numbers < 1 or larger than 1e9 with 7 significant digits + snprintf(str, kCapacity, "%.7g", d); + } else { + // Write numbers >= 1 and <= 1e9 with 6 decimals (7 to 15 sig digits) + snprintf(str, kCapacity, "%.6f", d); + } + + // Convert any found ',' or ''' char to '.'. This will happen only if the locale was set to + // write a ',' + // instead of a '.' for the decimal point. Decimal points are represented only by one of these + // three characters in practice. + for (char* p = str; *p; p++) { + if ((*p == ',') || (*p == '\'')) { + *p = '.'; + break; + } + } + } + } + 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.) {} + +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, scale = 0; + int subscale = 0, signsubscale = 1; + bool positiveSign = true; + const char decimalSeparator = + '.'; // The JSON standard specifies that numbers use '.' regardless of locale. + + // Could use sscanf for this? + if (*num == '-') { + positiveSign = false; + 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 == decimalSeparator) && 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 *= pow(10.0, (scale + subscale * signsubscale)); + + if (!positiveSign) { + n = -n; + } + + // 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; + // no break, fall through + case 3: + *--ptr2 = ((uc | 0x80) & 0xBF); + uc >>= 6; + // no break + case 2: + *--ptr2 = ((uc | 0x80) & 0xBF); + uc >>= 6; + // no break + case 1: + *--ptr2 = (char)(uc | firstByteMark[len]); + // no break + } + 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: + snprintf(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 (!OVR_strncmp(buff, "null", 4)) { + Type = JSON_Null; + return buff + 4; + } + if (!OVR_strncmp(buff, "false", 5)) { + Type = JSON_Bool; + Value = "false"; + dValue = 0.; + return buff + 5; + } + if (!OVR_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 ((int)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_FAIL(); + 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; + intptr_t 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; + intptr_t 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 + 4 : 4); + if (!out) + return 0; + ptr = out; + *ptr++ = '{'; + + if (fmt) { +#ifdef OVR_OS_WIN32 + *ptr++ = '\r'; +#endif + *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 ? 3 + 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) { +#ifdef OVR_OS_WIN32 + *ptr++ = '\r'; +#endif + *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) { +#ifdef OVR_OS_WIN32 + *ptr++ = '\r'; +#endif + *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 = Children.GetNext(p)) { + 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.IsLast(child)) { + child = 0; + break; + } + child = child->GetNext(); + 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.IsLast(child)) { + child = 0; + break; + } + child = child->GetNext(); + } + } + + return child; +} + +//----------------------------------------------------------------------------- +// Adds a new item to the end of the child list +void JSON::AddItem(const char* string, JSON* item) { + if (item) { + 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(); + } +} + +JSON* JSON::CreateBool(bool b) { + JSON* item = new JSON(JSON_Bool); + if (item) { + item->dValue = b ? 1. : 0.; + item->Value = b ? "true" : "false"; + } + return item; +} + +JSON* JSON::CreateNumber(double num) { + JSON* item = new JSON(JSON_Number); + if (item) { + item->dValue = num; + } + return item; +} + +JSON* JSON::CreateInt(int num) { + JSON* item = new JSON(JSON_Number); + if (item) { + item->dValue = num; + } + return item; +} + +JSON* JSON::CreateString(const char* s) { + JSON* item = new JSON(JSON_String); + if (item && s) { + item->Value = s; + } + 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) { + 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(); + } + + 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; + } + + 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; + } + + 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; +} + +char* JSON::PrintValue(bool fmt) { + return PrintValue(0, fmt); +} + +//----------------------------------------------------------------------------- +// 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(); + uint8_t* buff = (uint8_t*)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) { + intptr_t len = OVR_strlen(text); + OVR_ASSERT(len <= (intptr_t)(int)len); + + int bytes = f.Write((uint8_t*)text, (int)len); + f.Close(); + OVR_FREE(text); + return (bytes == len); + } else { + return false; + } +} + +//----------------------------------------------------------------------------- +// Serializes the JSON object to a String +String JSON::Stringify(bool fmt) { + char* text = PrintValue(0, fmt); + String copy(text); + OVR_FREE(text); + return copy; +} + +} // namespace OVR |