]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/ceph_json.cc
update source to Ceph Pacific 16.2.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 val.set(json_spirit::write_string(data), false);
253 }
254 }
255 } else {
256 set_failure();
257 }
258
259 return success;
260 }
261
262 // parse the internal json_buffer up to len
263 bool JSONParser::parse(int len)
264 {
265 string json_string = json_buffer.substr(0, len);
266 success = read(json_string, data);
267 if (success)
268 handle_value(data);
269 else
270 set_failure();
271
272 return success;
273 }
274
275 // parse the complete internal json_buffer
276 bool JSONParser::parse()
277 {
278 success = read(json_buffer, data);
279 if (success)
280 handle_value(data);
281 else
282 set_failure();
283
284 return success;
285 }
286
287 // parse a supplied ifstream, for testing. DELETE ME
288 bool JSONParser::parse(const char *file_name)
289 {
290 ifstream is(file_name);
291 success = read(is, data);
292 if (success)
293 handle_value(data);
294 else
295 set_failure();
296
297 return success;
298 }
299
300
301 void decode_json_obj(long& val, JSONObj *obj)
302 {
303 string s = obj->get_data();
304 const char *start = s.c_str();
305 char *p;
306
307 errno = 0;
308 val = strtol(start, &p, 10);
309
310 /* Check for various possible errors */
311
312 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
313 (errno != 0 && val == 0)) {
314 throw JSONDecoder::err("failed to parse number");
315 }
316
317 if (p == start) {
318 throw JSONDecoder::err("failed to parse number");
319 }
320
321 while (*p != '\0') {
322 if (!isspace(*p)) {
323 throw JSONDecoder::err("failed to parse number");
324 }
325 p++;
326 }
327 }
328
329 void decode_json_obj(unsigned long& val, JSONObj *obj)
330 {
331 string s = obj->get_data();
332 const char *start = s.c_str();
333 char *p;
334
335 errno = 0;
336 val = strtoul(start, &p, 10);
337
338 /* Check for various possible errors */
339
340 if ((errno == ERANGE && val == ULONG_MAX) ||
341 (errno != 0 && val == 0)) {
342 throw JSONDecoder::err("failed to number");
343 }
344
345 if (p == start) {
346 throw JSONDecoder::err("failed to parse number");
347 }
348
349 while (*p != '\0') {
350 if (!isspace(*p)) {
351 throw JSONDecoder::err("failed to parse number");
352 }
353 p++;
354 }
355 }
356
357 void decode_json_obj(long long& val, JSONObj *obj)
358 {
359 string s = obj->get_data();
360 const char *start = s.c_str();
361 char *p;
362
363 errno = 0;
364 val = strtoll(start, &p, 10);
365
366 /* Check for various possible errors */
367
368 if ((errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) ||
369 (errno != 0 && val == 0)) {
370 throw JSONDecoder::err("failed to parse number");
371 }
372
373 if (p == start) {
374 throw JSONDecoder::err("failed to parse number");
375 }
376
377 while (*p != '\0') {
378 if (!isspace(*p)) {
379 throw JSONDecoder::err("failed to parse number");
380 }
381 p++;
382 }
383 }
384
385 void decode_json_obj(unsigned long long& val, JSONObj *obj)
386 {
387 string s = obj->get_data();
388 const char *start = s.c_str();
389 char *p;
390
391 errno = 0;
392 val = strtoull(start, &p, 10);
393
394 /* Check for various possible errors */
395
396 if ((errno == ERANGE && val == ULLONG_MAX) ||
397 (errno != 0 && val == 0)) {
398 throw JSONDecoder::err("failed to number");
399 }
400
401 if (p == start) {
402 throw JSONDecoder::err("failed to parse number");
403 }
404
405 while (*p != '\0') {
406 if (!isspace(*p)) {
407 throw JSONDecoder::err("failed to parse number");
408 }
409 p++;
410 }
411 }
412
413 void decode_json_obj(int& val, JSONObj *obj)
414 {
415 long l;
416 decode_json_obj(l, obj);
417 #if LONG_MAX > INT_MAX
418 if (l > INT_MAX || l < INT_MIN) {
419 throw JSONDecoder::err("integer out of range");
420 }
421 #endif
422
423 val = (int)l;
424 }
425
426 void decode_json_obj(unsigned& val, JSONObj *obj)
427 {
428 unsigned long l;
429 decode_json_obj(l, obj);
430 #if ULONG_MAX > UINT_MAX
431 if (l > UINT_MAX) {
432 throw JSONDecoder::err("unsigned integer out of range");
433 }
434 #endif
435
436 val = (unsigned)l;
437 }
438
439 void decode_json_obj(bool& val, JSONObj *obj)
440 {
441 string s = obj->get_data();
442 if (strcasecmp(s.c_str(), "true") == 0) {
443 val = true;
444 return;
445 }
446 if (strcasecmp(s.c_str(), "false") == 0) {
447 val = false;
448 return;
449 }
450 int i;
451 decode_json_obj(i, obj);
452 val = (bool)i;
453 }
454
455 void decode_json_obj(bufferlist& val, JSONObj *obj)
456 {
457 string s = obj->get_data();
458
459 bufferlist bl;
460 bl.append(s.c_str(), s.size());
461 try {
462 val.decode_base64(bl);
463 } catch (ceph::buffer::error& err) {
464 throw JSONDecoder::err("failed to decode base64");
465 }
466 }
467
468 void decode_json_obj(utime_t& val, JSONObj *obj)
469 {
470 string s = obj->get_data();
471 uint64_t epoch;
472 uint64_t nsec;
473 int r = utime_t::parse_date(s, &epoch, &nsec);
474 if (r == 0) {
475 val = utime_t(epoch, nsec);
476 } else {
477 throw JSONDecoder::err("failed to decode utime_t");
478 }
479 }
480
481 void decode_json_obj(ceph::real_time& val, JSONObj *obj)
482 {
483 const std::string& s = obj->get_data();
484 uint64_t epoch;
485 uint64_t nsec;
486 int r = utime_t::parse_date(s, &epoch, &nsec);
487 if (r == 0) {
488 using namespace std::chrono;
489 val = real_time{seconds(epoch) + nanoseconds(nsec)};
490 } else {
491 throw JSONDecoder::err("failed to decode real_time");
492 }
493 }
494
495 void decode_json_obj(ceph::coarse_real_time& val, JSONObj *obj)
496 {
497 const std::string& s = obj->get_data();
498 uint64_t epoch;
499 uint64_t nsec;
500 int r = utime_t::parse_date(s, &epoch, &nsec);
501 if (r == 0) {
502 using namespace std::chrono;
503 val = coarse_real_time{seconds(epoch) + nanoseconds(nsec)};
504 } else {
505 throw JSONDecoder::err("failed to decode coarse_real_time");
506 }
507 }
508
509 void decode_json_obj(ceph_dir_layout& i, JSONObj *obj){
510
511 unsigned tmp;
512 JSONDecoder::decode_json("dir_hash", tmp, obj, true);
513 i.dl_dir_hash = tmp;
514 JSONDecoder::decode_json("unused1", tmp, obj, true);
515 i.dl_unused1 = tmp;
516 JSONDecoder::decode_json("unused2", tmp, obj, true);
517 i.dl_unused2 = tmp;
518 JSONDecoder::decode_json("unused3", tmp, obj, true);
519 i.dl_unused3 = tmp;
520 }
521
522 void encode_json(const char *name, const string& val, Formatter *f)
523 {
524 f->dump_string(name, val);
525 }
526
527 void encode_json(const char *name, const char *val, Formatter *f)
528 {
529 f->dump_string(name, val);
530 }
531
532 void encode_json(const char *name, bool val, Formatter *f)
533 {
534 string s;
535 if (val)
536 s = "true";
537 else
538 s = "false";
539
540 f->dump_string(name, s);
541 }
542
543 void encode_json(const char *name, int val, Formatter *f)
544 {
545 f->dump_int(name, val);
546 }
547
548 void encode_json(const char *name, long val, Formatter *f)
549 {
550 f->dump_int(name, val);
551 }
552
553 void encode_json(const char *name, unsigned val, Formatter *f)
554 {
555 f->dump_unsigned(name, val);
556 }
557
558 void encode_json(const char *name, unsigned long val, Formatter *f)
559 {
560 f->dump_unsigned(name, val);
561 }
562
563 void encode_json(const char *name, unsigned long long val, Formatter *f)
564 {
565 f->dump_unsigned(name, val);
566 }
567
568 void encode_json(const char *name, long long val, Formatter *f)
569 {
570 f->dump_int(name, val);
571 }
572
573 void encode_json(const char *name, const utime_t& val, Formatter *f)
574 {
575 val.gmtime(f->dump_stream(name));
576 }
577
578 void encode_json(const char *name, const ceph::real_time& val, Formatter *f)
579 {
580 encode_json(name, utime_t{val}, f);
581 }
582
583 void encode_json(const char *name, const ceph::coarse_real_time& val, Formatter *f)
584 {
585 encode_json(name, utime_t{val}, f);
586 }
587
588 void encode_json(const char *name, const bufferlist& bl, Formatter *f)
589 {
590 /* need to copy data from bl, as it is const bufferlist */
591 bufferlist src = bl;
592
593 bufferlist b64;
594 src.encode_base64(b64);
595
596 string s(b64.c_str(), b64.length());
597
598 encode_json(name, s, f);
599 }
600
601
602
603 /* JSONFormattable */
604
605 const JSONFormattable& JSONFormattable::operator[](const string& name) const
606 {
607 auto i = obj.find(name);
608 if (i == obj.end()) {
609 return default_formattable;
610 }
611 return i->second;
612 }
613
614 const JSONFormattable& JSONFormattable::operator[](size_t index) const
615 {
616 if (index >= arr.size()) {
617 return default_formattable;
618 }
619 return arr[index];
620 }
621
622 JSONFormattable& JSONFormattable::operator[](const string& name)
623 {
624 auto i = obj.find(name);
625 if (i == obj.end()) {
626 return default_formattable;
627 }
628 return i->second;
629 }
630
631 JSONFormattable& JSONFormattable::operator[](size_t index)
632 {
633 if (index >= arr.size()) {
634 return default_formattable;
635 }
636 return arr[index];
637 }
638
639 bool JSONFormattable::exists(const string& name) const
640 {
641 auto i = obj.find(name);
642 return (i != obj.end());
643 }
644
645 bool JSONFormattable::exists(size_t index) const
646 {
647 return (index < arr.size());
648 }
649
650 bool JSONFormattable::find(const string& name, string *val) const
651 {
652 auto i = obj.find(name);
653 if (i == obj.end()) {
654 return false;
655 }
656 *val = i->second.val();
657 return true;
658 }
659
660 int JSONFormattable::val_int() const {
661 return atoi(value.str.c_str());
662 }
663
664 long JSONFormattable::val_long() const {
665 return atol(value.str.c_str());
666 }
667
668 long long JSONFormattable::val_long_long() const {
669 return atoll(value.str.c_str());
670 }
671
672 bool JSONFormattable::val_bool() const {
673 return (boost::iequals(value.str, "true") ||
674 boost::iequals(value.str, "on") ||
675 boost::iequals(value.str, "yes") ||
676 boost::iequals(value.str, "1"));
677 }
678
679 string JSONFormattable::def(const string& def_val) const {
680 if (type == FMT_NONE) {
681 return def_val;
682 }
683 return val();
684 }
685
686 int JSONFormattable::def(int def_val) const {
687 if (type == FMT_NONE) {
688 return def_val;
689 }
690 return val_int();
691 }
692
693 bool JSONFormattable::def(bool def_val) const {
694 if (type == FMT_NONE) {
695 return def_val;
696 }
697 return val_bool();
698 }
699
700 string JSONFormattable::get(const string& name, const string& def_val) const
701 {
702 return (*this)[name].def(def_val);
703 }
704
705 int JSONFormattable::get_int(const string& name, int def_val) const
706 {
707 return (*this)[name].def(def_val);
708 }
709
710 bool JSONFormattable::get_bool(const string& name, bool def_val) const
711 {
712 return (*this)[name].def(def_val);
713 }
714
715 struct field_entity {
716 bool is_obj{false}; /* either obj field or array entity */
717 string name; /* if obj */
718 int index{0}; /* if array */
719 bool append{false};
720
721 field_entity() {}
722 explicit field_entity(const string& n) : is_obj(true), name(n) {}
723 explicit field_entity(int i) : is_obj(false), index(i) {}
724 };
725
726 static int parse_entity(const string& s, vector<field_entity> *result)
727 {
728 size_t ofs = 0;
729
730 while (ofs < s.size()) {
731 size_t next_arr = s.find('[', ofs);
732 if (next_arr == string::npos) {
733 if (ofs != 0) {
734 return -EINVAL;
735 }
736 result->push_back(field_entity(s));
737 return 0;
738 }
739 if (next_arr > ofs) {
740 string field = s.substr(ofs, next_arr - ofs);
741 result->push_back(field_entity(field));
742 ofs = next_arr;
743 }
744 size_t end_arr = s.find(']', next_arr + 1);
745 if (end_arr == string::npos) {
746 return -EINVAL;
747 }
748
749 string index_str = s.substr(next_arr + 1, end_arr - next_arr - 1);
750
751 ofs = end_arr + 1;
752
753 if (!index_str.empty()) {
754 result->push_back(field_entity(atoi(index_str.c_str())));
755 } else {
756 field_entity f;
757 f.append = true;
758 result->push_back(f);
759 }
760 }
761 return 0;
762 }
763
764 static bool is_numeric(const string& val)
765 {
766 try {
767 boost::lexical_cast<double>(val);
768 } catch (const boost::bad_lexical_cast& e) {
769 return false;
770 }
771 return true;
772 }
773
774 int JSONFormattable::set(const string& name, const string& val)
775 {
776 boost::escaped_list_separator<char> els('\\', '.', '"');
777 boost::tokenizer<boost::escaped_list_separator<char> > tok(name, els);
778
779 JSONFormattable *f = this;
780
781 JSONParser jp;
782
783 bool is_valid_json = jp.parse(val.c_str(), val.size());
784
785 for (const auto& i : tok) {
786 vector<field_entity> v;
787 int ret = parse_entity(i, &v);
788 if (ret < 0) {
789 return ret;
790 }
791 for (const auto& vi : v) {
792 if (f->type == FMT_NONE) {
793 if (vi.is_obj) {
794 f->type = FMT_OBJ;
795 } else {
796 f->type = FMT_ARRAY;
797 }
798 }
799
800 if (f->type == FMT_OBJ) {
801 if (!vi.is_obj) {
802 return -EINVAL;
803 }
804 f = &f->obj[vi.name];
805 } else if (f->type == FMT_ARRAY) {
806 if (vi.is_obj) {
807 return -EINVAL;
808 }
809 int index = vi.index;
810 if (vi.append) {
811 index = f->arr.size();
812 } else if (index < 0) {
813 index = f->arr.size() + index;
814 if (index < 0) {
815 return -EINVAL; /* out of bounds */
816 }
817 }
818 if ((size_t)index >= f->arr.size()) {
819 f->arr.resize(index + 1);
820 }
821 f = &f->arr[index];
822 }
823 }
824 }
825
826 if (is_valid_json) {
827 f->decode_json(&jp);
828 } else {
829 f->type = FMT_VALUE;
830 f->value.set(val, !is_numeric(val));
831 }
832
833 return 0;
834 }
835
836 int JSONFormattable::erase(const string& name)
837 {
838 boost::escaped_list_separator<char> els('\\', '.', '"');
839 boost::tokenizer<boost::escaped_list_separator<char> > tok(name, els);
840
841 JSONFormattable *f = this;
842 JSONFormattable *parent = nullptr;
843 field_entity last_entity;
844
845 for (auto& i : tok) {
846 vector<field_entity> v;
847 int ret = parse_entity(i, &v);
848 if (ret < 0) {
849 return ret;
850 }
851 for (const auto& vi : v) {
852 if (f->type == FMT_NONE ||
853 f->type == FMT_VALUE) {
854 if (vi.is_obj) {
855 f->type = FMT_OBJ;
856 } else {
857 f->type = FMT_ARRAY;
858 }
859 }
860
861 parent = f;
862
863 if (f->type == FMT_OBJ) {
864 if (!vi.is_obj) {
865 return -EINVAL;
866 }
867 auto iter = f->obj.find(vi.name);
868 if (iter == f->obj.end()) {
869 return 0; /* nothing to erase */
870 }
871 f = &iter->second;
872 } else if (f->type == FMT_ARRAY) {
873 if (vi.is_obj) {
874 return -EINVAL;
875 }
876 int index = vi.index;
877 if (index < 0) {
878 index = f->arr.size() + index;
879 if (index < 0) { /* out of bounds, nothing to remove */
880 return 0;
881 }
882 }
883 if ((size_t)index >= f->arr.size()) {
884 return 0; /* index beyond array boundaries */
885 }
886 f = &f->arr[index];
887 }
888 last_entity = vi;
889 }
890 }
891
892 if (!parent) {
893 *this = JSONFormattable(); /* erase everything */
894 } else {
895 if (last_entity.is_obj) {
896 parent->obj.erase(last_entity.name);
897 } else {
898 int index = (last_entity.index >= 0 ? last_entity.index : parent->arr.size() + last_entity.index);
899 if (index < 0 || (size_t)index >= parent->arr.size()) {
900 return 0;
901 }
902 parent->arr.erase(parent->arr.begin() + index);
903 }
904 }
905
906 return 0;
907 }
908
909 void JSONFormattable::derive_from(const JSONFormattable& parent)
910 {
911 for (auto& o : parent.obj) {
912 if (obj.find(o.first) == obj.end()) {
913 obj[o.first] = o.second;
914 }
915 }
916 }
917
918 void encode_json(const char *name, const JSONFormattable& v, Formatter *f)
919 {
920 v.encode_json(name, f);
921 }
922
923 void JSONFormattable::encode_json(const char *name, Formatter *f) const
924 {
925 switch (type) {
926 case JSONFormattable::FMT_VALUE:
927 ::encode_json(name, value, f);
928 break;
929 case JSONFormattable::FMT_ARRAY:
930 ::encode_json(name, arr, f);
931 break;
932 case JSONFormattable::FMT_OBJ:
933 f->open_object_section(name);
934 for (auto iter : obj) {
935 ::encode_json(iter.first.c_str(), iter.second, f);
936 }
937 f->close_section();
938 break;
939 case JSONFormattable::FMT_NONE:
940 break;
941 }
942 }
943
944 bool JSONFormattable::handle_value(std::string_view name, std::string_view s, bool quoted) {
945 JSONFormattable *new_val;
946 if (cur_enc->is_array()) {
947 cur_enc->arr.push_back(JSONFormattable());
948 new_val = &cur_enc->arr.back();
949 } else {
950 cur_enc->set_type(JSONFormattable::FMT_OBJ);
951 new_val = &cur_enc->obj[string{name}];
952 }
953 new_val->set_type(JSONFormattable::FMT_VALUE);
954 new_val->value.set(s, quoted);
955
956 return false;
957 }
958
959 bool JSONFormattable::handle_open_section(std::string_view name,
960 const char *ns,
961 bool section_is_array) {
962 if (cur_enc->is_array()) {
963 cur_enc->arr.push_back(JSONFormattable());
964 cur_enc = &cur_enc->arr.back();
965 } else if (enc_stack.size() > 1) {
966 /* only open a new section if already nested,
967 * otherwise root is the container
968 */
969 cur_enc = &cur_enc->obj[string{name}];
970 }
971 enc_stack.push_back(cur_enc);
972
973 if (section_is_array) {
974 cur_enc->set_type(JSONFormattable::FMT_ARRAY);
975 } else {
976 cur_enc->set_type(JSONFormattable::FMT_OBJ);
977 }
978
979 return false; /* continue processing */
980 }
981
982 bool JSONFormattable::handle_close_section() {
983 if (enc_stack.size() <= 1) {
984 return false;
985 }
986
987 enc_stack.pop_back();
988 cur_enc = enc_stack.back();
989 return false; /* continue processing */
990 }
991