]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/ceph_json.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / common / ceph_json.cc
1 #include "common/ceph_json.h"
2 #include "include/utime.h"
3
4 // for testing DELETE ME
5 #include <fstream>
6 #include <include/types.h>
7
8 #include <boost/algorithm/string.hpp>
9 #include <boost/tokenizer.hpp>
10 #include <boost/lexical_cast.hpp>
11
12 #include "json_spirit/json_spirit_writer_template.h"
13
14 using namespace json_spirit;
15
16 using std::ifstream;
17 using std::pair;
18 using std::ostream;
19 using std::string;
20 using std::vector;
21
22 using ceph::bufferlist;
23 using ceph::Formatter;
24
25 #define dout_subsys ceph_subsys_rgw
26
27 static JSONFormattable default_formattable;
28
29 void encode_json(const char *name, const JSONObj::data_val& v, Formatter *f)
30 {
31 if (v.quoted) {
32 encode_json(name, v.str, f);
33 } else {
34 f->dump_format_unquoted(name, "%s", v.str.c_str());
35 }
36 }
37
38 JSONObjIter::JSONObjIter()
39 {
40 }
41
42 JSONObjIter::~JSONObjIter()
43 {
44 }
45
46 void JSONObjIter::set(const JSONObjIter::map_iter_t &_cur, const JSONObjIter::map_iter_t &_last)
47 {
48 cur = _cur;
49 last = _last;
50 }
51
52 void JSONObjIter::operator++()
53 {
54 if (cur != last)
55 ++cur;
56 }
57
58 JSONObj *JSONObjIter::operator*()
59 {
60 return cur->second;
61 }
62
63 // does not work, FIXME
64 ostream& operator<<(ostream &out, const JSONObj &obj) {
65 out << obj.name << ": " << obj.val;
66 return out;
67 }
68
69 JSONObj::~JSONObj()
70 {
71 for (auto iter = children.begin(); iter != children.end(); ++iter) {
72 JSONObj *obj = iter->second;
73 delete obj;
74 }
75 }
76
77
78 void JSONObj::add_child(string el, JSONObj *obj)
79 {
80 children.insert(pair<string, JSONObj *>(el, obj));
81 }
82
83 bool JSONObj::get_attr(string name, data_val& attr)
84 {
85 auto iter = attr_map.find(name);
86 if (iter == attr_map.end())
87 return false;
88 attr = iter->second;
89 return true;
90 }
91
92 JSONObjIter JSONObj::find(const string& name)
93 {
94 JSONObjIter iter;
95 auto first = children.find(name);
96 if (first != children.end()) {
97 auto last = children.upper_bound(name);
98 iter.set(first, last);
99 }
100 return iter;
101 }
102
103 JSONObjIter JSONObj::find_first()
104 {
105 JSONObjIter iter;
106 iter.set(children.begin(), children.end());
107 return iter;
108 }
109
110 JSONObjIter JSONObj::find_first(const string& name)
111 {
112 JSONObjIter iter;
113 auto first = children.find(name);
114 iter.set(first, children.end());
115 return iter;
116 }
117
118 JSONObj *JSONObj::find_obj(const string& name)
119 {
120 JSONObjIter iter = find(name);
121 if (iter.end())
122 return NULL;
123
124 return *iter;
125 }
126
127 bool JSONObj::get_data(const string& key, data_val *dest)
128 {
129 JSONObj *obj = find_obj(key);
130 if (!obj)
131 return false;
132
133 *dest = obj->get_data_val();
134
135 return true;
136 }
137
138 /* accepts a JSON Array or JSON Object contained in
139 * a JSON Spirit Value, v, and creates a JSONObj for each
140 * child contained in v
141 */
142 void JSONObj::handle_value(Value v)
143 {
144 if (v.type() == obj_type) {
145 Object temp_obj = v.get_obj();
146 for (Object::size_type i = 0; i < temp_obj.size(); i++) {
147 Pair temp_pair = temp_obj[i];
148 string temp_name = temp_pair.name_;
149 Value temp_value = temp_pair.value_;
150 JSONObj *child = new JSONObj;
151 child->init(this, temp_value, temp_name);
152 add_child(temp_name, child);
153 }
154 } else if (v.type() == array_type) {
155 Array temp_array = v.get_array();
156 Value value;
157
158 for (unsigned j = 0; j < temp_array.size(); j++) {
159 Value cur = temp_array[j];
160 string temp_name;
161
162 JSONObj *child = new JSONObj;
163 child->init(this, cur, temp_name);
164 add_child(child->get_name(), child);
165 }
166 }
167 }
168
169 void JSONObj::init(JSONObj *p, Value v, string n)
170 {
171 name = n;
172 parent = p;
173 data = v;
174
175 handle_value(v);
176 if (v.type() == str_type) {
177 val.set(v.get_str(), true);
178 } else {
179 val.set(json_spirit::write_string(v), false);
180 }
181 attr_map.insert(pair<string,data_val>(name, val));
182 }
183
184 JSONObj *JSONObj::get_parent()
185 {
186 return parent;
187 }
188
189 bool JSONObj::is_object()
190 {
191 return (data.type() == obj_type);
192 }
193
194 bool JSONObj::is_array()
195 {
196 return (data.type() == array_type);
197 }
198
199 vector<string> JSONObj::get_array_elements()
200 {
201 vector<string> elements;
202 Array temp_array;
203
204 if (data.type() == array_type)
205 temp_array = data.get_array();
206
207 int array_size = temp_array.size();
208 if (array_size > 0)
209 for (int i = 0; i < array_size; i++) {
210 Value temp_value = temp_array[i];
211 string temp_string;
212 temp_string = write(temp_value, raw_utf8);
213 elements.push_back(temp_string);
214 }
215
216 return elements;
217 }
218
219 JSONParser::JSONParser() : buf_len(0), success(true)
220 {
221 }
222
223 JSONParser::~JSONParser()
224 {
225 }
226
227
228
229 void JSONParser::handle_data(const char *s, int len)
230 {
231 json_buffer.append(s, len); // check for problems with null termination FIXME
232 buf_len += len;
233 }
234
235 // parse a supplied JSON fragment
236 bool JSONParser::parse(const char *buf_, int len)
237 {
238 if (!buf_) {
239 set_failure();
240 return false;
241 }
242
243 string json_string(buf_, len);
244 success = read(json_string, data);
245 if (success) {
246 handle_value(data);
247 if (data.type() != obj_type &&
248 data.type() != array_type) {
249 if (data.type() == str_type) {
250 val.set(data.get_str(), true);
251 } else {
252 const std::string& s = json_spirit::write_string(data);
253 if (s.size() == (uint64_t)len) { /* Check if entire string is read */
254 val.set(s, false);
255 } else {
256 set_failure();
257 }
258 }
259 }
260 } else {
261 set_failure();
262 }
263
264 return success;
265 }
266
267 // parse the internal json_buffer up to len
268 bool JSONParser::parse(int len)
269 {
270 string json_string = json_buffer.substr(0, len);
271 success = read(json_string, data);
272 if (success)
273 handle_value(data);
274 else
275 set_failure();
276
277 return success;
278 }
279
280 // parse the complete internal json_buffer
281 bool JSONParser::parse()
282 {
283 success = read(json_buffer, data);
284 if (success)
285 handle_value(data);
286 else
287 set_failure();
288
289 return success;
290 }
291
292 // parse a supplied ifstream, for testing. DELETE ME
293 bool JSONParser::parse(const char *file_name)
294 {
295 ifstream is(file_name);
296 success = read(is, data);
297 if (success)
298 handle_value(data);
299 else
300 set_failure();
301
302 return success;
303 }
304
305
306 void decode_json_obj(long& val, JSONObj *obj)
307 {
308 string s = obj->get_data();
309 const char *start = s.c_str();
310 char *p;
311
312 errno = 0;
313 val = strtol(start, &p, 10);
314
315 /* Check for various possible errors */
316
317 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
318 (errno != 0 && val == 0)) {
319 throw JSONDecoder::err("failed to parse number");
320 }
321
322 if (p == start) {
323 throw JSONDecoder::err("failed to parse number");
324 }
325
326 while (*p != '\0') {
327 if (!isspace(*p)) {
328 throw JSONDecoder::err("failed to parse number");
329 }
330 p++;
331 }
332 }
333
334 void decode_json_obj(unsigned long& val, JSONObj *obj)
335 {
336 string s = obj->get_data();
337 const char *start = s.c_str();
338 char *p;
339
340 errno = 0;
341 val = strtoul(start, &p, 10);
342
343 /* Check for various possible errors */
344
345 if ((errno == ERANGE && val == ULONG_MAX) ||
346 (errno != 0 && val == 0)) {
347 throw JSONDecoder::err("failed to number");
348 }
349
350 if (p == start) {
351 throw JSONDecoder::err("failed to parse number");
352 }
353
354 while (*p != '\0') {
355 if (!isspace(*p)) {
356 throw JSONDecoder::err("failed to parse number");
357 }
358 p++;
359 }
360 }
361
362 void decode_json_obj(long long& val, JSONObj *obj)
363 {
364 string s = obj->get_data();
365 const char *start = s.c_str();
366 char *p;
367
368 errno = 0;
369 val = strtoll(start, &p, 10);
370
371 /* Check for various possible errors */
372
373 if ((errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) ||
374 (errno != 0 && val == 0)) {
375 throw JSONDecoder::err("failed to parse number");
376 }
377
378 if (p == start) {
379 throw JSONDecoder::err("failed to parse number");
380 }
381
382 while (*p != '\0') {
383 if (!isspace(*p)) {
384 throw JSONDecoder::err("failed to parse number");
385 }
386 p++;
387 }
388 }
389
390 void decode_json_obj(unsigned long long& val, JSONObj *obj)
391 {
392 string s = obj->get_data();
393 const char *start = s.c_str();
394 char *p;
395
396 errno = 0;
397 val = strtoull(start, &p, 10);
398
399 /* Check for various possible errors */
400
401 if ((errno == ERANGE && val == ULLONG_MAX) ||
402 (errno != 0 && val == 0)) {
403 throw JSONDecoder::err("failed to number");
404 }
405
406 if (p == start) {
407 throw JSONDecoder::err("failed to parse number");
408 }
409
410 while (*p != '\0') {
411 if (!isspace(*p)) {
412 throw JSONDecoder::err("failed to parse number");
413 }
414 p++;
415 }
416 }
417
418 void decode_json_obj(int& val, JSONObj *obj)
419 {
420 long l;
421 decode_json_obj(l, obj);
422 #if LONG_MAX > INT_MAX
423 if (l > INT_MAX || l < INT_MIN) {
424 throw JSONDecoder::err("integer out of range");
425 }
426 #endif
427
428 val = (int)l;
429 }
430
431 void decode_json_obj(unsigned& val, JSONObj *obj)
432 {
433 unsigned long l;
434 decode_json_obj(l, obj);
435 #if ULONG_MAX > UINT_MAX
436 if (l > UINT_MAX) {
437 throw JSONDecoder::err("unsigned integer out of range");
438 }
439 #endif
440
441 val = (unsigned)l;
442 }
443
444 void decode_json_obj(bool& val, JSONObj *obj)
445 {
446 string s = obj->get_data();
447 if (strcasecmp(s.c_str(), "true") == 0) {
448 val = true;
449 return;
450 }
451 if (strcasecmp(s.c_str(), "false") == 0) {
452 val = false;
453 return;
454 }
455 int i;
456 decode_json_obj(i, obj);
457 val = (bool)i;
458 }
459
460 void decode_json_obj(bufferlist& val, JSONObj *obj)
461 {
462 string s = obj->get_data();
463
464 bufferlist bl;
465 bl.append(s.c_str(), s.size());
466 try {
467 val.decode_base64(bl);
468 } catch (ceph::buffer::error& err) {
469 throw JSONDecoder::err("failed to decode base64");
470 }
471 }
472
473 void decode_json_obj(utime_t& val, JSONObj *obj)
474 {
475 string s = obj->get_data();
476 uint64_t epoch;
477 uint64_t nsec;
478 int r = utime_t::parse_date(s, &epoch, &nsec);
479 if (r == 0) {
480 val = utime_t(epoch, nsec);
481 } else {
482 throw JSONDecoder::err("failed to decode utime_t");
483 }
484 }
485
486 void decode_json_obj(ceph::real_time& val, JSONObj *obj)
487 {
488 const std::string& s = obj->get_data();
489 uint64_t epoch;
490 uint64_t nsec;
491 int r = utime_t::parse_date(s, &epoch, &nsec);
492 if (r == 0) {
493 using namespace std::chrono;
494 val = real_time{seconds(epoch) + nanoseconds(nsec)};
495 } else {
496 throw JSONDecoder::err("failed to decode real_time");
497 }
498 }
499
500 void decode_json_obj(ceph::coarse_real_time& val, JSONObj *obj)
501 {
502 const std::string& s = obj->get_data();
503 uint64_t epoch;
504 uint64_t nsec;
505 int r = utime_t::parse_date(s, &epoch, &nsec);
506 if (r == 0) {
507 using namespace std::chrono;
508 val = coarse_real_time{seconds(epoch) + nanoseconds(nsec)};
509 } else {
510 throw JSONDecoder::err("failed to decode coarse_real_time");
511 }
512 }
513
514 void decode_json_obj(ceph_dir_layout& i, JSONObj *obj){
515
516 unsigned tmp;
517 JSONDecoder::decode_json("dir_hash", tmp, obj, true);
518 i.dl_dir_hash = tmp;
519 JSONDecoder::decode_json("unused1", tmp, obj, true);
520 i.dl_unused1 = tmp;
521 JSONDecoder::decode_json("unused2", tmp, obj, true);
522 i.dl_unused2 = tmp;
523 JSONDecoder::decode_json("unused3", tmp, obj, true);
524 i.dl_unused3 = tmp;
525 }
526
527 void encode_json(const char *name, std::string_view val, Formatter *f)
528 {
529 f->dump_string(name, val);
530 }
531
532 void encode_json(const char *name, const string& val, Formatter *f)
533 {
534 f->dump_string(name, val);
535 }
536
537 void encode_json(const char *name, const char *val, Formatter *f)
538 {
539 f->dump_string(name, val);
540 }
541
542 void encode_json(const char *name, bool val, Formatter *f)
543 {
544 f->dump_bool(name, val);
545 }
546
547 void encode_json(const char *name, int val, Formatter *f)
548 {
549 f->dump_int(name, val);
550 }
551
552 void encode_json(const char *name, long val, Formatter *f)
553 {
554 f->dump_int(name, val);
555 }
556
557 void encode_json(const char *name, unsigned val, Formatter *f)
558 {
559 f->dump_unsigned(name, val);
560 }
561
562 void encode_json(const char *name, unsigned long val, Formatter *f)
563 {
564 f->dump_unsigned(name, val);
565 }
566
567 void encode_json(const char *name, unsigned long long val, Formatter *f)
568 {
569 f->dump_unsigned(name, val);
570 }
571
572 void encode_json(const char *name, long long val, Formatter *f)
573 {
574 f->dump_int(name, val);
575 }
576
577 void encode_json(const char *name, const utime_t& val, Formatter *f)
578 {
579 val.gmtime(f->dump_stream(name));
580 }
581
582 void encode_json(const char *name, const ceph::real_time& val, Formatter *f)
583 {
584 encode_json(name, utime_t{val}, f);
585 }
586
587 void encode_json(const char *name, const ceph::coarse_real_time& val, Formatter *f)
588 {
589 encode_json(name, utime_t{val}, f);
590 }
591
592 void encode_json(const char *name, const bufferlist& bl, Formatter *f)
593 {
594 /* need to copy data from bl, as it is const bufferlist */
595 bufferlist src = bl;
596
597 bufferlist b64;
598 src.encode_base64(b64);
599
600 string s(b64.c_str(), b64.length());
601
602 encode_json(name, s, f);
603 }
604
605
606
607 /* JSONFormattable */
608
609 const JSONFormattable& JSONFormattable::operator[](const string& name) const
610 {
611 auto i = obj.find(name);
612 if (i == obj.end()) {
613 return default_formattable;
614 }
615 return i->second;
616 }
617
618 const JSONFormattable& JSONFormattable::operator[](size_t index) const
619 {
620 if (index >= arr.size()) {
621 return default_formattable;
622 }
623 return arr[index];
624 }
625
626 JSONFormattable& JSONFormattable::operator[](const string& name)
627 {
628 auto i = obj.find(name);
629 if (i == obj.end()) {
630 return default_formattable;
631 }
632 return i->second;
633 }
634
635 JSONFormattable& JSONFormattable::operator[](size_t index)
636 {
637 if (index >= arr.size()) {
638 return default_formattable;
639 }
640 return arr[index];
641 }
642
643 bool JSONFormattable::exists(const string& name) const
644 {
645 auto i = obj.find(name);
646 return (i != obj.end());
647 }
648
649 bool JSONFormattable::exists(size_t index) const
650 {
651 return (index < arr.size());
652 }
653
654 bool JSONFormattable::find(const string& name, string *val) const
655 {
656 auto i = obj.find(name);
657 if (i == obj.end()) {
658 return false;
659 }
660 *val = i->second.val();
661 return true;
662 }
663
664 int JSONFormattable::val_int() const {
665 return atoi(value.str.c_str());
666 }
667
668 long JSONFormattable::val_long() const {
669 return atol(value.str.c_str());
670 }
671
672 long long JSONFormattable::val_long_long() const {
673 return atoll(value.str.c_str());
674 }
675
676 bool JSONFormattable::val_bool() const {
677 return (boost::iequals(value.str, "true") ||
678 boost::iequals(value.str, "on") ||
679 boost::iequals(value.str, "yes") ||
680 boost::iequals(value.str, "1"));
681 }
682
683 string JSONFormattable::def(const string& def_val) const {
684 if (type == FMT_NONE) {
685 return def_val;
686 }
687 return val();
688 }
689
690 int JSONFormattable::def(int def_val) const {
691 if (type == FMT_NONE) {
692 return def_val;
693 }
694 return val_int();
695 }
696
697 bool JSONFormattable::def(bool def_val) const {
698 if (type == FMT_NONE) {
699 return def_val;
700 }
701 return val_bool();
702 }
703
704 string JSONFormattable::get(const string& name, const string& def_val) const
705 {
706 return (*this)[name].def(def_val);
707 }
708
709 int JSONFormattable::get_int(const string& name, int def_val) const
710 {
711 return (*this)[name].def(def_val);
712 }
713
714 bool JSONFormattable::get_bool(const string& name, bool def_val) const
715 {
716 return (*this)[name].def(def_val);
717 }
718
719 struct field_entity {
720 bool is_obj{false}; /* either obj field or array entity */
721 string name; /* if obj */
722 int index{0}; /* if array */
723 bool append{false};
724
725 field_entity() {}
726 explicit field_entity(const string& n) : is_obj(true), name(n) {}
727 explicit field_entity(int i) : is_obj(false), index(i) {}
728 };
729
730 static int parse_entity(const string& s, vector<field_entity> *result)
731 {
732 size_t ofs = 0;
733
734 while (ofs < s.size()) {
735 size_t next_arr = s.find('[', ofs);
736 if (next_arr == string::npos) {
737 if (ofs != 0) {
738 return -EINVAL;
739 }
740 result->push_back(field_entity(s));
741 return 0;
742 }
743 if (next_arr > ofs) {
744 string field = s.substr(ofs, next_arr - ofs);
745 result->push_back(field_entity(field));
746 ofs = next_arr;
747 }
748 size_t end_arr = s.find(']', next_arr + 1);
749 if (end_arr == string::npos) {
750 return -EINVAL;
751 }
752
753 string index_str = s.substr(next_arr + 1, end_arr - next_arr - 1);
754
755 ofs = end_arr + 1;
756
757 if (!index_str.empty()) {
758 result->push_back(field_entity(atoi(index_str.c_str())));
759 } else {
760 field_entity f;
761 f.append = true;
762 result->push_back(f);
763 }
764 }
765 return 0;
766 }
767
768 static bool is_numeric(const string& val)
769 {
770 try {
771 boost::lexical_cast<double>(val);
772 } catch (const boost::bad_lexical_cast& e) {
773 return false;
774 }
775 return true;
776 }
777
778 int JSONFormattable::set(const string& name, const string& val)
779 {
780 boost::escaped_list_separator<char> els('\\', '.', '"');
781 boost::tokenizer<boost::escaped_list_separator<char> > tok(name, els);
782
783 JSONFormattable *f = this;
784
785 JSONParser jp;
786
787 bool is_valid_json = jp.parse(val.c_str(), val.size());
788
789 for (const auto& i : tok) {
790 vector<field_entity> v;
791 int ret = parse_entity(i, &v);
792 if (ret < 0) {
793 return ret;
794 }
795 for (const auto& vi : v) {
796 if (f->type == FMT_NONE) {
797 if (vi.is_obj) {
798 f->type = FMT_OBJ;
799 } else {
800 f->type = FMT_ARRAY;
801 }
802 }
803
804 if (f->type == FMT_OBJ) {
805 if (!vi.is_obj) {
806 return -EINVAL;
807 }
808 f = &f->obj[vi.name];
809 } else if (f->type == FMT_ARRAY) {
810 if (vi.is_obj) {
811 return -EINVAL;
812 }
813 int index = vi.index;
814 if (vi.append) {
815 index = f->arr.size();
816 } else if (index < 0) {
817 index = f->arr.size() + index;
818 if (index < 0) {
819 return -EINVAL; /* out of bounds */
820 }
821 }
822 if ((size_t)index >= f->arr.size()) {
823 f->arr.resize(index + 1);
824 }
825 f = &f->arr[index];
826 }
827 }
828 }
829
830 if (is_valid_json) {
831 f->decode_json(&jp);
832 } else {
833 f->type = FMT_VALUE;
834 f->value.set(val, !is_numeric(val));
835 }
836
837 return 0;
838 }
839
840 int JSONFormattable::erase(const string& name)
841 {
842 boost::escaped_list_separator<char> els('\\', '.', '"');
843 boost::tokenizer<boost::escaped_list_separator<char> > tok(name, els);
844
845 JSONFormattable *f = this;
846 JSONFormattable *parent = nullptr;
847 field_entity last_entity;
848
849 for (auto& i : tok) {
850 vector<field_entity> v;
851 int ret = parse_entity(i, &v);
852 if (ret < 0) {
853 return ret;
854 }
855 for (const auto& vi : v) {
856 if (f->type == FMT_NONE ||
857 f->type == FMT_VALUE) {
858 if (vi.is_obj) {
859 f->type = FMT_OBJ;
860 } else {
861 f->type = FMT_ARRAY;
862 }
863 }
864
865 parent = f;
866
867 if (f->type == FMT_OBJ) {
868 if (!vi.is_obj) {
869 return -EINVAL;
870 }
871 auto iter = f->obj.find(vi.name);
872 if (iter == f->obj.end()) {
873 return 0; /* nothing to erase */
874 }
875 f = &iter->second;
876 } else if (f->type == FMT_ARRAY) {
877 if (vi.is_obj) {
878 return -EINVAL;
879 }
880 int index = vi.index;
881 if (index < 0) {
882 index = f->arr.size() + index;
883 if (index < 0) { /* out of bounds, nothing to remove */
884 return 0;
885 }
886 }
887 if ((size_t)index >= f->arr.size()) {
888 return 0; /* index beyond array boundaries */
889 }
890 f = &f->arr[index];
891 }
892 last_entity = vi;
893 }
894 }
895
896 if (!parent) {
897 *this = JSONFormattable(); /* erase everything */
898 } else {
899 if (last_entity.is_obj) {
900 parent->obj.erase(last_entity.name);
901 } else {
902 int index = (last_entity.index >= 0 ? last_entity.index : parent->arr.size() + last_entity.index);
903 if (index < 0 || (size_t)index >= parent->arr.size()) {
904 return 0;
905 }
906 parent->arr.erase(parent->arr.begin() + index);
907 }
908 }
909
910 return 0;
911 }
912
913 void JSONFormattable::derive_from(const JSONFormattable& parent)
914 {
915 for (auto& o : parent.obj) {
916 if (obj.find(o.first) == obj.end()) {
917 obj[o.first] = o.second;
918 }
919 }
920 }
921
922 void encode_json(const char *name, const JSONFormattable& v, Formatter *f)
923 {
924 v.encode_json(name, f);
925 }
926
927 void JSONFormattable::encode_json(const char *name, Formatter *f) const
928 {
929 switch (type) {
930 case JSONFormattable::FMT_VALUE:
931 ::encode_json(name, value, f);
932 break;
933 case JSONFormattable::FMT_ARRAY:
934 ::encode_json(name, arr, f);
935 break;
936 case JSONFormattable::FMT_OBJ:
937 f->open_object_section(name);
938 for (auto iter : obj) {
939 ::encode_json(iter.first.c_str(), iter.second, f);
940 }
941 f->close_section();
942 break;
943 case JSONFormattable::FMT_NONE:
944 break;
945 }
946 }
947
948 bool JSONFormattable::handle_value(std::string_view name, std::string_view s, bool quoted) {
949 JSONFormattable *new_val;
950 if (cur_enc->is_array()) {
951 cur_enc->arr.push_back(JSONFormattable());
952 new_val = &cur_enc->arr.back();
953 } else {
954 cur_enc->set_type(JSONFormattable::FMT_OBJ);
955 new_val = &cur_enc->obj[string{name}];
956 }
957 new_val->set_type(JSONFormattable::FMT_VALUE);
958 new_val->value.set(s, quoted);
959
960 return false;
961 }
962
963 bool JSONFormattable::handle_open_section(std::string_view name,
964 const char *ns,
965 bool section_is_array) {
966 if (cur_enc->is_array()) {
967 cur_enc->arr.push_back(JSONFormattable());
968 cur_enc = &cur_enc->arr.back();
969 } else if (enc_stack.size() > 1) {
970 /* only open a new section if already nested,
971 * otherwise root is the container
972 */
973 cur_enc = &cur_enc->obj[string{name}];
974 }
975 enc_stack.push_back(cur_enc);
976
977 if (section_is_array) {
978 cur_enc->set_type(JSONFormattable::FMT_ARRAY);
979 } else {
980 cur_enc->set_type(JSONFormattable::FMT_OBJ);
981 }
982
983 return false; /* continue processing */
984 }
985
986 bool JSONFormattable::handle_close_section() {
987 if (enc_stack.size() <= 1) {
988 return false;
989 }
990
991 enc_stack.pop_back();
992 cur_enc = enc_stack.back();
993 return false; /* continue processing */
994 }
995