Simpleson
json.h
Go to the documentation of this file.
1#ifndef JSON_H
2#define JSON_H
3
8#include <cstdlib>
9#include <string>
10#include <vector>
11#include <cstdio>
12#include <utility>
13#include <stdexcept>
14#include <cctype>
15
17namespace json
18{
20 class invalid_key : public std::exception
21 {
22 public:
24 const std::string key;
25
30 inline invalid_key(const std::string &key) : key(key) { }
31
33 inline virtual ~invalid_key() throw() { }
34
36 virtual const char* what() const throw()
37 {
38 return key.c_str();
39 }
40 };
41
43 class parsing_error : public std::invalid_argument
44 {
45 public:
50 inline parsing_error(const char *message) : std::invalid_argument(message) { }
51
53 inline virtual ~parsing_error() throw() { }
54 };
55
56 /* \brief Namespace for handling of JSON data types */
57 namespace jtype
58 {
60 enum jtype {
68 };
69
77 jtype detect(const char *input);
78 }
79
81 namespace parsing
82 {
91 const char* tlws(const char *start);
92
99 std::string read_digits(const char *input);
100
108 std::string escape_quotes(const char *input);
109
117 std::string unescape_quotes(const char *input);
118
121 {
124
126 std::string value;
127
129 const char *remainder;
130 };
131
138 parse_results parse(const char *input);
139
147 template <typename T>
148 T get_number(const char *input, const char* format)
149 {
150 T result;
151 std::sscanf(input, format, &result);
152 return result;
153 }
154
162 template <typename T>
163 std::string get_number_string(const T &number, const char *format)
164 {
165 std::vector<char> cstr(6);
166 int remainder = std::snprintf(&cstr[0], cstr.size(), format, number);
167 if(remainder < 0) {
168 return std::string();
169 } else if(remainder >= (int)cstr.size()) {
170 cstr.resize(remainder + 1);
171 std::snprintf(&cstr[0], cstr.size(), format, number);
172 }
173 std::string result(&cstr[0]);
174 return result;
175 }
176
183 std::vector<std::string> parse_array(const char *input);
184 }
185
187 typedef std::pair<std::string, std::string> kvp;
188
202 {
203 private:
205 std::vector<kvp> data;
206
211 bool array_flag;
212
213 public:
218 inline jobject(bool array = false)
219 : array_flag(array)
220 { }
221
223 inline jobject(const jobject &other)
224 : data(other.data),
225 array_flag(other.array_flag)
226 { }
227
229 inline virtual ~jobject() { }
230
235 bool is_array() const { return this->array_flag; }
236
238 inline size_t size() const { return this->data.size(); }
239
241 inline void clear() { this->data.resize(0); }
242
247 bool operator== (const json::jobject other) const { return ((std::string)(*this)) == (std::string)other; }
248
250 bool operator!= (const json::jobject other) const { return ((std::string)(*this)) != (std::string)other; }
251
253 inline jobject& operator=(const jobject rhs)
254 {
255 this->array_flag = rhs.array_flag;
256 this->data = rhs.data;
257 return *this;
258 }
259
264 jobject& operator+=(const kvp& other)
265 {
266 if (!this->array_flag && this->has_key(other.first)) throw json::parsing_error("Key conflict");
267 if(this->array_flag && other.first != "") throw json::parsing_error("Array cannot have key");
268 if(!this->array_flag && other.first == "") throw json::parsing_error("Missing key");
269 this->data.push_back(other);
270 return *this;
271 }
272
275 {
276 if(this->array_flag != other.array_flag) throw json::parsing_error("Array/object mismatch");
277 json::jobject copy(other);
278 for (size_t i = 0; i < copy.size(); i++) {
279 this->operator+=(copy.data.at(i));
280 }
281 return *this;
282 }
283
286 {
287 jobject result = *this;
288 result += other;
289 return result;
290 }
291
298 static jobject parse(const char *input);
299
304 static inline jobject parse(const std::string input) { return parse(input.c_str()); }
305
312 inline bool static tryparse(const char *input, jobject &output)
313 {
314 try
315 {
316 output = parse(input);
317 }
318 catch(...)
319 {
320 return true;
321 }
322 return false;
323 }
324
331 inline bool has_key(const std::string &key) const
332 {
333 if(this->array_flag) return false;
334 for (size_t i = 0; i < this->size(); i++) if (this->data.at(i).first == key) return true;
335 return false;
336 }
337
345 void set(const std::string &key, const std::string &value);
346
352 inline std::string get(const size_t index) const
353 {
354 return this->data.at(index).second;
355 }
356
363 inline std::string get(const std::string &key) const
364 {
365 if(this->array_flag) throw json::invalid_key(key);
366 for (size_t i = 0; i < this->size(); i++) if (this->data.at(i).first == key) return this->get(i);
367 throw json::invalid_key(key);
368 }
369
375 void remove(const std::string &key);
376
381 void remove(const size_t index)
382 {
383 this->data.erase(this->data.begin() + index);
384 }
385
387 class entry
388 {
389 protected:
394 virtual const std::string& ref() const = 0;
395
402 template<typename T>
403 inline T get_number(const char* format) const
404 {
405 return json::parsing::get_number<T>(this->ref().c_str(), format);
406 }
407
414 template<typename T>
415 inline std::vector<T> get_number_array(const char* format) const
416 {
417 std::vector<std::string> numbers = json::parsing::parse_array(this->ref().c_str());
418 std::vector<T> result;
419 for (size_t i = 0; i < numbers.size(); i++)
420 {
421 result.push_back(json::parsing::get_number<T>(numbers[i].c_str(), format));
422 }
423 return result;
424 }
425
426 public:
428 inline std::string as_string() const
429 {
431 json::parsing::parse(this->ref().c_str()).value.c_str()
432 );
433 }
434
436 inline operator std::string() const
437 {
438 return this->as_string();
439 }
440
442 bool operator== (const std::string other) const { return ((std::string)(*this)) == other; }
443
445 bool operator!= (const std::string other) const { return !(((std::string)(*this)) == other); }
446
448 operator int() const;
449
451 operator unsigned int() const;
452
454 operator long() const;
455
457 operator unsigned long() const;
458
460 operator char() const;
461
463 operator float() const;
464
466 operator double() const;
467
473 {
474 return json::jobject::parse(this->ref().c_str());
475 }
476
478 inline operator json::jobject() const
479 {
480 return this->as_object();
481 }
482
484 operator std::vector<int>() const;
485
487 operator std::vector<unsigned int>() const;
488
490 operator std::vector<long>() const;
491
493 operator std::vector<unsigned long>() const;
494
496 operator std::vector<char>() const;
497
499 operator std::vector<float>() const;
500
502 operator std::vector<double>() const;
503
505 operator std::vector<json::jobject>() const
506 {
507 const std::vector<std::string> objs = json::parsing::parse_array(this->ref().c_str());
508 std::vector<json::jobject> results;
509 for (size_t i = 0; i < objs.size(); i++) results.push_back(json::jobject::parse(objs[i].c_str()));
510 return results;
511 }
512
514 operator std::vector<std::string>() const { return json::parsing::parse_array(this->ref().c_str()); }
515
520 template<typename T>
521 inline std::vector<T> as_array() const
522 {
523 return (std::vector<T>)(*this);
524 }
525
527 inline bool is_true() const
528 {
529 json::parsing::parse_results result = json::parsing::parse(this->ref().c_str());
530 return (result.type == json::jtype::jbool && result.value == "true");
531 }
532
534 inline bool is_null() const
535 {
536 return json::parsing::parse(this->ref().c_str()).type == json::jtype::jnull;
537 }
538 };
539
541 class const_value : public entry
542 {
543 private:
545 std::string data;
546
547 protected:
552 inline const std::string& ref() const
553 {
554 return this->data;
555 }
556
557 public:
562 inline const_value(std::string value)
563 : data(value)
564 { }
565
573 inline const_value get(const std::string &key) const
574 {
575 return const_value(json::jobject::parse(this->data).get(key));
576 }
577
585 inline const_value array(const size_t index) const
586 {
587 return const_value(json::jobject::parse(this->data).get(index));
588 }
589 };
590
595 class const_proxy : public entry
596 {
597 private:
599 const jobject &source;
600
601 protected:
603 const std::string key;
604
606 inline const std::string& ref() const
607 {
608 for (size_t i = 0; i < this->source.size(); i++) if (this->source.data.at(i).first == key) return this->source.data.at(i).second;
609 throw json::invalid_key(key);
610 }
611
612 public:
618 const_proxy(const jobject &source, const std::string key) : source(source), key(key)
619 {
620 if(source.array_flag) throw std::logic_error("Source cannot be an array");
621 }
622
630 const_value array(size_t index) const
631 {
632 const char *value = this->ref().c_str();
633 if(json::jtype::detect(value) != json::jtype::jarray)
634 throw std::invalid_argument("Input is not an array");
635 const std::vector<std::string> values = json::parsing::parse_array(value);
636 return const_value(values[index]);
637 }
638 };
639
645 {
646 private:
648 jobject &sink;
649
650 protected:
657 template<typename T>
658 inline void set_number(const T value, const char* format)
659 {
660 this->sink.set(key, json::parsing::get_number_string(value, format));
661 }
662
668 void set_array(const std::vector<std::string> &values, const bool wrap = false);
669
676 template<typename T>
677 inline void set_number_array(const std::vector<T> &values, const char* format)
678 {
679 std::vector<std::string> numbers;
680 for (size_t i = 0; i < values.size(); i++)
681 {
682 numbers.push_back(json::parsing::get_number_string(values[i], format));
683 }
684 this->set_array(numbers);
685 }
686 public:
692 proxy(jobject &source, const std::string key)
693 : json::jobject::const_proxy(source, key),
694 sink(source)
695 { }
696
698 inline void operator= (const std::string value)
699 {
700 this->sink.set(this->key, "\"" + json::parsing::escape_quotes(value.c_str()) + "\"");
701 }
702
704 inline void operator= (const char* value)
705 {
706 this->operator=(std::string(value));
707 }
708
710 void operator=(const int input) { this->set_number(input, "%i"); }
711
713 void operator=(const unsigned int input) { this->set_number(input, "%u"); }
714
716 void operator=(const long input) { this->set_number(input, "%li"); }
717
719 void operator=(const unsigned long input) { this->set_number(input, "%lu"); }
720
722 void operator=(const char input) { this->set_number(input, "%c"); }
723
725 void operator=(const double input) { this->set_number(input, "%e"); }
726
728 void operator=(const float input) { this->set_number(input, "%e"); }
729
732 {
733 this->sink.set(key, (std::string)input);
734 }
735
737 void operator=(const std::vector<int> input) { this->set_number_array(input, "%i"); }
738
740 void operator=(const std::vector<unsigned int> input) { this->set_number_array(input, "%u"); }
741
743 void operator=(const std::vector<long> input) { this->set_number_array(input, "%li"); }
744
746 void operator=(const std::vector<unsigned long> input) { this->set_number_array(input, "%lu"); }
747
749 void operator=(const std::vector<char> input) { this->set_number_array(input, "%c"); }
750
752 void operator=(const std::vector<float> input) { this->set_number_array(input, "%e"); }
753
755 void operator=(const std::vector<double> input) { this->set_number_array(input, "%e"); }
756
758 void operator=(const std::vector<std::string> input) { this->set_array(input, true); }
759
761 void operator=(const std::vector<json::jobject> input)
762 {
763 std::vector<std::string> objs;
764 for (size_t i = 0; i < input.size(); i++)
765 {
766 objs.push_back((std::string)input[i]);
767 }
768 this->set_array(objs, false);
769 }
770
775 inline void set_boolean(const bool value)
776 {
777 if (value) this->sink.set(key, "true");
778 else this->sink.set(key, "false");
779 }
780
782 inline void set_null()
783 {
784 this->sink.set(key, "null");
785 }
786
788 inline void clear()
789 {
790 this->sink.remove(key);
791 }
792 };
793
800 inline virtual jobject::proxy operator[](const std::string key)
801 {
802 if(this->array_flag) throw json::invalid_key(key);
803 return jobject::proxy(*this, key);
804 }
805
812 inline virtual const jobject::const_proxy operator[](const std::string key) const
813 {
814 if(this->array_flag) throw json::invalid_key(key);
815 return jobject::const_proxy(*this, key);
816 }
817
825 inline const jobject::const_value array(const size_t index) const
826 {
827 return jobject::const_value(this->data.at(index).second);
828 }
829
831 operator std::string() const;
832
836 inline std::string as_string() const
837 {
838 return this->operator std::string();
839 }
840
846 std::string pretty(unsigned int indent_level = 0) const;
847 };
848}
849
850#endif // !JSON_H
Exception used for invalid JSON keys.
Definition: json.h:21
virtual ~invalid_key()
Destructor.
Definition: json.h:33
invalid_key(const std::string &key)
Constructor.
Definition: json.h:30
const std::string key
The key used that was invalid.
Definition: json.h:24
virtual const char * what() const
Returns the invalid key.
Definition: json.h:36
Represents an entry as a constant proxy to the value.
Definition: json.h:596
const_value array(size_t index) const
Returns another constant value from this array.
Definition: json.h:630
const std::string & ref() const
Returns a reference to the value.
Definition: json.h:606
const std::string key
The key for the referenced value.
Definition: json.h:603
const_proxy(const jobject &source, const std::string key)
Constructor.
Definition: json.h:618
Represents an entry as a constant value.
Definition: json.h:542
const_value(std::string value)
Constructs a proxy with the provided value.
Definition: json.h:562
const std::string & ref() const
Reference to the entry data.
Definition: json.h:552
const_value array(const size_t index) const
Returns another constant value from this array.
Definition: json.h:585
const_value get(const std::string &key) const
Returns another constant value from this object.
Definition: json.h:573
Representation of a value in the object.
Definition: json.h:388
bool operator==(const std::string other) const
Comparison operator.
Definition: json.h:442
T get_number(const char *format) const
Converts an serialzed value to a numeric value.
Definition: json.h:403
std::string as_string() const
Returns a string representation of the value.
Definition: json.h:428
bool is_null() const
Returns true if the value is a null value.
Definition: json.h:534
virtual const std::string & ref() const =0
A method for reference the entry's value.
json::jobject as_object() const
Casts the value as a JSON object.
Definition: json.h:472
bool is_true() const
Returns true if the value is a boolean and set to true.
Definition: json.h:527
std::vector< T > as_array() const
Casts an array.
Definition: json.h:521
bool operator!=(const std::string other) const
Comparison operator.
Definition: json.h:445
std::vector< T > get_number_array(const char *format) const
Converts a serialized array of numbers to a vector of numbers.
Definition: json.h:415
A proxy that allows modification of the value.
Definition: json.h:645
void operator=(const std::vector< unsigned int > input)
Assigns an array of unsigned integers.
Definition: json.h:740
proxy(jobject &source, const std::string key)
Constructor.
Definition: json.h:692
void set_array(const std::vector< std::string > &values, const bool wrap=false)
Stores an array of values.
Definition: json.cpp:431
void operator=(const std::vector< int > input)
Assigns an array of integers.
Definition: json.h:737
void set_null()
Definition: json.h:782
void operator=(const std::vector< json::jobject > input)
Assigns an array of JSON objects.
Definition: json.h:761
void operator=(const unsigned long input)
Assigns a long unsigned integer.
Definition: json.h:719
void operator=(const std::vector< long > input)
Assigns an array of long integers.
Definition: json.h:743
void operator=(const std::vector< unsigned long > input)
Assigns an array of unsigned long integers.
Definition: json.h:746
void operator=(const long input)
Assigns a long integer.
Definition: json.h:716
void operator=(const std::vector< std::string > input)
Assigns an array of strings.
Definition: json.h:758
void set_number(const T value, const char *format)
Sets a number value in the parent object.
Definition: json.h:658
void operator=(json::jobject input)
Assigns a JSON object or array.
Definition: json.h:731
void operator=(const char input)
Assigns an character.
Definition: json.h:722
void operator=(const std::vector< char > input)
Assigns an array of characters.
Definition: json.h:749
void operator=(const double input)
Assigns an double floating-point integer
Definition: json.h:725
void set_boolean(const bool value)
Sets a boolean value.
Definition: json.h:775
void set_number_array(const std::vector< T > &values, const char *format)
Stores an array of numbers.
Definition: json.h:677
void operator=(const std::vector< float > input)
Assigns an array of floating-point numbers.
Definition: json.h:752
void operator=(const unsigned int input)
Assigns an unsigned integer.
Definition: json.h:713
void operator=(const std::vector< double > input)
Assigns an array of double floating-point numbers.
Definition: json.h:755
void operator=(const std::string value)
Assigns a string value.
Definition: json.h:698
void clear()
Definition: json.h:788
void operator=(const float input)
Assigns an floating-point integer
Definition: json.h:728
void operator=(const int input)
Assigns an integer.
Definition: json.h:710
The class used for manipulating JSON objects and arrays.
Definition: json.h:202
static jobject parse(const char *input)
Parses a serialized JSON string.
Definition: json.cpp:444
void set(const std::string &key, const std::string &value)
Sets the value assocaited with the key.
Definition: json.cpp:501
static bool tryparse(const char *input, jobject &output)
Definition: json.h:312
virtual ~jobject()
Destructor.
Definition: json.h:229
bool operator!=(const json::jobject other) const
Comparison operator.
Definition: json.h:250
const jobject::const_value array(const size_t index) const
Returns the value of an element in an array.
Definition: json.h:825
bool is_array() const
Flag for differentiating objects and arrays.
Definition: json.h:235
virtual const jobject::const_proxy operator[](const std::string key) const
Returns an element of the JSON object.
Definition: json.h:812
size_t size() const
Returns the number of entries in the JSON object or array.
Definition: json.h:238
void clear()
Clears the JSON object or array.
Definition: json.h:241
std::string get(const size_t index) const
Returns the serialized value at a given index.
Definition: json.h:352
static jobject parse(const std::string input)
Parses a serialized JSON string.
Definition: json.h:304
jobject & operator+=(const jobject &other)
Appends one JSON object to another.
Definition: json.h:274
jobject(const jobject &other)
Copy constructor.
Definition: json.h:223
jobject(bool array=false)
Default constructor.
Definition: json.h:218
jobject & operator+=(const kvp &other)
Appends a key-value pair to a JSON object.
Definition: json.h:264
void remove(const size_t index)
Removes the entry at the specified index.
Definition: json.h:381
std::string pretty(unsigned int indent_level=0) const
Returns a pretty (multi-line indented) serialzed representation of the object or array.
Definition: json.cpp:554
bool has_key(const std::string &key) const
Determines if an object contains a key.
Definition: json.h:331
std::string get(const std::string &key) const
Returns the serialized value associated with a key.
Definition: json.h:363
std::string as_string() const
Serialzes the object or array.
Definition: json.h:836
void remove(const std::string &key)
Removes the entry associated with the key.
Definition: json.cpp:518
jobject & operator=(const jobject rhs)
Assignment operator.
Definition: json.h:253
jobject operator+(jobject &other)
Merges two JSON objects.
Definition: json.h:285
bool operator==(const json::jobject other) const
Comparison operator.
Definition: json.h:247
virtual jobject::proxy operator[](const std::string key)
Returns an element of the JSON object.
Definition: json.h:800
Exception used when invalid JSON is encountered.
Definition: json.h:44
parsing_error(const char *message)
Constructor.
Definition: json.h:50
virtual ~parsing_error()
Destructor.
Definition: json.h:53
jtype
Descriptor for the type of JSON data.
Definition: json.h:60
@ jarray
JSON array.
Definition: json.h:64
@ jnull
Null value.
Definition: json.h:66
@ not_valid
Value does not conform to JSON standard.
Definition: json.h:67
@ jstring
String value.
Definition: json.h:61
@ jbool
Boolean value.
Definition: json.h:65
@ jnumber
Number value.
Definition: json.h:62
const char * tlws(const char *start)
(t)rims (l)eading (w)hite (s)pace
Definition: json.cpp:50
std::string read_digits(const char *input)
Reads a set of digits from a string.
Definition: json.cpp:97
parse_results parse(const char *input)
Parses the first value encountered in a JSON string.
Definition: json.cpp:165
std::vector< std::string > parse_array(const char *input)
Parses a JSON array.
Definition: json.cpp:386
std::string unescape_quotes(const char *input)
Removes the escape charater from quotes.
Definition: json.cpp:145
T get_number(const char *input, const char *format)
Template for reading a numeric value.
Definition: json.h:148
std::string get_number_string(const T &number, const char *format)
Converts a number to a string.
Definition: json.h:163
std::string escape_quotes(const char *input)
Escape quotes in a string.
Definition: json.cpp:130
Base namespace for simpleson.
Definition: json.h:18
std::pair< std::string, std::string > kvp
(k)ey (v)alue (p)air
Definition: json.h:187
Structure for capturing the results of parsing.
Definition: json.h:121
std::string value
The parsed value encountered.
Definition: json.h:126
const char * remainder
A pointer to the first character after the parsed value.
Definition: json.h:129
jtype::jtype type
The type of value encountered while parsing.
Definition: json.h:123