1 #include "common/ceph_json.h"
2 #include "include/utime.h"
4 // for testing DELETE ME
6 #include <include/types.h>
8 #include <boost/algorithm/string.hpp>
9 #include <boost/tokenizer.hpp>
10 #include <boost/lexical_cast.hpp>
12 #include "json_spirit/json_spirit_writer_template.h"
14 using namespace json_spirit
;
16 #define dout_subsys ceph_subsys_rgw
19 static JSONFormattable default_formattable
;
22 void encode_json(const char *name
, const JSONObj::data_val
& v
, Formatter
*f
)
25 encode_json(name
, v
.str
, f
);
27 f
->dump_format_unquoted(name
, "%s", v
.str
.c_str());
31 JSONObjIter::JSONObjIter()
35 JSONObjIter::~JSONObjIter()
39 void JSONObjIter::set(const JSONObjIter::map_iter_t
&_cur
, const JSONObjIter::map_iter_t
&_last
)
45 void JSONObjIter::operator++()
51 JSONObj
*JSONObjIter::operator*()
56 // does not work, FIXME
57 ostream
& operator<<(ostream
&out
, const JSONObj
&obj
) {
58 out
<< obj
.name
<< ": " << obj
.val
;
64 multimap
<string
, JSONObj
*>::iterator iter
;
65 for (iter
= children
.begin(); iter
!= children
.end(); ++iter
) {
66 JSONObj
*obj
= iter
->second
;
72 void JSONObj::add_child(string el
, JSONObj
*obj
)
74 children
.insert(pair
<string
, JSONObj
*>(el
, obj
));
77 bool JSONObj::get_attr(string name
, data_val
& attr
)
79 auto iter
= attr_map
.find(name
);
80 if (iter
== attr_map
.end())
86 JSONObjIter
JSONObj::find(const string
& name
)
89 map
<string
, JSONObj
*>::iterator first
;
90 map
<string
, JSONObj
*>::iterator last
;
91 first
= children
.find(name
);
92 if (first
!= children
.end()) {
93 last
= children
.upper_bound(name
);
94 iter
.set(first
, last
);
99 JSONObjIter
JSONObj::find_first()
102 iter
.set(children
.begin(), children
.end());
106 JSONObjIter
JSONObj::find_first(const string
& name
)
109 map
<string
, JSONObj
*>::iterator first
;
110 first
= children
.find(name
);
111 iter
.set(first
, children
.end());
115 JSONObj
*JSONObj::find_obj(const string
& name
)
117 JSONObjIter iter
= find(name
);
124 bool JSONObj::get_data(const string
& key
, data_val
*dest
)
126 JSONObj
*obj
= find_obj(key
);
130 *dest
= obj
->get_data_val();
135 /* accepts a JSON Array or JSON Object contained in
136 * a JSON Spirit Value, v, and creates a JSONObj for each
137 * child contained in v
139 void JSONObj::handle_value(Value v
)
141 if (v
.type() == obj_type
) {
142 Object temp_obj
= v
.get_obj();
143 for (Object::size_type i
= 0; i
< temp_obj
.size(); i
++) {
144 Pair temp_pair
= temp_obj
[i
];
145 string temp_name
= temp_pair
.name_
;
146 Value temp_value
= temp_pair
.value_
;
147 JSONObj
*child
= new JSONObj
;
148 child
->init(this, temp_value
, temp_name
);
149 add_child(temp_name
, child
);
151 } else if (v
.type() == array_type
) {
152 Array temp_array
= v
.get_array();
155 for (unsigned j
= 0; j
< temp_array
.size(); j
++) {
156 Value cur
= temp_array
[j
];
159 JSONObj
*child
= new JSONObj
;
160 child
->init(this, cur
, temp_name
);
161 add_child(child
->get_name(), child
);
166 void JSONObj::init(JSONObj
*p
, Value v
, string n
)
173 if (v
.type() == str_type
) {
174 val
.set(v
.get_str(), true);
176 val
.set(json_spirit::write_string(v
), false);
178 attr_map
.insert(pair
<string
,data_val
>(name
, val
));
181 JSONObj
*JSONObj::get_parent()
186 bool JSONObj::is_object()
188 return (data
.type() == obj_type
);
191 bool JSONObj::is_array()
193 return (data
.type() == array_type
);
196 vector
<string
> JSONObj::get_array_elements()
198 vector
<string
> elements
;
201 if (data
.type() == array_type
)
202 temp_array
= data
.get_array();
204 int array_size
= temp_array
.size();
206 for (int i
= 0; i
< array_size
; i
++) {
207 Value temp_value
= temp_array
[i
];
209 temp_string
= write(temp_value
, raw_utf8
);
210 elements
.push_back(temp_string
);
216 JSONParser::JSONParser() : buf_len(0), success(true)
220 JSONParser::~JSONParser()
226 void JSONParser::handle_data(const char *s
, int len
)
228 json_buffer
.append(s
, len
); // check for problems with null termination FIXME
232 // parse a supplied JSON fragment
233 bool JSONParser::parse(const char *buf_
, int len
)
240 string
json_string(buf_
, len
);
241 success
= read(json_string
, data
);
244 if (data
.type() != obj_type
&&
245 data
.type() != array_type
) {
246 if (data
.type() == str_type
) {
247 val
.set(data
.get_str(), true);
249 val
.set(json_spirit::write_string(data
), false);
259 // parse the internal json_buffer up to len
260 bool JSONParser::parse(int len
)
262 string json_string
= json_buffer
.substr(0, len
);
263 success
= read(json_string
, data
);
272 // parse the complete internal json_buffer
273 bool JSONParser::parse()
275 success
= read(json_buffer
, data
);
284 // parse a supplied ifstream, for testing. DELETE ME
285 bool JSONParser::parse(const char *file_name
)
287 ifstream
is(file_name
);
288 success
= read(is
, data
);
298 void decode_json_obj(long& val
, JSONObj
*obj
)
300 string s
= obj
->get_data();
301 const char *start
= s
.c_str();
305 val
= strtol(start
, &p
, 10);
307 /* Check for various possible errors */
309 if ((errno
== ERANGE
&& (val
== LONG_MAX
|| val
== LONG_MIN
)) ||
310 (errno
!= 0 && val
== 0)) {
311 throw JSONDecoder::err("failed to parse number");
315 throw JSONDecoder::err("failed to parse number");
320 throw JSONDecoder::err("failed to parse number");
326 void decode_json_obj(unsigned long& val
, JSONObj
*obj
)
328 string s
= obj
->get_data();
329 const char *start
= s
.c_str();
333 val
= strtoul(start
, &p
, 10);
335 /* Check for various possible errors */
337 if ((errno
== ERANGE
&& val
== ULONG_MAX
) ||
338 (errno
!= 0 && val
== 0)) {
339 throw JSONDecoder::err("failed to number");
343 throw JSONDecoder::err("failed to parse number");
348 throw JSONDecoder::err("failed to parse number");
354 void decode_json_obj(long long& val
, JSONObj
*obj
)
356 string s
= obj
->get_data();
357 const char *start
= s
.c_str();
361 val
= strtoll(start
, &p
, 10);
363 /* Check for various possible errors */
365 if ((errno
== ERANGE
&& (val
== LLONG_MAX
|| val
== LLONG_MIN
)) ||
366 (errno
!= 0 && val
== 0)) {
367 throw JSONDecoder::err("failed to parse number");
371 throw JSONDecoder::err("failed to parse number");
376 throw JSONDecoder::err("failed to parse number");
382 void decode_json_obj(unsigned long long& val
, JSONObj
*obj
)
384 string s
= obj
->get_data();
385 const char *start
= s
.c_str();
389 val
= strtoull(start
, &p
, 10);
391 /* Check for various possible errors */
393 if ((errno
== ERANGE
&& val
== ULLONG_MAX
) ||
394 (errno
!= 0 && val
== 0)) {
395 throw JSONDecoder::err("failed to number");
399 throw JSONDecoder::err("failed to parse number");
404 throw JSONDecoder::err("failed to parse number");
410 void decode_json_obj(int& val
, JSONObj
*obj
)
413 decode_json_obj(l
, obj
);
414 #if LONG_MAX > INT_MAX
415 if (l
> INT_MAX
|| l
< INT_MIN
) {
416 throw JSONDecoder::err("integer out of range");
423 void decode_json_obj(unsigned& val
, JSONObj
*obj
)
426 decode_json_obj(l
, obj
);
427 #if ULONG_MAX > UINT_MAX
429 throw JSONDecoder::err("unsigned integer out of range");
436 void decode_json_obj(bool& val
, JSONObj
*obj
)
438 string s
= obj
->get_data();
439 if (strcasecmp(s
.c_str(), "true") == 0) {
443 if (strcasecmp(s
.c_str(), "false") == 0) {
448 decode_json_obj(i
, obj
);
452 void decode_json_obj(bufferlist
& val
, JSONObj
*obj
)
454 string s
= obj
->get_data();
457 bl
.append(s
.c_str(), s
.size());
459 val
.decode_base64(bl
);
460 } catch (buffer::error
& err
) {
461 throw JSONDecoder::err("failed to decode base64");
465 void decode_json_obj(utime_t
& val
, JSONObj
*obj
)
467 string s
= obj
->get_data();
470 int r
= utime_t::parse_date(s
, &epoch
, &nsec
);
472 val
= utime_t(epoch
, nsec
);
474 throw JSONDecoder::err("failed to decode utime_t");
478 void encode_json(const char *name
, const string
& val
, Formatter
*f
)
480 f
->dump_string(name
, val
);
483 void encode_json(const char *name
, const char *val
, Formatter
*f
)
485 f
->dump_string(name
, val
);
488 void encode_json(const char *name
, bool val
, Formatter
*f
)
496 f
->dump_string(name
, s
);
499 void encode_json(const char *name
, int val
, Formatter
*f
)
501 f
->dump_int(name
, val
);
504 void encode_json(const char *name
, long val
, Formatter
*f
)
506 f
->dump_int(name
, val
);
509 void encode_json(const char *name
, unsigned val
, Formatter
*f
)
511 f
->dump_unsigned(name
, val
);
514 void encode_json(const char *name
, unsigned long val
, Formatter
*f
)
516 f
->dump_unsigned(name
, val
);
519 void encode_json(const char *name
, unsigned long long val
, Formatter
*f
)
521 f
->dump_unsigned(name
, val
);
524 void encode_json(const char *name
, long long val
, Formatter
*f
)
526 f
->dump_int(name
, val
);
529 void encode_json(const char *name
, const utime_t
& val
, Formatter
*f
)
531 val
.gmtime(f
->dump_stream(name
));
534 void encode_json(const char *name
, const bufferlist
& bl
, Formatter
*f
)
536 /* need to copy data from bl, as it is const bufferlist */
540 src
.encode_base64(b64
);
542 string
s(b64
.c_str(), b64
.length());
544 encode_json(name
, s
, f
);
549 /* JSONFormattable */
551 const JSONFormattable
& JSONFormattable::operator[](const string
& name
) const
553 auto i
= obj
.find(name
);
554 if (i
== obj
.end()) {
555 return default_formattable
;
560 const JSONFormattable
& JSONFormattable::operator[](size_t index
) const
562 if (index
>= arr
.size()) {
563 return default_formattable
;
568 JSONFormattable
& JSONFormattable::operator[](const string
& name
)
570 auto i
= obj
.find(name
);
571 if (i
== obj
.end()) {
572 return default_formattable
;
577 JSONFormattable
& JSONFormattable::operator[](size_t index
)
579 if (index
>= arr
.size()) {
580 return default_formattable
;
585 bool JSONFormattable::exists(const string
& name
) const
587 auto i
= obj
.find(name
);
588 return (i
!= obj
.end());
591 bool JSONFormattable::exists(size_t index
) const
593 return (index
< arr
.size());
596 bool JSONFormattable::find(const string
& name
, string
*val
) const
598 auto i
= obj
.find(name
);
599 if (i
== obj
.end()) {
602 *val
= i
->second
.val();
606 int JSONFormattable::val_int() const {
607 return atoi(value
.str
.c_str());
610 long JSONFormattable::val_long() const {
611 return atol(value
.str
.c_str());
614 long long JSONFormattable::val_long_long() const {
615 return atoll(value
.str
.c_str());
618 bool JSONFormattable::val_bool() const {
619 return (boost::iequals(value
.str
, "true") ||
620 boost::iequals(value
.str
, "on") ||
621 boost::iequals(value
.str
, "yes") ||
622 boost::iequals(value
.str
, "1"));
625 string
JSONFormattable::def(const string
& def_val
) const {
626 if (type
== FMT_NONE
) {
632 int JSONFormattable::def(int def_val
) const {
633 if (type
== FMT_NONE
) {
639 bool JSONFormattable::def(bool def_val
) const {
640 if (type
== FMT_NONE
) {
646 string
JSONFormattable::get(const string
& name
, const string
& def_val
) const
648 return (*this)[name
].def(def_val
);
651 int JSONFormattable::get_int(const string
& name
, int def_val
) const
653 return (*this)[name
].def(def_val
);
656 bool JSONFormattable::get_bool(const string
& name
, bool def_val
) const
658 return (*this)[name
].def(def_val
);
661 struct field_entity
{
662 bool is_obj
{false}; /* either obj field or array entity */
663 string name
; /* if obj */
664 int index
{0}; /* if array */
668 explicit field_entity(const string
& n
) : is_obj(true), name(n
) {}
669 explicit field_entity(int i
) : is_obj(false), index(i
) {}
672 static int parse_entity(const string
& s
, vector
<field_entity
> *result
)
676 while (ofs
< s
.size()) {
677 size_t next_arr
= s
.find('[', ofs
);
678 if (next_arr
== string::npos
) {
682 result
->push_back(field_entity(s
));
685 if (next_arr
> ofs
) {
686 string field
= s
.substr(ofs
, next_arr
- ofs
);
687 result
->push_back(field_entity(field
));
690 size_t end_arr
= s
.find(']', next_arr
+ 1);
691 if (end_arr
== string::npos
) {
695 string index_str
= s
.substr(next_arr
+ 1, end_arr
- next_arr
- 1);
699 if (!index_str
.empty()) {
700 result
->push_back(field_entity(atoi(index_str
.c_str())));
704 result
->push_back(f
);
710 static bool is_numeric(const string
& val
)
713 boost::lexical_cast
<double>(val
);
714 } catch (const boost::bad_lexical_cast
& e
) {
720 int JSONFormattable::set(const string
& name
, const string
& val
)
722 boost::escaped_list_separator
<char> els('\\', '.', '"');
723 boost::tokenizer
<boost::escaped_list_separator
<char> > tok(name
, els
);
725 JSONFormattable
*f
= this;
729 bool is_valid_json
= jp
.parse(val
.c_str(), val
.size());
731 for (const auto& i
: tok
) {
732 vector
<field_entity
> v
;
733 int ret
= parse_entity(i
, &v
);
737 for (const auto& vi
: v
) {
738 if (f
->type
== FMT_NONE
) {
746 if (f
->type
== FMT_OBJ
) {
750 f
= &f
->obj
[vi
.name
];
751 } else if (f
->type
== FMT_ARRAY
) {
755 int index
= vi
.index
;
757 index
= f
->arr
.size();
758 } else if (index
< 0) {
759 index
= f
->arr
.size() + index
;
761 return -EINVAL
; /* out of bounds */
764 if ((size_t)index
>= f
->arr
.size()) {
765 f
->arr
.resize(index
+ 1);
776 f
->value
.set(val
, !is_numeric(val
));
782 int JSONFormattable::erase(const string
& name
)
784 boost::escaped_list_separator
<char> els('\\', '.', '"');
785 boost::tokenizer
<boost::escaped_list_separator
<char> > tok(name
, els
);
787 JSONFormattable
*f
= this;
788 JSONFormattable
*parent
= nullptr;
789 field_entity last_entity
;
791 for (auto& i
: tok
) {
792 vector
<field_entity
> v
;
793 int ret
= parse_entity(i
, &v
);
797 for (const auto& vi
: v
) {
798 if (f
->type
== FMT_NONE
||
799 f
->type
== FMT_VALUE
) {
809 if (f
->type
== FMT_OBJ
) {
813 auto iter
= f
->obj
.find(vi
.name
);
814 if (iter
== f
->obj
.end()) {
815 return 0; /* nothing to erase */
818 } else if (f
->type
== FMT_ARRAY
) {
822 int index
= vi
.index
;
824 index
= f
->arr
.size() + index
;
825 if (index
< 0) { /* out of bounds, nothing to remove */
829 if ((size_t)index
>= f
->arr
.size()) {
830 return 0; /* index beyond array boundaries */
839 *this = JSONFormattable(); /* erase everything */
841 if (last_entity
.is_obj
) {
842 parent
->obj
.erase(last_entity
.name
);
844 int index
= (last_entity
.index
>= 0 ? last_entity
.index
: parent
->arr
.size() + last_entity
.index
);
845 if (index
< 0 || (size_t)index
>= parent
->arr
.size()) {
848 parent
->arr
.erase(parent
->arr
.begin() + index
);
855 void JSONFormattable::derive_from(const JSONFormattable
& parent
)
857 for (auto& o
: parent
.obj
) {
858 if (obj
.find(o
.first
) == obj
.end()) {
859 obj
[o
.first
] = o
.second
;
864 void encode_json(const char *name
, const JSONFormattable
& v
, Formatter
*f
)
866 v
.encode_json(name
, f
);
869 void JSONFormattable::encode_json(const char *name
, Formatter
*f
) const
872 case JSONFormattable::FMT_VALUE
:
873 ::encode_json(name
, value
, f
);
875 case JSONFormattable::FMT_ARRAY
:
876 ::encode_json(name
, arr
, f
);
878 case JSONFormattable::FMT_OBJ
:
879 f
->open_object_section(name
);
880 for (auto iter
: obj
) {
881 ::encode_json(iter
.first
.c_str(), iter
.second
, f
);
885 case JSONFormattable::FMT_NONE
:
890 bool JSONFormattable::handle_value(std::string_view name
, std::string_view s
, bool quoted
) {
891 JSONFormattable
*new_val
;
892 if (cur_enc
->is_array()) {
893 cur_enc
->arr
.push_back(JSONFormattable());
894 new_val
= &cur_enc
->arr
.back();
896 cur_enc
->set_type(JSONFormattable::FMT_OBJ
);
897 new_val
= &cur_enc
->obj
[string
{name
}];
899 new_val
->set_type(JSONFormattable::FMT_VALUE
);
900 new_val
->value
.set(s
, quoted
);
905 bool JSONFormattable::handle_open_section(std::string_view name
,
907 bool section_is_array
) {
908 if (cur_enc
->is_array()) {
909 cur_enc
->arr
.push_back(JSONFormattable());
910 cur_enc
= &cur_enc
->arr
.back();
911 } else if (enc_stack
.size() > 1) {
912 /* only open a new section if already nested,
913 * otherwise root is the container
915 cur_enc
= &cur_enc
->obj
[string
{name
}];
917 enc_stack
.push_back(cur_enc
);
919 if (section_is_array
) {
920 cur_enc
->set_type(JSONFormattable::FMT_ARRAY
);
922 cur_enc
->set_type(JSONFormattable::FMT_OBJ
);
925 return false; /* continue processing */
928 bool JSONFormattable::handle_close_section() {
929 if (enc_stack
.size() <= 1) {
933 enc_stack
.pop_back();
934 cur_enc
= enc_stack
.back();
935 return false; /* continue processing */