diff options
Diffstat (limited to 'plugins/JSON/Source/JSONWorker.cpp')
| -rw-r--r-- | plugins/JSON/Source/JSONWorker.cpp | 676 | 
1 files changed, 676 insertions, 0 deletions
diff --git a/plugins/JSON/Source/JSONWorker.cpp b/plugins/JSON/Source/JSONWorker.cpp new file mode 100644 index 0000000000..093d9a75b2 --- /dev/null +++ b/plugins/JSON/Source/JSONWorker.cpp @@ -0,0 +1,676 @@ +#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((unsigned json_char)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); +				JSON_ASSERT_SAFE((unsigned json_char)*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((unsigned json_char)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); +			 JSON_ASSERT_SAFE((unsigned json_char)*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 unsigned json_char SurrogatePair(const unsigned json_char hi, const unsigned json_char lo){ +	   JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit")); +	   JSON_ASSERT(sizeof(unsigned json_char) == 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; +	   unsigned json_char first = UTF8(pos); +	   if ((*(pos + 1) == '\\') && (*(pos + 2) == 'u')){ +		  pos += 2; +		  unsigned json_char 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 + +unsigned json_char JSONWorker::UTF8(const json_char * & pos){ +    #ifdef JSON_UNICODE +	   ++pos; +	   unsigned json_char 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 char szU8Buffer[10]; + +json_char* JSONWorker::UTF8_2(const json_char * & pos){ +    #ifdef JSON_UNICODE +	   ++pos; +	   unsigned json_char 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 +    unsigned json_char 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 +    unsigned json_char 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 unsigned json_char top = ((unsigned json_char)(*(str++) - 48)); +    const unsigned json_char middle = (unsigned json_char)(*(str++) - 48); +    const unsigned json_char bottom = (unsigned json_char)(*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(unsigned json_char 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(unsigned json_char) == 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(unsigned json_char p){ +    #ifdef JSON_UNICODE +	   if (p > 0xFFFF) return toSurrogatePair(p); +    #endif +    json_string res(JSON_TEXT("\\u")); +    #ifdef JSON_UNICODE +	   unsigned json_char hihi = ((p & 0xF000) >> 12) + 48; +	   if (hihi > 57) hihi += 7; //A-F don't immediately follow 0-9, so have to further adjust those +	   unsigned json_char 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; +	   unsigned json_char hi = ((p & 0x00F0) >> 4) + 48; +    #else +	   res += JSON_TEXT("00"); +	   unsigned json_char 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 +    unsigned json_char 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 (((unsigned json_char)(*p) < 32) || ((unsigned json_char)(*p) > 126)){ +				//res += toUTF8((unsigned json_char)(*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); +}  | 
