Jamoma API  0.6.0.a19
JSONWorker.cpp
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(((long)end - (long)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)end - (long)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)end - (long)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)end - (long)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