dxjson 1.0
JSON library for C++
Loading...
Searching...
No Matches
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
20using namespace dx;
21
25static double json_epsilon = std::numeric_limits<double>::epsilon();
26
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
40namespace 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
410void String::write(std::ostream &out) const {
411 JSON_Utility::WriteEscapedString(this->val, out, true);
412}
413
414void 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
428void 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
439const 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
446const 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
453JSON& Object::jsonAtKey(const std::string &s) {
454 return val[s];
455}
456
457void 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
466void JSON::readFromString(const std::string &jstr) {
467 std::stringstream inp(jstr);
468 this->read(inp);
469}
470
471const 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
482JSON& 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
492const JSON& JSON::operator[](const char *str) const {
493 return operator[](std::string(str));
494}
495
496// For non-const JSON objects
497JSON& JSON::operator[](const char *str) {
498 return operator[](std::string(str));
499}
500
501const 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
508const 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
537JSON& 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
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
547JSON::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
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
583JSON& JSON::operator =(const std::string &s) {
584 clear();
585 val = new String(s);
586 return *this;
587}
588
589JSON& JSON::operator =(const char &c) {
590 return operator=(std::string(1u, c));
591}
592
593JSON& JSON::operator =(const bool &x) {
594 clear();
595 val = new Boolean(x);
596 return *this;
597}
598
599JSON& 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
606JSON& JSON::operator =(const char s[]) {
607 return operator =(std::string(s));
608}
609
610
611size_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
632void 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
640std::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
648bool 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
655bool 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
661bool JSON::has(const char *x) const {
662 return has(std::string(x));
663}
664
665bool 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
678void JSON::read(std::istream &in) {
679 JSON_Utility::ReadJSONValue(in, *this, false);
680}
681
682void 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
688void 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
694void String::read(std::istream &in) {
695 val = JSON_Utility::ReadString(in);
696}
697
698void 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
726void 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
733void 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
777void 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
812void 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
817void 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
823bool 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
828bool 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
855bool 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
860bool 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
865bool Null::isEqual(const Value* other) const {
866 const Null *p = dynamic_cast<const Null*>(other);
867 return (p != NULL);
868}
869
870bool 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
875bool 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
888bool 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
894JSON::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
900JSON::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
906JSON::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
912JSON::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
918JSON::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
924JSON::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
930JSON::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
936JSON::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
943JSON::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*/
949JSON::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/*
955JSON::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*/
961JSON::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/*
967JSON::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*/
973JSON::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/*
979JSON::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*/
985JSON::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
991void 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}
std::string toString(bool onlyTopLevel=false) const
Definition dxjson.cpp:640
const_object_iterator object_begin() const
Definition dxjson.cpp:894
void resize_array(size_t desired_size)
Definition dxjson.cpp:991
void readFromString(const std::string &jstr)
Definition dxjson.cpp:466
const_object_iterator object_end() const
Definition dxjson.cpp:918
const_array_reverse_iterator array_rbegin() const
Definition dxjson.cpp:949
bool has(const T &indx) const
Definition dxjson.h:488
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
void push_back(const JSON &j)
Definition dxjson.cpp:632
void write(std::ostream &out) const
Definition dxjson.cpp:457
void clear()
Definition dxjson.h:197
static double getEpsilon()
Definition dxjson.cpp:27
const JSON & operator[](const size_t &indx) const
Definition dxjson.cpp:501
const_array_reverse_iterator array_rend() const
Definition dxjson.cpp:973
const_array_iterator array_end() const
Definition dxjson.cpp:924
void erase(const size_t &indx)
Definition dxjson.cpp:682
Value * val
Definition dxjson.h:152
void read(std::istream &in)
Definition dxjson.cpp:678
JSON & operator=(const T &rhs)
Definition dxjson.h:766
JSONValue
Definition dxjson.h:100