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
;
22 using ceph::bufferlist
;
23 using ceph::Formatter
;
25 #define dout_subsys ceph_subsys_rgw
27 static JSONFormattable default_formattable
;
29 void encode_json(const char *name
, const JSONObj::data_val
& v
, Formatter
*f
)
32 encode_json(name
, v
.str
, f
);
34 f
->dump_format_unquoted(name
, "%s", v
.str
.c_str());
38 JSONObjIter::JSONObjIter()
42 JSONObjIter::~JSONObjIter()
46 void JSONObjIter::set(const JSONObjIter::map_iter_t
&_cur
, const JSONObjIter::map_iter_t
&_last
)
52 void JSONObjIter::operator++()
58 JSONObj
*JSONObjIter::operator*()
63 // does not work, FIXME
64 ostream
& operator<<(ostream
&out
, const JSONObj
&obj
) {
65 out
<< obj
.name
<< ": " << obj
.val
;
71 for (auto iter
= children
.begin(); iter
!= children
.end(); ++iter
) {
72 JSONObj
*obj
= iter
->second
;
78 void JSONObj::add_child(string el
, JSONObj
*obj
)
80 children
.insert(pair
<string
, JSONObj
*>(el
, obj
));
83 bool JSONObj::get_attr(string name
, data_val
& attr
)
85 auto iter
= attr_map
.find(name
);
86 if (iter
== attr_map
.end())
92 JSONObjIter
JSONObj::find(const string
& name
)
95 auto first
= children
.find(name
);
96 if (first
!= children
.end()) {
97 auto last
= children
.upper_bound(name
);
98 iter
.set(first
, last
);
103 JSONObjIter
JSONObj::find_first()
106 iter
.set(children
.begin(), children
.end());
110 JSONObjIter
JSONObj::find_first(const string
& name
)
113 auto first
= children
.find(name
);
114 iter
.set(first
, children
.end());
118 JSONObj
*JSONObj::find_obj(const string
& name
)
120 JSONObjIter iter
= find(name
);
127 bool JSONObj::get_data(const string
& key
, data_val
*dest
)
129 JSONObj
*obj
= find_obj(key
);
133 *dest
= obj
->get_data_val();
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
142 void JSONObj::handle_value(Value v
)
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
);
154 } else if (v
.type() == array_type
) {
155 Array temp_array
= v
.get_array();
158 for (unsigned j
= 0; j
< temp_array
.size(); j
++) {
159 Value cur
= temp_array
[j
];
162 JSONObj
*child
= new JSONObj
;
163 child
->init(this, cur
, temp_name
);
164 add_child(child
->get_name(), child
);
169 void JSONObj::init(JSONObj
*p
, Value v
, string n
)
176 if (v
.type() == str_type
) {
177 val
.set(v
.get_str(), true);
179 val
.set(json_spirit::write_string(v
), false);
181 attr_map
.insert(pair
<string
,data_val
>(name
, val
));
184 JSONObj
*JSONObj::get_parent()
189 bool JSONObj::is_object()
191 return (data
.type() == obj_type
);
194 bool JSONObj::is_array()
196 return (data
.type() == array_type
);
199 vector
<string
> JSONObj::get_array_elements()
201 vector
<string
> elements
;
204 if (data
.type() == array_type
)
205 temp_array
= data
.get_array();
207 int array_size
= temp_array
.size();
209 for (int i
= 0; i
< array_size
; i
++) {
210 Value temp_value
= temp_array
[i
];
212 temp_string
= write(temp_value
, raw_utf8
);
213 elements
.push_back(temp_string
);
219 JSONParser::JSONParser() : buf_len(0), success(true)
223 JSONParser::~JSONParser()
229 void JSONParser::handle_data(const char *s
, int len
)
231 json_buffer
.append(s
, len
); // check for problems with null termination FIXME
235 // parse a supplied JSON fragment
236 bool JSONParser::parse(const char *buf_
, int len
)
243 string
json_string(buf_
, len
);
244 success
= read(json_string
, 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);
252 val
.set(json_spirit::write_string(data
), false);
262 // parse the internal json_buffer up to len
263 bool JSONParser::parse(int len
)
265 string json_string
= json_buffer
.substr(0, len
);
266 success
= read(json_string
, data
);
275 // parse the complete internal json_buffer
276 bool JSONParser::parse()
278 success
= read(json_buffer
, data
);
287 // parse a supplied ifstream, for testing. DELETE ME
288 bool JSONParser::parse(const char *file_name
)
290 ifstream
is(file_name
);
291 success
= read(is
, data
);
301 void decode_json_obj(long& val
, JSONObj
*obj
)
303 string s
= obj
->get_data();
304 const char *start
= s
.c_str();
308 val
= strtol(start
, &p
, 10);
310 /* Check for various possible errors */
312 if ((errno
== ERANGE
&& (val
== LONG_MAX
|| val
== LONG_MIN
)) ||
313 (errno
!= 0 && val
== 0)) {
314 throw JSONDecoder::err("failed to parse number");
318 throw JSONDecoder::err("failed to parse number");
323 throw JSONDecoder::err("failed to parse number");
329 void decode_json_obj(unsigned long& val
, JSONObj
*obj
)
331 string s
= obj
->get_data();
332 const char *start
= s
.c_str();
336 val
= strtoul(start
, &p
, 10);
338 /* Check for various possible errors */
340 if ((errno
== ERANGE
&& val
== ULONG_MAX
) ||
341 (errno
!= 0 && val
== 0)) {
342 throw JSONDecoder::err("failed to number");
346 throw JSONDecoder::err("failed to parse number");
351 throw JSONDecoder::err("failed to parse number");
357 void decode_json_obj(long long& val
, JSONObj
*obj
)
359 string s
= obj
->get_data();
360 const char *start
= s
.c_str();
364 val
= strtoll(start
, &p
, 10);
366 /* Check for various possible errors */
368 if ((errno
== ERANGE
&& (val
== LLONG_MAX
|| val
== LLONG_MIN
)) ||
369 (errno
!= 0 && val
== 0)) {
370 throw JSONDecoder::err("failed to parse number");
374 throw JSONDecoder::err("failed to parse number");
379 throw JSONDecoder::err("failed to parse number");
385 void decode_json_obj(unsigned long long& val
, JSONObj
*obj
)
387 string s
= obj
->get_data();
388 const char *start
= s
.c_str();
392 val
= strtoull(start
, &p
, 10);
394 /* Check for various possible errors */
396 if ((errno
== ERANGE
&& val
== ULLONG_MAX
) ||
397 (errno
!= 0 && val
== 0)) {
398 throw JSONDecoder::err("failed to number");
402 throw JSONDecoder::err("failed to parse number");
407 throw JSONDecoder::err("failed to parse number");
413 void decode_json_obj(int& val
, JSONObj
*obj
)
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");
426 void decode_json_obj(unsigned& val
, JSONObj
*obj
)
429 decode_json_obj(l
, obj
);
430 #if ULONG_MAX > UINT_MAX
432 throw JSONDecoder::err("unsigned integer out of range");
439 void decode_json_obj(bool& val
, JSONObj
*obj
)
441 string s
= obj
->get_data();
442 if (strcasecmp(s
.c_str(), "true") == 0) {
446 if (strcasecmp(s
.c_str(), "false") == 0) {
451 decode_json_obj(i
, obj
);
455 void decode_json_obj(bufferlist
& val
, JSONObj
*obj
)
457 string s
= obj
->get_data();
460 bl
.append(s
.c_str(), s
.size());
462 val
.decode_base64(bl
);
463 } catch (ceph::buffer::error
& err
) {
464 throw JSONDecoder::err("failed to decode base64");
468 void decode_json_obj(utime_t
& val
, JSONObj
*obj
)
470 string s
= obj
->get_data();
473 int r
= utime_t::parse_date(s
, &epoch
, &nsec
);
475 val
= utime_t(epoch
, nsec
);
477 throw JSONDecoder::err("failed to decode utime_t");
481 void decode_json_obj(ceph::real_time
& val
, JSONObj
*obj
)
483 const std::string
& s
= obj
->get_data();
486 int r
= utime_t::parse_date(s
, &epoch
, &nsec
);
488 using namespace std::chrono
;
489 val
= real_time
{seconds(epoch
) + nanoseconds(nsec
)};
491 throw JSONDecoder::err("failed to decode real_time");
495 void decode_json_obj(ceph::coarse_real_time
& val
, JSONObj
*obj
)
497 const std::string
& s
= obj
->get_data();
500 int r
= utime_t::parse_date(s
, &epoch
, &nsec
);
502 using namespace std::chrono
;
503 val
= coarse_real_time
{seconds(epoch
) + nanoseconds(nsec
)};
505 throw JSONDecoder::err("failed to decode coarse_real_time");
509 void decode_json_obj(ceph_dir_layout
& i
, JSONObj
*obj
){
512 JSONDecoder::decode_json("dir_hash", tmp
, obj
, true);
514 JSONDecoder::decode_json("unused1", tmp
, obj
, true);
516 JSONDecoder::decode_json("unused2", tmp
, obj
, true);
518 JSONDecoder::decode_json("unused3", tmp
, obj
, true);
522 void encode_json(const char *name
, const string
& val
, Formatter
*f
)
524 f
->dump_string(name
, val
);
527 void encode_json(const char *name
, const char *val
, Formatter
*f
)
529 f
->dump_string(name
, val
);
532 void encode_json(const char *name
, bool val
, Formatter
*f
)
540 f
->dump_string(name
, s
);
543 void encode_json(const char *name
, int val
, Formatter
*f
)
545 f
->dump_int(name
, val
);
548 void encode_json(const char *name
, long val
, Formatter
*f
)
550 f
->dump_int(name
, val
);
553 void encode_json(const char *name
, unsigned val
, Formatter
*f
)
555 f
->dump_unsigned(name
, val
);
558 void encode_json(const char *name
, unsigned long val
, Formatter
*f
)
560 f
->dump_unsigned(name
, val
);
563 void encode_json(const char *name
, unsigned long long val
, Formatter
*f
)
565 f
->dump_unsigned(name
, val
);
568 void encode_json(const char *name
, long long val
, Formatter
*f
)
570 f
->dump_int(name
, val
);
573 void encode_json(const char *name
, const utime_t
& val
, Formatter
*f
)
575 val
.gmtime(f
->dump_stream(name
));
578 void encode_json(const char *name
, const ceph::real_time
& val
, Formatter
*f
)
580 encode_json(name
, utime_t
{val
}, f
);
583 void encode_json(const char *name
, const ceph::coarse_real_time
& val
, Formatter
*f
)
585 encode_json(name
, utime_t
{val
}, f
);
588 void encode_json(const char *name
, const bufferlist
& bl
, Formatter
*f
)
590 /* need to copy data from bl, as it is const bufferlist */
594 src
.encode_base64(b64
);
596 string
s(b64
.c_str(), b64
.length());
598 encode_json(name
, s
, f
);
603 /* JSONFormattable */
605 const JSONFormattable
& JSONFormattable::operator[](const string
& name
) const
607 auto i
= obj
.find(name
);
608 if (i
== obj
.end()) {
609 return default_formattable
;
614 const JSONFormattable
& JSONFormattable::operator[](size_t index
) const
616 if (index
>= arr
.size()) {
617 return default_formattable
;
622 JSONFormattable
& JSONFormattable::operator[](const string
& name
)
624 auto i
= obj
.find(name
);
625 if (i
== obj
.end()) {
626 return default_formattable
;
631 JSONFormattable
& JSONFormattable::operator[](size_t index
)
633 if (index
>= arr
.size()) {
634 return default_formattable
;
639 bool JSONFormattable::exists(const string
& name
) const
641 auto i
= obj
.find(name
);
642 return (i
!= obj
.end());
645 bool JSONFormattable::exists(size_t index
) const
647 return (index
< arr
.size());
650 bool JSONFormattable::find(const string
& name
, string
*val
) const
652 auto i
= obj
.find(name
);
653 if (i
== obj
.end()) {
656 *val
= i
->second
.val();
660 int JSONFormattable::val_int() const {
661 return atoi(value
.str
.c_str());
664 long JSONFormattable::val_long() const {
665 return atol(value
.str
.c_str());
668 long long JSONFormattable::val_long_long() const {
669 return atoll(value
.str
.c_str());
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"));
679 string
JSONFormattable::def(const string
& def_val
) const {
680 if (type
== FMT_NONE
) {
686 int JSONFormattable::def(int def_val
) const {
687 if (type
== FMT_NONE
) {
693 bool JSONFormattable::def(bool def_val
) const {
694 if (type
== FMT_NONE
) {
700 string
JSONFormattable::get(const string
& name
, const string
& def_val
) const
702 return (*this)[name
].def(def_val
);
705 int JSONFormattable::get_int(const string
& name
, int def_val
) const
707 return (*this)[name
].def(def_val
);
710 bool JSONFormattable::get_bool(const string
& name
, bool def_val
) const
712 return (*this)[name
].def(def_val
);
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 */
722 explicit field_entity(const string
& n
) : is_obj(true), name(n
) {}
723 explicit field_entity(int i
) : is_obj(false), index(i
) {}
726 static int parse_entity(const string
& s
, vector
<field_entity
> *result
)
730 while (ofs
< s
.size()) {
731 size_t next_arr
= s
.find('[', ofs
);
732 if (next_arr
== string::npos
) {
736 result
->push_back(field_entity(s
));
739 if (next_arr
> ofs
) {
740 string field
= s
.substr(ofs
, next_arr
- ofs
);
741 result
->push_back(field_entity(field
));
744 size_t end_arr
= s
.find(']', next_arr
+ 1);
745 if (end_arr
== string::npos
) {
749 string index_str
= s
.substr(next_arr
+ 1, end_arr
- next_arr
- 1);
753 if (!index_str
.empty()) {
754 result
->push_back(field_entity(atoi(index_str
.c_str())));
758 result
->push_back(f
);
764 static bool is_numeric(const string
& val
)
767 boost::lexical_cast
<double>(val
);
768 } catch (const boost::bad_lexical_cast
& e
) {
774 int JSONFormattable::set(const string
& name
, const string
& val
)
776 boost::escaped_list_separator
<char> els('\\', '.', '"');
777 boost::tokenizer
<boost::escaped_list_separator
<char> > tok(name
, els
);
779 JSONFormattable
*f
= this;
783 bool is_valid_json
= jp
.parse(val
.c_str(), val
.size());
785 for (const auto& i
: tok
) {
786 vector
<field_entity
> v
;
787 int ret
= parse_entity(i
, &v
);
791 for (const auto& vi
: v
) {
792 if (f
->type
== FMT_NONE
) {
800 if (f
->type
== FMT_OBJ
) {
804 f
= &f
->obj
[vi
.name
];
805 } else if (f
->type
== FMT_ARRAY
) {
809 int index
= vi
.index
;
811 index
= f
->arr
.size();
812 } else if (index
< 0) {
813 index
= f
->arr
.size() + index
;
815 return -EINVAL
; /* out of bounds */
818 if ((size_t)index
>= f
->arr
.size()) {
819 f
->arr
.resize(index
+ 1);
830 f
->value
.set(val
, !is_numeric(val
));
836 int JSONFormattable::erase(const string
& name
)
838 boost::escaped_list_separator
<char> els('\\', '.', '"');
839 boost::tokenizer
<boost::escaped_list_separator
<char> > tok(name
, els
);
841 JSONFormattable
*f
= this;
842 JSONFormattable
*parent
= nullptr;
843 field_entity last_entity
;
845 for (auto& i
: tok
) {
846 vector
<field_entity
> v
;
847 int ret
= parse_entity(i
, &v
);
851 for (const auto& vi
: v
) {
852 if (f
->type
== FMT_NONE
||
853 f
->type
== FMT_VALUE
) {
863 if (f
->type
== FMT_OBJ
) {
867 auto iter
= f
->obj
.find(vi
.name
);
868 if (iter
== f
->obj
.end()) {
869 return 0; /* nothing to erase */
872 } else if (f
->type
== FMT_ARRAY
) {
876 int index
= vi
.index
;
878 index
= f
->arr
.size() + index
;
879 if (index
< 0) { /* out of bounds, nothing to remove */
883 if ((size_t)index
>= f
->arr
.size()) {
884 return 0; /* index beyond array boundaries */
893 *this = JSONFormattable(); /* erase everything */
895 if (last_entity
.is_obj
) {
896 parent
->obj
.erase(last_entity
.name
);
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()) {
902 parent
->arr
.erase(parent
->arr
.begin() + index
);
909 void JSONFormattable::derive_from(const JSONFormattable
& parent
)
911 for (auto& o
: parent
.obj
) {
912 if (obj
.find(o
.first
) == obj
.end()) {
913 obj
[o
.first
] = o
.second
;
918 void encode_json(const char *name
, const JSONFormattable
& v
, Formatter
*f
)
920 v
.encode_json(name
, f
);
923 void JSONFormattable::encode_json(const char *name
, Formatter
*f
) const
926 case JSONFormattable::FMT_VALUE
:
927 ::encode_json(name
, value
, f
);
929 case JSONFormattable::FMT_ARRAY
:
930 ::encode_json(name
, arr
, f
);
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
);
939 case JSONFormattable::FMT_NONE
:
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();
950 cur_enc
->set_type(JSONFormattable::FMT_OBJ
);
951 new_val
= &cur_enc
->obj
[string
{name
}];
953 new_val
->set_type(JSONFormattable::FMT_VALUE
);
954 new_val
->value
.set(s
, quoted
);
959 bool JSONFormattable::handle_open_section(std::string_view name
,
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
969 cur_enc
= &cur_enc
->obj
[string
{name
}];
971 enc_stack
.push_back(cur_enc
);
973 if (section_is_array
) {
974 cur_enc
->set_type(JSONFormattable::FMT_ARRAY
);
976 cur_enc
->set_type(JSONFormattable::FMT_OBJ
);
979 return false; /* continue processing */
982 bool JSONFormattable::handle_close_section() {
983 if (enc_stack
.size() <= 1) {
987 enc_stack
.pop_back();
988 cur_enc
= enc_stack
.back();
989 return false; /* continue processing */