dxjson  1.0
JSON library for C++
 All Classes Namespaces Files Functions Variables Enumerations Pages
dxjson.cpp
1 // Copyright (C) 2013-2016 DNAnexus, Inc.
2 //
3 // This file is part of dx-toolkit (DNAnexus platform client libraries).
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License"); you may
6 // not use this file except in compliance with the License. You may obtain a
7 // copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 // License for the specific language governing permissions and limitations
15 // under the License.
16 
17 #include "dxjson.h"
18 #include <cstdio>
19 
20 using namespace dx;
21 
25 static double json_epsilon = std::numeric_limits<double>::epsilon();
26 
27 double JSON::getEpsilon() {
28  return json_epsilon;
29 }
30 
31 // TODO:
32 // 1) Currently json strings are "escaped" only when using write() method, and stored as normal
33 // std::string. So if we use iterators like object_iterator for accessing all key in
34 // a json object, we will read them as normal strings (as they are stored in memory),
35 // rather then their stringified() form. For ex, a key: "\n" (a single character - newline),
36 // will be read as char arr[] = {10, 0} (as stored internally) by an object_iterator,
37 // rather than arr[] = {'\','n', 0} (as would have been printed out by toString() ).
38 // Figure out what the "correct" convention should be, and if required fix it.
39 
40 namespace JSON_Utility
41 {
42 
43  std::string getValidatedUTF8String(const std::string &src) {
44  std::string out;
45  utf8::replace_invalid(src.begin(), src.end(), back_inserter(out));
46  return out;
47  }
48 
49  std::string itos(int i) // convert int to string
50  {
51  std::stringstream s;
52  s << i;
53  return s.str();
54  }
55 
56  void SkipWhiteSpace(std::istream &in)
57  {
58  int c;
59  do
60  {
61  c = in.get();
62  } while ((c >= 0) && isspace(c));
63  if (c >= 0)
64  in.unget();
65  }
66 
67  void WriteEscapedString(const std::string &s, std::ostream &out, bool enclosingQuotes = true)
68  {
69  if (enclosingQuotes)
70  out<<'"';
71 
72  for (unsigned i = 0; i < s.length(); ++i)
73  {
74  if (s[i] >= 0x0000 && s[i] <= 0x001f)
75  {
76  // Control character case, should be escaped
77  // http://stackoverflow.com/questions/4901133/json-and-escaping-characters
78  char temphex[5] = {0};
79  switch(s[i]) {
80  case '\b':
81  out<<"\\b";
82  break;
83  case '\f':
84  out<<"\\f";
85  break;
86  case '\n':
87  out<<"\\n";
88  break;
89  case '\r':
90  out<<"\\r";
91  break;
92  case '\t':
93  out<<"\\t";
94  break;
95  default:
96  out<<"\\u";
97  sprintf(temphex, "%04x", s[i]);
98  out<<std::string(temphex);
99  break;
100  }
101  }
102  else {
103  switch(s[i]) {
104  case '"':
105  out<<"\\\"";
106  break;
107  case '\\':
108  out<<"\\\\";
109  break;
110  default:
111  out<<s[i];
112  }
113  }
114  }
115  if (enclosingQuotes)
116  out<<'"';
117  }
118 
119  // Returns true if "ch" represent start of a number token in JSON
120  bool isNumberStart(int ch) {
121  if (ch == '-' || isdigit(ch))
122  return true;
123  return false;
124  }
125 
126  bool isNullStart(int ch) {
127  return (ch == 'n');
128  }
129 
130  bool isStringStart(int ch) {
131  return (ch == '\"');
132  }
133 
134  bool isBooleanStart(int ch) {
135  return (ch == 't' || ch == 'f');
136  }
137 
138  bool isArrayStart(int ch) {
139  return (ch == '[');
140  }
141 
142  bool isObjectStart(int ch) {
143  return (ch == '{');
144  }
145 
146  // This function is designed specifically for use from ReadNumberValue() only
147  // It assumes that string provided as *input* to the function is already in this form (regex):
148  // [0-9-]{1,1}[-0-9+eE.]*
149  // It will then perform extra checks to find out if it corresponds to a valid JSON number or not
150  // Ref: http://www.json.org
151  // http://jsonlint.com/
152  // Added later:
153  // Note: actually now this function does not assume input in any particular format
154  // and finds out if any arbitrary json string is a valid number or not.
155  bool isValidJsonNumber(const std::string &s) {
156  unsigned len = s.length();
157  bool dot = false;
158  bool e = false;
159  if (len == 0)
160  return false;
161 
162  unsigned start = (s[0] == '-') ? 1 : 0;
163  if (!isdigit(s[start]))
164  return false;
165 
166  if (start + 1 == len)
167  return true;
168 
169  if (s[start] == '0' && isdigit(s[start + 1]))
170  return false;
171 
172  for (unsigned i = start + 1; i < len; ++i) {
173  switch (s[i]) {
174  case '.':
175  if (e || dot)
176  return false;
177  dot = true;
178  break;
179  case 'e': // Desired fall through to next case statement ('E')
180  case 'E':
181  if (e)
182  return false;
183  e = true;
184  if (i + 1 >= len)
185  return false;
186  else {
187  if (s[i + 1] == '+' || s[i + 1] == '-') {
188  i++;
189  if (i + 1 >= len)
190  return false;
191  }
192  }
193  break;
194  default:
195  if (!isdigit(s[i]))
196  return false;
197  }
198  }
199  return true;
200  }
201  Value* ReadNumberValue(std::istream &in) {
202  Value *toReturn = NULL;
203  std::string toParse = "";
204  int ch;
205  bool isDouble = false; // By default the number is integer, unless set otherwise
206  do {
207  ch = in.get();
208  if (in.eof())
209  break;
210 
211  // For time being allow all ., -, +,digit,e,E, as valid characters
212  // Then use isValidJsonNumber() to test validity more strictly
213  if (isdigit(ch) || ch == '+' || ch == '-') // All integer characters
214  toParse += ch;
215  else {
216  if (ch == '.' || ch == 'e' || ch == 'E') { // All floating point characters
217  isDouble = true;
218  toParse += ch;
219  }
220  else // If none of these valid characters, then input is over. Push last character back
221  {
222  in.unget();
223  break;
224  }
225  }
226  } while (true);
227 
228  // Validate number now
229  // TODO: Rather than parsing string again add logic of isValidJsonNumber() to the
230  // above do-while loop itself. : Slight optimization.
231  if (!isValidJsonNumber(toParse))
232  throw JSONException("Invalid JSON number: \"" + toParse + "\". Unable to parse");
233 
234  std::stringstream stream(toParse);
235  if (isDouble) {
236  Real *r = new Real();
237  stream>>r->val;
238  toReturn = dynamic_cast<Value*>(r);
239  }
240  else {
241  Integer *i = new Integer();
242  stream>>i->val;
243  toReturn = dynamic_cast<Value*>(i);
244  }
245  assert(toReturn != NULL); // To check that dynamic_cast was succesful
246  return toReturn;
247  }
248 
249  void ReadJSONValue(std::istream &in, JSON &j, bool topLevel = false) {
250  j.clear();
251  JSON_Utility::SkipWhiteSpace(in);
252 
253  if (in.eof())
254  throw JSONException("Unexpected EOF");
255 
256  int ch = in.get();
257  in.unget();
258  if (isObjectStart(ch))
259  j.val = new Object();
260 
261  if (isArrayStart(ch))
262  j.val = new Array();
263 
264  // If it's not an object or array, throw error if it was supposed to be a top-level object
265  if (topLevel && j.val == NULL)
266  throw JSONException("JSON::read() - Expected top level JSON to be an Object OR Array");
267 
268  if (isStringStart(ch))
269  j.val = new String();
270 
271  if (isBooleanStart(ch))
272  j.val = new Boolean();
273 
274  if (isNullStart(ch))
275  j.val = new Null();
276 
277  if (j.val != NULL)
278  j.val->read(in);
279  else {
280  // Treat number case slightly differently - since there can be two different types of numbers
281  if (isNumberStart(ch))
282  j.val = JSON_Utility::ReadNumberValue(in);
283  else
284  throw JSONException("Illegal JSON value. Cannot start with : " + std::string(1, char(ch)));
285  }
286  }
287 
288 /* std::string appendUTF8(uint32_t x) {
289  std::string temp_str = "";
290  //unsigned char tmp[5] = {0};
291  utf8::append(x, std::back_inserter(temp_str));
292  //return std::string(tmp);
293  return temp_str;
294  }*/
295  // See this function in utf8 namespace to fix invalid utf8 characters
296  // void fix_utf8_string(std::string& str);
297 
298  inline int32_t hexdigit_to_num(char ch) {
299  if (ch >= '0' && ch <= '9')
300  return uint32_t(ch - '0');
301  ch = toupper(ch);
302  if (ch >= 'A' && ch <= 'F')
303  return uint32_t(ch - 'A' + 10);
304  throw JSONException("Invalid Hex digit in unicode escape \\uxxxx: " + std::string(1,ch));
305  }
306 
307  inline int32_t string4_to_hex(char str[]) {
308  // We assume that str is always exactly 4 character long
309  return ( (hexdigit_to_num(str[0]) << 12) +
310  (hexdigit_to_num(str[1]) << 8) +
311  (hexdigit_to_num(str[2]) << 4) +
312  (hexdigit_to_num(str[3])) );
313  }
314 
315  // This function converts a json string (utf8) to a C++ string
316  // All escaped sequences are resolved and it is made sure that no invalid
317  // UTF-8 character is present in string after parsing (any invalid character
318  // is replaced with the replacement character: U+FFFFD)
319  // Care must be taken to not call it two times for a string inside an operation
320  // (for example, while using [] operator)
321 
322  std::string parseUtf8JsonString(const std::string &inp) {
323  std::string out = "";
324 
325  std::string temp;
326  size_t inplength = inp.length();
327 
328  for (unsigned i = 0; i < inplength; i++) {
329  if (inp[i] != '\\') {
330  out += inp[i];
331  }
332  else {
333  if ( (i + 1) >= inplength)
334  throw JSONException("Cannot end a string with \\ charcter");
335  i++;
336  char hex[4];
337  int32_t first16bit, second16bit;
338  int32_t codepoint;
339  switch(inp[i]) {
340  case '"': out += '"'; break;
341  case '\\': out += '\\'; break;
342  case '/': out += '/'; break;
343  case 'b': out += '\b'; break;
344  case 'f': out += '\f'; break;
345  case 'n': out += '\n'; break;
346  case 'r': out += '\r'; break;
347  case 't': out += '\t'; break;
348 
349  case 'u':
350  if (i + 4 >= inplength)
351  throw JSONException("Expected exactly 4 hex digits after \\u");
352  copy(inp.begin() + i + 1, inp.begin() + i + 1 + 5, hex);
353  i += 4;
354  first16bit = string4_to_hex(hex);
355  codepoint = first16bit;
356  if (0xD800 <= first16bit && first16bit <= 0xDBFF) {
357  // Surrogate pair case
358  // Must have next 6 characters of the form: \uxxxx as well
359 
360  if ( (i + 6) >= inplength || inp[i + 1] != '\\' || inp[i + 2] != 'u')
361  throw JSONException("Missing surrogate pair in unicode sequence");
362  i += 2;
363  copy(inp.begin() + i + 1, inp.begin() + i + 1 + 5, hex);
364  i += 4;
365  second16bit = string4_to_hex(hex);
366 
367  if (0xDC00 <= second16bit && second16bit <= 0xDFFF) {
368  /* valid second surrogate */
369  codepoint = ((first16bit - 0xD800) << 10) + (second16bit - 0xDC00) + 0x10000;
370  }
371  else {
372  // Invalid second surrogate
373  throw JSONException("Invalid second 16 bit value in surrogate pair: first 16 bit = " + JSON_Utility::itos(first16bit) + " and second 16 bit = " + JSON_Utility::itos(second16bit));
374  }
375  }
376  try {
377  utf8::append(codepoint, back_inserter(out));
378  }
379  catch(utf8::invalid_code_point &e) {
380  throw JSONException("Invalid UTF-8 code point found in text. Value = " + itos(codepoint) + ". Location = " + inp + "\nInternal message = " + e.what());
381  }
382  break;
383  default:
384  throw JSONException("Illegal escape sequence:" + std::string(1, inp[i]));
385  }
386  }
387  }
388  return getValidatedUTF8String(out);
389  }
390 
391  std::string ReadString(std::istream &in) {
392  std::string out = "";
393  int ch = in.get();
394  assert(ch == '"'); // First character in a string should be quote
395  std::string str;
396  int prev = 0;
397  do {
398  ch = in.get();
399  if (in.eof() || in.fail())
400  throw JSONException("Unexpected EOF while reading string");
401  if (ch == '"' && prev != '\\') // String is over
402  break;
403  str += char(ch);
404  prev = (prev == '\\') ? 0 : ch;
405  } while (1);
406  return parseUtf8JsonString(str);
407  }
408 }
409 
410 void String::write(std::ostream &out) const {
411  JSON_Utility::WriteEscapedString(this->val, out, true);
412 }
413 
414 void Object::write(std::ostream &out) const {
415  out<<"{";
416  bool firstElem = true;
417 
418  for (std::map<std::string, JSON>::const_iterator it = val.begin(); it != val.end(); ++it, firstElem = false) {
419  if (!firstElem)
420  out<<",";
421  JSON_Utility::WriteEscapedString((*it).first, out, true);
422  out<<":";
423  (*it).second.write(out);
424  }
425  out<<"}";
426 }
427 
428 void Array::write(std::ostream &out) const {
429  out<<"[";
430  bool firstElem = true;
431  for (unsigned i = 0; i < val.size(); ++i, firstElem = false) {
432  if (!firstElem)
433  out<<",";
434  val[i].write(out);
435  }
436  out<<"]";
437 }
438 
439 const JSON& Array::jsonAtIndex(size_t i) const {
440  if (val.size() == 0u || i >= val.size())
441  throw JSONException("Illegal: Out of bound JSON_ARRAY access");
442  return val[i];
443 }
444 
445 // STL map's [] operator cannot be used on constant objects
446 const JSON& Object::jsonAtKey(const std::string &s) const {
447  std::map<std::string, JSON>::const_iterator it = this->val.find(s);
448  if (it == val.end())
449  throw JSONException("Cannot add new key to a constant JSON_OBJECT");
450  return it->second;
451 }
452 
453 JSON& Object::jsonAtKey(const std::string &s) {
454  return val[s];
455 }
456 
457 void JSON::write(std::ostream &out) const {
458  if (this->type() == JSON_UNDEFINED) {
459  throw JSONException("Cannot call write() method on uninitialized json object");
460  }
461  out.precision(std::numeric_limits<double>::digits10);
462  val->write(out);
463  out.flush();
464 }
465 
466 void JSON::readFromString(const std::string &jstr) {
467  std::stringstream inp(jstr);
468  this->read(inp);
469 }
470 
471 const JSON& JSON::operator[](const std::string &s) const {
472  if (this->type() != JSON_OBJECT)
473  throw JSONException("Cannot use string to index value of a non-JSON_OBJECT using [] operator");
474 
475  // No need for dynamic_cast (since I already checked for JSON_OBJECT case), and
476  // dynamic_cast is expensive
477  const Object *o = static_cast<Object*>(val);
478  return o->jsonAtKey(s);
479 }
480 
481 // For non-const JSON objects
482 JSON& JSON::operator[](const std::string &s) {
483  if (this->type() != JSON_OBJECT)
484  throw JSONException("Cannot use string to index value of a non-JSON_OBJECT using [] operator");
485 
486  // No need for dynamic_cast (since I already checked for JSON_OBJECT case), and
487  // dynamic_cast is expensive
488  Object *o = static_cast<Object*>(val);
489  return o->jsonAtKey(s);
490 }
491 
492 const JSON& JSON::operator[](const char *str) const {
493  return operator[](std::string(str));
494 }
495 
496 // For non-const JSON objects
497 JSON& JSON::operator[](const char *str) {
498  return operator[](std::string(str));
499 }
500 
501 const JSON& JSON::operator[](const size_t &indx) const {
502  if (this->type() != JSON_ARRAY)
503  throw JSONException("Cannot use integer to index value of non-JSON_ARRAY using [] operator");
504  Array *a = static_cast<Array*>(val);
505  return a->jsonAtIndex(indx);
506 }
507 
508 const JSON& JSON::operator[](const JSON &j) const {
509  if (this->type() == JSON_ARRAY) {
510  return (*this)[size_t(j)];
511  }
512  if (this->type() == JSON_OBJECT) {
513  if (j.type() != JSON_STRING)
514  throw JSONException("Cannot use a non-string value to index JSON_OBJECT using []");
515 
516  String *ptr = static_cast<String*>(j.val);
517  return (*this)[ptr->val];
518  }
519  throw JSONException("Only JSON_OBJECT and JSON_ARRAY can be indexed using []");
520 }
521 
523  if (this->type() == JSON_ARRAY) {
524  return (*this)[size_t(j)];
525  }
526  if (this->type() == JSON_OBJECT) {
527  if (j.type() != JSON_STRING)
528  throw JSONException("Cannot use a non-string value to index JSON_OBJECT using []");
529 
530  String *ptr = static_cast<String*>(j.val);
531  return (*this)[ptr->val];
532  }
533  throw JSONException("Only JSON_OBJECT and JSON_ARRAY can be indexed using []");
534 }
535 
536 // A dirty hack for creating non-const versions of [] (for array indexing) overload using const versions above
537 JSON& JSON::operator [](const size_t &indx) { return const_cast<JSON&>( (*(const_cast<const JSON*>(this)))[indx]); }
538 //JSON& JSON::operator [](const std::string &s) { return const_cast<JSON&>( (*(const_cast<const JSON*>(this)))[s]); }
539 //JSON& JSON::operator [](const JSON &j) { return const_cast<JSON&>( (*(const_cast<const JSON*>(this)))[j]); }
540 //JSON& JSON::operator [](const char *str) { return const_cast<JSON&>( (*(const_cast<const JSON*>(this)))[str]); }
541 
542 JSON::JSON(const JSONValue &rhs) {
543  val = NULL; // So that clear() works fine on this, else we will be deallocating some arbitrary memory - dangerous!
544  *this = operator=(rhs);
545 }
546 
547 JSON::JSON(const JSON &rhs) {
548  if (rhs.type() != JSON_UNDEFINED)
549  val = rhs.val->returnMyNewCopy();
550  else
551  val = NULL;
552 }
553 
555  clear();
556  switch(rhs) {
557  case JSON_ARRAY: val = new Array(); break;
558  case JSON_OBJECT: val = new Object(); break;
559  case JSON_INTEGER: val = new Integer(); break;
560  case JSON_REAL: val = new Real(); break;
561  case JSON_STRING: val = new String(); break;
562  case JSON_BOOLEAN: val = new Boolean(); break;
563  case JSON_NULL: val = new Null(); break;
564  default: throw JSONException("Illegal JSONValue value for JSON initialization");
565  }
566  return *this;
567 }
568 
569 JSON& JSON::operator =(const JSON &rhs) {
570  if (this == &rhs) // Self-assignment check
571  return *this;
572 
573  clear();
574 
575  if (rhs.type() != JSON_UNDEFINED)
576  val = rhs.val->returnMyNewCopy();
577  else
578  val = NULL;
579 
580  return *this;
581 }
582 
583 JSON& JSON::operator =(const std::string &s) {
584  clear();
585  val = new String(s);
586  return *this;
587 }
588 
589 JSON& JSON::operator =(const char &c) {
590  return operator=(std::string(1u, c));
591 }
592 
593 JSON& JSON::operator =(const bool &x) {
594  clear();
595  val = new Boolean(x);
596  return *this;
597 }
598 
599 JSON& JSON::operator =(const Null &x __attribute__ ((unused)) ) {
600  // x is intended to be unused in this function. Since null has exactly one value.
601  clear();
602  val = new Null();
603  return *this;
604 }
605 
606 JSON& JSON::operator =(const char s[]) {
607  return operator =(std::string(s));
608 }
609 
610 
611 size_t JSON::size() const {
612  // Using static_cast everywhere instead of dynamic_cast, since we explicitly check it's type
613  // before statically casting, and dynamic_cast is expensive
614 
615  JSONValue t = type();
616  if (t != JSON_ARRAY && t != JSON_OBJECT && t != JSON_STRING)
617  throw JSONException("size()/length() can only be called for JSON_ARRAY/JSON_OBJECT/JSON_STRING");
618  if (t == JSON_ARRAY) {
619  Array *tmp = static_cast<Array*>(this->val);
620  return tmp->val.size();
621  }
622  else {
623  if (t == JSON_OBJECT) {
624  Object *tmp = static_cast<Object*>(this->val);
625  return tmp->val.size();
626  }
627  }
628  String *tmp = static_cast<String*>(this->val);
629  return tmp->val.size();
630 }
631 
632 void JSON::push_back(const JSON &j) {
633  if (this->type() != JSON_ARRAY)
634  throw JSONException("Cannot push_back to a non-array");
635  Array *tmp = static_cast<Array*>(this->val);
636  assert(tmp != NULL);
637  tmp->push_back(j);
638 }
639 
640 std::string JSON::toString(bool onlyTopLevel) const {
641  if (onlyTopLevel && this->type() != JSON_OBJECT && this->type() != JSON_ARRAY)
642  throw JSONException("Only a JSON_OBJECT/JSON_ARRAY can call toString() with onlyTopLevel flag set to true");
643  std::stringstream in;
644  write(in);
645  return in.str();
646 }
647 
648 bool JSON::has(const size_t &indx) const {
649  if (this->type() != JSON_ARRAY)
650  throw JSONException("Illegal call to has(size_t) for non JSON_ARRAY object");
651  size_t size = ((Array*)(this->val))->val.size();
652  return (indx < size);
653 }
654 
655 bool JSON::has(const std::string &key) const {
656  if (this->type() != JSON_OBJECT)
657  throw JSONException("Illegal call to has(size_t) for non JSON_OBJECT object");
658  return (((Object*)(this->val))->val.count(key) > 0u);
659 }
660 
661 bool JSON::has(const char *x) const {
662  return has(std::string(x));
663 }
664 
665 bool JSON::has(const JSON &j) const {
666 
667  switch(this->type()) {
668  case JSON_ARRAY: return has((const size_t)j);
669  case JSON_OBJECT:
670  if (j.type() != JSON_STRING)
671  throw JSONException("For a JSON_OBJECT, has(JSON &j) requires j to be JSON_STRING");
672  return has( ((String*)(j.val))->val);
673 
674  default: throw JSONException("Illegal json object as input to has(const JSON &j)");
675  }
676 }
677 
678 void JSON::read(std::istream &in) {
679  JSON_Utility::ReadJSONValue(in, *this, false);
680 }
681 
682 void JSON::erase(const size_t &indx) {
683  if (this->type() != JSON_ARRAY)
684  throw JSONException("erase(size_t) can only be called for a JSON_ARRAY");
685  (static_cast<Array*>(this->val))->erase(indx);
686 }
687 
688 void JSON::erase(const std::string &indx) {
689  if (this->type() != JSON_OBJECT)
690  throw JSONException("erase(string) can only be called for a JSON_OBJECT");
691  (static_cast<Object*>(this->val))->erase(indx);
692 }
693 
694 void String::read(std::istream &in) {
695  val = JSON_Utility::ReadString(in);
696 }
697 
698 void Boolean::read(std::istream &in) {
699 
700  // To store output of read() - maximum = "false", artificially adding "\0" at end
701  // since read() does not.
702  char str[6] = {0};
703 
704  str[0] = in.get();
705  bool fail = false;
706  unsigned size = 0;
707  if (str[0] == 't')
708  size = 3; // read "rue"
709  else
710  size = 4; // read "alse"
711 
712  in.read(&str[1], size);
713  fail = (in.gcount() == size) ? false : true;
714  if (!fail && size == 3u && (strcmp(str, "true") == 0))
715  val = true;
716  else
717  if (!fail && size == 4u && (strcmp(str, "false") == 0))
718  val = false;
719  else
720  fail = true;
721 
722  if (fail)
723  throw JSONException("Invalid Boolean value, expected exactly one of : 'true' or 'false'");
724 }
725 
726 void Null::read(std::istream &in) {
727  char str[5] = {0};
728  in.read(str, 4);
729  if (in.gcount() !=4 || (strcmp(str, "null") != 0))
730  throw JSONException("Invalid JSON null, expected exactly: null");
731 }
732 
733 void Object::read(std::istream &in) {
734  int ch;
735  val.clear();
736  JSON_Utility::SkipWhiteSpace(in);
737  ch = in.get();
738  assert(ch == '{'); // Must be a valid object for Object::read to be called
739 
740  bool firstKey = true;
741  do {
742  JSON_Utility::SkipWhiteSpace(in);
743  ch = in.get();
744  if (in.eof() || in.fail())
745  throw JSONException("Unexpected EOF while parsing object. ch = " + std::string(1, ch));
746 
747  // End of parsing for this JSON object
748  if (ch == '}')
749  break;
750 
751  // Keys:value pairs must be separated by , inside JSON object
752  if (!firstKey && ch != ',')
753  throw JSONException("Expected , while parsing object. Got : " + std::string(1, ch));
754 
755  if (!firstKey) {
756  JSON_Utility::SkipWhiteSpace(in);
757  ch = in.get();
758  }
759 
760  if (!JSON_Utility::isStringStart(ch))
761  throw JSONException("Expected start of a valid object key (string) at this location");
762 
763  // Push back the quote (") in stream again, and parse the key value (string)
764  in.unget();
765 
766  std::string key = JSON_Utility::ReadString(in);
767  JSON_Utility::SkipWhiteSpace(in);
768  ch = in.get();
769  if (ch != ':')
770  throw JSONException("Expected :, got : " + std::string(1, ch));
771  JSON_Utility::SkipWhiteSpace(in);
772  JSON_Utility::ReadJSONValue(in, val[key], false);
773  firstKey = false;
774  } while (true);
775 }
776 
777 void Array::read(std::istream &in) {
778  int ch;
779  val.clear();
780  JSON_Utility::SkipWhiteSpace(in);
781  ch = in.get();
782  assert(ch == '['); // Must be a valid array for Array::read to be called
783 
784  bool firstKey = true;
785  do {
786  JSON_Utility::SkipWhiteSpace(in);
787  ch = in.get();
788  if (in.eof() || in.fail())
789  throw JSONException("Unexpected EOF while parsing array");
790 
791  // End of parsing this array
792  if (ch == ']')
793  break;
794 
795  if (!firstKey && ch != ',')
796  throw JSONException("Expected ,(comma) GOT: " + std::string(1, ch));
797 
798  if (!firstKey) {
799  JSON_Utility::SkipWhiteSpace(in);
800  }
801  else
802  in.unget();
803 
804  JSON_Utility::SkipWhiteSpace(in);
805  JSON tmpValue;
806  val.push_back(tmpValue); // Append a blank json object. We will fill it soon
807  JSON_Utility::ReadJSONValue(in, val[val.size() - 1u], false);
808  firstKey = false;
809  } while (true);
810 }
811 
812 void Object::erase(const std::string &key) {
813  if (val.erase(key) == 0)
814  throw JSONException("Cannot erase non-existent key from a JSON_OBJECT. Key supplied = " + key);
815 }
816 
817 void Array::erase(const size_t &indx) {
818  if (indx >= val.size())
819  throw JSONException("Cannot erase out of bound element in a JSON_ARRAY. indx supplied = " + boost::lexical_cast<std::string>(indx));
820  val.erase(val.begin() + indx);
821 }
822 
823 bool Integer::isEqual(const Value *other) const {
824  const Integer *p = dynamic_cast<const Integer*>(other);
825  return (p != NULL && this->val == p->val);
826 }
827 
828 bool Real::isEqual(const Value* other) const {
829  const Real *p = dynamic_cast<const Real*>(other);
830 
831  // In our implementation of isEqual, "Real" is *never* equal to Integer
832  // TODO: Decide if this is desired behavior ?
833  if (p == NULL)
834  return false;
835 
836  //Ref: 1. http://floating-point-gui.de/errors/comparison/
837  // 2. http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
838  double diff = fabs(this->val - p->val);
839  double eps = JSON::getEpsilon();
840 
841  // If numbers are really close (absolute error), return true
842  // needed for numbers near zero
843  if (diff <= eps) {
844  return true;
845  }
846  // Now use absolute error to check for "closeness"
847  double absA = fabs(this->val);
848  double absB = fabs(p->val);
849  double largest = (absA > absB) ? absA : absB;
850  // always use largest to check for relative error
851  // so that isEqual() remain commutative
852  return diff <= (largest * eps);
853 }
854 
855 bool String::isEqual(const Value* other) const {
856  const String *p = dynamic_cast<const String*>(other);
857  return (p != NULL && this->val == p->val);
858 }
859 
860 bool Boolean::isEqual(const Value* other) const {
861  const Boolean *p = dynamic_cast<const Boolean*>(other);
862  return (p != NULL && this->val == p->val);
863 }
864 
865 bool Null::isEqual(const Value* other) const {
866  const Null *p = dynamic_cast<const Null*>(other);
867  return (p != NULL);
868 }
869 
870 bool Array::isEqual(const Value* other) const {
871  const Array *p = dynamic_cast<const Array*>(other);
872  return (p != NULL && this->val.size() == p->val.size() && equal(this->val.begin(), this->val.end(), p->val.begin()));
873 }
874 
875 bool Object::isEqual(const Value* other) const {
876  const Object *p = dynamic_cast<const Object*>(other);
877  if (p == NULL || this->val.size() != p->val.size())
878  return false;
879  std::map<std::string, JSON>::const_iterator it1,it2;
880  for (it1 = this->val.begin(), it2 = p->val.begin(); it1 != this->val.end() && it2 != p->val.end(); ++it1, ++it2) {
881  if (it1->first != it2->first || it1->second != it2->second)
882  return false;
883  }
884  return (it1 == this->val.end() && it2 == p->val.end());
885 }
886 
887 
888 bool JSON::operator ==(const JSON& other) const {
889  if (this->type() != other.type() || this->type() == JSON_UNDEFINED)
890  return false;
891  return (this->val->isEqual(other.val));
892 }
893 
894 JSON::const_object_iterator JSON::object_begin() const {
895  if (this->type() != JSON_OBJECT)
896  throw JSONException("Cannot get JSON::object_iterator for a non-JSON_OBJECT");
897  return (static_cast<Object*>(this->val))->val.begin();
898 }
899 
900 JSON::const_array_iterator JSON::array_begin() const {
901  if (this->type() != JSON_ARRAY)
902  throw JSONException("Cannot get JSON::array_iterator for a non-JSON_ARRAY");
903  return (static_cast<Array*>(this->val))->val.begin();
904 }
905 
906 JSON::object_iterator JSON::object_begin() {
907  if (this->type() != JSON_OBJECT)
908  throw JSONException("Cannot get JSON::object_iterator for a non-JSON_OBJECT");
909  return (static_cast<Object*>(this->val))->val.begin();
910 }
911 
912 JSON::array_iterator JSON::array_begin() {
913  if (this->type() != JSON_ARRAY)
914  throw JSONException("Cannot get JSON::array_iterator for a non-JSON_ARRAY");
915  return (static_cast<Array*>(this->val))->val.begin();
916 }
917 
918 JSON::const_object_iterator JSON::object_end() const {
919  if (this->type() != JSON_OBJECT)
920  throw JSONException("Cannot get JSON::object_iterator for a non-JSON_OBJECT");
921  return (static_cast<Object*>(this->val))->val.end();
922 }
923 
924 JSON::const_array_iterator JSON::array_end() const {
925  if (this->type() != JSON_ARRAY)
926  throw JSONException("Cannot get JSON::array_iterator for a non-JSON_ARRAY");
927  return (static_cast<Array*>(this->val))->val.end();
928 }
929 
930 JSON::object_iterator JSON::object_end() {
931  if (this->type() != JSON_OBJECT)
932  throw JSONException("Cannot get JSON::object_iterator for a non-JSON_OBJECT");
933  return (static_cast<Object*>(this->val))->val.end();
934 }
935 
936 JSON::array_iterator JSON::array_end() {
937  if (this->type() != JSON_ARRAY)
938  throw JSONException("Cannot get JSON::array_iterator for a non-JSON_ARRAY");
939  return (static_cast<Array*>(this->val))->val.end();
940 }
941 /*
942 // Reverse iterators
943 JSON::const_object_reverse_iterator JSON::object_rbegin() const {
944  if (this->type() != JSON_OBJECT)
945  throw JSONException("Cannot get JSON::object_reverse_iterator for a non-JSON_OBJECT");
946  return (static_cast<Object*>(this->val))->val.rbegin();
947 }
948 */
949 JSON::const_array_reverse_iterator JSON::array_rbegin() const {
950  if (this->type() != JSON_ARRAY)
951  throw JSONException("Cannot get JSON::array_reverse_iterator for a non-JSON_ARRAY");
952  return (static_cast<Array*>(this->val))->val.rbegin();
953 }
954 /*
955 JSON::object_reverse_iterator JSON::object_rbegin() {
956  if (this->type() != JSON_OBJECT)
957  throw JSONException("Cannot get JSON::object_reverse_iterator for a non-JSON_OBJECT");
958  return (static_cast<Object*>(this->val))->val.rbegin();
959 }
960 */
961 JSON::array_reverse_iterator JSON::array_rbegin() {
962  if (this->type() != JSON_ARRAY)
963  throw JSONException("Cannot get JSON::array_reverse_iterator for a non-JSON_ARRAY");
964  return (static_cast<Array*>(this->val))->val.rbegin();
965 }
966 /*
967 JSON::const_object_reverse_iterator JSON::object_rend() const {
968  if (this->type() != JSON_OBJECT)
969  throw JSONException("Cannot get JSON::object_reverse_iterator for a non-JSON_OBJECT");
970  return (static_cast<Object*>(this->val))->val.rend();
971 }
972 */
973 JSON::const_array_reverse_iterator JSON::array_rend() const {
974  if (this->type() != JSON_ARRAY)
975  throw JSONException("Cannot get JSON::array_reverse_iterator for a non-JSON_ARRAY");
976  return (static_cast<Array*>(this->val))->val.rend();
977 }
978 /*
979 JSON::object_reverse_iterator JSON::object_rend() {
980  if (this->type() != JSON_OBJECT)
981  throw JSONException("Cannot get JSON::object_reverse_iterator for a non-JSON_OBJECT");
982  return (static_cast<Object*>(this->val))->val.rend();
983 }
984 */
985 JSON::array_reverse_iterator JSON::array_rend() {
986  if (this->type() != JSON_ARRAY)
987  throw JSONException("Cannot get JSON::array_reverse_iterator for a non-JSON_ARRAY");
988  return (static_cast<Array*>(this->val))->val.rend();
989 }
990 
991 void JSON::resize_array(size_t desired_size) {
992  if (this->type() != JSON_ARRAY)
993  throw JSONException("Cannot call resize_array() on a non JSON_ARRAY object");
994  (static_cast<Array*>(this->val))->val.resize(desired_size);
995 }
const_object_iterator object_end() const
Definition: dxjson.cpp:918
Value * val
Definition: dxjson.h:152
void write(std::ostream &out) const
Definition: dxjson.cpp:457
std::string toString(bool onlyTopLevel=false) const
Definition: dxjson.cpp:640
const_array_reverse_iterator array_rend() const
Definition: dxjson.cpp:973
JSON & operator=(const T &rhs)
Definition: dxjson.h:766
void erase(const size_t &indx)
Definition: dxjson.cpp:682
bool operator==(const JSON &other) const
Definition: dxjson.cpp:888
const_array_iterator array_begin() const
Definition: dxjson.cpp:900
JSONValue type() const
Definition: dxjson.h:450
size_t size() const
Definition: dxjson.cpp:611
static double getEpsilon()
Definition: dxjson.cpp:27
const_array_iterator array_end() const
Definition: dxjson.cpp:924
bool has(const T &indx) const
Definition: dxjson.h:488
JSON()
Definition: dxjson.h:175
void read(std::istream &in)
Definition: dxjson.cpp:678
JSONValue
Definition: dxjson.h:100
const_object_iterator object_begin() const
Definition: dxjson.cpp:894
const JSON & operator[](const size_t &indx) const
Definition: dxjson.cpp:501
void readFromString(const std::string &jstr)
Definition: dxjson.cpp:466
void push_back(const JSON &j)
Definition: dxjson.cpp:632
void resize_array(size_t desired_size)
Definition: dxjson.cpp:991
void clear()
Definition: dxjson.h:197
const_array_reverse_iterator array_rbegin() const
Definition: dxjson.cpp:949