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