HoviTron Video Pipeline
JsonParser.cpp
1/* The copyright in this software is being made available under the BSD
2* License, included below. This software may be subject to other third party
3* and contributor rights, including patent rights, and no such rights are
4* granted under this license.
5*
6* Copyright (c) 2010-2018, ITU/ISO/IEC
7* All rights reserved.
8*
9* Redistribution and use in source and binary forms, with or without
10* modification, are permitted provided that the following conditions are met:
11*
12* * Redistributions of source code must retain the above copyright notice,
13* this list of conditions and the following disclaimer.
14* * Redistributions in binary form must reproduce the above copyright notice,
15* this list of conditions and the following disclaimer in the documentation
16* and/or other materials provided with the distribution.
17* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
18* be used to endorse or promote products derived from this software without
19* specific prior written permission.
20*
21* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31* THE POSSIBILITY OF SUCH DAMAGE.
32*/
33
34/*
35Original authors:
36
37Universite Libre de Bruxelles, Brussels, Belgium:
38Sarah Fachada, Sarah.Fernandes.Pinto.Fachada@ulb.ac.be
39Daniele Bonatto, Daniele.Bonatto@ulb.ac.be
40Arnaud Schenkel, arnaud.schenkel@ulb.ac.be
41
42Koninklijke Philips N.V., Eindhoven, The Netherlands:
43Bart Kroon, bart.kroon@philips.com
44Bart Sonneveldt, bart.sonneveldt@philips.com
45*/
46
47#include "../include/JsonParser.h"
48
49#include <cassert>
50#include <cctype>
51#include <cmath>
52#include <iostream>
53#include <map>
54#include <memory>
55#include <sstream>
56#include <string>
57#include <vector>
58
59namespace json
60{
61 namespace
62 {
63 void skipWhitespace(std::istream& stream)
64 {
65 while (!stream.eof() && std::isspace(stream.peek())) {
66 stream.get();
67 }
68 }
69
70 void matchCharacter(std::istream& stream, std::istream::int_type expected)
71 {
72 auto actual = stream.get();
73
74 if (actual != expected) {
75 std::ostringstream what;
76 what << "Expected '" << static_cast<char>(expected) << "' but found '" << static_cast<char>(actual) << "' (0x" << std::hex << actual << ")";
77 throw std::runtime_error(what.str());
78 }
79 }
80
81 void matchText(std::istream& stream, std::string const& text)
82 {
83 for (auto ch : text) {
84 matchCharacter(stream, ch);
85 }
86 }
87 }
88
89 static std::shared_ptr<Value> readValue(std::istream& stream);
90
91 struct Value
92 {
93 Value(Node::Type type) : type(type) {}
94
95 virtual ~Value() {}
96
97 Node::Type type;
98 };
99
100 struct String : public Value
101 {
102 public:
103 String(std::istream& stream) : Value(Node::Type::string)
104 {
105 matchCharacter(stream, '"');
106 auto ch = stream.get();
107
108 while (ch != '"') {
109 if (ch == '\\') {
110 throw std::logic_error("JSON parser: string escaping not implemented");
111 }
112 value.push_back(static_cast<char>(ch));
113 ch = stream.get();
114 }
115 }
116
117 std::string value;
118 };
119
120 struct Number : public Value
121 {
122 Number(std::istream& stream) : Value(Node::Type::number)
123 {
124 stream >> value;
125 }
126
127 double value;
128 };
129
130 struct Object : public Value
131 {
132 Object(std::istream& stream) : Value(Node::Type::object)
133 {
134 matchCharacter(stream, '{');
135 skipWhitespace(stream);
136
137 while (stream.peek() != '}') {
138 if (!value.empty()) {
139 matchCharacter(stream, ',');
140 skipWhitespace(stream);
141 }
142
143 auto key = String(stream);
144 skipWhitespace(stream);
145 matchCharacter(stream, ':');
146 skipWhitespace(stream);
147 value[key.value] = readValue(stream);
148 skipWhitespace(stream);
149 }
150
151 stream.get();
152 }
153
154 std::map<std::string, std::shared_ptr<Value>> value;
155 };
156
157 struct Array : public Value
158 {
159 Array(std::istream& stream) : Value(Node::Type::array)
160 {
161 matchCharacter(stream, '[');
162 skipWhitespace(stream);
163
164 if (stream.peek() != ']') {
165 value.push_back(readValue(stream));
166 skipWhitespace(stream);
167
168 while (stream.peek() == ',') {
169 stream.get();
170 value.push_back(readValue(stream));
171 skipWhitespace(stream);
172 }
173 }
174
175 matchCharacter(stream, ']');
176 }
177
178 std::vector<std::shared_ptr<Value>> value;
179 };
180
181 struct Bool : public Value
182 {
183 public:
184 Bool(std::istream& stream) : Value(Node::Type::boolean)
185 {
186 value = stream.peek() == 't';
187 matchText(stream, value ? "true" : "false");
188 }
189
190 bool value;
191 };
192
193 struct Null : public Value
194 {
195 Null() : Value(Node::Type::null) {}
196
197 Null(std::istream& stream) : Null()
198 {
199 matchText(stream, "null");
200 }
201 };
202
203 Node Node::readFrom(std::istream& stream)
204 {
205 try {
206 stream.exceptions(std::ios::badbit | std::ios::failbit);
207 auto value = readValue(stream);
208 skipWhitespace(stream);
209
210 if (!stream.eof()) {
211 auto ch = stream.get();
212 std::ostringstream what;
213 what << "Stray character " << static_cast<char>(ch) << " (0x" << std::ios::hex << ch << ")";
214 throw std::runtime_error(what.str());
215 }
216
217 return{ value };
218 }
219 catch (std::runtime_error& e) {
220 throw std::runtime_error(std::string("JSON parser: ") + e.what());
221 }
222 catch (std::exception& e) {
223 throw std::logic_error(std::string("JSON parser bug: ") + e.what());
224 }
225 }
226
227 void Node::setOverrides(Node overrides)
228 {
229 assert(type() == Type::object && overrides.type() == Type::object);
230 m_overrides = std::dynamic_pointer_cast<Object>(overrides.m_value);
231 }
232
233 Node::Type Node::type() const
234 {
235 return m_value->type;
236 }
237
238 Node Node::optional(std::string const& key) const
239 {
240 if (m_overrides) {
241 try {
242 return{ m_overrides->value.at(key) };
243 }
244 catch (std::out_of_range&) {}
245 }
246 try {
247 return{ dynamic_cast<Object&>(*m_value).value.at(key) };
248 }
249 catch (std::out_of_range&) {
250 return{ std::make_shared<Null>() };
251 }
252 catch (std::bad_cast&) {
253 std::ostringstream what;
254 what << "JSON parser: Querying optional key '" << key << "', but node is not an object";
255 throw std::runtime_error(what.str());
256 }
257 }
258
259 Node Node::require(std::string const& key) const
260 {
261 auto node = optional(key);
262 if (node)
263 return node;
264 std::ostringstream stream;
265 stream << "JSON parser: Parameter " << key << " is required but missing";
266 throw std::runtime_error(stream.str());
267 }
268
269 Node Node::at(std::size_t index) const
270 {
271 if (type() != Type::array) {
272 throw std::runtime_error("JSON parser: Expected an array");
273 }
274 return{ dynamic_cast<Array&>(*m_value).value.at(index) };
275 }
276
277 std::size_t Node::size() const
278 {
279 switch (type()) {
280 case Type::array:
281 return dynamic_cast<Array&>(*m_value).value.size();
282 case Type::object:
283 return dynamic_cast<Object&>(*m_value).value.size();
284 default:
285 throw std::runtime_error("JSON parser: Expected an array or object");
286 }
287
288 }
289
290 double Node::asDouble() const
291 {
292 if (type() != Type::number) {
293 throw std::runtime_error("JSON parser: Expected a number");
294 }
295 return dynamic_cast<Number&>(*m_value).value;
296 }
297
298 float Node::asFloat() const
299 {
300 return static_cast<float>(asDouble());
301 }
302
303 int Node::asInt() const
304 {
305 auto value = asDouble();
306 auto rounded = static_cast<int>(std::lround(value));
307 auto error = value - rounded;
308 if (error > 1e-6) {
309 throw std::runtime_error("JSON parser: Expected an integer value");
310 }
311 return rounded;
312 }
313
314 std::string const& Node::asString() const
315 {
316 if (type() != Type::string) {
317 throw std::runtime_error("JSON parser: Expected a string");
318 }
319 return dynamic_cast<String&>(*m_value).value;
320 }
321
322 bool Node::asBool() const
323 {
324 if (type() != Type::boolean) {
325 throw std::runtime_error("JSON parser: Expected a boolean");
326 }
327 return dynamic_cast<Bool&>(*m_value).value;
328 }
329
330 Node::operator bool() const
331 {
332 switch (type()) {
333 case Type::null:
334 return false;
335 case Type::boolean:
336 return asBool();
337 default:
338 return true;
339 }
340 }
341
342 Node::Node()
343 : m_value(new Null)
344 {}
345
346 Node::Node(std::shared_ptr<Value> value)
347 : m_value(value)
348 {}
349
350 static std::shared_ptr<Value> readValue(std::istream& stream)
351 {
352 skipWhitespace(stream);
353 auto ch = stream.peek();
354
355 switch (ch) {
356 case '{': return std::make_shared<Object>(stream);
357 case '[': return std::make_shared<Array>(stream);
358 case '"': return std::make_shared<String>(stream);
359 case 't': return std::make_shared<Bool>(stream);
360 case 'f': return std::make_shared<Bool>(stream);
361 case 'n': return std::make_shared<Null>(stream);
362 default: break;
363 }
364
365 if (ch == '-' || std::isdigit(ch)) {
366 return std::make_shared<Number>(stream);
367 }
368
369 std::ostringstream what;
370 what << "Invalid character " << static_cast<char>(ch) << " (0x" << std::ios::hex << ch << ")";
371 throw std::runtime_error(what.str());
372 }
373}
Node optional(std::string const &key) const
Definition: JsonParser.cpp:238
std::size_t size() const
Definition: JsonParser.cpp:277
std::string const & asString() const
Definition: JsonParser.cpp:314
Type type() const
Definition: JsonParser.cpp:233
double asDouble() const
Definition: JsonParser.cpp:290
Node require(std::string const &key) const
Definition: JsonParser.cpp:259
int asInt() const
Definition: JsonParser.cpp:303
Node at(std::size_t index) const
Definition: JsonParser.cpp:269
bool asBool() const
Definition: JsonParser.cpp:322
static Node readFrom(std::istream &)
Definition: JsonParser.cpp:203
float asFloat() const
Definition: JsonParser.cpp:298