1 #include "JSONWorker.h"
2 
3 bool used_ascii_one = false;  //used to know whether or not to check for intermediates when writing, once flipped, can't be unflipped
ascii_one(void)4 inline json_char ascii_one(void) json_nothrow {
5 	used_ascii_one = true;
6 	return JSON_TEXT('\1');
7 }
8 
9 #ifdef JSON_READ_PRIORITY
10 
parse(const json_string & json)11 JSONNode JSONWorker::parse(const json_string & json) json_throws(std::invalid_argument) {
12 	json_auto<json_char> s;
13 	size_t len;
14 	s.set(RemoveWhiteSpace(json, len, true));
15 	return _parse_unformatted(s.ptr, s.ptr + len);
16 }
17 
parse_unformatted(const json_string & json)18 JSONNode JSONWorker::parse_unformatted(const json_string & json) json_throws(std::invalid_argument) {
19     #if defined JSON_DEBUG || defined JSON_SAFE
20 	   #ifndef JSON_NO_EXCEPTIONS
21 		  JSON_ASSERT_SAFE((json[0] == JSON_TEXT('{')) || (json[0] == JSON_TEXT('[')), JSON_TEXT("Not JSON!"), throw std::invalid_argument(json_global(EMPTY_STD_STRING)););
22 	   #else
23 		  JSON_ASSERT_SAFE((json[0] == JSON_TEXT('{')) || (json[0] == JSON_TEXT('[')), JSON_TEXT("Not JSON!"), return JSONNode(JSON_NULL););
24 	   #endif
25     #endif
26 	return _parse_unformatted(json.data(), json.data() + json.length());
27 }
28 
_parse_unformatted(const json_char * json,const json_char * const end)29 JSONNode JSONWorker::_parse_unformatted(const json_char * json, const json_char * const end) json_throws(std::invalid_argument) {
30     #ifdef JSON_COMMENTS
31 	   json_char firstchar = *json;
32 	   json_string _comment;
33 	   json_char * runner = (json_char*)json;
34 	   if (json_unlikely(firstchar == JSON_TEMP_COMMENT_IDENTIFIER)){  //multiple comments will be consolidated into one
35 		  newcomment:
36 		  while(*(++runner) != JSON_TEMP_COMMENT_IDENTIFIER){
37 			 JSON_ASSERT(runner != end, JSON_TEXT("Removing white space failed"));
38 			 _comment += *runner;
39 		  }
40 		  firstchar = *(++runner); //step past the trailing tag
41 		  if (json_unlikely(firstchar == JSON_TEMP_COMMENT_IDENTIFIER)){
42 			 _comment += JSON_TEXT('\n');
43 			 goto newcomment;
44 		  }
45 	   }
46     #else
47 	   const json_char firstchar = *json;
48     #endif
49 
50     switch (firstchar){
51         case JSON_TEXT('{'):
52         case JSON_TEXT('['):
53 		  #if defined JSON_DEBUG || defined JSON_SAFE
54 			 if (firstchar == JSON_TEXT('[')){
55 				if (json_unlikely(*(end - 1) != JSON_TEXT(']'))){
56 				    JSON_FAIL(JSON_TEXT("Missing final ]"));
57 				    break;
58 				}
59 			 } else {
60 				if (json_unlikely(*(end - 1) != JSON_TEXT('}'))){
61 				    JSON_FAIL(JSON_TEXT("Missing final }"));
62 				    break;
63 				}
64 			 }
65 		  #endif
66 		  #ifdef JSON_COMMENTS
67 			 JSONNode foo(json_string(runner, end - runner));
68 			 foo.set_comment(_comment);
69 			 return JSONNode(true, foo);  //forces it to simply return the original interal, even with ref counting off
70 		  #else
71 			 return JSONNode(json_string(json, end - json));
72 		  #endif
73     }
74 
75     JSON_FAIL(JSON_TEXT("Not JSON!"));
76     #ifndef JSON_NO_EXCEPTIONS
77 	   throw std::invalid_argument(json_global(EMPTY_STD_STRING));
78     #else
79 	   return JSONNode(JSON_NULL);
80     #endif
81 }
82 #endif
83 
84 #define QUOTECASE()\
85     case JSON_TEXT('\"'):\
86 	   while (*(++p) != JSON_TEXT('\"')){\
87 		  JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), return json_string::npos;);\
88 	   }\
89 	   break;
90 
91 #if defined(JSON_DEBUG) || defined(JSON_SAFE)
92     #define NULLCASE(error)\
93 	   case JSON_TEXT('\0'):\
94 		  JSON_FAIL_SAFE(error, return json_string::npos;);\
95 		  break;
96 #else
97     #define NULLCASE(error)
98 #endif
99 
100 #define BRACKET(left, right)\
101     case left: {\
102 	   size_t brac = 1;\
103 	   while (brac){\
104 		  switch (*(++p)){\
105 			 case right:\
106 				--brac;\
107 				break;\
108 			 case left:\
109 				++brac;\
110 				break;\
111 			 QUOTECASE()\
112 			 NULLCASE(JSON_TEXT("Null terminator inside of a bracket"))\
113 		  }\
114 	   }\
115 	   break;}\
116     case right:\
117 	   return json_string::npos;
118 
119 
120 
121 #if defined(JSON_READ_PRIORITY) || defined(JSON_STREAM)
122 	#if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY)))
123 		#define FIND_NEXT_RELEVANT(ch, vt, po) JSONWorker::FindNextRelevant<ch>(vt, po)
124 		template<json_char ch>
FindNextRelevant(const json_string & value_t,const size_t pos)125 		size_t JSONWorker::FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow {
126 	#else
127 		#define FIND_NEXT_RELEVANT(ch, vt, po) JSONWorker::FindNextRelevant(ch, vt, po)
128 		size_t JSONWorker::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow {
129 	#endif
130 		json_string::const_iterator start = value_t.begin();
131 		json_string::const_iterator e = value_t.end();
132 	   for (json_string::const_iterator p = value_t.begin() + pos; p != e; ++p){
133 		  if (json_unlikely(*p == ch)) return p - start;
134 		  switch (*p){
135 				BRACKET(JSON_TEXT('['), JSON_TEXT(']'))
136 				BRACKET(JSON_TEXT('{'), JSON_TEXT('}'))
137 				QUOTECASE()
138 		  }
139 	   };
140 	   return json_string::npos;
141     }
142 #endif
143 
144 #ifdef JSON_COMMENTS
145     #define COMMENT_DELIMITER() *runner++ = JSON_TEMP_COMMENT_IDENTIFIER
146     #define AND_RUNNER ,runner
147     inline void SingleLineComment(const json_char * & p, const json_char * const end, json_char * & runner) json_nothrow {
148 	   //It is okay to add two '\5' characters here because at minimun the # and '\n' are replaced, so it's at most the same size
149 	   COMMENT_DELIMITER();
150 	   while((++p != end) && (*p != JSON_TEXT('\n'))){
151 		  *runner++ = *p;
152 	   }
153 	   COMMENT_DELIMITER();
154     }
155 #else
156     #define COMMENT_DELIMITER() (void)0
157     #define AND_RUNNER
158 #endif
159 
160 #ifndef JSON_STRICT
161 inline void SingleLineComment(const json_char * & p, const json_char * const end) json_nothrow {
162     while((++p != end) && (*p != JSON_TEXT('\n')));
163 }
164 #endif
165 
166 #if defined(JSON_LESS_MEMORY) && defined(JSON_READ_PRIORITY)
167 	#define PRIVATE_REMOVEWHITESPACE(T, value_t, escapeQuotes, len) private_RemoveWhiteSpace(T, value_t, escapeQuotes, len)
168 	json_char * private_RemoveWhiteSpace(bool T, const json_string & value_t, bool escapeQuotes, size_t & len) json_nothrow {
169 #else
170 	#define PRIVATE_REMOVEWHITESPACE(T, value_t, escapeQuotes, len) private_RemoveWhiteSpace<T>(value_t, escapeQuotes, len)
171 	template<bool T>
172 	json_char * private_RemoveWhiteSpace(const json_string & value_t, bool escapeQuotes, size_t & len) json_nothrow {
173 #endif
174 	json_char * result;
175 	json_char * runner = result = json_malloc<json_char>(value_t.length() + 1);  //dealing with raw memory is faster than adding to a json_string
176 	JSON_ASSERT(result != 0, json_global(ERROR_OUT_OF_MEMORY));
177 	const json_char * const end = value_t.data() + value_t.length();
178 	for(const json_char * p = value_t.data(); p != end; ++p){
179 	  switch(*p){
180 		 case JSON_TEXT(' '):   //defined as white space
181 		 case JSON_TEXT('\t'):  //defined as white space
182 		 case JSON_TEXT('\n'):  //defined as white space
183 		 case JSON_TEXT('\r'):  //defined as white space
184 			break;
185 		#ifndef JSON_STRICT
186 			case JSON_TEXT('/'):  //a C comment
187 				if (*(++p) == JSON_TEXT('*')){  //a multiline comment
188 				   if (T) COMMENT_DELIMITER();
189 				   while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))){
190 					  if(p == end){
191 							COMMENT_DELIMITER();
192 							goto endofrunner;
193 						}
194 					  if (T) *runner++ = *p;
195 				   }
196 				   ++p;
197 				   if (T) COMMENT_DELIMITER();
198 				   break;
199 				}
200 				//Should be a single line C comment, so let it fall through to use the bash comment stripper
201 				JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofrunner;);
202 			case JSON_TEXT('#'):  //a bash comment
203 				if (T){
204 					SingleLineComment(p, end AND_RUNNER);
205 				} else {
206 					SingleLineComment(p, end);
207 				}
208 				break;
209 		 #endif
210 		 case JSON_TEXT('\"'):  //a quote
211 			*runner++ = JSON_TEXT('\"');
212 			while(*(++p) != JSON_TEXT('\"')){  //find the end of the quotation, as white space is preserved within it
213 				if(p == end) goto endofrunner;
214 				switch(*p){
215 				   case JSON_TEXT('\\'):
216 					  *runner++ = JSON_TEXT('\\');
217 					  if (escapeQuotes){
218 							*runner++ = (*++p == JSON_TEXT('\"')) ? ascii_one() : *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
219 					  } else {
220 							*runner++ = *++p;
221 					  }
222 					  break;
223 				   default:
224 					  *runner++ = *p;
225 					  break;
226 				}
227 			}
228 			//no break, let it fall through so that the trailing quote gets added
229 		 default:
230 			JSON_ASSERT_SAFE((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofrunner;);
231 			JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofrunner;);
232 			*runner++ = *p;
233 			break;
234 	  }
235 	}
236 	endofrunner:
237 	len = runner - result;
238 	return result;
239 }
240 
241 #ifdef JSON_READ_PRIORITY
242     json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t, size_t & len, bool escapeQuotes) json_nothrow  {
243 		json_char * result = PRIVATE_REMOVEWHITESPACE(true, value_t, escapeQuotes, len);
244 		result[len] = JSON_TEXT('\0');
245 		return result;
246     }
247 #endif
248 
249 json_char * JSONWorker::RemoveWhiteSpaceAndCommentsC(const json_string & value_t, bool escapeQuotes) json_nothrow {
250 	size_t len;
251 	json_char * result = PRIVATE_REMOVEWHITESPACE(false, value_t, escapeQuotes, len);
252 	result[len] = JSON_TEXT('\0');
253 	return result;
254 }
255 
256 json_string JSONWorker::RemoveWhiteSpaceAndComments(const json_string & value_t, bool escapeQuotes) json_nothrow {
257 	json_auto<json_char> s;
258     size_t len;
259 	s.set(PRIVATE_REMOVEWHITESPACE(false, value_t, escapeQuotes, len));
260 	return json_string(s.ptr, len);
261 }
262 
263 #ifdef JSON_READ_PRIORITY
264 /*
265  These three functions analyze json_string literals and convert them into std::strings
266  This includes dealing with special characters and utf characters
267  */
268 #ifdef JSON_UNICODE
269     inline json_uchar SurrogatePair(const json_uchar hi, const json_uchar lo) json_pure;
270     inline json_uchar SurrogatePair(const json_uchar hi, const json_uchar lo) json_nothrow {
271 	   JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit"));
272 	   JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("size of json_char is not 32-bit"));
273 	   return (((hi << 10) & 0x1FFC00) + 0x10000) | lo & 0x3FF;
274     }
275 
276     void JSONWorker::UTF(const json_char * & pos, json_string & result, const json_char * const end) json_nothrow {
277 		JSON_ASSERT_SAFE(((long long int )end - (long long int )pos) > 4, JSON_TEXT("UTF will go out of bounds"), return;);
278 	   json_uchar first = UTF8(pos, end);
279 	   if (json_unlikely((first > 0xD800) && (first < 0xDBFF) &&
280 		  (*(pos + 1) == '\\') && (*(pos + 2) == 'u'))){
281 			 const json_char * original_pos = pos;  //if the 2nd character is not correct I need to roll back the iterator
282 			 pos += 2;
283 			 json_uchar second = UTF8(pos, end);
284 			 //surrogate pair, not two characters
285 			 if (json_unlikely((second > 0xDC00) && (second < 0xDFFF))){
286 				result += SurrogatePair(first, second);
287 			 } else {
288 				pos = original_pos;
289 			 }
290 	   } else {
291 		  result += first;
292 	   }
293     }
294 #endif
295 
296 json_uchar JSONWorker::UTF8(const json_char * & pos, const json_char * const end) json_nothrow {
297 	JSON_ASSERT_SAFE(((long long int)end - (long long int)pos) > 4, JSON_TEXT("UTF will go out of bounds"), return JSON_TEXT('\0'););
298     #ifdef JSON_UNICODE
299 	   ++pos;
300 	   json_uchar temp = Hex(pos) << 8;
301 	   ++pos;
302 	   return temp | Hex(pos);
303     #else
304 	   JSON_ASSERT(*(pos + 1) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hihi)"));
305 	   JSON_ASSERT(*(pos + 2) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hilo)"));
306 	   pos += 3;
307 	   return Hex(pos);
308     #endif
309 }
310 
311 
312 json_char JSONWorker::Hex(const json_char * & pos) json_nothrow {
313     /*
314 	takes the numeric value of the next two characters and convert them
315 	\u0058 becomes 0x58
316 
317 	In case of \u, it's SpecialChar's responsibility to move past the first two chars
318 	as this method is also used for \x
319 	*/
320     //First character
321     json_uchar hi = *pos++ - 48;
322     if (hi > 48){  //A-F don't immediately follow 0-9, so have to pull them down a little
323 	   hi -= 39;
324     } else if (hi > 9){  //neither do a-f
325 	   hi -= 7;
326     }
327     //second character
328     json_uchar lo = *pos - 48;
329     if (lo > 48){  //A-F don't immediately follow 0-9, so have to pull them down a little
330 	   lo -= 39;
331     } else if (lo > 9){  //neither do a-f
332 	   lo -= 7;
333     }
334     //combine them
335     return (json_char)((hi << 4) | lo);
336 }
337 
338 #ifndef JSON_STRICT
339     inline json_char FromOctal(const json_char * & str, const json_char * const end) json_nothrow {
340 	   JSON_ASSERT_SAFE(((long long int)end - (long long int)str) > 3, JSON_TEXT("Octal will go out of bounds"), return JSON_TEXT('\0'););
341 	   str += 2;
342 	   return (json_char)(((((json_uchar)(*(str - 2) - 48))) << 6) | (((json_uchar)(*(str - 1) - 48)) << 3) | ((json_uchar)(*str - 48)));
343     }
344 #endif
345 
346 void JSONWorker::SpecialChar(const json_char * & pos, const json_char * const end, json_string & res) json_nothrow {
347 	JSON_ASSERT_SAFE(pos != end, JSON_TEXT("Special char termantion"), return;);
348     /*
349 	   Since JSON uses forward slash escaping for special characters within strings, I have to
350 	   convert these escaped characters into C characters
351 	*/
352     switch(*pos){
353 	   case JSON_TEXT('\1'):  //quote character (altered by RemoveWhiteSpace)
354 		  res += JSON_TEXT('\"');
355 		  break;
356 	   case JSON_TEXT('t'):	//tab character
357 		  res += JSON_TEXT('\t');
358 		  break;
359 	   case JSON_TEXT('n'):	//newline character
360 		  res += JSON_TEXT('\n');
361 		  break;
362 	   case JSON_TEXT('r'):	//return character
363 		  res += JSON_TEXT('\r');
364 		  break;
365 	   case JSON_TEXT('\\'):	//backslash
366 		  res += JSON_TEXT('\\');
367 		  break;
368 	   case JSON_TEXT('/'):	//forward slash
369 		  res += JSON_TEXT('/');
370 		  break;
371 	   case JSON_TEXT('b'):	//backspace
372 		  res += JSON_TEXT('\b');
373 		  break;
374 	   case JSON_TEXT('f'):	//formfeed
375 		  res += JSON_TEXT('\f');
376 		  break;
377 	   case JSON_TEXT('v'):	//vertical tab
378 		  res += JSON_TEXT('\v');
379 		  break;
380 	   case JSON_TEXT('u'):	//utf character
381 		  #ifdef JSON_UNICODE
382 			 UTF(pos, res, end);
383 		  #else
384 			 res += UTF8(pos, end);
385 		  #endif
386 		  break;
387 	   #ifndef JSON_STRICT
388 		  case JSON_TEXT('x'):   //hexidecimal ascii code
389 			 JSON_ASSERT_SAFE(((long long int )end - (long long int )pos) > 3, JSON_TEXT("Hex will go out of bounds"), res += JSON_TEXT('\0'); return;);
390 			 res += Hex(++pos);
391 			 break;
392 
393 		  #ifdef __GNUC__
394 			 case JSON_TEXT('0') ... JSON_TEXT('7'):
395 		  #else
396 			 //octal encoding
397 			 case JSON_TEXT('0'):
398 			 case JSON_TEXT('1'):
399 			 case JSON_TEXT('2'):
400 			 case JSON_TEXT('3'):
401 			 case JSON_TEXT('4'):
402 			 case JSON_TEXT('5'):
403 			 case JSON_TEXT('6'):
404 			 case JSON_TEXT('7'):
405 		  #endif
406 			 res += FromOctal(pos, end);
407 			 break;
408 		  default:
409 			 res += *pos;
410 			 break;
411 	   #elif defined(JSON_DEBUG)
412 		  default:
413 			 JSON_FAIL(JSON_TEXT("Unsupported escaped character"));
414 			 break;
415 	   #endif
416     }
417 }
418 
419 #ifdef JSON_LESS_MEMORY
420     inline void doflag(const internalJSONNode * flag, bool which, bool x) json_nothrow {
421 	   if (json_likely(which)){
422 		  flag -> _name_encoded = x;
423 	   } else {
424 		  flag -> _string_encoded = x;
425 	   }
426     }
427 
428     json_string JSONWorker::FixString(const json_string & value_t, const internalJSONNode * flag, bool which) json_nothrow {
429     #define setflag(x) doflag(flag, which, x)
430 #else
431     json_string JSONWorker::FixString(const json_string & value_t, bool & flag) json_nothrow {
432     #define setflag(x) flag = x
433 #endif
434 
435     //Do things like unescaping
436     setflag(false);
437     json_string res;
438     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
439 	const json_char * const end = value_t.data() + value_t.length();
440     for(const json_char * p = value_t.data(); p != end; ++p){
441 	   switch (*p){
442 		  case JSON_TEXT('\\'):
443 			 setflag(true);
444 			 SpecialChar(++p, end, res);
445 			 break;
446 		  default:
447 			 res += *p;
448 			 break;
449 	   }
450     }
451 	shrinkString(res);  //because this is actually setting something to be stored, shrink it it need be
452 	return res;
453 }
454 #endif
455 
456 #ifdef JSON_UNICODE
457     #ifdef JSON_ESCAPE_WRITES
458 	   json_string JSONWorker::toSurrogatePair(json_uchar C) json_nothrow {
459 		  JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit"));
460 		  JSON_ASSERT(sizeof(unsigned short) == 2, JSON_TEXT("size of unsigned short is not 16-bit"));
461 		  JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("json_char is not 32-bit"));
462 
463 		  //Compute the high surrogate
464 		  unsigned short HiSurrogate = 0xD800 | (((unsigned short)((unsigned int)((C >> 16) & 31)) - 1) << 6) | ((unsigned short)C) >> 10;
465 
466 		  //compute the low surrogate
467 		  unsigned short LoSurrogate = (unsigned short) (0xDC00 | ((unsigned short)C & 1023));
468 
469 		  json_string res;
470 		  res += toUTF8(HiSurrogate);
471 		  res += toUTF8(LoSurrogate);
472 		  return res;
473 	   }
474     #endif
475 #endif
476 
477 #ifdef JSON_ESCAPE_WRITES
478     json_string JSONWorker::toUTF8(json_uchar p) json_nothrow {
479 	   #ifdef JSON_UNICODE
480 		  if (json_unlikely(p > 0xFFFF)) return toSurrogatePair(p);
481 	   #endif
482 	   json_string res(JSON_TEXT("\\u"));
483 	   #ifdef JSON_UNICODE
484 		  START_MEM_SCOPE
485 			 json_uchar hihi = ((p & 0xF000) >> 12) + 48;
486 			 if (hihi > 57) hihi += 7; //A-F don't immediately follow 0-9, so have to further adjust those
487 			 json_uchar hilo = ((p & 0x0F00) >> 8) + 48;
488 			 if (hilo > 57) hilo += 7; //A-F don't immediately follow 0-9, so have to further adjust those
489 			 res += hihi;
490 			 res += hilo;
491 		  END_MEM_SCOPE
492 		  json_uchar hi = ((p & 0x00F0) >> 4) + 48;
493 	   #else
494 		  res += JSON_TEXT("00");
495 		  json_uchar hi = (p >> 4) + 48;
496 	   #endif
497 	   //convert the character to be escaped into two digits between 0 and 15
498 	   if (hi > 57) hi += 7; //A-F don't immediately follow 0-9, so have to further adjust those
499 	   json_uchar lo = (p & 0x000F) + 48;
500 	   if (lo > 57) lo += 7; //A-F don't immediately follow 0-9, so have to further adjust those
501 	   res += hi;
502 	   res += lo;
503 	   return res;
504     }
505 #endif
506 
507 void JSONWorker::UnfixString(const json_string & value_t, bool flag, json_string & res) json_nothrow {
508     if (!flag){
509 		res += value_t;
510 		return;
511 	}
512     //Re-escapes a json_string so that it can be written out into a JSON file
513 	const json_char * const end = value_t.data() + value_t.length();
514     for(const json_char * p = value_t.data(); p != end; ++p){
515 	   switch(*p){
516 		  case JSON_TEXT('\"'):  //quote character
517 			 res += JSON_TEXT("\\\"");
518 			 break;
519 		  case JSON_TEXT('\\'):	//backslash
520 			 res += JSON_TEXT("\\\\");
521 			 break;
522 		  #ifdef JSON_ESCAPE_WRITES
523 			 case JSON_TEXT('\t'):	//tab character
524 				res += JSON_TEXT("\\t");
525 				break;
526 			 case JSON_TEXT('\n'):	//newline character
527 				res += JSON_TEXT("\\n");
528 				break;
529 			 case JSON_TEXT('\r'):	//return character
530 				res += JSON_TEXT("\\r");
531 				break;
532 			 case JSON_TEXT('/'):	//forward slash
533 				res += JSON_TEXT("\\/");
534 				break;
535 			 case JSON_TEXT('\b'):	//backspace
536 				res += JSON_TEXT("\\b");
537 				break;
538 			 case JSON_TEXT('\f'):	//formfeed
539 				res += JSON_TEXT("\\f");
540 				break;
541 			 default:
542 			 {
543 				if (json_unlikely(((json_uchar)(*p) < 32) || ((json_uchar)(*p) > 126))){
544 				    res += toUTF8((json_uchar)(*p));
545 				} else {
546 				    res += *p;
547 				}
548 			}
549 				break;
550 		  #else
551 			 default:
552 				res += *p;
553 				break;
554 		  #endif
555 	   }
556     }
557 }
558 
559 #ifdef JSON_READ_PRIORITY
560 //Create a childnode
561 #ifdef JSON_COMMENTS
562     #define ARRAY_PARAM bool array  //Just to supress warnings
563 #else
564     #define ARRAY_PARAM bool
565 #endif
566 inline void JSONWorker::NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, ARRAY_PARAM) json_nothrow {
567     #ifdef JSON_COMMENTS
568 	   JSONNode * child;
569 	   START_MEM_SCOPE
570 		  json_string _comment;
571 		  START_MEM_SCOPE
572 			 const json_char * runner = ((array) ? value.data() : name.data());
573 			 #ifdef JSON_DEBUG
574 				const json_char * const end = runner + value.length();
575 			#endif
576 			 if (json_unlikely(*runner == JSON_TEMP_COMMENT_IDENTIFIER)){  //multiple comments will be consolidated into one
577 				size_t count;
578 				const json_char * start;
579 			    newcomment:
580 				count = 0;
581 				start = runner + 1;
582 				while(*(++runner) != JSON_TEMP_COMMENT_IDENTIFIER){
583 				    JSON_ASSERT(runner != end, JSON_TEXT("Removing white space failed"));
584 					++count;
585 				}
586 				if (count) _comment += json_string(start, count);
587 				if (json_unlikely(*(++runner) == JSON_TEMP_COMMENT_IDENTIFIER)){ //step past the trailing tag
588 				    _comment += JSON_TEXT('\n');
589 				    goto newcomment;
590 				}
591 			 }
592 			 internalJSONNode * myinternal;
593 			 if (array){
594 				myinternal = internalJSONNode::newInternal(name, runner);
595 			 } else {
596 				myinternal = internalJSONNode::newInternal(++runner, value);
597 			 }
598 			 child = JSONNode::newJSONNode(myinternal);
599 		  END_MEM_SCOPE
600 		  child -> set_comment(_comment);
601 	   END_MEM_SCOPE
602 	   const_cast<internalJSONNode*>(parent) -> CHILDREN -> push_back(child);   //attach it to the parent node
603     #else
604 	if (name.empty()){
605 	   	const_cast<internalJSONNode*>(parent) -> CHILDREN -> push_back(JSONNode::newJSONNode(internalJSONNode::newInternal(name, value)));	    //attach it to the parent node
606 	} else {
607 		const_cast<internalJSONNode*>(parent) -> CHILDREN -> push_back(JSONNode::newJSONNode(internalJSONNode::newInternal(json_string(name.begin() + 1, name.end()), value)));	    //attach it to the parent node
608 	}
609     #endif
610 }
611 
612 //Create a subarray
613 void JSONWorker::DoArray(const internalJSONNode * parent, const json_string & value_t) json_nothrow {
614 	//This takes an array and creates nodes out of them
615 	JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoArray is empty"));
616 	JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('['), JSON_TEXT("DoArray is not an array"), parent -> Nullify(); return;);
617 	if (json_unlikely(value_t.length() <= 2)) return;  // just a [] (blank array)
618 
619 	#ifdef JSON_SAFE
620 		json_string newValue;  //share this so it has a reserved buffer
621 	#endif
622 	size_t starting = 1;  //ignore the [
623 
624 	//Not sure what's in the array, so we have to use commas
625 	for(size_t ending = FIND_NEXT_RELEVANT(JSON_TEXT(','), value_t, 1);
626 		ending != json_string::npos;
627 		ending = FIND_NEXT_RELEVANT(JSON_TEXT(','), value_t, starting)){
628 
629 		#ifdef JSON_SAFE
630 			newValue.assign(value_t.begin() + starting, value_t.begin() + ending);
631 			JSON_ASSERT_SAFE(FIND_NEXT_RELEVANT(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;);
632 			NewNode(parent, json_global(EMPTY_JSON_STRING), newValue, true);
633 		#else
634 			NewNode(parent, json_global(EMPTY_JSON_STRING), json_string(value_t.begin() + starting, value_t.begin() + ending), true);
635 		#endif
636 		starting = ending + 1;
637 	}
638 	//since the last one will not find the comma, we have to add it here, but ignore the final ]
639 
640 	#ifdef JSON_SAFE
641 		newValue.assign(value_t.begin() + starting, value_t.end() - 1);
642 		JSON_ASSERT_SAFE(FIND_NEXT_RELEVANT(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;);
643 		NewNode(parent, json_global(EMPTY_JSON_STRING), newValue, true);
644 	#else
645 		NewNode(parent, json_global(EMPTY_JSON_STRING), json_string(value_t.begin() + starting, value_t.end() - 1), true);
646 	#endif
647 }
648 
649 
650 //Create all child nodes
651 void JSONWorker::DoNode(const internalJSONNode * parent, const json_string & value_t) json_nothrow {
652 	//This take a node and creates its members and such
653 	JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoNode is empty"));
654 	JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('{'), JSON_TEXT("DoNode is not an node"), parent -> Nullify(); return;);
655 	if (json_unlikely(value_t.length() <= 2)) return;  // just a {} (blank node)
656 
657 	size_t name_ending = FIND_NEXT_RELEVANT(JSON_TEXT(':'), value_t, 1);  //find where the name ends
658 	JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;);
659 	json_string name(value_t.begin() + 1, value_t.begin() + name_ending - 1);	  //pull the name out
660 	for (size_t value_ending = FIND_NEXT_RELEVANT(JSON_TEXT(','), value_t, name_ending),  //find the end of the value
661 		 name_starting = 1;  //ignore the {
662 		 value_ending != json_string::npos;
663 		 value_ending = FIND_NEXT_RELEVANT(JSON_TEXT(','), value_t, name_ending)){
664 
665 		NewNode(parent, name, json_string(value_t.begin() + name_ending + 1, value_t.begin() + value_ending), false);
666 		name_starting = value_ending + 1;
667 		name_ending = FIND_NEXT_RELEVANT(JSON_TEXT(':'), value_t, name_starting);
668 		JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;);
669 		name.assign(value_t.begin() + name_starting, value_t.begin() + name_ending - 1);
670 	}
671 	//since the last one will not find the comma, we have to add it here
672 	NewNode(parent, name, json_string(value_t.begin() + name_ending + 1, value_t.end() - 1), false);
673 }
674 #endif
675