summaryrefslogtreecommitdiff
path: root/src/modules/json/JSONWorker.cpp
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2012-12-17 14:19:09 +0000
committerKirill Volinsky <mataes2007@gmail.com>2012-12-17 14:19:09 +0000
commitd3a54e309c8c6335a5d6384d3e239bd7bc9390f6 (patch)
treed45e6ca446392d9ce9acf5b4b20e75dd5d85af4f /src/modules/json/JSONWorker.cpp
parent375155f8dcd69863f1b9a220c5f890596844e99d (diff)
cleanup
git-svn-id: http://svn.miranda-ng.org/main/trunk@2757 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'src/modules/json/JSONWorker.cpp')
-rw-r--r--src/modules/json/JSONWorker.cpp1398
1 files changed, 697 insertions, 701 deletions
diff --git a/src/modules/json/JSONWorker.cpp b/src/modules/json/JSONWorker.cpp
index 488089345f..83ab246ee1 100644
--- a/src/modules/json/JSONWorker.cpp
+++ b/src/modules/json/JSONWorker.cpp
@@ -1,701 +1,697 @@
-/*
-
-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 "JSONWorker.h"
-
-#ifdef JSON_VALIDATE
-JSONNode JSONWorker::validate(const json_string & json){
- JSONNode res = parse(json);
- if (!res.validate()) {
- throw std::invalid_argument(EMPTY_STRING2);
- }
- return JSONNode(true, res); //forces it to simply return the original interal, even with ref counting off
-}
-#endif
-
-JSONNode JSONWorker::parse(const json_string & json){
- json_auto<json_char> s;
- #if defined JSON_DEBUG || defined JSON_SAFE
- json_char lastchar;
- s.set(RemoveWhiteSpace(json, lastchar));
- #else
- s.set(RemoveWhiteSpace(json));
- #endif
-
- #ifdef JSON_COMMENTS
- json_char firstchar = s.ptr[0];
- json_string _comment;
- json_char * runner = s.ptr;
- if (firstchar == '\5') { //multiple comments will be consolidated into one
- newcomment:
- while(*(++runner) != '\5') {
- JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed"));
- _comment += *runner;
- }
- firstchar = *(++runner); //step past the trailing tag
- if (firstchar == '\5') {
- _comment += '\n';
- goto newcomment;
- }
- }
- #else
- const json_char firstchar = s.ptr[0];
- #endif
-
- switch (firstchar){
- case '{':
- case '[':
- #if defined JSON_DEBUG || defined JSON_SAFE
- if (firstchar == '[') {
- if (lastchar != ']') {
- JSON_FAIL(JSON_TEXT("Missing final ]"));
- break;
- }
- } else {
- if (lastchar != '}') {
- JSON_FAIL(JSON_TEXT("Missing final }"));
- break;
- }
- }
- #endif
- #ifdef JSON_COMMENTS
- JSONNode foo(runner);
- foo.set_comment(_comment);
- return JSONNode(true, foo); //forces it to simply return the original interal, even with ref counting off
- #else
- return JSONNode(s.ptr);
- #endif
- }
-
- JSON_FAIL(JSON_TEXT("Not JSON!"));
- throw std::invalid_argument(EMPTY_STRING2);
-}
-
-#define QUOTECASE()\
- case JSON_TEXT('\"'):\
- while (*(++p) != JSON_TEXT('\"')) {\
- JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), return json_string::npos;);\
- }\
- break;
-
-#ifdef JSON_DEBUG
- #define NULLCASE(error)\
- case JSON_TEXT('\0'):\
- JSON_FAIL_SAFE(error, return json_string::npos;);\
- break;
-#else
- #define NULLCASE(error)
-#endif
-
-#define BRACKET(left, right)\
- case left: {\
- size_t brac = 1;\
- while (brac){\
- switch (*(++p)) {\
- case right:\
- --brac;\
- break;\
- case left:\
- ++brac;\
- break;\
- QUOTECASE()\
- NULLCASE(JSON_TEXT("Null terminator inside of a bracket"))\
- }\
- }\
- break;}\
- case right:\
- return json_string::npos;
-
-size_t JSONWorker::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos){
- const json_char * start = value_t.c_str();
- const json_char * p = start + pos; //start at the correct offset
- do {
- if (*p == ch) return p - start;
- switch (*p){
- BRACKET(JSON_TEXT('['), JSON_TEXT(']'))
- BRACKET(JSON_TEXT('{'), JSON_TEXT('}'))
- QUOTECASE()
- }
- } while(*(++p));
- return json_string::npos;
-}
-
-#ifdef JSON_COMMENTS
- #define COMMENT_DELIMITER() *runner++='\5'
- #define AND_RUNNER ,runner
- inline void SingleLineComment(const json_char * & p, json_char * & runner){
- COMMENT_DELIMITER();
- while((*(++p)) && (*p != JSON_TEXT('\n'))) {
- *runner++=*p;
- }
- COMMENT_DELIMITER();
- }
-#else
- #define COMMENT_DELIMITER() (void)0
- #define AND_RUNNER
-#endif
-
-inline void SingleLineComment(const json_char * & p){
- while((*(++p)) && (*p != JSON_TEXT('\n')));
-}
-
-
-#if defined JSON_DEBUG || defined JSON_SAFE
- json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t, json_char & last){
-#else
- json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t){
-#endif
- json_char * result;
- json_char * runner = result = json_malloc<json_char>(value_t.length() + 1); //dealing with raw memory is faster than adding to a json_string
- JSON_ASSERT(result, JSON_TEXT("Out of memory"));
- const json_char * p = value_t.c_str();
- while(*p){
- switch(*p){
- case JSON_TEXT(' '): //defined as white space
- case JSON_TEXT('\t'): //defined as white space
- case JSON_TEXT('\n'): //defined as white space
- case JSON_TEXT('\r'): //defined as white space
- break;
- case JSON_TEXT('/'): //a C comment
- if (*(++p) == JSON_TEXT('*')) { //a multiline comment
- COMMENT_DELIMITER();
- while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))) {
- JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), COMMENT_DELIMITER(); goto endofloop;);
- *runner++=*p;
- }
- ++p;
- COMMENT_DELIMITER();
- break;
- }
- //Should be a single line C comment, so let it fall through to use the bash comment stripper
- JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;);
- case JSON_TEXT('#'): //a bash comment
- SingleLineComment(p AND_RUNNER);
- break;
- case JSON_TEXT('\"'): //a quote
- *runner++=JSON_TEXT('\"');
- while(*(++p) != JSON_TEXT('\"')) { //find the end of the quotation, as white space is preserved within it
- JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), goto endofloop;);
- switch(*p){
- case JSON_TEXT('\\'):
- *runner++=JSON_TEXT('\\');
- *runner++=(*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p; //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on
- break;
- default:
- *runner++=*p;
- break;
- }
- }
- //no break, let it fall through so that the trailing quote gets added
- default:
- JSON_ASSERT_SAFE((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;);
- JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;);
- *runner++=*p;
- break;
- }
- ++p;
- }
- #ifdef JSON_SAFE
- endofloop:
- #endif
- #if defined JSON_DEBUG || defined JSON_SAFE
- last = *(runner - 1);
- #endif
- *runner = JSON_TEXT('\0');
- return result;
- }
-
-json_string JSONWorker::RemoveWhiteSpaceAndComments(const json_string & value_t){
- json_string result;
- result.reserve(value_t.length());
- const json_char * p = value_t.c_str();
- while(*p){
- switch(*p){
- case JSON_TEXT(' '): //defined as white space
- case JSON_TEXT('\t'): //defined as white space
- case JSON_TEXT('\n'): //defined as white space
- case JSON_TEXT('\r'): //defined as white space
- break;
- case JSON_TEXT('/'): //a C comment
- if (*(++p) == JSON_TEXT('*')) { //a multiline comment
- while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))) {
- JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), goto endofloop;);
- }
- ++p;
- break;
- }
- //Should be a single line C comment, so let it fall through to use the bash comment stripper
- JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;);
- case JSON_TEXT('#'): //a bash comment
- SingleLineComment(p);
- break;
- case JSON_TEXT('\"'): //a quote
- result += JSON_TEXT('\"');
- while(*(++p) != JSON_TEXT('\"')) { //find the end of the quotation, as white space is preserved within it
- JSON_ASSERT(*p, JSON_TEXT("Null terminator inside of a quotation"));
- switch(*p){
- case JSON_TEXT('\\'):
- result += JSON_TEXT('\\');
- result += (*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p; //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on
- break;
- default:
- result += *p;
- break;
- }
- }
- //no break, let it fall through so that the trailing quote gets added
- default:
- JSON_ASSERT_SAFE((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;);
- JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;);
- result += *p;
- break;
- }
- ++p;
- }
- #ifdef JSON_SAFE
- endofloop:
- #endif
- return result;
-}
-
-/*
- These three functions analyze json_string literals and convert them into std::strings
- This includes dealing with special characters and utf characters
- */
-#ifdef JSON_UNICODE
- inline json_uchar SurrogatePair(const json_uchar hi, const json_uchar lo){
- JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit"));
- JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("size of json_char is not 32-bit"));
- return (((hi << 10) & 0x1FFC00) + 0x10000) | lo & 0x3FF;
- }
-
- json_string JSONWorker::UTF(const json_char * & pos){
- json_string result;
- json_uchar first = UTF8(pos);
- if ((*(pos + 1) == '\\') && (*(pos + 2) == 'u')) {
- pos += 2;
- json_uchar second = UTF8(pos);
- //surrogate pair, not two characters
- if ((first > 0xD800) && (first < 0xDBFF) && (second > 0xDC00) && (second < 0xDFFF)) {
- result += SurrogatePair(first, second);
- } else {
- result += first;
- result += second;
- }
- } else {
- result += first;
- }
- JSON_ASSERT(!result.empty(), JSON_TEXT("missing case, somehow UTF returned empty"));
- return result;
- }
-#endif
-
-json_uchar JSONWorker::UTF8(const json_char * & pos){
- #ifdef JSON_UNICODE
- ++pos;
- json_uchar temp = Hex(pos) << 8;
- ++pos;
- return temp | Hex(pos);
- #else
- JSON_ASSERT(*(pos + 1) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hihi)"));
- JSON_ASSERT(*(pos + 2) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hilo)"));
- pos += 3;
- return Hex(pos);
- #endif
-}
-
-static json_char szU8Buffer[10];
-
-json_char* JSONWorker::UTF8_2(const json_char * & pos){
- #ifdef JSON_UNICODE
- ++pos;
- json_uchar temp = Hex(pos) << 8;
- ++pos;
- *szU8Buffer = temp | Hex(pos);
- szU8Buffer[1] = 0;
- return szU8Buffer;
- #else
- union {
- unsigned short uChar;
- unsigned char uByte[2];
- };
- pos++;
- strncpy(szU8Buffer+5,pos,4);
- szU8Buffer[9] = 0;
- uChar = strtoul(szU8Buffer+5,NULL,16);
- if (uChar<0x80) {
- szU8Buffer[0] = uChar;
- szU8Buffer[1] = 0;
- } else if (uChar<0x7ff) {
- szU8Buffer[0] = 0xc0+(uByte[1]<<2)+(uByte[0]>>6);
- szU8Buffer[1] = 0x80+(uByte[0]&0x3f);
- szU8Buffer[2] = 0;
- } else {
- szU8Buffer[0] = 0xe0+(uByte[1]>>4);
- szU8Buffer[1] = 0x80+((uByte[1]&0x0f)<<2)+(uByte[0]>>6);
- szU8Buffer[2] = 0x80+(uByte[0]&0x3f);
- szU8Buffer[3] = 0;
- }
-
- pos += 3;
- return szU8Buffer;
- #endif
-}
-
-
-json_char JSONWorker::Hex(const json_char * & pos){
- /*
- takes the numeric value of the next two characters and convert them
- \u0058 becomes 0x58
-
- In case of \u, it's SpecialChar's responsibility to move past the first two chars
- as this method is also used for \x
- */
- //First character
- json_uchar hi = *pos++ - 48;
- if (hi > 48){ //A-F don't immediately follow 0-9, so have to pull them down a little
- hi -= 39;
- } else if (hi > 9){ //neither do a-f
- hi -= 7;
- }
- //second character
- json_uchar lo = *pos - 48;
- if (lo > 48){ //A-F don't immediately follow 0-9, so have to pull them down a little
- lo -= 39;
- } else if (lo > 9){ //neither do a-f
- lo -= 7;
- }
- //combine them
- return (json_char)((hi << 4) | lo);
-}
-
-inline json_char FromOctal(const json_char * & str){
- JSON_ASSERT(json_strlen(str) > 3, JSON_TEXT("Octal will go out of bounds"));
- const json_uchar top = ((json_uchar)(*(str++) - 48));
- const json_uchar middle = (json_uchar)(*(str++) - 48);
- const json_uchar bottom = (json_uchar)(*str - 48);
- return (json_char)((top << 6) | (middle << 3) | bottom);
-}
-
-void JSONWorker::SpecialChar(const json_char * & pos, json_string & res){
- /*
- Since JSON uses forward slash escaping for special characters within strings, I have to
- convert these escaped characters into C characters
- */
- switch(*pos){
- case JSON_TEXT('\1'): //quote character (altered by RemoveWhiteSpace)
- res += JSON_TEXT('\"');
- break;
- case JSON_TEXT('t'): //tab character
- res += JSON_TEXT('\t');
- break;
- case JSON_TEXT('n'): //newline character
- res += JSON_TEXT('\n');
- break;
- case JSON_TEXT('r'): //return character
- res += JSON_TEXT('\r');
- break;
- case JSON_TEXT('\\'): //backslash
- res += JSON_TEXT('\\');
- break;
- case JSON_TEXT('/'): //forward slash
- res += JSON_TEXT('/');
- break;
- case JSON_TEXT('b'): //backspace
- res += JSON_TEXT('\b');
- break;
- case JSON_TEXT('f'): //formfeed
- res += JSON_TEXT('\f');
- break;
- case JSON_TEXT('v'): //vertical tab
- res += JSON_TEXT('\v');
- break;
- case JSON_TEXT('\''): //apostrophe
- res += JSON_TEXT('\'');
- break;
- case JSON_TEXT('x'): //hexidecimal ascii code
- res += Hex(++pos);
- break;
- case JSON_TEXT('u'): //utf character
- #ifdef JSON_UNICODE
- res += UTF(pos);
- #else
- //res += UTF8(pos);
- res.append(UTF8_2(pos));
- #endif
- break;
-
- //octal encoding
- case JSON_TEXT('1'):
- case JSON_TEXT('2'):
- case JSON_TEXT('3'):
- case JSON_TEXT('4'):
- case JSON_TEXT('5'):
- case JSON_TEXT('6'):
- case JSON_TEXT('7'):
- case JSON_TEXT('0'):
- res += FromOctal(pos);
- break;
-
- #ifdef JSON_DEBUG
- default:
- JSON_FAIL(JSON_TEXT("Unsupported escaped character"));
- #endif
- }
-}
-
-#ifdef JSON_LESS_MEMORY
- inline void doflag(const internalJSONNode * flag, bool which, bool x){
- if (which){
- flag -> _name_encoded = x;
- } else {
- flag -> _string_encoded = x;
- }
- }
-
- json_string JSONWorker::FixString(const json_string & value_t, const internalJSONNode * flag, bool which){
- #define setflag(x) doflag(flag, which, x)
-#else
- json_string JSONWorker::FixString(const json_string & value_t, bool & flag){
- #define setflag(x) flag = x
-#endif
- /*
- Do things like unescaping
- */
- setflag(false);
- json_string res;
- res.reserve(value_t.length()); //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating
- const json_char * p = value_t.c_str();
- while(*p){
- switch (*p){
- case JSON_TEXT('\\'):
- setflag(true);
- SpecialChar(++p, res);
- break;
- default:
- res += *p;
- break;
- }
- ++p;
- }
- return res;
-}
-
-#ifdef JSON_UNICODE
- json_string JSONWorker::toSurrogatePair(json_uchar C){
- JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit"));
- JSON_ASSERT(sizeof(unsigned short) == 2, JSON_TEXT("size of unsigned short is not 16-bit"));
- JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("json_char is not 32-bit"));
- //Compute the high surrogate
- const unsigned int U = (C >> 16) & 31;
- unsigned short HiSurrogate = 0xD800 | (((unsigned short)U - 1) << 6) | ((unsigned short)C) >> 10;
-
- //compute the low surrogate
- unsigned short LoSurrogate = (unsigned short) (0xDC00 | ((unsigned short)C) & 1023);
-
- json_string res;
- res += toUTF8(HiSurrogate);
- res += toUTF8(LoSurrogate);
- return res;
- }
-#endif
-
-json_string JSONWorker::toUTF8(json_uchar p){
- #ifdef JSON_UNICODE
- if (p > 0xFFFF) return toSurrogatePair(p);
- #endif
- json_string res(JSON_TEXT("\\u"));
- #ifdef JSON_UNICODE
- json_uchar hihi = ((p & 0xF000) >> 12) + 48;
- if (hihi > 57) hihi += 7; //A-F don't immediately follow 0-9, so have to further adjust those
- json_uchar hilo = ((p & 0x0F00) >> 8) + 48;
- if (hilo > 57) hilo += 7; //A-F don't immediately follow 0-9, so have to further adjust those
- res += hihi;
- res += hilo;
- json_uchar hi = ((p & 0x00F0) >> 4) + 48;
- #else
- res += JSON_TEXT("00");
- json_uchar hi = (p >> 4) + 48;
- #endif
- //convert the character to be escaped into two digits between 0 and 15
- if (hi > 57) hi += 7; //A-F don't immediately follow 0-9, so have to further adjust those
- json_uchar lo = (p & 0x000F) + 48;
- if (lo > 57) lo += 7; //A-F don't immediately follow 0-9, so have to further adjust those
- res += hi;
- res += lo;
- return res;
-}
-
-json_string JSONWorker::UnfixString(const json_string & value_t, bool flag){
- if (!flag) return value_t;
- /*
- Re-escapes a json_string so that it can be written out into a JSON file
- */
- json_string res;
- res.reserve(value_t.length()); //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating
- const json_char * p = value_t.c_str();
- while(*p){
- switch(*p){
- case JSON_TEXT('\"'): //quote character
- res += JSON_TEXT("\\\"");
- break;
- case JSON_TEXT('\t'): //tab character
- res += JSON_TEXT("\\t");
- break;
- case JSON_TEXT('\n'): //newline character
- res += JSON_TEXT("\\n");
- break;
- case JSON_TEXT('\r'): //return character
- res += JSON_TEXT("\\r");
- break;
- case JSON_TEXT('\\'): //backslash
- res += JSON_TEXT("\\\\");
- break;
- case JSON_TEXT('/'): //forward slash
- res += JSON_TEXT("\\/");
- break;
- case JSON_TEXT('\b'): //backspace
- res += JSON_TEXT("\\b");
- break;
- case JSON_TEXT('\f'): //formfeed
- res += JSON_TEXT("\\f");
- break;
- case JSON_TEXT('\v'): //vertical tab
- res += JSON_TEXT("\\v");
- break;
- case JSON_TEXT('\''): //apostrophe
- res += JSON_TEXT("\\\'");
- break;
- default:
- /*if (((json_uchar)(*p) < 32) || ((json_uchar)(*p) > 126)) {
- //res += toUTF8((json_uchar)(*p));
- } else*/ {
- res += *p;
- }
- break;
- }
- ++p;
- }
- return res;
-}
-
-
-//Create a childnode
-#ifdef JSON_COMMENTS
- #define ARRAY_PARAM bool array //Just to supress warnings
-#else
- #define ARRAY_PARAM bool
-#endif
-inline void JSONWorker::NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, ARRAY_PARAM){
- #ifdef JSON_COMMENTS
- const json_char * runner = (array) ? value.c_str() : name.c_str();
- json_string _comment;
- if (*runner == '\5') { //multiple comments will be consolidated into one
- newcomment:
- while(*(++runner) != '\5') {
- JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed"));
- _comment += *runner;
- }
- if (*(++runner) == '\5') { //step past the trailing tag
- _comment += '\n';
- goto newcomment;
- }
- }
- internalJSONNode * myinternal;
- if (array){
- myinternal = internalJSONNode::newInternal(name, runner);
- } else {
- myinternal = internalJSONNode::newInternal(++runner, value);
- }
- JSONNode * child = JSONNode::newJSONNode(myinternal);
- child -> set_comment(_comment);
- const_cast<internalJSONNode*>(parent) -> Children.push_back(child); //attach it to the parent node
- #else
- const_cast<internalJSONNode*>(parent) -> Children.push_back(JSONNode::newJSONNode(internalJSONNode::newInternal(name.c_str() + 1, value))); //attach it to the parent node
- #endif
-}
-
-//Create a subarray
-void JSONWorker::DoArray(const internalJSONNode * parent, const json_string & value_t){
- /*
- This takes an array and creates nodes out of them
- */
- JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoArray is empty"));
- JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('['), JSON_TEXT("DoArray is not an array"), parent -> Nullify(); return;);
- const size_t len = value_t.length();
- if (len <= 2) return; // just a [] (blank array)
-
- //Not sure what's in the array, so we have to use commas
- size_t starting = 1; //ignore the [
- size_t ending = FindNextRelevant(JSON_TEXT(','), value_t, 1);
- while (ending != json_string::npos){
- #ifdef JSON_SAFE
- json_string newValue = value_t.substr(starting, ending - starting);
- JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;);
- NewNode(parent, JSON_TEXT(""), newValue, true);
- #else
- NewNode(parent, JSON_TEXT(""), value_t.substr(starting, ending - starting), true);
- #endif
- starting = ending + 1;
- ending = FindNextRelevant(JSON_TEXT(','), value_t, starting);
- }
- //since the last one will not find the comma, we have to add it here, but ignore the final ]
-
- #ifdef JSON_SAFE
- json_string newValue = value_t.substr(starting, len - starting - 1);
- JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;);
- NewNode(parent, JSON_TEXT(""), newValue, true);
- #else
- NewNode(parent, JSON_TEXT(""), value_t.substr(starting, len - starting - 1), true);
- #endif
-}
-
-
-//Create all child nodes
-void JSONWorker::DoNode(const internalJSONNode * parent, const json_string & value_t){
- /*
- This take a node and creates its members and such
- */
- JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoNode is empty"));
- JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('{'), JSON_TEXT("DoNode is not an node"), parent -> Nullify(); return;);
- const size_t len = value_t.length();
- if (len <= 2) return; // just a {} (blank node)
-
- size_t name_starting = 1; //ignore the {
- size_t name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, 1); //find where the name ends
- JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;);
- json_string name = value_t.substr(name_starting, name_ending - 2); //pull the name out
- size_t value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending); //find the end of the value
- while (value_ending != json_string::npos){
- NewNode(parent, name, value_t.substr(name_ending + 1, value_ending - name_ending - 1), false);
- name_starting = value_ending + 1;
- name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, name_starting);
- JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;);
- name = value_t.substr(name_starting, name_ending - name_starting - 1);
- value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending);
- }
- //since the last one will not find the comma, we have to add it here
- NewNode(parent, name, value_t.substr(name_ending + 1, len - name_ending - 2), false);
-}
+/*
+
+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 "JSONWorker.h"
+
+#ifdef JSON_VALIDATE
+JSONNode JSONWorker::validate(const json_string & json){
+ JSONNode res = parse(json);
+ if (!res.validate()) {
+ throw std::invalid_argument(EMPTY_STRING2);
+ }
+ return JSONNode(true, res); //forces it to simply return the original interal, even with ref counting off
+}
+#endif
+
+JSONNode JSONWorker::parse(const json_string & json){
+ json_auto<json_char> s;
+ #if defined JSON_DEBUG || defined JSON_SAFE
+ json_char lastchar;
+ s.set(RemoveWhiteSpace(json, lastchar));
+ #else
+ s.set(RemoveWhiteSpace(json));
+ #endif
+
+ #ifdef JSON_COMMENTS
+ json_char firstchar = s.ptr[0];
+ json_string _comment;
+ json_char * runner = s.ptr;
+ if (firstchar == '\5') { //multiple comments will be consolidated into one
+ newcomment:
+ while(*(++runner) != '\5') {
+ JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed"));
+ _comment += *runner;
+ }
+ firstchar = *(++runner); //step past the trailing tag
+ if (firstchar == '\5') {
+ _comment += '\n';
+ goto newcomment;
+ }
+ }
+ #else
+ const json_char firstchar = s.ptr[0];
+ #endif
+
+ switch (firstchar){
+ case '{':
+ case '[':
+ #if defined JSON_DEBUG || defined JSON_SAFE
+ if (firstchar == '[') {
+ if (lastchar != ']') {
+ JSON_FAIL(JSON_TEXT("Missing final ]"));
+ break;
+ }
+ } else {
+ if (lastchar != '}') {
+ JSON_FAIL(JSON_TEXT("Missing final }"));
+ break;
+ }
+ }
+ #endif
+ #ifdef JSON_COMMENTS
+ JSONNode foo(runner);
+ foo.set_comment(_comment);
+ return JSONNode(true, foo); //forces it to simply return the original interal, even with ref counting off
+ #else
+ return JSONNode(s.ptr);
+ #endif
+ }
+
+ JSON_FAIL(JSON_TEXT("Not JSON!"));
+ throw std::invalid_argument(EMPTY_STRING2);
+}
+
+#define QUOTECASE()\
+ case JSON_TEXT('\"'):\
+ while (*(++p) != JSON_TEXT('\"')) {\
+ JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), return json_string::npos;);\
+ }\
+ break;
+
+#ifdef JSON_DEBUG
+ #define NULLCASE(error)\
+ case JSON_TEXT('\0'):\
+ JSON_FAIL_SAFE(error, return json_string::npos;);\
+ break;
+#else
+ #define NULLCASE(error)
+#endif
+
+#define BRACKET(left, right)\
+ case left: {\
+ size_t brac = 1;\
+ while (brac){\
+ switch (*(++p)) {\
+ case right:\
+ --brac;\
+ break;\
+ case left:\
+ ++brac;\
+ break;\
+ QUOTECASE()\
+ NULLCASE(JSON_TEXT("Null terminator inside of a bracket"))\
+ }\
+ }\
+ break;}\
+ case right:\
+ return json_string::npos;
+
+size_t JSONWorker::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos){
+ const json_char * start = value_t.c_str();
+ const json_char * p = start + pos; //start at the correct offset
+ do {
+ if (*p == ch) return p - start;
+ switch (*p){
+ BRACKET(JSON_TEXT('['), JSON_TEXT(']'))
+ BRACKET(JSON_TEXT('{'), JSON_TEXT('}'))
+ QUOTECASE()
+ }
+ } while(*(++p));
+ return json_string::npos;
+}
+
+#ifdef JSON_COMMENTS
+ #define COMMENT_DELIMITER() *runner++='\5'
+ #define AND_RUNNER ,runner
+ inline void SingleLineComment(const json_char * & p, json_char * & runner){
+ COMMENT_DELIMITER();
+ while((*(++p)) && (*p != JSON_TEXT('\n'))) {
+ *runner++=*p;
+ }
+ COMMENT_DELIMITER();
+ }
+#else
+ #define COMMENT_DELIMITER() (void)0
+ #define AND_RUNNER
+#endif
+
+inline void SingleLineComment(const json_char * & p){
+ while((*(++p)) && (*p != JSON_TEXT('\n')));
+}
+
+#if defined JSON_DEBUG || defined JSON_SAFE
+ json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t, json_char & last){
+#else
+ json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t){
+#endif
+ json_char * result;
+ json_char * runner = result = json_malloc<json_char>(value_t.length() + 1); //dealing with raw memory is faster than adding to a json_string
+ JSON_ASSERT(result, JSON_TEXT("Out of memory"));
+ const json_char * p = value_t.c_str();
+ while(*p){
+ switch(*p){
+ case JSON_TEXT(' '): //defined as white space
+ case JSON_TEXT('\t'): //defined as white space
+ case JSON_TEXT('\n'): //defined as white space
+ case JSON_TEXT('\r'): //defined as white space
+ break;
+ case JSON_TEXT('/'): //a C comment
+ if (*(++p) == JSON_TEXT('*')) { //a multiline comment
+ COMMENT_DELIMITER();
+ while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))) {
+ JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), COMMENT_DELIMITER(); goto endofloop;);
+ *runner++=*p;
+ }
+ ++p;
+ COMMENT_DELIMITER();
+ break;
+ }
+ //Should be a single line C comment, so let it fall through to use the bash comment stripper
+ JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;);
+ case JSON_TEXT('#'): //a bash comment
+ SingleLineComment(p AND_RUNNER);
+ break;
+ case JSON_TEXT('\"'): //a quote
+ *runner++=JSON_TEXT('\"');
+ while(*(++p) != JSON_TEXT('\"')) { //find the end of the quotation, as white space is preserved within it
+ JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), goto endofloop;);
+ switch(*p){
+ case JSON_TEXT('\\'):
+ *runner++=JSON_TEXT('\\');
+ *runner++=(*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p; //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on
+ break;
+ default:
+ *runner++=*p;
+ break;
+ }
+ }
+ //no break, let it fall through so that the trailing quote gets added
+ default:
+ JSON_ASSERT_SAFE((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;);
+ JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;);
+ *runner++=*p;
+ break;
+ }
+ ++p;
+ }
+ #ifdef JSON_SAFE
+ endofloop:
+ #endif
+ #if defined JSON_DEBUG || defined JSON_SAFE
+ last = *(runner - 1);
+ #endif
+ *runner = JSON_TEXT('\0');
+ return result;
+ }
+
+json_string JSONWorker::RemoveWhiteSpaceAndComments(const json_string & value_t){
+ json_string result;
+ result.reserve(value_t.length());
+ const json_char * p = value_t.c_str();
+ while(*p){
+ switch(*p){
+ case JSON_TEXT(' '): //defined as white space
+ case JSON_TEXT('\t'): //defined as white space
+ case JSON_TEXT('\n'): //defined as white space
+ case JSON_TEXT('\r'): //defined as white space
+ break;
+ case JSON_TEXT('/'): //a C comment
+ if (*(++p) == JSON_TEXT('*')) { //a multiline comment
+ while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))) {
+ JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), goto endofloop;);
+ }
+ ++p;
+ break;
+ }
+ //Should be a single line C comment, so let it fall through to use the bash comment stripper
+ JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;);
+ case JSON_TEXT('#'): //a bash comment
+ SingleLineComment(p);
+ break;
+ case JSON_TEXT('\"'): //a quote
+ result += JSON_TEXT('\"');
+ while(*(++p) != JSON_TEXT('\"')) { //find the end of the quotation, as white space is preserved within it
+ JSON_ASSERT(*p, JSON_TEXT("Null terminator inside of a quotation"));
+ switch(*p){
+ case JSON_TEXT('\\'):
+ result += JSON_TEXT('\\');
+ result += (*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p; //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on
+ break;
+ default:
+ result += *p;
+ break;
+ }
+ }
+ //no break, let it fall through so that the trailing quote gets added
+ default:
+ JSON_ASSERT_SAFE((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;);
+ JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;);
+ result += *p;
+ break;
+ }
+ ++p;
+ }
+ #ifdef JSON_SAFE
+ endofloop:
+ #endif
+ return result;
+}
+
+/*
+ These three functions analyze json_string literals and convert them into std::strings
+ This includes dealing with special characters and utf characters
+ */
+#ifdef JSON_UNICODE
+ inline json_uchar SurrogatePair(const json_uchar hi, const json_uchar lo){
+ JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit"));
+ JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("size of json_char is not 32-bit"));
+ return (((hi << 10) & 0x1FFC00) + 0x10000) | lo & 0x3FF;
+ }
+
+ json_string JSONWorker::UTF(const json_char * & pos){
+ json_string result;
+ json_uchar first = UTF8(pos);
+ if ((*(pos + 1) == '\\') && (*(pos + 2) == 'u')) {
+ pos += 2;
+ json_uchar second = UTF8(pos);
+ //surrogate pair, not two characters
+ if ((first > 0xD800) && (first < 0xDBFF) && (second > 0xDC00) && (second < 0xDFFF)) {
+ result += SurrogatePair(first, second);
+ } else {
+ result += first;
+ result += second;
+ }
+ } else {
+ result += first;
+ }
+ JSON_ASSERT(!result.empty(), JSON_TEXT("missing case, somehow UTF returned empty"));
+ return result;
+ }
+#endif
+
+json_uchar JSONWorker::UTF8(const json_char * & pos){
+ #ifdef JSON_UNICODE
+ ++pos;
+ json_uchar temp = Hex(pos) << 8;
+ ++pos;
+ return temp | Hex(pos);
+ #else
+ JSON_ASSERT(*(pos + 1) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hihi)"));
+ JSON_ASSERT(*(pos + 2) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hilo)"));
+ pos += 3;
+ return Hex(pos);
+ #endif
+}
+
+static json_char szU8Buffer[10];
+
+json_char* JSONWorker::UTF8_2(const json_char * & pos){
+ #ifdef JSON_UNICODE
+ ++pos;
+ json_uchar temp = Hex(pos) << 8;
+ ++pos;
+ *szU8Buffer = temp | Hex(pos);
+ szU8Buffer[1] = 0;
+ return szU8Buffer;
+ #else
+ union {
+ unsigned short uChar;
+ unsigned char uByte[2];
+ };
+ pos++;
+ strncpy(szU8Buffer+5,pos,4);
+ szU8Buffer[9] = 0;
+ uChar = strtoul(szU8Buffer+5,NULL,16);
+ if (uChar<0x80) {
+ szU8Buffer[0] = uChar;
+ szU8Buffer[1] = 0;
+ } else if (uChar<0x7ff) {
+ szU8Buffer[0] = 0xc0+(uByte[1]<<2)+(uByte[0]>>6);
+ szU8Buffer[1] = 0x80+(uByte[0]&0x3f);
+ szU8Buffer[2] = 0;
+ } else {
+ szU8Buffer[0] = 0xe0+(uByte[1]>>4);
+ szU8Buffer[1] = 0x80+((uByte[1]&0x0f)<<2)+(uByte[0]>>6);
+ szU8Buffer[2] = 0x80+(uByte[0]&0x3f);
+ szU8Buffer[3] = 0;
+ }
+
+ pos += 3;
+ return szU8Buffer;
+ #endif
+}
+
+json_char JSONWorker::Hex(const json_char * & pos){
+ /*
+ takes the numeric value of the next two characters and convert them
+ \u0058 becomes 0x58
+
+ In case of \u, it's SpecialChar's responsibility to move past the first two chars
+ as this method is also used for \x
+ */
+ //First character
+ json_uchar hi = *pos++ - 48;
+ if (hi > 48){ //A-F don't immediately follow 0-9, so have to pull them down a little
+ hi -= 39;
+ } else if (hi > 9){ //neither do a-f
+ hi -= 7;
+ }
+ //second character
+ json_uchar lo = *pos - 48;
+ if (lo > 48){ //A-F don't immediately follow 0-9, so have to pull them down a little
+ lo -= 39;
+ } else if (lo > 9){ //neither do a-f
+ lo -= 7;
+ }
+ //combine them
+ return (json_char)((hi << 4) | lo);
+}
+
+inline json_char FromOctal(const json_char * & str){
+ JSON_ASSERT(json_strlen(str) > 3, JSON_TEXT("Octal will go out of bounds"));
+ const json_uchar top = ((json_uchar)(*(str++) - 48));
+ const json_uchar middle = (json_uchar)(*(str++) - 48);
+ const json_uchar bottom = (json_uchar)(*str - 48);
+ return (json_char)((top << 6) | (middle << 3) | bottom);
+}
+
+void JSONWorker::SpecialChar(const json_char * & pos, json_string & res){
+ /*
+ Since JSON uses forward slash escaping for special characters within strings, I have to
+ convert these escaped characters into C characters
+ */
+ switch(*pos){
+ case JSON_TEXT('\1'): //quote character (altered by RemoveWhiteSpace)
+ res += JSON_TEXT('\"');
+ break;
+ case JSON_TEXT('t'): //tab character
+ res += JSON_TEXT('\t');
+ break;
+ case JSON_TEXT('n'): //newline character
+ res += JSON_TEXT('\n');
+ break;
+ case JSON_TEXT('r'): //return character
+ res += JSON_TEXT('\r');
+ break;
+ case JSON_TEXT('\\'): //backslash
+ res += JSON_TEXT('\\');
+ break;
+ case JSON_TEXT('/'): //forward slash
+ res += JSON_TEXT('/');
+ break;
+ case JSON_TEXT('b'): //backspace
+ res += JSON_TEXT('\b');
+ break;
+ case JSON_TEXT('f'): //formfeed
+ res += JSON_TEXT('\f');
+ break;
+ case JSON_TEXT('v'): //vertical tab
+ res += JSON_TEXT('\v');
+ break;
+ case JSON_TEXT('\''): //apostrophe
+ res += JSON_TEXT('\'');
+ break;
+ case JSON_TEXT('x'): //hexidecimal ascii code
+ res += Hex(++pos);
+ break;
+ case JSON_TEXT('u'): //utf character
+ #ifdef JSON_UNICODE
+ res += UTF(pos);
+ #else
+ //res += UTF8(pos);
+ res.append(UTF8_2(pos));
+ #endif
+ break;
+
+ //octal encoding
+ case JSON_TEXT('1'):
+ case JSON_TEXT('2'):
+ case JSON_TEXT('3'):
+ case JSON_TEXT('4'):
+ case JSON_TEXT('5'):
+ case JSON_TEXT('6'):
+ case JSON_TEXT('7'):
+ case JSON_TEXT('0'):
+ res += FromOctal(pos);
+ break;
+
+ #ifdef JSON_DEBUG
+ default:
+ JSON_FAIL(JSON_TEXT("Unsupported escaped character"));
+ #endif
+ }
+}
+
+#ifdef JSON_LESS_MEMORY
+ inline void doflag(const internalJSONNode * flag, bool which, bool x){
+ if (which){
+ flag -> _name_encoded = x;
+ } else {
+ flag -> _string_encoded = x;
+ }
+ }
+
+ json_string JSONWorker::FixString(const json_string & value_t, const internalJSONNode * flag, bool which){
+ #define setflag(x) doflag(flag, which, x)
+#else
+ json_string JSONWorker::FixString(const json_string & value_t, bool & flag){
+ #define setflag(x) flag = x
+#endif
+ /*
+ Do things like unescaping
+ */
+ setflag(false);
+ json_string res;
+ res.reserve(value_t.length()); //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating
+ const json_char * p = value_t.c_str();
+ while(*p){
+ switch (*p){
+ case JSON_TEXT('\\'):
+ setflag(true);
+ SpecialChar(++p, res);
+ break;
+ default:
+ res += *p;
+ break;
+ }
+ ++p;
+ }
+ return res;
+}
+
+#ifdef JSON_UNICODE
+ json_string JSONWorker::toSurrogatePair(json_uchar C){
+ JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit"));
+ JSON_ASSERT(sizeof(unsigned short) == 2, JSON_TEXT("size of unsigned short is not 16-bit"));
+ JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("json_char is not 32-bit"));
+ //Compute the high surrogate
+ const unsigned int U = (C >> 16) & 31;
+ unsigned short HiSurrogate = 0xD800 | (((unsigned short)U - 1) << 6) | ((unsigned short)C) >> 10;
+
+ //compute the low surrogate
+ unsigned short LoSurrogate = (unsigned short) (0xDC00 | ((unsigned short)C) & 1023);
+
+ json_string res;
+ res += toUTF8(HiSurrogate);
+ res += toUTF8(LoSurrogate);
+ return res;
+ }
+#endif
+
+json_string JSONWorker::toUTF8(json_uchar p){
+ #ifdef JSON_UNICODE
+ if (p > 0xFFFF) return toSurrogatePair(p);
+ #endif
+ json_string res(JSON_TEXT("\\u"));
+ #ifdef JSON_UNICODE
+ json_uchar hihi = ((p & 0xF000) >> 12) + 48;
+ if (hihi > 57) hihi += 7; //A-F don't immediately follow 0-9, so have to further adjust those
+ json_uchar hilo = ((p & 0x0F00) >> 8) + 48;
+ if (hilo > 57) hilo += 7; //A-F don't immediately follow 0-9, so have to further adjust those
+ res += hihi;
+ res += hilo;
+ json_uchar hi = ((p & 0x00F0) >> 4) + 48;
+ #else
+ res += JSON_TEXT("00");
+ json_uchar hi = (p >> 4) + 48;
+ #endif
+ //convert the character to be escaped into two digits between 0 and 15
+ if (hi > 57) hi += 7; //A-F don't immediately follow 0-9, so have to further adjust those
+ json_uchar lo = (p & 0x000F) + 48;
+ if (lo > 57) lo += 7; //A-F don't immediately follow 0-9, so have to further adjust those
+ res += hi;
+ res += lo;
+ return res;
+}
+
+json_string JSONWorker::UnfixString(const json_string & value_t, bool flag){
+ if (!flag) return value_t;
+ /*
+ Re-escapes a json_string so that it can be written out into a JSON file
+ */
+ json_string res;
+ res.reserve(value_t.length()); //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating
+ const json_char * p = value_t.c_str();
+ while(*p){
+ switch(*p){
+ case JSON_TEXT('\"'): //quote character
+ res += JSON_TEXT("\\\"");
+ break;
+ case JSON_TEXT('\t'): //tab character
+ res += JSON_TEXT("\\t");
+ break;
+ case JSON_TEXT('\n'): //newline character
+ res += JSON_TEXT("\\n");
+ break;
+ case JSON_TEXT('\r'): //return character
+ res += JSON_TEXT("\\r");
+ break;
+ case JSON_TEXT('\\'): //backslash
+ res += JSON_TEXT("\\\\");
+ break;
+ case JSON_TEXT('/'): //forward slash
+ res += JSON_TEXT("\\/");
+ break;
+ case JSON_TEXT('\b'): //backspace
+ res += JSON_TEXT("\\b");
+ break;
+ case JSON_TEXT('\f'): //formfeed
+ res += JSON_TEXT("\\f");
+ break;
+ case JSON_TEXT('\v'): //vertical tab
+ res += JSON_TEXT("\\v");
+ break;
+ case JSON_TEXT('\''): //apostrophe
+ res += JSON_TEXT("\\\'");
+ break;
+ default:
+ /*if (((json_uchar)(*p) < 32) || ((json_uchar)(*p) > 126)) {
+ //res += toUTF8((json_uchar)(*p));
+ } else*/ {
+ res += *p;
+ }
+ break;
+ }
+ ++p;
+ }
+ return res;
+}
+
+//Create a childnode
+#ifdef JSON_COMMENTS
+ #define ARRAY_PARAM bool array //Just to supress warnings
+#else
+ #define ARRAY_PARAM bool
+#endif
+inline void JSONWorker::NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, ARRAY_PARAM){
+ #ifdef JSON_COMMENTS
+ const json_char * runner = (array) ? value.c_str() : name.c_str();
+ json_string _comment;
+ if (*runner == '\5') { //multiple comments will be consolidated into one
+ newcomment:
+ while(*(++runner) != '\5') {
+ JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed"));
+ _comment += *runner;
+ }
+ if (*(++runner) == '\5') { //step past the trailing tag
+ _comment += '\n';
+ goto newcomment;
+ }
+ }
+ internalJSONNode * myinternal;
+ if (array){
+ myinternal = internalJSONNode::newInternal(name, runner);
+ } else {
+ myinternal = internalJSONNode::newInternal(++runner, value);
+ }
+ JSONNode * child = JSONNode::newJSONNode(myinternal);
+ child -> set_comment(_comment);
+ const_cast<internalJSONNode*>(parent) -> Children.push_back(child); //attach it to the parent node
+ #else
+ const_cast<internalJSONNode*>(parent) -> Children.push_back(JSONNode::newJSONNode(internalJSONNode::newInternal(name.c_str() + 1, value))); //attach it to the parent node
+ #endif
+}
+
+//Create a subarray
+void JSONWorker::DoArray(const internalJSONNode * parent, const json_string & value_t){
+ /*
+ This takes an array and creates nodes out of them
+ */
+ JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoArray is empty"));
+ JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('['), JSON_TEXT("DoArray is not an array"), parent -> Nullify(); return;);
+ const size_t len = value_t.length();
+ if (len <= 2) return; // just a [] (blank array)
+
+ //Not sure what's in the array, so we have to use commas
+ size_t starting = 1; //ignore the [
+ size_t ending = FindNextRelevant(JSON_TEXT(','), value_t, 1);
+ while (ending != json_string::npos){
+ #ifdef JSON_SAFE
+ json_string newValue = value_t.substr(starting, ending - starting);
+ JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;);
+ NewNode(parent, JSON_TEXT(""), newValue, true);
+ #else
+ NewNode(parent, JSON_TEXT(""), value_t.substr(starting, ending - starting), true);
+ #endif
+ starting = ending + 1;
+ ending = FindNextRelevant(JSON_TEXT(','), value_t, starting);
+ }
+ //since the last one will not find the comma, we have to add it here, but ignore the final ]
+
+ #ifdef JSON_SAFE
+ json_string newValue = value_t.substr(starting, len - starting - 1);
+ JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;);
+ NewNode(parent, JSON_TEXT(""), newValue, true);
+ #else
+ NewNode(parent, JSON_TEXT(""), value_t.substr(starting, len - starting - 1), true);
+ #endif
+}
+
+//Create all child nodes
+void JSONWorker::DoNode(const internalJSONNode * parent, const json_string & value_t){
+ /*
+ This take a node and creates its members and such
+ */
+ JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoNode is empty"));
+ JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('{'), JSON_TEXT("DoNode is not an node"), parent -> Nullify(); return;);
+ const size_t len = value_t.length();
+ if (len <= 2) return; // just a {} (blank node)
+
+ size_t name_starting = 1; //ignore the {
+ size_t name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, 1); //find where the name ends
+ JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;);
+ json_string name = value_t.substr(name_starting, name_ending - 2); //pull the name out
+ size_t value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending); //find the end of the value
+ while (value_ending != json_string::npos){
+ NewNode(parent, name, value_t.substr(name_ending + 1, value_ending - name_ending - 1), false);
+ name_starting = value_ending + 1;
+ name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, name_starting);
+ JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;);
+ name = value_t.substr(name_starting, name_ending - name_starting - 1);
+ value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending);
+ }
+ //since the last one will not find the comma, we have to add it here
+ NewNode(parent, name, value_t.substr(name_ending + 1, len - name_ending - 2), false);
+}