diff options
| author | Kirill Volinsky <mataes2007@gmail.com> | 2012-12-17 14:19:09 +0000 | 
|---|---|---|
| committer | Kirill Volinsky <mataes2007@gmail.com> | 2012-12-17 14:19:09 +0000 | 
| commit | d3a54e309c8c6335a5d6384d3e239bd7bc9390f6 (patch) | |
| tree | d45e6ca446392d9ce9acf5b4b20e75dd5d85af4f /src/modules/json/JSONWorker.cpp | |
| parent | 375155f8dcd69863f1b9a220c5f890596844e99d (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.cpp | 1398 | 
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);
 +}
  | 
