Mercurial > code
comparison C++/modules/Json/Json.cpp @ 405:f81478065901
Json:
- Complete rewrite,
- Convert jansson tree to own C++ tree,
- Conversion from Value to Object/Array makes copies
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 05 Oct 2015 17:04:40 +0200 |
parents | 9ab878fb9fa2 |
children | d485d36a8de1 |
comparison
equal
deleted
inserted
replaced
404:9ab878fb9fa2 | 405:f81478065901 |
---|---|
1 /* | 1 /* |
2 * Json.cpp -- jansson C++11 wrapper | 2 * Json.cpp -- C++14 JSON manipulation using jansson parser |
3 * | 3 * |
4 * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr> | 4 * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr> |
5 * | 5 * |
6 * Permission to use, copy, modify, and/or distribute this software for any | 6 * Permission to use, copy, modify, and/or distribute this software for any |
7 * purpose with or without fee is hereby granted, provided that the above | 7 * purpose with or without fee is hereby granted, provided that the above |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 */ | 17 */ |
18 | 18 |
19 #include <stdexcept> | 19 #include "Json.h" |
20 | 20 |
21 #include "Json.h" | 21 #include <jansson.h> |
22 | 22 |
23 namespace json { | 23 namespace json { |
24 | 24 |
25 /* -------------------------------------------------------- | 25 namespace { |
26 * Object | 26 |
27 * -------------------------------------------------------- */ | 27 void readObject(Value &parent, json_t *object); |
28 void readArray(Value &parent, json_t *array); | |
29 | |
30 Value readValue(json_t *v) | |
31 { | |
32 if (json_is_null(v)) { | |
33 return Value{nullptr}; | |
34 } | |
35 if (json_is_string(v)) { | |
36 return Value{json_string_value(v)}; | |
37 } | |
38 if (json_is_number(v)) { | |
39 return Value{json_number_value(v)}; | |
40 } | |
41 if (json_is_boolean(v)) { | |
42 return Value{json_boolean_value(v)}; | |
43 } | |
44 if (json_is_object(v)) { | |
45 Object object; | |
46 | |
47 readObject(object, v); | |
48 | |
49 return object; | |
50 } | |
51 if (json_is_array(v)) { | |
52 Array array; | |
53 | |
54 readArray(array, v); | |
55 | |
56 return array; | |
57 } | |
58 | |
59 return Value{}; | |
60 } | |
61 | |
62 void readObject(Value &parent, json_t *object) | |
63 { | |
64 const char *key; | |
65 json_t *value; | |
66 | |
67 json_object_foreach(object, key, value) { | |
68 static_cast<Object &>(parent).insert(key, readValue(value)); | |
69 } | |
70 } | |
71 | |
72 void readArray(Value &parent, json_t *array) | |
73 { | |
74 size_t index; | |
75 json_t *value; | |
76 | |
77 json_array_foreach(array, index, value) { | |
78 static_cast<Array &>(parent).append(readValue(value)); | |
79 } | |
80 } | |
81 | |
82 template <typename Func, typename... Args> | |
83 Value convert(Func fn, Args&&... args) | |
84 { | |
85 json_error_t error; | |
86 json_t *json = fn(std::forward<Args>(args)..., &error); | |
87 | |
88 if (json == nullptr) { | |
89 throw Error{error.text, error.source, error.line, error.column, error.position}; | |
90 } | |
91 | |
92 Value value; | |
93 | |
94 if (json_is_object(json)) { | |
95 value = Object{}; | |
96 readObject(value, json); | |
97 } else { | |
98 value = Array{}; | |
99 readArray(value, json); | |
100 } | |
101 | |
102 json_decref(json); | |
103 | |
104 return value; | |
105 } | |
106 | |
107 } // !namespace | |
108 | |
109 bool Value::toBool() const noexcept | |
110 { | |
111 if (m_type != Type::Boolean) | |
112 return false; | |
113 | |
114 return m_boolean; | |
115 } | |
116 | |
117 double Value::toNumber() const noexcept | |
118 { | |
119 if (m_type != Type::Number) | |
120 return 0; | |
121 | |
122 return m_number; | |
123 } | |
124 | |
125 std::string Value::toString() const noexcept | |
126 { | |
127 if (m_type != Type::String) { | |
128 return ""; | |
129 } | |
130 | |
131 return m_string; | |
132 } | |
28 | 133 |
29 Object Value::toObject() const noexcept | 134 Object Value::toObject() const noexcept |
30 { | 135 { |
31 json_incref(m_handle.get()); | 136 if (m_type != Type::Object) { |
137 return Object{}; | |
138 } | |
32 | 139 |
33 return Object(m_handle.get()); | 140 return Object(*this); |
34 } | 141 } |
35 | 142 |
36 Array Value::toArray() const noexcept | 143 Array Value::toArray() const noexcept |
37 { | 144 { |
38 json_incref(m_handle.get()); | 145 if (m_type != Type::Array) { |
146 return Array{}; | |
147 } | |
39 | 148 |
40 return Array(m_handle.get()); | 149 return Array(*this); |
41 } | 150 } |
42 | 151 |
43 /* -------------------------------------------------------- | 152 Document::Document(Buffer buffer) |
44 * Array | |
45 * -------------------------------------------------------- */ | |
46 | |
47 Value Array::at(int index) const | |
48 { | 153 { |
49 auto value = json_array_get(m_handle.get(), index); | 154 m_value = convert(json_loads, buffer.text.c_str(), 0); |
50 | |
51 if (value == nullptr) | |
52 throw Error("index out of bounds"); | |
53 | |
54 json_incref(value); | |
55 | |
56 return Value{value}; | |
57 } | 155 } |
58 | 156 |
59 Value Array::operator[](int index) const noexcept | 157 Document::Document(File file) |
60 { | 158 { |
61 auto value = json_array_get(m_handle.get(), index); | 159 m_value = convert(json_load_file, file.path.c_str(), 0); |
62 | |
63 if (value == nullptr) | |
64 return Value(); | |
65 | |
66 json_incref(value); | |
67 | |
68 return Value(value); | |
69 } | |
70 | |
71 Array::Ref Array::operator[](int index) noexcept | |
72 { | |
73 auto value = json_array_get(m_handle.get(), index); | |
74 | |
75 if (value == nullptr) | |
76 value = json_null(); | |
77 else | |
78 json_incref(value); | |
79 | |
80 return Ref(value, *this, index); | |
81 } | |
82 | |
83 /* -------------------------------------------------------- | |
84 * Object | |
85 * -------------------------------------------------------- */ | |
86 | |
87 Object::Ref Object::operator[](const std::string &name) | |
88 { | |
89 if (typeOf() != Type::Object) | |
90 return Ref(Value(), *this, name); | |
91 | |
92 auto value = json_object_get(m_handle.get(), name.c_str()); | |
93 | |
94 json_incref(value); | |
95 | |
96 return Ref(value, *this, name); | |
97 } | |
98 | |
99 Value Object::operator[](const std::string &name) const | |
100 { | |
101 if (typeOf() != Type::Object) | |
102 return Value(); | |
103 | |
104 auto value = json_object_get(m_handle.get(), name.c_str()); | |
105 | |
106 if (value == nullptr) | |
107 return Value(); | |
108 | |
109 json_incref(value); | |
110 | |
111 return Value(value); | |
112 } | |
113 | |
114 /* -------------------------------------------------------- | |
115 * Document | |
116 * -------------------------------------------------------- */ | |
117 | |
118 Value Document::read(std::string content, int flags) const | |
119 { | |
120 json_error_t error; | |
121 json_t *json = json_loads(content.c_str(), flags, &error); | |
122 | |
123 if (json == nullptr) | |
124 throw Error(error); | |
125 | |
126 return Value(json); | |
127 } | |
128 | |
129 Value Document::read(std::ifstream &stream, int flags) const | |
130 { | |
131 if (!stream.is_open()) | |
132 throw Error("File not opened"); | |
133 | |
134 stream.seekg(0, stream.end); | |
135 auto length = stream.tellg(); | |
136 stream.seekg(0, stream.beg); | |
137 | |
138 std::string buffer; | |
139 buffer.resize(length, ' '); | |
140 | |
141 stream.read(&buffer[0], length); | |
142 stream.close(); | |
143 | |
144 return read(std::move(buffer), flags); | |
145 } | |
146 | |
147 Document::Document(std::ifstream &stream, int flags) | |
148 { | |
149 m_value = read(stream, flags); | |
150 } | |
151 | |
152 Document::Document(std::ifstream &&stream, int flags) | |
153 { | |
154 m_value = read(stream, flags); | |
155 } | |
156 | |
157 Document::Document(std::string content, int flags) | |
158 { | |
159 m_value = read(std::move(content), flags); | |
160 } | 160 } |
161 | 161 |
162 } // !json | 162 } // !json |