JSONWorker.cpp 24 KB

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