From 8768290e05cf27d6d291639fb64e636363ddbb67 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Mon, 19 Nov 2012 14:43:17 +0000 Subject: tabs and spaces cleaning git-svn-id: http://svn.miranda-ng.org/main/trunk@2374 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/modules/json/JSON_Base64.cpp | 272 ++++---- src/modules/json/JSON_Base64.h | 28 +- src/modules/json/internalJSONNode.cpp | 1140 ++++++++++++++++----------------- src/modules/json/internalJSONNode.h | 905 +++++++++++++------------- 4 files changed, 1170 insertions(+), 1175 deletions(-) (limited to 'src/modules/json') diff --git a/src/modules/json/JSON_Base64.cpp b/src/modules/json/JSON_Base64.cpp index 07147afadc..66f2002b6b 100644 --- a/src/modules/json/JSON_Base64.cpp +++ b/src/modules/json/JSON_Base64.cpp @@ -1,136 +1,136 @@ -/* - -Miranda IM: the free IM client for Microsoft* Windows* - -Copyright 2000-2009 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\..\core\commonheaders.h" - -#include "JSON_Base64.h" -#include "JSONDefs.h" - -#ifdef JSON_BINARY //if this is not needed, don't waste space compiling it - -static const json_char * chars64 = JSON_TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); -#ifdef JSON_UNICODE - static std::string BASE64_EMPTY_STRING; -#else - #define BASE64_EMPTY_STRING EMPTY_STRING -#endif - -json_string JSONBase64::json_encode64(const unsigned char * binary, size_t bytes){ - size_t misaligned = bytes % 3; - size_t aligned = (bytes - misaligned) / 3; //divide by three once and inc is faster than add 3 each time - json_string result; - result.reserve((size_t)(((float)bytes) * 1.37f) + 4); - - //do all of the ones that are 3 byte aligned - for (size_t i=0; i < aligned; ++i){ - result += chars64[(binary[0] & 0xFC) >> 2]; - result += chars64[((binary[0] & 0x03) << 4) + ((binary[1] & 0xF0) >> 4)]; - result += chars64[((binary[1] & 0x0F) << 2) + ((binary[2] & 0xC0) >> 6)]; - result += chars64[binary[2] & 0x3F]; - binary += 3; - } - - if (misaligned){ - //copy the rest into a temporary buffer - unsigned char temp[3]; - for (unsigned int i=0; i < misaligned; ++i){ - temp[i] = *binary++; - } - for (unsigned int i = (unsigned int)misaligned; i < 3; ++i){ - temp[i] = '\0'; - } - - //now do the final three bytes - result += chars64[(temp[0] & 0xFC) >> 2]; - result += chars64[((temp[0] & 0x03) << 4) + ((temp[1] & 0xF0) >> 4)]; - if (misaligned == 2){ - result += chars64[((temp[1] & 0x0F) << 2) + ((temp[2] & 0xC0) >> 6)]; - result += JSON_TEXT('='); - } else { - result += JSON_TEXT(" = = "); - } - } - JSON_ASSERT((size_t)(((float)bytes) * 1.37f) + 4 >= result.length(), JSON_TEXT("Didn't reserve enough space for a one-time go")); - return result; -} - -inline json_char toBinary(json_char c){ - if (c == JSON_TEXT('+')) { - return JSON_TEXT('>'); - } else if (c == JSON_TEXT('/')) { - return JSON_TEXT('?'); - } else if (c < JSON_TEXT(':')) { - return c + JSON_TEXT('\x04'); - } else if (c < JSON_TEXT('[')) { - return c - JSON_TEXT('\x41'); - } - return c - 71; -} - -/* - Must be a std::string because it's binary, and chars must be 1 byte - */ -std::string JSONBase64::json_decode64(const json_string & encoded){ - const size_t length = encoded.length(); - #if defined JSON_DEBUG || defined JSON_SAFE - size_t pos = encoded.find_first_not_of(chars64); - if (pos != json_string::npos){ - JSON_ASSERT_SAFE(encoded[pos] == JSON_TEXT('='), JSON_TEXT("Not Base64"), return BASE64_EMPTY_STRING;); - if (pos != length - 1){ - JSON_ASSERT_SAFE(pos == length - 2, JSON_TEXT("Not Base64"), return BASE64_EMPTY_STRING;); - JSON_ASSERT_SAFE(encoded[pos + 1] == JSON_TEXT('='), JSON_TEXT("Not Base64"), return BASE64_EMPTY_STRING;); - } - } - #endif - const json_char * runner = encoded.c_str(); - size_t aligned = length / 4; //don't do the last ones as they might be = padding - std::string result; - if (aligned){ - --aligned; - result.reserve((size_t)((float)length / 1.37) + 1); - - //first do the ones that can not have any padding - for (unsigned int i=0; i < aligned; ++i){ - const json_char second = toBinary(runner[1]); - const json_char third = toBinary(runner[2]); - result += (toBinary(runner[0]) << 2) + ((second & 0x30) >> 4); - result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2); - result += ((third & 0x3) << 6) + toBinary(runner[3]); - runner += 4; - } - - //now do the ones that might have padding, the first two characters can not be padding, so do them quickly - const char second = toBinary(runner[1]); - result += (toBinary(runner[0]) << 2) + ((second & 0x30) >> 4); - if (runner[2] != '=') { //not two = pads - const char third = toBinary(runner[2]); - result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2); - if (runner[3] != '=') { //no padding - result += ((third & 0x3) << 6) + toBinary(runner[3]); - } - } - } - return result; -} - -#endif +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\..\core\commonheaders.h" + +#include "JSON_Base64.h" +#include "JSONDefs.h" + +#ifdef JSON_BINARY //if this is not needed, don't waste space compiling it + +static const json_char * chars64 = JSON_TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); +#ifdef JSON_UNICODE + static std::string BASE64_EMPTY_STRING; +#else + #define BASE64_EMPTY_STRING EMPTY_STRING +#endif + +json_string JSONBase64::json_encode64(const unsigned char * binary, size_t bytes){ + size_t misaligned = bytes % 3; + size_t aligned = (bytes - misaligned) / 3; //divide by three once and inc is faster than add 3 each time + json_string result; + result.reserve((size_t)(((float)bytes) * 1.37f) + 4); + + //do all of the ones that are 3 byte aligned + for (size_t i=0; i < aligned; ++i){ + result += chars64[(binary[0] & 0xFC) >> 2]; + result += chars64[((binary[0] & 0x03) << 4) + ((binary[1] & 0xF0) >> 4)]; + result += chars64[((binary[1] & 0x0F) << 2) + ((binary[2] & 0xC0) >> 6)]; + result += chars64[binary[2] & 0x3F]; + binary += 3; + } + + if (misaligned){ + //copy the rest into a temporary buffer + unsigned char temp[3]; + for (unsigned int i=0; i < misaligned; ++i){ + temp[i] = *binary++; + } + for (unsigned int i = (unsigned int)misaligned; i < 3; ++i){ + temp[i] = '\0'; + } + + //now do the final three bytes + result += chars64[(temp[0] & 0xFC) >> 2]; + result += chars64[((temp[0] & 0x03) << 4) + ((temp[1] & 0xF0) >> 4)]; + if (misaligned == 2){ + result += chars64[((temp[1] & 0x0F) << 2) + ((temp[2] & 0xC0) >> 6)]; + result += JSON_TEXT('='); + } else { + result += JSON_TEXT(" = = "); + } + } + JSON_ASSERT((size_t)(((float)bytes) * 1.37f) + 4 >= result.length(), JSON_TEXT("Didn't reserve enough space for a one-time go")); + return result; +} + +inline json_char toBinary(json_char c){ + if (c == JSON_TEXT('+')) { + return JSON_TEXT('>'); + } else if (c == JSON_TEXT('/')) { + return JSON_TEXT('?'); + } else if (c < JSON_TEXT(':')) { + return c + JSON_TEXT('\x04'); + } else if (c < JSON_TEXT('[')) { + return c - JSON_TEXT('\x41'); + } + return c - 71; +} + +/* + Must be a std::string because it's binary, and chars must be 1 byte + */ +std::string JSONBase64::json_decode64(const json_string & encoded){ + const size_t length = encoded.length(); + #if defined JSON_DEBUG || defined JSON_SAFE + size_t pos = encoded.find_first_not_of(chars64); + if (pos != json_string::npos){ + JSON_ASSERT_SAFE(encoded[pos] == JSON_TEXT('='), JSON_TEXT("Not Base64"), return BASE64_EMPTY_STRING;); + if (pos != length - 1){ + JSON_ASSERT_SAFE(pos == length - 2, JSON_TEXT("Not Base64"), return BASE64_EMPTY_STRING;); + JSON_ASSERT_SAFE(encoded[pos + 1] == JSON_TEXT('='), JSON_TEXT("Not Base64"), return BASE64_EMPTY_STRING;); + } + } + #endif + const json_char * runner = encoded.c_str(); + size_t aligned = length / 4; //don't do the last ones as they might be = padding + std::string result; + if (aligned){ + --aligned; + result.reserve((size_t)((float)length / 1.37) + 1); + + //first do the ones that can not have any padding + for (unsigned int i=0; i < aligned; ++i){ + const json_char second = toBinary(runner[1]); + const json_char third = toBinary(runner[2]); + result += (toBinary(runner[0]) << 2) + ((second & 0x30) >> 4); + result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2); + result += ((third & 0x3) << 6) + toBinary(runner[3]); + runner += 4; + } + + //now do the ones that might have padding, the first two characters can not be padding, so do them quickly + const char second = toBinary(runner[1]); + result += (toBinary(runner[0]) << 2) + ((second & 0x30) >> 4); + if (runner[2] != '=') { //not two = pads + const char third = toBinary(runner[2]); + result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2); + if (runner[3] != '=') { //no padding + result += ((third & 0x3) << 6) + toBinary(runner[3]); + } + } + } + return result; +} + +#endif diff --git a/src/modules/json/JSON_Base64.h b/src/modules/json/JSON_Base64.h index 1e2d76baa8..6c14aeb866 100644 --- a/src/modules/json/JSON_Base64.h +++ b/src/modules/json/JSON_Base64.h @@ -1,14 +1,14 @@ -#ifndef JSON_BASE64_H -#define JSON_BASE64_H - -#include "JSONDebug.h" -#ifdef JSON_BINARY //if this is not needed, don't waste space compiling it - -class JSONBase64 { -public: - static json_string json_encode64(const unsigned char * binary, size_t bytes); - static std::string json_decode64(const json_string & encoded); -}; - -#endif -#endif +#ifndef JSON_BASE64_H +#define JSON_BASE64_H + +#include "JSONDebug.h" +#ifdef JSON_BINARY //if this is not needed, don't waste space compiling it + +class JSONBase64 { +public: + static json_string json_encode64(const unsigned char * binary, size_t bytes); + static std::string json_decode64(const json_string & encoded); +}; + +#endif +#endif diff --git a/src/modules/json/internalJSONNode.cpp b/src/modules/json/internalJSONNode.cpp index dfe4971827..3137c70b85 100644 --- a/src/modules/json/internalJSONNode.cpp +++ b/src/modules/json/internalJSONNode.cpp @@ -1,572 +1,568 @@ -/* - -Miranda IM: the free IM client for Microsoft* Windows* - -Copyright 2000-2009 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\..\core\commonheaders.h" -#include - -#include "libJSON.h" -#include "internalJSONNode.h" -#include "NumberToString.h" //So that I can convert numbers into strings -#include "JSONNode.h" //To fill in the foreward declaration -#include "JSONWorker.h" //For fetching and parsing and such - -/* - The point of these constants is for faster assigning, if I - were to constantly assign to a string literal, there would be - lots of copies, but since strings are copy on write, this assignment - is much faster -*/ -static const json_string CONST_TRUE(JSON_TEXT("true")); -static const json_string CONST_FALSE(JSON_TEXT("false")); -static const json_string CONST_NULL(JSON_TEXT("null")); - -#ifdef JSON_UNIT_TEST - void internalJSONNode::incinternalAllocCount(void){ JSONNode::incinternalAllocCount(); } - void internalJSONNode::decinternalAllocCount(void){ JSONNode::decinternalAllocCount(); } -#endif - -internalJSONNode::internalJSONNode(const internalJSONNode & orig) : - _type(orig._type), _name(orig._name), _name_encoded(orig._name_encoded), Children(), - _string(orig._string), _string_encoded(orig._string_encoded), _value(orig._value) - initializeRefCount(1) - initializeFetch(orig.fetched) - initializeMutex(0) - initializeComment(orig._comment) - initializeValid(orig.isValid){ - - - incinternalAllocCount(); - #ifdef JSON_MUTEX_CALLBACKS - _set_mutex(orig.mylock, false); - #endif - if (!orig.Children.empty()) { - Children.reserve(orig.Children.size()); - json_foreach(orig.Children, myrunner){ - Children.push_back(JSONNode::newJSONNode((*myrunner) -> duplicate())); - } - } -} - -#ifdef JSON_PREPARSE - #define SetFetchedFalseOrDo(code) code -#else - #define SetFetchedFalseOrDo(code) SetFetched(false) -#endif - -#ifdef JSON_VALIDATE - #define NOTVALID false -#else - #define NOTVALID -#endif - -//this one is specialized because the root can only be array or node -internalJSONNode::internalJSONNode(const json_string & unparsed) : _type(), _name(),_name_encoded(false), _string(unparsed), _string_encoded(), _value(), Children() - initializeMutex(0) - initializeRefCount(1) - initializeFetch(false) - initializeComment(0) - initializeValid(0){ - - incinternalAllocCount(); - switch (unparsed[0]) { - case JSON_TEXT('{'): //node - _type = JSON_NODE; - #ifdef JSON_PREPARSE - FetchNode(); - #endif - break; - case JSON_TEXT('['): //array - _type = JSON_ARRAY; - #ifdef JSON_PREPARSE - FetchArray(); - #endif - break; - default: - JSON_FAIL_SAFE(JSON_TEXT("root not starting with either { or ["), Nullify(NOTVALID);); - break; - } -} - -internalJSONNode::internalJSONNode(const json_string & name_t, const json_string & value_t) : _type(), _name_encoded(), _name(JSONWorker::FixString(name_t, NAME_ENCODED)), _string(), _string_encoded(), _value(), Children() - initializeMutex(0) - initializeRefCount(1) - initializeFetch(0) - initializeComment(0) - initializeValid(0){ - - incinternalAllocCount(); - - if (value_t.empty()) { - _type = JSON_NULL; - #ifdef JSON_VALIDATE - isValid = true; - #endif - SetFetched(true); - return; - } - - _string = value_t; - const json_char firstchar = value_t[0]; - #if defined JSON_DEBUG || defined JSON_SAFE - const json_char lastchar = value_t[value_t.length() - 1]; - #endif - - switch (firstchar){ - case JSON_TEXT('\"'): //a json_string literal, still escaped and with leading and trailing quotes - JSON_ASSERT_SAFE(lastchar == JSON_TEXT('\"'), JSON_TEXT("Unterminated quote"), Nullify(NOTVALID); return;); - _type = JSON_STRING; - SetFetchedFalseOrDo(FetchString()); - break; - case JSON_TEXT('{'): //a child node, or set of children - JSON_ASSERT_SAFE(lastchar == JSON_TEXT('}'), JSON_TEXT("Missing }"), Nullify(NOTVALID); return;); - _type = JSON_NODE; - SetFetchedFalseOrDo(FetchNode()); - break; - case JSON_TEXT('['): //an array - JSON_ASSERT_SAFE(lastchar == JSON_TEXT(']'), JSON_TEXT("Missing ]"), Nullify(NOTVALID); return;); - _type = JSON_ARRAY; - SetFetchedFalseOrDo(FetchArray()); - break; - case JSON_TEXT('t'): - JSON_ASSERT_SAFE(value_t == JSON_TEXT("true"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); - _value._bool = true; - _type = JSON_BOOL; - SetFetched(true); - break; - case JSON_TEXT('f'): - JSON_ASSERT_SAFE(value_t == JSON_TEXT("false"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); - _value._bool = false; - _type = JSON_BOOL; - SetFetched(true); - break; - case JSON_TEXT('n'): - JSON_ASSERT_SAFE(value_t == JSON_TEXT("null"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); - _type = JSON_NULL; - SetFetched(true); - #ifdef JSON_VALIDATE - isValid = true; - #endif - break; - default: - JSON_ASSERT_SAFE(value_t.find_first_not_of(JSON_TEXT("0123456789.e+-")) == json_string::npos, json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); - _type = JSON_NUMBER; - SetFetchedFalseOrDo(FetchNumber()); - break; - } -} - -internalJSONNode::~internalJSONNode(void){ - decinternalAllocCount(); - #ifdef JSON_MUTEX_CALLBACKS - _unset_mutex(); - #endif - //DO NOT delete the children! It automatically gets removed -} - -void internalJSONNode::FetchString(void) const { - JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON json_string type is empty?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't start with a quotation?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't end with a quotation?"), Nullify(NOTVALID); return;); - _string = JSONWorker::FixString(_string.substr(1, _string.length() - 2), STRING_ENCODED); -} - -void internalJSONNode::FetchNode(void) const { - JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('{'), JSON_TEXT("JSON node type doesn't start with a bracket?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('}'), JSON_TEXT("JSON node type doesn't end with a bracket?"), Nullify(NOTVALID); return;); - JSONWorker::DoNode(this, _string); - clearString(_string); -} - -void internalJSONNode::FetchArray(void) const { - JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('['), JSON_TEXT("JSON node type doesn't start with a square bracket?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT(']'), JSON_TEXT("JSON node type doesn't end with a square bracket?"), Nullify(NOTVALID); return;); - JSONWorker::DoArray(this, _string); - clearString(_string); -} - -void internalJSONNode::FetchNumber(void) const { - #ifdef JSON_UNICODE - { - const size_t len = _string.length(); - json_auto temp(len + 1); - wcstombs(temp.ptr, _string.c_str(), len); - temp.ptr[len] = '\0'; - _value._number = (json_number)atof(temp.ptr); - } - #else - _value._number = (json_number)atof(_string.c_str()); - #endif -} - -#ifndef JSON_PREPARSE - void internalJSONNode::Fetch(void) const { - if (fetched) return; - switch (type()) { - case JSON_STRING: - FetchString(); - break; - case JSON_NODE: - FetchNode(); - break; - case JSON_ARRAY: - FetchArray(); - break; - case JSON_NUMBER: - FetchNumber(); - break; - #if defined JSON_DEBUG || defined JSON_SAFE - default: - JSON_FAIL(JSON_TEXT("Fetching an unknown type")); - Nullify(NOTVALID); - #endif - } - fetched = true; - } -#endif - -void internalJSONNode::Set(const json_string & val){ - _type = JSON_STRING; - _string = val; - _string_encoded = true; - SetFetched(true); -} - - -#ifdef JSON_LIBRARY - void internalJSONNode::Set(long val){ - _type = JSON_NUMBER; - _value._number = (json_number)val; - _string = NumberToString::_itoa(val, sizeof(long)); - SetFetched(true); - } - - void internalJSONNode::Set(json_number val){ - _type = JSON_NUMBER; - _value._number = val; - _string = NumberToString::_ftoa(val); - SetFetched(true); - } -#else - #define SET(converter, type)\ - void internalJSONNode::Set(type val){\ - _type = JSON_NUMBER;\ - _value._number = (json_number)val;\ - _string = NumberToString::converter(val, sizeof(type));\ - SetFetched(true);\ - } - #define SET_INTEGER(type) SET(_itoa, type) SET(_uitoa, unsigned type) - #define SET_FLOAT(type) \ - void internalJSONNode::Set(type val){\ - _type = JSON_NUMBER;\ - _value._number = (json_number)val;\ - _string = NumberToString::_ftoa(val);\ - SetFetched(true);\ - } - - SET_INTEGER(char) - SET_INTEGER(short) - SET_INTEGER(int) - SET_INTEGER(long) - #ifndef JSON_ISO_STRICT - SET_INTEGER(long long) - #endif - - SET_FLOAT(float) - SET_FLOAT(double) -#endif - -void internalJSONNode::Set(bool val){ - _type = JSON_BOOL; - _value._bool = val; - _string = val ? CONST_TRUE : CONST_FALSE; - SetFetched(true); -} - -bool internalJSONNode::IsEqualTo(const internalJSONNode * val) const { - #ifdef JSON_REF_COUNT - if (this == val) return true; //reference counting the same internal object, so they must be equal - #endif - if (type() != val -> type()) return false; //aren't even same type - if (_name != val -> _name) return false; //names aren't the same - if (type() == JSON_NULL) return true; //both null, can't be different - #ifndef JSON_PREPARSE - Fetch(); - val -> Fetch(); - #endif - switch (type()) { - case JSON_STRING: - return val -> _string == _string; - case JSON_NUMBER: - return NumberToString::areEqual(val -> _value._number, _value._number); - case JSON_BOOL: - return val -> _value._bool == _value._bool; - }; - - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Checking for equality, not sure what type")); - if (Children.size() != val -> Children.size()) return false; //if they arne't he same size then they certainly aren't equal - - //make sure each children is the same - JSONNode ** valrunner = val -> Children.begin(); - json_foreach(Children, myrunner){ - JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); - JSON_ASSERT(*valrunner, JSON_TEXT("a null pointer within the children")); - JSON_ASSERT(valrunner != val -> Children.end(), JSON_TEXT("at the end of other one's children, but they're the same size?")); - if (**myrunner != **valrunner) return false; - ++valrunner; - } - return true; -} - -#ifdef JSON_VALIDATE -void internalJSONNode::Nullify(bool validation) const { - isValid = validation; -#else -void internalJSONNode::Nullify(void) const { -#endif - _type = JSON_NULL; - _string = CONST_NULL; - SetFetched(true); -} - -#ifdef JSON_MUTEX_CALLBACKS - #define JSON_MUTEX_COPY ,mylock -#else - #define JSON_MUTEX_COPY -#endif - -#ifdef JSON_LIBRARY -void internalJSONNode::push_back(JSONNode * node){ -#else -void internalJSONNode::push_back(const JSONNode & node){ -#endif - JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing back to something that is not an array or object")); - #ifdef JSON_LIBRARY - #ifdef JSON_MUTEX_CALLBACKS - if (mylock) node -> set_mutex(mylock); - #endif - Children.push_back(node); - #else - Children.push_back(JSONNode::newJSONNode(node JSON_MUTEX_COPY)); - #endif -} - -void internalJSONNode::push_front(const JSONNode & node){ - JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing front to something that is not an array or object")); - Children.push_front(JSONNode::newJSONNode(node JSON_MUTEX_COPY)); -} - -JSONNode * internalJSONNode::pop_back(json_index_t pos){ - JSONNode * result = Children[pos]; - JSONNode ** temp = Children.begin() + pos; - Children.erase(temp); - return result; -} - -JSONNode * internalJSONNode::pop_back(const json_string & name_t){ - if (JSONNode ** res = at(name_t)) { - JSONNode * result = *res; - Children.erase(res); - return result; - } - return 0; -} - -#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode * internalJSONNode::pop_back_nocase(const json_string & name_t){ - if (JSONNode ** res = at_nocase(name_t)) { - JSONNode * result = *res; - Children.erase(res); - return result; - } - return 0; - } -#endif - -JSONNode ** internalJSONNode::at(const json_string & name_t){ - Fetch(); - json_foreach(Children, myrunner){ - JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); - if ((*myrunner) -> name() == name_t) return myrunner; - } - return 0; -} - -#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - bool internalJSONNode::AreEqualNoCase(const json_char * ch_one, const json_char * ch_two){ - while (*ch_one){ //only need to check one, if the other one terminates early, the check will cause it to fail - const json_char c_one = *ch_one; - const json_char c_two = *ch_two; - if (c_one != c_two){ - if ((c_two > 64) && (c_two < 91)) { //A - Z - if (c_one != (json_char)(c_two + 32)) return false; - } else if ((c_two > 96) && (c_two < 123)) { //a - z - if (c_one != (json_char)(c_two - 32)) return false; - } else { //not a letter, so return false - return false; - } - } - ++ch_one; - ++ch_two; - - } - return *ch_two == '\0'; //this one has to be null terminated too, or else json_string two is longer, hence, not equal - } - - JSONNode ** internalJSONNode::at_nocase(const json_string & name_t){ - Fetch(); - json_foreach(Children, myrunner){ - JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); - if (AreEqualNoCase((*myrunner) -> name().c_str(), name_t.c_str())) return myrunner; - } - return 0; - } -#endif - -#ifndef JSON_PREPARSE - void internalJSONNode::preparse(void){ - Fetch(); - json_foreach(Children, myrunner){ - (*myrunner) -> preparse(); - } - } -#endif - -#ifdef JSON_VALIDATE - bool internalJSONNode::validate(void){ - json_foreach(Children, myrunner){ - if ((*myrunner) -> type() != JSON_NULL){ - #ifndef JSON_PREPARSE - (*myrunner) -> internal -> Fetch(); - #endif - if ((*myrunner) -> type() == JSON_NULL) return false; - } else if (!((*myrunner) -> internal -> isValid)) { - JSON_FAIL(_name + JSON_TEXT(" is null and not valid")); - return false; - } - } - json_foreach(Children, runner){ - if (!((*runner) -> internal -> validate())) return false; - } - return true; - } -#endif - -#ifdef JSON_DEBUG - #ifndef JSON_LIBRARY - JSONNode internalJSONNode::Dump(size_t & totalbytes) const { - JSONNode dumpage(JSON_NODE); - dumpage.set_name(JSON_TEXT("internalJSONNode")); - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); - - size_t memory = sizeof(internalJSONNode); - memory += _name.capacity() * sizeof(json_char); - memory += _string.capacity() * sizeof(json_char); - memory += Children.capacity() * sizeof(JSONNode*); - #ifdef JSON_COMMENTS - memory += _comment.capacity() * sizeof(json_char); - #endif - totalbytes += memory; - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), memory))); - - - #ifdef JSON_REF_COUNT - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("refcount"), refcount))); - #endif - #ifdef JSON_MUTEX_CALLBACKS - dumpage.push_back(JSON_NEW(DumpMutex())); - #endif - - - #define DUMPCASE(ty)\ - case ty:\ - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT(#ty))));\ - break; - - switch(type()) { - DUMPCASE(JSON_NULL) - DUMPCASE(JSON_STRING) - DUMPCASE(JSON_NUMBER) - DUMPCASE(JSON_BOOL) - DUMPCASE(JSON_ARRAY) - DUMPCASE(JSON_NODE) - default: - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT("Unknown")))); - } - - JSONNode str(JSON_NODE); - str.set_name(JSON_TEXT("_name")); - str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _name))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _name.length()))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _name.capacity()))); - - #ifdef JSON_LESS_MEMORY - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _type & 0x10))); - #else - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _name_encoded))); - #endif - dumpage.push_back(JSON_NEW(str)); - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_string_encoded"), _string_encoded))); - str.clear(); - str.set_name(JSON_TEXT("_string")); - str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _string))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _string.length()))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _string.capacity()))); - dumpage.push_back(JSON_NEW(str)); - - JSONNode unio(JSON_NODE); - unio.set_name(JSON_TEXT("_value")); - unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_bool"), _value._bool))); - unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_number"), _value._number))); - dumpage.push_back(JSON_NEW(unio)); - - #ifndef JSON_PREPARSE - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("fetched"), fetched))); - #endif - - #ifdef JSON_COMMENTS - str.clear(); - str.set_name(JSON_TEXT("_comment")); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("value"), _comment))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _comment.length()))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _comment.capacity()))); - dumpage.push_back(JSON_NEW(str)); - #endif - - JSONNode arra(JSON_NODE); - arra.set_name(JSON_TEXT("Children")); - arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("size"), Children.size()))); - arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("capacity"), Children.capacity()))); - JSONNode chil(JSON_ARRAY); - chil.set_name(JSON_TEXT("array")); - json_foreach(Children, it){ - chil.push_back(JSON_NEW((*it) -> dump(totalbytes))); - } - arra.push_back(JSON_NEW(chil)); - dumpage.push_back(JSON_NEW(arra)); - - return dumpage; - } - #endif -#endif +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\..\core\commonheaders.h" +#include + +#include "libJSON.h" +#include "internalJSONNode.h" +#include "NumberToString.h" //So that I can convert numbers into strings +#include "JSONNode.h" //To fill in the foreward declaration +#include "JSONWorker.h" //For fetching and parsing and such + +/* + The point of these constants is for faster assigning, if I + were to constantly assign to a string literal, there would be + lots of copies, but since strings are copy on write, this assignment + is much faster +*/ +static const json_string CONST_TRUE(JSON_TEXT("true")); +static const json_string CONST_FALSE(JSON_TEXT("false")); +static const json_string CONST_NULL(JSON_TEXT("null")); + +#ifdef JSON_UNIT_TEST + void internalJSONNode::incinternalAllocCount(void){ JSONNode::incinternalAllocCount(); } + void internalJSONNode::decinternalAllocCount(void){ JSONNode::decinternalAllocCount(); } +#endif + +internalJSONNode::internalJSONNode(const internalJSONNode & orig) : + _type(orig._type), _name(orig._name), _name_encoded(orig._name_encoded), Children(), + _string(orig._string), _string_encoded(orig._string_encoded), _value(orig._value) + initializeRefCount(1) + initializeFetch(orig.fetched) + initializeMutex(0) + initializeComment(orig._comment) + initializeValid(orig.isValid){ + + incinternalAllocCount(); + #ifdef JSON_MUTEX_CALLBACKS + _set_mutex(orig.mylock, false); + #endif + if (!orig.Children.empty()) { + Children.reserve(orig.Children.size()); + json_foreach(orig.Children, myrunner){ + Children.push_back(JSONNode::newJSONNode((*myrunner) -> duplicate())); + } + } +} + +#ifdef JSON_PREPARSE + #define SetFetchedFalseOrDo(code) code +#else + #define SetFetchedFalseOrDo(code) SetFetched(false) +#endif + +#ifdef JSON_VALIDATE + #define NOTVALID false +#else + #define NOTVALID +#endif + +//this one is specialized because the root can only be array or node +internalJSONNode::internalJSONNode(const json_string & unparsed) : _type(), _name(),_name_encoded(false), _string(unparsed), _string_encoded(), _value(), Children() + initializeMutex(0) + initializeRefCount(1) + initializeFetch(false) + initializeComment(0) + initializeValid(0){ + + incinternalAllocCount(); + switch (unparsed[0]) { + case JSON_TEXT('{'): //node + _type = JSON_NODE; + #ifdef JSON_PREPARSE + FetchNode(); + #endif + break; + case JSON_TEXT('['): //array + _type = JSON_ARRAY; + #ifdef JSON_PREPARSE + FetchArray(); + #endif + break; + default: + JSON_FAIL_SAFE(JSON_TEXT("root not starting with either { or ["), Nullify(NOTVALID);); + break; + } +} + +internalJSONNode::internalJSONNode(const json_string & name_t, const json_string & value_t) : _type(), _name_encoded(), _name(JSONWorker::FixString(name_t, NAME_ENCODED)), _string(), _string_encoded(), _value(), Children() + initializeMutex(0) + initializeRefCount(1) + initializeFetch(0) + initializeComment(0) + initializeValid(0){ + + incinternalAllocCount(); + + if (value_t.empty()) { + _type = JSON_NULL; + #ifdef JSON_VALIDATE + isValid = true; + #endif + SetFetched(true); + return; + } + + _string = value_t; + const json_char firstchar = value_t[0]; + #if defined JSON_DEBUG || defined JSON_SAFE + const json_char lastchar = value_t[value_t.length() - 1]; + #endif + + switch (firstchar){ + case JSON_TEXT('\"'): //a json_string literal, still escaped and with leading and trailing quotes + JSON_ASSERT_SAFE(lastchar == JSON_TEXT('\"'), JSON_TEXT("Unterminated quote"), Nullify(NOTVALID); return;); + _type = JSON_STRING; + SetFetchedFalseOrDo(FetchString()); + break; + case JSON_TEXT('{'): //a child node, or set of children + JSON_ASSERT_SAFE(lastchar == JSON_TEXT('}'), JSON_TEXT("Missing }"), Nullify(NOTVALID); return;); + _type = JSON_NODE; + SetFetchedFalseOrDo(FetchNode()); + break; + case JSON_TEXT('['): //an array + JSON_ASSERT_SAFE(lastchar == JSON_TEXT(']'), JSON_TEXT("Missing ]"), Nullify(NOTVALID); return;); + _type = JSON_ARRAY; + SetFetchedFalseOrDo(FetchArray()); + break; + case JSON_TEXT('t'): + JSON_ASSERT_SAFE(value_t == JSON_TEXT("true"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); + _value._bool = true; + _type = JSON_BOOL; + SetFetched(true); + break; + case JSON_TEXT('f'): + JSON_ASSERT_SAFE(value_t == JSON_TEXT("false"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); + _value._bool = false; + _type = JSON_BOOL; + SetFetched(true); + break; + case JSON_TEXT('n'): + JSON_ASSERT_SAFE(value_t == JSON_TEXT("null"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); + _type = JSON_NULL; + SetFetched(true); + #ifdef JSON_VALIDATE + isValid = true; + #endif + break; + default: + JSON_ASSERT_SAFE(value_t.find_first_not_of(JSON_TEXT("0123456789.e+-")) == json_string::npos, json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); + _type = JSON_NUMBER; + SetFetchedFalseOrDo(FetchNumber()); + break; + } +} + +internalJSONNode::~internalJSONNode(void){ + decinternalAllocCount(); + #ifdef JSON_MUTEX_CALLBACKS + _unset_mutex(); + #endif + //DO NOT delete the children! It automatically gets removed +} + +void internalJSONNode::FetchString(void) const { + JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON json_string type is empty?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't start with a quotation?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't end with a quotation?"), Nullify(NOTVALID); return;); + _string = JSONWorker::FixString(_string.substr(1, _string.length() - 2), STRING_ENCODED); +} + +void internalJSONNode::FetchNode(void) const { + JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('{'), JSON_TEXT("JSON node type doesn't start with a bracket?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('}'), JSON_TEXT("JSON node type doesn't end with a bracket?"), Nullify(NOTVALID); return;); + JSONWorker::DoNode(this, _string); + clearString(_string); +} + +void internalJSONNode::FetchArray(void) const { + JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('['), JSON_TEXT("JSON node type doesn't start with a square bracket?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT(']'), JSON_TEXT("JSON node type doesn't end with a square bracket?"), Nullify(NOTVALID); return;); + JSONWorker::DoArray(this, _string); + clearString(_string); +} + +void internalJSONNode::FetchNumber(void) const { + #ifdef JSON_UNICODE + { + const size_t len = _string.length(); + json_auto temp(len + 1); + wcstombs(temp.ptr, _string.c_str(), len); + temp.ptr[len] = '\0'; + _value._number = (json_number)atof(temp.ptr); + } + #else + _value._number = (json_number)atof(_string.c_str()); + #endif +} + +#ifndef JSON_PREPARSE + void internalJSONNode::Fetch(void) const { + if (fetched) return; + switch (type()) { + case JSON_STRING: + FetchString(); + break; + case JSON_NODE: + FetchNode(); + break; + case JSON_ARRAY: + FetchArray(); + break; + case JSON_NUMBER: + FetchNumber(); + break; + #if defined JSON_DEBUG || defined JSON_SAFE + default: + JSON_FAIL(JSON_TEXT("Fetching an unknown type")); + Nullify(NOTVALID); + #endif + } + fetched = true; + } +#endif + +void internalJSONNode::Set(const json_string & val){ + _type = JSON_STRING; + _string = val; + _string_encoded = true; + SetFetched(true); +} + +#ifdef JSON_LIBRARY + void internalJSONNode::Set(long val){ + _type = JSON_NUMBER; + _value._number = (json_number)val; + _string = NumberToString::_itoa(val, sizeof(long)); + SetFetched(true); + } + + void internalJSONNode::Set(json_number val){ + _type = JSON_NUMBER; + _value._number = val; + _string = NumberToString::_ftoa(val); + SetFetched(true); + } +#else + #define SET(converter, type)\ + void internalJSONNode::Set(type val){\ + _type = JSON_NUMBER;\ + _value._number = (json_number)val;\ + _string = NumberToString::converter(val, sizeof(type));\ + SetFetched(true);\ + } + #define SET_INTEGER(type) SET(_itoa, type) SET(_uitoa, unsigned type) + #define SET_FLOAT(type) \ + void internalJSONNode::Set(type val){\ + _type = JSON_NUMBER;\ + _value._number = (json_number)val;\ + _string = NumberToString::_ftoa(val);\ + SetFetched(true);\ + } + + SET_INTEGER(char) + SET_INTEGER(short) + SET_INTEGER(int) + SET_INTEGER(long) + #ifndef JSON_ISO_STRICT + SET_INTEGER(long long) + #endif + + SET_FLOAT(float) + SET_FLOAT(double) +#endif + +void internalJSONNode::Set(bool val){ + _type = JSON_BOOL; + _value._bool = val; + _string = val ? CONST_TRUE : CONST_FALSE; + SetFetched(true); +} + +bool internalJSONNode::IsEqualTo(const internalJSONNode * val) const { + #ifdef JSON_REF_COUNT + if (this == val) return true; //reference counting the same internal object, so they must be equal + #endif + if (type() != val -> type()) return false; //aren't even same type + if (_name != val -> _name) return false; //names aren't the same + if (type() == JSON_NULL) return true; //both null, can't be different + #ifndef JSON_PREPARSE + Fetch(); + val -> Fetch(); + #endif + switch (type()) { + case JSON_STRING: + return val -> _string == _string; + case JSON_NUMBER: + return NumberToString::areEqual(val -> _value._number, _value._number); + case JSON_BOOL: + return val -> _value._bool == _value._bool; + }; + + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Checking for equality, not sure what type")); + if (Children.size() != val -> Children.size()) return false; //if they arne't he same size then they certainly aren't equal + + //make sure each children is the same + JSONNode ** valrunner = val -> Children.begin(); + json_foreach(Children, myrunner){ + JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); + JSON_ASSERT(*valrunner, JSON_TEXT("a null pointer within the children")); + JSON_ASSERT(valrunner != val -> Children.end(), JSON_TEXT("at the end of other one's children, but they're the same size?")); + if (**myrunner != **valrunner) return false; + ++valrunner; + } + return true; +} + +#ifdef JSON_VALIDATE +void internalJSONNode::Nullify(bool validation) const { + isValid = validation; +#else +void internalJSONNode::Nullify(void) const { +#endif + _type = JSON_NULL; + _string = CONST_NULL; + SetFetched(true); +} + +#ifdef JSON_MUTEX_CALLBACKS + #define JSON_MUTEX_COPY ,mylock +#else + #define JSON_MUTEX_COPY +#endif + +#ifdef JSON_LIBRARY +void internalJSONNode::push_back(JSONNode * node){ +#else +void internalJSONNode::push_back(const JSONNode & node){ +#endif + JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing back to something that is not an array or object")); + #ifdef JSON_LIBRARY + #ifdef JSON_MUTEX_CALLBACKS + if (mylock) node -> set_mutex(mylock); + #endif + Children.push_back(node); + #else + Children.push_back(JSONNode::newJSONNode(node JSON_MUTEX_COPY)); + #endif +} + +void internalJSONNode::push_front(const JSONNode & node){ + JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing front to something that is not an array or object")); + Children.push_front(JSONNode::newJSONNode(node JSON_MUTEX_COPY)); +} + +JSONNode * internalJSONNode::pop_back(json_index_t pos){ + JSONNode * result = Children[pos]; + JSONNode ** temp = Children.begin() + pos; + Children.erase(temp); + return result; +} + +JSONNode * internalJSONNode::pop_back(const json_string & name_t){ + if (JSONNode ** res = at(name_t)) { + JSONNode * result = *res; + Children.erase(res); + return result; + } + return 0; +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode * internalJSONNode::pop_back_nocase(const json_string & name_t){ + if (JSONNode ** res = at_nocase(name_t)) { + JSONNode * result = *res; + Children.erase(res); + return result; + } + return 0; + } +#endif + +JSONNode ** internalJSONNode::at(const json_string & name_t){ + Fetch(); + json_foreach(Children, myrunner){ + JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); + if ((*myrunner) -> name() == name_t) return myrunner; + } + return 0; +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + bool internalJSONNode::AreEqualNoCase(const json_char * ch_one, const json_char * ch_two){ + while (*ch_one){ //only need to check one, if the other one terminates early, the check will cause it to fail + const json_char c_one = *ch_one; + const json_char c_two = *ch_two; + if (c_one != c_two){ + if ((c_two > 64) && (c_two < 91)) { //A - Z + if (c_one != (json_char)(c_two + 32)) return false; + } else if ((c_two > 96) && (c_two < 123)) { //a - z + if (c_one != (json_char)(c_two - 32)) return false; + } else { //not a letter, so return false + return false; + } + } + ++ch_one; + ++ch_two; + + } + return *ch_two == '\0'; //this one has to be null terminated too, or else json_string two is longer, hence, not equal + } + + JSONNode ** internalJSONNode::at_nocase(const json_string & name_t){ + Fetch(); + json_foreach(Children, myrunner){ + JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); + if (AreEqualNoCase((*myrunner) -> name().c_str(), name_t.c_str())) return myrunner; + } + return 0; + } +#endif + +#ifndef JSON_PREPARSE + void internalJSONNode::preparse(void){ + Fetch(); + json_foreach(Children, myrunner){ + (*myrunner) -> preparse(); + } + } +#endif + +#ifdef JSON_VALIDATE + bool internalJSONNode::validate(void){ + json_foreach(Children, myrunner){ + if ((*myrunner) -> type() != JSON_NULL){ + #ifndef JSON_PREPARSE + (*myrunner) -> internal -> Fetch(); + #endif + if ((*myrunner) -> type() == JSON_NULL) return false; + } else if (!((*myrunner) -> internal -> isValid)) { + JSON_FAIL(_name + JSON_TEXT(" is null and not valid")); + return false; + } + } + json_foreach(Children, runner){ + if (!((*runner) -> internal -> validate())) return false; + } + return true; + } +#endif + +#ifdef JSON_DEBUG + #ifndef JSON_LIBRARY + JSONNode internalJSONNode::Dump(size_t & totalbytes) const { + JSONNode dumpage(JSON_NODE); + dumpage.set_name(JSON_TEXT("internalJSONNode")); + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); + + size_t memory = sizeof(internalJSONNode); + memory += _name.capacity() * sizeof(json_char); + memory += _string.capacity() * sizeof(json_char); + memory += Children.capacity() * sizeof(JSONNode*); + #ifdef JSON_COMMENTS + memory += _comment.capacity() * sizeof(json_char); + #endif + totalbytes += memory; + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), memory))); + + #ifdef JSON_REF_COUNT + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("refcount"), refcount))); + #endif + #ifdef JSON_MUTEX_CALLBACKS + dumpage.push_back(JSON_NEW(DumpMutex())); + #endif + + #define DUMPCASE(ty)\ + case ty:\ + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT(#ty))));\ + break; + + switch(type()) { + DUMPCASE(JSON_NULL) + DUMPCASE(JSON_STRING) + DUMPCASE(JSON_NUMBER) + DUMPCASE(JSON_BOOL) + DUMPCASE(JSON_ARRAY) + DUMPCASE(JSON_NODE) + default: + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT("Unknown")))); + } + + JSONNode str(JSON_NODE); + str.set_name(JSON_TEXT("_name")); + str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _name))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _name.length()))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _name.capacity()))); + + #ifdef JSON_LESS_MEMORY + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _type & 0x10))); + #else + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _name_encoded))); + #endif + dumpage.push_back(JSON_NEW(str)); + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_string_encoded"), _string_encoded))); + str.clear(); + str.set_name(JSON_TEXT("_string")); + str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _string))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _string.length()))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _string.capacity()))); + dumpage.push_back(JSON_NEW(str)); + + JSONNode unio(JSON_NODE); + unio.set_name(JSON_TEXT("_value")); + unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_bool"), _value._bool))); + unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_number"), _value._number))); + dumpage.push_back(JSON_NEW(unio)); + + #ifndef JSON_PREPARSE + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("fetched"), fetched))); + #endif + + #ifdef JSON_COMMENTS + str.clear(); + str.set_name(JSON_TEXT("_comment")); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("value"), _comment))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _comment.length()))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _comment.capacity()))); + dumpage.push_back(JSON_NEW(str)); + #endif + + JSONNode arra(JSON_NODE); + arra.set_name(JSON_TEXT("Children")); + arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("size"), Children.size()))); + arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("capacity"), Children.capacity()))); + JSONNode chil(JSON_ARRAY); + chil.set_name(JSON_TEXT("array")); + json_foreach(Children, it){ + chil.push_back(JSON_NEW((*it) -> dump(totalbytes))); + } + arra.push_back(JSON_NEW(chil)); + dumpage.push_back(JSON_NEW(arra)); + + return dumpage; + } + #endif +#endif diff --git a/src/modules/json/internalJSONNode.h b/src/modules/json/internalJSONNode.h index 9e9f9de983..8832bbd828 100644 --- a/src/modules/json/internalJSONNode.h +++ b/src/modules/json/internalJSONNode.h @@ -1,453 +1,452 @@ -#ifndef INTERNAL_JSONNODE_H -#define INTERNAL_JSONNODE_H - -#include "JSONDebug.h" -#include "JSONChildren.h" -#include "JSONMemory.h" -#ifdef JSON_DEBUG - #include //to check int value -#endif - -/* - This class is the work horse of libJSON, it handles all of the - functinality of JSONNode. This object is reference counted for - speed and memory reasons. - - If JSON_REF_COUNT is not on, this internal structure still has an important - purpose, as it can be passed around by JSONNoders that are flagged as temporary -*/ - -class JSONNode; //forward declaration - -#ifndef JSON_LIBRARY - #define DECL_SET_INTEGER(type) void Set(type); void Set(unsigned type); -#endif - -#ifdef JSON_MUTEX_CALLBACKS - #define initializeMutex(x) ,mylock(x) -#else - #define initializeMutex(x) -#endif - -#ifdef JSON_PREPARSE - #define SetFetched(b) (void)0 - #define Fetch() (void)0 - #define initializeFetch(x) -#else - #define initializeFetch(x) ,fetched(x) -#endif - -#ifdef JSON_REF_COUNT - #define initializeRefCount(x) ,refcount(x) -#else - #define initializeRefCount(x) -#endif - -#ifdef JSON_COMMENTS - #define initializeComment(x) ,_comment(x) -#else - #define initializeComment(x) -#endif - -#ifndef JSON_UNIT_TEST - #define incAllocCount() (void)0 - #define decAllocCount() (void)0 - #define incinternalAllocCount() (void)0 - #define decinternalAllocCount() (void)0 -#endif - -#ifdef JSON_VALIDATE - #define initializeValid(x) ,isValid(x) -#else - #define initializeValid(x) -#endif - -class internalJSONNode { -public: - internalJSONNode(char mytype = JSON_NULL); - internalJSONNode(const json_string & unparsed); - internalJSONNode(const json_string & name_t, const json_string & value_t); - internalJSONNode(const internalJSONNode & orig); - internalJSONNode & operator = (const internalJSONNode &); - ~internalJSONNode(void); - - static internalJSONNode * newInternal(char mytype = JSON_NULL); - static internalJSONNode * newInternal(const json_string & unparsed); - static internalJSONNode * newInternal(const json_string & name_t, const json_string & value_t); - static internalJSONNode * newInternal(const internalJSONNode & orig); //not copyable, only by this class - static void deleteInternal(internalJSONNode * ptr); - - json_index_t size(void) const; - bool empty(void) const; - unsigned char type(void) const; - - json_string name(void) const; - void setname(const json_string & newname); - #ifdef JSON_COMMENTS - void setcomment(const json_string & comment); - json_string getcomment(void) const; - #endif - json_string as_string(void) const; - long as_int(void) const; - json_number as_float(void) const; - bool as_bool(void) const; - - #ifndef JSON_PREPARSE - void preparse(void); - #endif - - #ifdef JSON_LIBRARY - void push_back(JSONNode * node); - #else - void push_back(const JSONNode & node); - #endif - void reserve(json_index_t size); - void push_front(const JSONNode & node); - JSONNode * pop_back(json_index_t pos); - JSONNode * pop_back(const json_string & name_t); - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode * pop_back_nocase(const json_string & name_t); - #endif - - JSONNode * at(json_index_t pos); - //These return ** because pop_back needs them - JSONNode ** at(const json_string & name_t); - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode ** at_nocase(const json_string & name_t); - #endif - - void Set(const json_string & val); - #ifdef JSON_LIBRARY - void Set(json_number val); - void Set(long val); - #else - DECL_SET_INTEGER(char) - DECL_SET_INTEGER(short) - DECL_SET_INTEGER(int) - DECL_SET_INTEGER(long) - #ifndef JSON_ISO_STRICT - DECL_SET_INTEGER(long long) - #endif - - void Set(float val); - void Set(double val); - #endif - void Set(bool val); - - bool IsEqualTo(const json_string & val)const ; - bool IsEqualTo(bool val) const; - bool IsEqualTo(const internalJSONNode * val) const; - - template - bool IsEqualToNum(T val) const; - - internalJSONNode * incRef(void); - #ifdef JSON_REF_COUNT - void decRef(void); - bool hasNoReferences(void); - #endif - internalJSONNode * makeUnique(void); - - JSONNode ** begin(void) const; - JSONNode ** end(void) const; - #ifdef JSON_REF_COUNT - size_t refcount BITS(20); - #endif - bool Fetched(void) const; - #ifdef JSON_MUTEX_CALLBACKS - void * mylock; - void _set_mutex(void * mutex, bool unset = true); - void _unset_mutex(void); - #endif - #ifdef JSON_UNIT_TEST - static void incinternalAllocCount(void); - static void decinternalAllocCount(void); - #endif - - #ifdef JSON_WRITER - json_string WriteName(bool formatted, bool arrayChild) const; - json_string WriteChildren(unsigned int indent); - json_string WriteComment(unsigned int indent) const; - json_string Write(unsigned int indent, bool arrayChild); - #endif - #ifdef JSON_DEBUG - #ifndef JSON_LIBRARY - JSONNode Dump(size_t & totalmemory) const; - JSONNode DumpMutex(void) const; - #endif - #endif - - //json parts - mutable unsigned char _type BITS(3); - mutable bool _name_encoded BITS(1); //must be above name due to initialization list order - json_string _name; - - mutable json_string _string; //these are both mutable because the string can change when it's fetched - mutable bool _string_encoded BITS(1); - - //the value of the json - union value_union_t { - bool _bool; - json_number _number; - }; - mutable value_union_t _value; //internal structure changes depending on type - - jsonChildren Children; //container that holds all of my children - - #ifdef JSON_VALIDATE - mutable bool isValid BITS(1); //this does not need to be initialized, it's only used if it's null - void Nullify(bool validation = true) const; - bool validate(void); - #else - void Nullify(void) const; - #endif - - //Fetching and such - #ifndef JSON_PREPARSE - mutable bool fetched BITS(1); - void SetFetched(bool val) const; - void Fetch(void) const; //it's const because it doesn't change the VALUE of the function - #endif - - #ifdef JSON_COMMENTS - json_string _comment; - #endif - - void FetchString(void) const; - void FetchNode(void) const; - void FetchArray(void) const; - void FetchNumber(void) const; - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - static bool AreEqualNoCase(const json_char * ch_one, const json_char * ch_two); - #endif -}; - -inline internalJSONNode::internalJSONNode(char mytype) : _type(mytype), Children(), _name(), _name_encoded(), _string(), _string_encoded(), _value() - initializeMutex(0) - initializeRefCount(1) - initializeFetch(true) - initializeComment(0) - initializeValid(true){ - - incinternalAllocCount(); -} - -inline internalJSONNode * internalJSONNode::incRef(void){ - #ifdef JSON_REF_COUNT - ++refcount; - return this; - #else - return makeUnique(); - #endif -} - -inline json_index_t internalJSONNode::size(void) const { - Fetch(); - return Children.size(); -} - -inline bool internalJSONNode::empty(void) const { - if (type() != JSON_NODE && type() != JSON_ARRAY) return true; - Fetch(); - return Children.empty(); -} - -inline unsigned char internalJSONNode::type(void) const { - #ifdef JSON_LESS_MEMORY - return _type & 0xF; - #else - return _type; - #endif -} - -inline json_string internalJSONNode::name(void) const { - return _name; -} - -inline void internalJSONNode::setname(const json_string & newname){ - _name = newname; - #ifdef JSON_LESS_MEMORY - _type |= 0x10; - #else - _name_encoded = true; - #endif -} - -#ifdef JSON_COMMENTS - inline void internalJSONNode::setcomment(const json_string & comment){ - _comment = comment; - } - - inline json_string internalJSONNode::getcomment(void) const { - return _comment; - } -#endif - -inline json_string internalJSONNode::as_string(void) const { - Fetch(); - return _string; -} - -inline long internalJSONNode::as_int(void) const { - Fetch(); - switch(type()) { - case JSON_NULL: - return 0; - case JSON_BOOL: - return _value._bool ? 1 : 0; - } - JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_int returning undefined results")); - JSON_ASSERT(_value._number > LONG_MIN, _string + JSON_TEXT(" is outside the lower range of long")); - JSON_ASSERT(_value._number < LONG_MAX, _string + JSON_TEXT(" is outside the upper range of long")); - JSON_ASSERT(_value._number == (json_number)((int)_value._number), json_string(JSON_TEXT("as_int will truncate ")) + _string); - return (int)_value._number; -} - -inline json_number internalJSONNode::as_float(void) const { - Fetch(); - switch(type()) { - case JSON_NULL: - return (json_number)0.0; - case JSON_BOOL: - return (json_number)(_value._bool ? 1.0 : 0.0); - } - JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_float returning undefined results")); - return _value._number; -} - -inline bool internalJSONNode::as_bool(void) const { - Fetch(); - switch(type()) { - case JSON_NUMBER: - return _value._number != 0.0f; - case JSON_NULL: - return false; - } - JSON_ASSERT(type() == JSON_BOOL, JSON_TEXT("as_bool returning undefined results")); - return _value._bool; -} - -inline bool internalJSONNode::IsEqualTo(const json_string & val) const { - if (type() != JSON_STRING) return false; - Fetch(); - return val == _string; -} - -inline bool internalJSONNode::IsEqualTo(bool val) const { - if (type() != JSON_BOOL) return false; - Fetch(); - return val == _value._bool; -} - -template -inline bool internalJSONNode::IsEqualToNum(T val) const { - if (type() != JSON_NUMBER) return false; - Fetch(); - return (json_number)val == _value._number; -} - -#ifdef JSON_REF_COUNT - inline void internalJSONNode::decRef(void){ - JSON_ASSERT(refcount != 0, JSON_TEXT("decRef on a 0 refcount internal")); - --refcount; - } - - inline bool internalJSONNode::hasNoReferences(void){ - return refcount == 0; - } -#endif - -inline internalJSONNode * internalJSONNode::makeUnique(void){ - #ifdef JSON_REF_COUNT - if (refcount > 1){ - decRef(); - return newInternal(*this); - } - JSON_ASSERT(refcount == 1, JSON_TEXT("makeUnique on a 0 refcount internal")); - return this; - #else - return newInternal(*this); - #endif -} - -#ifndef JSON_PREPARSE - inline void internalJSONNode::SetFetched(bool val) const { - fetched = val; - } -#endif - -inline bool internalJSONNode::Fetched(void) const { - #ifndef JSON_PREPARSE - return fetched; - #else - return true; - #endif -} - -inline JSONNode ** internalJSONNode::begin(void) const { - Fetch(); - return Children.begin(); -} - -inline JSONNode ** internalJSONNode::end(void) const { - Fetch(); - return Children.end(); -} - -inline JSONNode * internalJSONNode::at(json_index_t pos){ - Fetch(); - return Children[pos]; -} - -inline void internalJSONNode::reserve(json_index_t size){ - Fetch(); - Children.reserve2(size); -} - -/* - These functions are to allow allocation to be completely controlled by the callbacks -*/ - -inline void internalJSONNode::deleteInternal(internalJSONNode * ptr){ - #ifdef JSON_MEMORY_CALLBACKS - ptr -> ~internalJSONNode(); - libjson_free(ptr); - #else - delete ptr; - #endif -} - -inline internalJSONNode * internalJSONNode::newInternal(char mytype){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) internalJSONNode(mytype); - #else - return new internalJSONNode(mytype); - #endif -} - -inline internalJSONNode * internalJSONNode::newInternal(const json_string & unparsed){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) internalJSONNode(unparsed); - #else - return new internalJSONNode(unparsed); - #endif -} - -inline internalJSONNode * internalJSONNode::newInternal(const json_string & name_t, const json_string & value_t){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) internalJSONNode(name_t, value_t); - #else - return new internalJSONNode(name_t, value_t); - #endif -} - -inline internalJSONNode * internalJSONNode::newInternal(const internalJSONNode & orig){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) internalJSONNode(orig); - #else - return new internalJSONNode(orig); - #endif -} - - -#endif +#ifndef INTERNAL_JSONNODE_H +#define INTERNAL_JSONNODE_H + +#include "JSONDebug.h" +#include "JSONChildren.h" +#include "JSONMemory.h" +#ifdef JSON_DEBUG + #include //to check int value +#endif + +/* + This class is the work horse of libJSON, it handles all of the + functinality of JSONNode. This object is reference counted for + speed and memory reasons. + + If JSON_REF_COUNT is not on, this internal structure still has an important + purpose, as it can be passed around by JSONNoders that are flagged as temporary +*/ + +class JSONNode; //forward declaration + +#ifndef JSON_LIBRARY + #define DECL_SET_INTEGER(type) void Set(type); void Set(unsigned type); +#endif + +#ifdef JSON_MUTEX_CALLBACKS + #define initializeMutex(x) ,mylock(x) +#else + #define initializeMutex(x) +#endif + +#ifdef JSON_PREPARSE + #define SetFetched(b) (void)0 + #define Fetch() (void)0 +#define initializeFetch(x) +#else + #define initializeFetch(x) ,fetched(x) +#endif + +#ifdef JSON_REF_COUNT + #define initializeRefCount(x) ,refcount(x) +#else + #define initializeRefCount(x) +#endif + +#ifdef JSON_COMMENTS + #define initializeComment(x) ,_comment(x) +#else + #define initializeComment(x) +#endif + +#ifndef JSON_UNIT_TEST + #define incAllocCount() (void)0 + #define decAllocCount() (void)0 + #define incinternalAllocCount() (void)0 + #define decinternalAllocCount() (void)0 +#endif + +#ifdef JSON_VALIDATE + #define initializeValid(x) ,isValid(x) +#else + #define initializeValid(x) +#endif + +class internalJSONNode { +public: + internalJSONNode(char mytype = JSON_NULL); + internalJSONNode(const json_string & unparsed); + internalJSONNode(const json_string & name_t, const json_string & value_t); + internalJSONNode(const internalJSONNode & orig); + internalJSONNode & operator = (const internalJSONNode &); + ~internalJSONNode(void); + + static internalJSONNode * newInternal(char mytype = JSON_NULL); + static internalJSONNode * newInternal(const json_string & unparsed); + static internalJSONNode * newInternal(const json_string & name_t, const json_string & value_t); + static internalJSONNode * newInternal(const internalJSONNode & orig); //not copyable, only by this class + static void deleteInternal(internalJSONNode * ptr); + + json_index_t size(void) const; + bool empty(void) const; + unsigned char type(void) const; + + json_string name(void) const; + void setname(const json_string & newname); + #ifdef JSON_COMMENTS + void setcomment(const json_string & comment); + json_string getcomment(void) const; + #endif + json_string as_string(void) const; + long as_int(void) const; + json_number as_float(void) const; + bool as_bool(void) const; + + #ifndef JSON_PREPARSE + void preparse(void); + #endif + + #ifdef JSON_LIBRARY + void push_back(JSONNode * node); + #else + void push_back(const JSONNode & node); + #endif + void reserve(json_index_t size); + void push_front(const JSONNode & node); + JSONNode * pop_back(json_index_t pos); + JSONNode * pop_back(const json_string & name_t); + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode * pop_back_nocase(const json_string & name_t); + #endif + + JSONNode * at(json_index_t pos); + //These return ** because pop_back needs them + JSONNode ** at(const json_string & name_t); + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode ** at_nocase(const json_string & name_t); + #endif + + void Set(const json_string & val); + #ifdef JSON_LIBRARY + void Set(json_number val); + void Set(long val); + #else + DECL_SET_INTEGER(char) + DECL_SET_INTEGER(short) + DECL_SET_INTEGER(int) + DECL_SET_INTEGER(long) + #ifndef JSON_ISO_STRICT + DECL_SET_INTEGER(long long) + #endif + + void Set(float val); + void Set(double val); + #endif + void Set(bool val); + + bool IsEqualTo(const json_string & val)const ; + bool IsEqualTo(bool val) const; + bool IsEqualTo(const internalJSONNode * val) const; + + template + bool IsEqualToNum(T val) const; + + internalJSONNode * incRef(void); + #ifdef JSON_REF_COUNT + void decRef(void); + bool hasNoReferences(void); + #endif + internalJSONNode * makeUnique(void); + + JSONNode ** begin(void) const; + JSONNode ** end(void) const; + #ifdef JSON_REF_COUNT + size_t refcount BITS(20); + #endif + bool Fetched(void) const; + #ifdef JSON_MUTEX_CALLBACKS + void * mylock; + void _set_mutex(void * mutex, bool unset = true); + void _unset_mutex(void); + #endif + #ifdef JSON_UNIT_TEST + static void incinternalAllocCount(void); + static void decinternalAllocCount(void); + #endif + + #ifdef JSON_WRITER + json_string WriteName(bool formatted, bool arrayChild) const; + json_string WriteChildren(unsigned int indent); + json_string WriteComment(unsigned int indent) const; + json_string Write(unsigned int indent, bool arrayChild); + #endif + #ifdef JSON_DEBUG + #ifndef JSON_LIBRARY + JSONNode Dump(size_t & totalmemory) const; + JSONNode DumpMutex(void) const; + #endif + #endif + + //json parts + mutable unsigned char _type BITS(3); + mutable bool _name_encoded BITS(1); //must be above name due to initialization list order + json_string _name; + + mutable json_string _string; //these are both mutable because the string can change when it's fetched + mutable bool _string_encoded BITS(1); + + //the value of the json + union value_union_t { + bool _bool; + json_number _number; + }; + mutable value_union_t _value; //internal structure changes depending on type + + jsonChildren Children; //container that holds all of my children + + #ifdef JSON_VALIDATE + mutable bool isValid BITS(1); //this does not need to be initialized, it's only used if it's null + void Nullify(bool validation = true) const; + bool validate(void); + #else + void Nullify(void) const; + #endif + + //Fetching and such + #ifndef JSON_PREPARSE + mutable bool fetched BITS(1); + void SetFetched(bool val) const; + void Fetch(void) const; //it's const because it doesn't change the VALUE of the function + #endif + + #ifdef JSON_COMMENTS + json_string _comment; + #endif + + void FetchString(void) const; + void FetchNode(void) const; + void FetchArray(void) const; + void FetchNumber(void) const; + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + static bool AreEqualNoCase(const json_char * ch_one, const json_char * ch_two); + #endif +}; + +inline internalJSONNode::internalJSONNode(char mytype) : _type(mytype), Children(), _name(), _name_encoded(), _string(), _string_encoded(), _value() + initializeMutex(0) + initializeRefCount(1) + initializeFetch(true) + initializeComment(0) + initializeValid(true){ + + incinternalAllocCount(); +} + +inline internalJSONNode * internalJSONNode::incRef(void){ + #ifdef JSON_REF_COUNT + ++refcount; + return this; + #else + return makeUnique(); + #endif +} + +inline json_index_t internalJSONNode::size(void) const { + Fetch(); + return Children.size(); +} + +inline bool internalJSONNode::empty(void) const { + if (type() != JSON_NODE && type() != JSON_ARRAY) return true; + Fetch(); + return Children.empty(); +} + +inline unsigned char internalJSONNode::type(void) const { + #ifdef JSON_LESS_MEMORY + return _type & 0xF; + #else + return _type; + #endif +} + +inline json_string internalJSONNode::name(void) const { + return _name; +} + +inline void internalJSONNode::setname(const json_string & newname){ + _name = newname; + #ifdef JSON_LESS_MEMORY + _type |= 0x10; + #else + _name_encoded = true; + #endif +} + +#ifdef JSON_COMMENTS + inline void internalJSONNode::setcomment(const json_string & comment){ + _comment = comment; + } + + inline json_string internalJSONNode::getcomment(void) const { + return _comment; + } +#endif + +inline json_string internalJSONNode::as_string(void) const { + Fetch(); + return _string; +} + +inline long internalJSONNode::as_int(void) const { + Fetch(); + switch(type()) { + case JSON_NULL: + return 0; + case JSON_BOOL: + return _value._bool ? 1 : 0; + } + JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_int returning undefined results")); + JSON_ASSERT(_value._number > LONG_MIN, _string + JSON_TEXT(" is outside the lower range of long")); + JSON_ASSERT(_value._number < LONG_MAX, _string + JSON_TEXT(" is outside the upper range of long")); + JSON_ASSERT(_value._number == (json_number)((int)_value._number), json_string(JSON_TEXT("as_int will truncate ")) + _string); + return (int)_value._number; +} + +inline json_number internalJSONNode::as_float(void) const { + Fetch(); + switch(type()) { + case JSON_NULL: + return (json_number)0.0; + case JSON_BOOL: + return (json_number)(_value._bool ? 1.0 : 0.0); + } + JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_float returning undefined results")); + return _value._number; +} + +inline bool internalJSONNode::as_bool(void) const { + Fetch(); + switch(type()) { + case JSON_NUMBER: + return _value._number != 0.0f; + case JSON_NULL: + return false; + } + JSON_ASSERT(type() == JSON_BOOL, JSON_TEXT("as_bool returning undefined results")); + return _value._bool; +} + +inline bool internalJSONNode::IsEqualTo(const json_string & val) const { + if (type() != JSON_STRING) return false; + Fetch(); + return val == _string; +} + +inline bool internalJSONNode::IsEqualTo(bool val) const { + if (type() != JSON_BOOL) return false; + Fetch(); + return val == _value._bool; +} + +template +inline bool internalJSONNode::IsEqualToNum(T val) const { + if (type() != JSON_NUMBER) return false; + Fetch(); + return (json_number)val == _value._number; +} + +#ifdef JSON_REF_COUNT + inline void internalJSONNode::decRef(void){ + JSON_ASSERT(refcount != 0, JSON_TEXT("decRef on a 0 refcount internal")); + --refcount; + } + + inline bool internalJSONNode::hasNoReferences(void){ + return refcount == 0; + } +#endif + +inline internalJSONNode * internalJSONNode::makeUnique(void){ + #ifdef JSON_REF_COUNT + if (refcount > 1){ + decRef(); + return newInternal(*this); + } + JSON_ASSERT(refcount == 1, JSON_TEXT("makeUnique on a 0 refcount internal")); + return this; + #else + return newInternal(*this); + #endif +} + +#ifndef JSON_PREPARSE + inline void internalJSONNode::SetFetched(bool val) const { + fetched = val; + } +#endif + +inline bool internalJSONNode::Fetched(void) const { + #ifndef JSON_PREPARSE + return fetched; + #else + return true; + #endif +} + +inline JSONNode ** internalJSONNode::begin(void) const { + Fetch(); + return Children.begin(); +} + +inline JSONNode ** internalJSONNode::end(void) const { + Fetch(); + return Children.end(); +} + +inline JSONNode * internalJSONNode::at(json_index_t pos){ + Fetch(); + return Children[pos]; +} + +inline void internalJSONNode::reserve(json_index_t size){ + Fetch(); + Children.reserve2(size); +} + +/* + These functions are to allow allocation to be completely controlled by the callbacks +*/ + +inline void internalJSONNode::deleteInternal(internalJSONNode * ptr){ + #ifdef JSON_MEMORY_CALLBACKS + ptr -> ~internalJSONNode(); + libjson_free(ptr); + #else + delete ptr; + #endif +} + +inline internalJSONNode * internalJSONNode::newInternal(char mytype){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) internalJSONNode(mytype); + #else + return new internalJSONNode(mytype); + #endif +} + +inline internalJSONNode * internalJSONNode::newInternal(const json_string & unparsed){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) internalJSONNode(unparsed); + #else + return new internalJSONNode(unparsed); + #endif +} + +inline internalJSONNode * internalJSONNode::newInternal(const json_string & name_t, const json_string & value_t){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) internalJSONNode(name_t, value_t); + #else + return new internalJSONNode(name_t, value_t); + #endif +} + +inline internalJSONNode * internalJSONNode::newInternal(const internalJSONNode & orig){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) internalJSONNode(orig); + #else + return new internalJSONNode(orig); + #endif +} + +#endif -- cgit v1.2.3