|
1 | 1 | /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
|
2 | 2 |
|
3 | 3 | #include "base/json.hpp"
|
4 |
| -#include "base/debug.hpp" |
5 |
| -#include "base/namespace.hpp" |
6 |
| -#include "base/dictionary.hpp" |
7 | 4 | #include "base/array.hpp"
|
8 |
| -#include "base/objectlock.hpp" |
9 |
| -#include "base/convert.hpp" |
10 |
| -#include "base/utility.hpp" |
11 |
| -#include <bitset> |
12 |
| -#include <boost/exception_ptr.hpp> |
13 |
| -#include <cstdint> |
14 |
| -#include <json.hpp> |
15 | 5 | #include <stack>
|
16 |
| -#include <utility> |
17 |
| -#include <vector> |
18 | 6 |
|
19 | 7 | using namespace icinga;
|
20 | 8 |
|
@@ -143,165 +131,11 @@ class JsonSax : public nlohmann::json_sax<nlohmann::json>
|
143 | 131 | void FillCurrentTarget(Value value);
|
144 | 132 | };
|
145 | 133 |
|
146 |
| -const char l_Null[] = "null"; |
147 |
| -const char l_False[] = "false"; |
148 |
| -const char l_True[] = "true"; |
149 |
| -const char l_Indent[] = " "; |
150 |
| - |
151 |
| -// https://github.com/nlohmann/json/issues/1512 |
152 |
| -template<bool prettyPrint> |
153 |
| -class JsonEncoder |
154 |
| -{ |
155 |
| -public: |
156 |
| - void Null(); |
157 |
| - void Boolean(bool value); |
158 |
| - void NumberFloat(double value); |
159 |
| - void Strng(String value); |
160 |
| - void StartObject(); |
161 |
| - void Key(String value); |
162 |
| - void EndObject(); |
163 |
| - void StartArray(); |
164 |
| - void EndArray(); |
165 |
| - |
166 |
| - String GetResult(); |
167 |
| - |
168 |
| -private: |
169 |
| - std::vector<char> m_Result; |
170 |
| - String m_CurrentKey; |
171 |
| - std::stack<std::bitset<2>> m_CurrentSubtree; |
172 |
| - |
173 |
| - void AppendChar(char c); |
174 |
| - |
175 |
| - template<class Iterator> |
176 |
| - void AppendChars(Iterator begin, Iterator end); |
177 |
| - |
178 |
| - void AppendJson(nlohmann::json json); |
179 |
| - |
180 |
| - void BeforeItem(); |
181 |
| - |
182 |
| - void FinishContainer(char terminator); |
183 |
| -}; |
184 |
| - |
185 |
| -template<bool prettyPrint> |
186 |
| -void Encode(JsonEncoder<prettyPrint>& stateMachine, const Value& value); |
187 |
| - |
188 |
| -template<bool prettyPrint> |
189 |
| -inline |
190 |
| -void EncodeNamespace(JsonEncoder<prettyPrint>& stateMachine, const Namespace::Ptr& ns) |
191 |
| -{ |
192 |
| - stateMachine.StartObject(); |
193 |
| - |
194 |
| - ObjectLock olock(ns); |
195 |
| - for (const Namespace::Pair& kv : ns) { |
196 |
| - stateMachine.Key(Utility::ValidateUTF8(kv.first)); |
197 |
| - Encode(stateMachine, kv.second.Val); |
198 |
| - } |
199 |
| - |
200 |
| - stateMachine.EndObject(); |
201 |
| -} |
202 |
| - |
203 |
| -template<bool prettyPrint> |
204 |
| -inline |
205 |
| -void EncodeDictionary(JsonEncoder<prettyPrint>& stateMachine, const Dictionary::Ptr& dict) |
206 |
| -{ |
207 |
| - stateMachine.StartObject(); |
208 |
| - |
209 |
| - ObjectLock olock(dict); |
210 |
| - for (const Dictionary::Pair& kv : dict) { |
211 |
| - stateMachine.Key(Utility::ValidateUTF8(kv.first)); |
212 |
| - Encode(stateMachine, kv.second); |
213 |
| - } |
214 |
| - |
215 |
| - stateMachine.EndObject(); |
216 |
| -} |
217 |
| - |
218 |
| -template<bool prettyPrint> |
219 |
| -inline |
220 |
| -void EncodeArray(JsonEncoder<prettyPrint>& stateMachine, const Array::Ptr& arr) |
221 |
| -{ |
222 |
| - stateMachine.StartArray(); |
223 |
| - |
224 |
| - ObjectLock olock(arr); |
225 |
| - for (const Value& value : arr) { |
226 |
| - Encode(stateMachine, value); |
227 |
| - } |
228 |
| - |
229 |
| - stateMachine.EndArray(); |
230 |
| -} |
231 |
| - |
232 |
| -template<bool prettyPrint> |
233 |
| -void Encode(JsonEncoder<prettyPrint>& stateMachine, const Value& value) |
234 |
| -{ |
235 |
| - switch (value.GetType()) { |
236 |
| - case ValueNumber: |
237 |
| - stateMachine.NumberFloat(value.Get<double>()); |
238 |
| - break; |
239 |
| - |
240 |
| - case ValueBoolean: |
241 |
| - stateMachine.Boolean(value.ToBool()); |
242 |
| - break; |
243 |
| - |
244 |
| - case ValueString: |
245 |
| - stateMachine.Strng(Utility::ValidateUTF8(value.Get<String>())); |
246 |
| - break; |
247 |
| - |
248 |
| - case ValueObject: |
249 |
| - { |
250 |
| - const Object::Ptr& obj = value.Get<Object::Ptr>(); |
251 |
| - |
252 |
| - { |
253 |
| - Namespace::Ptr ns = dynamic_pointer_cast<Namespace>(obj); |
254 |
| - if (ns) { |
255 |
| - EncodeNamespace(stateMachine, ns); |
256 |
| - break; |
257 |
| - } |
258 |
| - } |
259 |
| - |
260 |
| - { |
261 |
| - Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(obj); |
262 |
| - if (dict) { |
263 |
| - EncodeDictionary(stateMachine, dict); |
264 |
| - break; |
265 |
| - } |
266 |
| - } |
267 |
| - |
268 |
| - { |
269 |
| - Array::Ptr arr = dynamic_pointer_cast<Array>(obj); |
270 |
| - if (arr) { |
271 |
| - EncodeArray(stateMachine, arr); |
272 |
| - break; |
273 |
| - } |
274 |
| - } |
275 |
| - |
276 |
| - // obj is most likely a function => "Object of type 'Function'" |
277 |
| - Encode(stateMachine, obj->ToString()); |
278 |
| - break; |
279 |
| - } |
280 |
| - |
281 |
| - case ValueEmpty: |
282 |
| - stateMachine.Null(); |
283 |
| - break; |
284 |
| - |
285 |
| - default: |
286 |
| - VERIFY(!"Invalid variant type."); |
287 |
| - } |
288 |
| -} |
289 |
| - |
290 | 134 | String icinga::JsonEncode(const Value& value, bool pretty_print)
|
291 | 135 | {
|
292 |
| - if (pretty_print) { |
293 |
| - JsonEncoder<true> stateMachine; |
294 |
| - |
295 |
| - Encode(stateMachine, value); |
296 |
| - |
297 |
| - return stateMachine.GetResult() + "\n"; |
298 |
| - } else { |
299 |
| - JsonEncoder<false> stateMachine; |
300 |
| - |
301 |
| - Encode(stateMachine, value); |
302 |
| - |
303 |
| - return stateMachine.GetResult(); |
304 |
| - } |
| 136 | + std::ostringstream oss; |
| 137 | + JsonEncode(value, oss, pretty_print); |
| 138 | + return oss.str(); |
305 | 139 | }
|
306 | 140 |
|
307 | 141 | /**
|
@@ -460,177 +294,3 @@ void JsonSax::FillCurrentTarget(Value value)
|
460 | 294 | }
|
461 | 295 | }
|
462 | 296 | }
|
463 |
| - |
464 |
| -template<bool prettyPrint> |
465 |
| -inline |
466 |
| -void JsonEncoder<prettyPrint>::Null() |
467 |
| -{ |
468 |
| - BeforeItem(); |
469 |
| - AppendChars((const char*)l_Null, (const char*)l_Null + 4); |
470 |
| -} |
471 |
| - |
472 |
| -template<bool prettyPrint> |
473 |
| -inline |
474 |
| -void JsonEncoder<prettyPrint>::Boolean(bool value) |
475 |
| -{ |
476 |
| - BeforeItem(); |
477 |
| - |
478 |
| - if (value) { |
479 |
| - AppendChars((const char*)l_True, (const char*)l_True + 4); |
480 |
| - } else { |
481 |
| - AppendChars((const char*)l_False, (const char*)l_False + 5); |
482 |
| - } |
483 |
| -} |
484 |
| - |
485 |
| -template<bool prettyPrint> |
486 |
| -inline |
487 |
| -void JsonEncoder<prettyPrint>::NumberFloat(double value) |
488 |
| -{ |
489 |
| - BeforeItem(); |
490 |
| - |
491 |
| - // Make sure 0.0 is serialized as 0, so e.g. Icinga DB can parse it as int. |
492 |
| - if (value < 0) { |
493 |
| - long long i = value; |
494 |
| - |
495 |
| - if (i == value) { |
496 |
| - AppendJson(i); |
497 |
| - } else { |
498 |
| - AppendJson(value); |
499 |
| - } |
500 |
| - } else { |
501 |
| - unsigned long long i = value; |
502 |
| - |
503 |
| - if (i == value) { |
504 |
| - AppendJson(i); |
505 |
| - } else { |
506 |
| - AppendJson(value); |
507 |
| - } |
508 |
| - } |
509 |
| -} |
510 |
| - |
511 |
| -template<bool prettyPrint> |
512 |
| -inline |
513 |
| -void JsonEncoder<prettyPrint>::Strng(String value) |
514 |
| -{ |
515 |
| - BeforeItem(); |
516 |
| - AppendJson(std::move(value)); |
517 |
| -} |
518 |
| - |
519 |
| -template<bool prettyPrint> |
520 |
| -inline |
521 |
| -void JsonEncoder<prettyPrint>::StartObject() |
522 |
| -{ |
523 |
| - BeforeItem(); |
524 |
| - AppendChar('{'); |
525 |
| - |
526 |
| - m_CurrentSubtree.push(2); |
527 |
| -} |
528 |
| - |
529 |
| -template<bool prettyPrint> |
530 |
| -inline |
531 |
| -void JsonEncoder<prettyPrint>::Key(String value) |
532 |
| -{ |
533 |
| - m_CurrentKey = std::move(value); |
534 |
| -} |
535 |
| - |
536 |
| -template<bool prettyPrint> |
537 |
| -inline |
538 |
| -void JsonEncoder<prettyPrint>::EndObject() |
539 |
| -{ |
540 |
| - FinishContainer('}'); |
541 |
| -} |
542 |
| - |
543 |
| -template<bool prettyPrint> |
544 |
| -inline |
545 |
| -void JsonEncoder<prettyPrint>::StartArray() |
546 |
| -{ |
547 |
| - BeforeItem(); |
548 |
| - AppendChar('['); |
549 |
| - |
550 |
| - m_CurrentSubtree.push(0); |
551 |
| -} |
552 |
| - |
553 |
| -template<bool prettyPrint> |
554 |
| -inline |
555 |
| -void JsonEncoder<prettyPrint>::EndArray() |
556 |
| -{ |
557 |
| - FinishContainer(']'); |
558 |
| -} |
559 |
| - |
560 |
| -template<bool prettyPrint> |
561 |
| -inline |
562 |
| -String JsonEncoder<prettyPrint>::GetResult() |
563 |
| -{ |
564 |
| - return String(m_Result.begin(), m_Result.end()); |
565 |
| -} |
566 |
| - |
567 |
| -template<bool prettyPrint> |
568 |
| -inline |
569 |
| -void JsonEncoder<prettyPrint>::AppendChar(char c) |
570 |
| -{ |
571 |
| - m_Result.emplace_back(c); |
572 |
| -} |
573 |
| - |
574 |
| -template<bool prettyPrint> |
575 |
| -template<class Iterator> |
576 |
| -inline |
577 |
| -void JsonEncoder<prettyPrint>::AppendChars(Iterator begin, Iterator end) |
578 |
| -{ |
579 |
| - m_Result.insert(m_Result.end(), begin, end); |
580 |
| -} |
581 |
| - |
582 |
| -template<bool prettyPrint> |
583 |
| -inline |
584 |
| -void JsonEncoder<prettyPrint>::AppendJson(nlohmann::json json) |
585 |
| -{ |
586 |
| - nlohmann::detail::serializer<nlohmann::json>(nlohmann::detail::output_adapter<char>(m_Result), ' ').dump(std::move(json), prettyPrint, true, 0); |
587 |
| -} |
588 |
| - |
589 |
| -template<bool prettyPrint> |
590 |
| -inline |
591 |
| -void JsonEncoder<prettyPrint>::BeforeItem() |
592 |
| -{ |
593 |
| - if (!m_CurrentSubtree.empty()) { |
594 |
| - auto& node (m_CurrentSubtree.top()); |
595 |
| - |
596 |
| - if (node[0]) { |
597 |
| - AppendChar(','); |
598 |
| - } else { |
599 |
| - node[0] = true; |
600 |
| - } |
601 |
| - |
602 |
| - if (prettyPrint) { |
603 |
| - AppendChar('\n'); |
604 |
| - |
605 |
| - for (auto i (m_CurrentSubtree.size()); i; --i) { |
606 |
| - AppendChars((const char*)l_Indent, (const char*)l_Indent + 4); |
607 |
| - } |
608 |
| - } |
609 |
| - |
610 |
| - if (node[1]) { |
611 |
| - AppendJson(std::move(m_CurrentKey)); |
612 |
| - AppendChar(':'); |
613 |
| - |
614 |
| - if (prettyPrint) { |
615 |
| - AppendChar(' '); |
616 |
| - } |
617 |
| - } |
618 |
| - } |
619 |
| -} |
620 |
| - |
621 |
| -template<bool prettyPrint> |
622 |
| -inline |
623 |
| -void JsonEncoder<prettyPrint>::FinishContainer(char terminator) |
624 |
| -{ |
625 |
| - if (prettyPrint && m_CurrentSubtree.top()[0]) { |
626 |
| - AppendChar('\n'); |
627 |
| - |
628 |
| - for (auto i (m_CurrentSubtree.size() - 1u); i; --i) { |
629 |
| - AppendChars((const char*)l_Indent, (const char*)l_Indent + 4); |
630 |
| - } |
631 |
| - } |
632 |
| - |
633 |
| - AppendChar(terminator); |
634 |
| - |
635 |
| - m_CurrentSubtree.pop(); |
636 |
| -} |
0 commit comments