The R Project SVN R-packages

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7747 ripley 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
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
 
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
 
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
 
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>
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((end > 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((end > 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((end > 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((end > 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