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 const std::string
& s
= json_spirit::write_string(data
);
253 if (s
.size() == (uint64_t)len
) { /* Check if entire string is read */
267 // parse the internal json_buffer up to len
268 bool JSONParser::parse(int len
)
270 string json_string
= json_buffer
.substr(0, len
);
271 success
= read(json_string
, data
);
280 // parse the complete internal json_buffer
281 bool JSONParser::parse()
283 success
= read(json_buffer
, data
);
292 // parse a supplied ifstream, for testing. DELETE ME
293 bool JSONParser::parse(const char *file_name
)
295 ifstream
is(file_name
);
296 success
= read(is
, data
);
306 void decode_json_obj(long& val
, JSONObj
*obj
)
308 string s
= obj
->get_data();
309 const char *start
= s
.c_str();
313 val
= strtol(start
, &p
, 10);
315 /* Check for various possible errors */
317 if ((errno
== ERANGE
&& (val
== LONG_MAX
|| val
== LONG_MIN
)) ||
318 (errno
!= 0 && val
== 0)) {
319 throw JSONDecoder::err("failed to parse number");
323 throw JSONDecoder::err("failed to parse number");
328 throw JSONDecoder::err("failed to parse number");
334 void decode_json_obj(unsigned long& val
, JSONObj
*obj
)
336 string s
= obj
->get_data();
337 const char *start
= s
.c_str();
341 val
= strtoul(start
, &p
, 10);
343 /* Check for various possible errors */
345 if ((errno
== ERANGE
&& val
== ULONG_MAX
) ||
346 (errno
!= 0 && val
== 0)) {
347 throw JSONDecoder::err("failed to number");
351 throw JSONDecoder::err("failed to parse number");
356 throw JSONDecoder::err("failed to parse number");
362 void decode_json_obj(long long& val
, JSONObj
*obj
)
364 string s
= obj
->get_data();
365 const char *start
= s
.c_str();
369 val
= strtoll(start
, &p
, 10);
371 /* Check for various possible errors */
373 if ((errno
== ERANGE
&& (val
== LLONG_MAX
|| val
== LLONG_MIN
)) ||
374 (errno
!= 0 && val
== 0)) {
375 throw JSONDecoder::err("failed to parse number");
379 throw JSONDecoder::err("failed to parse number");
384 throw JSONDecoder::err("failed to parse number");
390 void decode_json_obj(unsigned long long& val
, JSONObj
*obj
)
392 string s
= obj
->get_data();
393 const char *start
= s
.c_str();
397 val
= strtoull(start
, &p
, 10);
399 /* Check for various possible errors */
401 if ((errno
== ERANGE
&& val
== ULLONG_MAX
) ||
402 (errno
!= 0 && val
== 0)) {
403 throw JSONDecoder::err("failed to number");
407 throw JSONDecoder::err("failed to parse number");
412 throw JSONDecoder::err("failed to parse number");
418 void decode_json_obj(int& val
, JSONObj
*obj
)
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");
431 void decode_json_obj(unsigned& val
, JSONObj
*obj
)
434 decode_json_obj(l
, obj
);
435 #if ULONG_MAX > UINT_MAX
437 throw JSONDecoder::err("unsigned integer out of range");
444 void decode_json_obj(bool& val
, JSONObj
*obj
)
446 string s
= obj
->get_data();
447 if (strcasecmp(s
.c_str(), "true") == 0) {
451 if (strcasecmp(s
.c_str(), "false") == 0) {
456 decode_json_obj(i
, obj
);
460 void decode_json_obj(bufferlist
& val
, JSONObj
*obj
)
462 string s
= obj
->get_data();
465 bl
.append(s
.c_str(), s
.size());
467 val
.decode_base64(bl
);
468 } catch (ceph::buffer::error
& err
) {
469 throw JSONDecoder::err("failed to decode base64");
473 void decode_json_obj(utime_t
& val
, JSONObj
*obj
)
475 string s
= obj
->get_data();
478 int r
= utime_t::parse_date(s
, &epoch
, &nsec
);
480 val
= utime_t(epoch
, nsec
);
482 throw JSONDecoder::err("failed to decode utime_t");
486 void decode_json_obj(ceph::real_time
& val
, JSONObj
*obj
)
488 const std::string
& s
= obj
->get_data();
491 int r
= utime_t::parse_date(s
, &epoch
, &nsec
);
493 using namespace std::chrono
;
494 val
= real_time
{seconds(epoch
) + nanoseconds(nsec
)};
496 throw JSONDecoder::err("failed to decode real_time");
500 void decode_json_obj(ceph::coarse_real_time
& val
, JSONObj
*obj
)
502 const std::string
& s
= obj
->get_data();
505 int r
= utime_t::parse_date(s
, &epoch
, &nsec
);
507 using namespace std::chrono
;
508 val
= coarse_real_time
{seconds(epoch
) + nanoseconds(nsec
)};
510 throw JSONDecoder::err("failed to decode coarse_real_time");
514 void decode_json_obj(ceph_dir_layout
& i
, JSONObj
*obj
){
517 JSONDecoder::decode_json("dir_hash", tmp
, obj
, true);
519 JSONDecoder::decode_json("unused1", tmp
, obj
, true);
521 JSONDecoder::decode_json("unused2", tmp
, obj
, true);
523 JSONDecoder::decode_json("unused3", tmp
, obj
, true);
527 void encode_json(const char *name
, std::string_view val
, Formatter
*f
)
529 f
->dump_string(name
, val
);
532 void encode_json(const char *name
, const string
& val
, Formatter
*f
)
534 f
->dump_string(name
, val
);
537 void encode_json(const char *name
, const char *val
, Formatter
*f
)
539 f
->dump_string(name
, val
);
542 void encode_json(const char *name
, bool val
, Formatter
*f
)
544 f
->dump_bool(name
, val
);
547 void encode_json(const char *name
, int val
, Formatter
*f
)
549 f
->dump_int(name
, val
);
552 void encode_json(const char *name
, long val
, Formatter
*f
)
554 f
->dump_int(name
, val
);
557 void encode_json(const char *name
, unsigned val
, Formatter
*f
)
559 f
->dump_unsigned(name
, val
);
562 void encode_json(const char *name
, unsigned long val
, Formatter
*f
)
564 f
->dump_unsigned(name
, val
);
567 void encode_json(const char *name
, unsigned long long val
, Formatter
*f
)
569 f
->dump_unsigned(name
, val
);
572 void encode_json(const char *name
, long long val
, Formatter
*f
)
574 f
->dump_int(name
, val
);
577 void encode_json(const char *name
, const utime_t
& val
, Formatter
*f
)
579 val
.gmtime(f
->dump_stream(name
));
582 void encode_json(const char *name
, const ceph::real_time
& val
, Formatter
*f
)
584 encode_json(name
, utime_t
{val
}, f
);
587 void encode_json(const char *name
, const ceph::coarse_real_time
& val
, Formatter
*f
)
589 encode_json(name
, utime_t
{val
}, f
);
592 void encode_json(const char *name
, const bufferlist
& bl
, Formatter
*f
)
594 /* need to copy data from bl, as it is const bufferlist */
598 src
.encode_base64(b64
);
600 string
s(b64
.c_str(), b64
.length());
602 encode_json(name
, s
, f
);
607 /* JSONFormattable */
609 const JSONFormattable
& JSONFormattable::operator[](const string
& name
) const
611 auto i
= obj
.find(name
);
612 if (i
== obj
.end()) {
613 return default_formattable
;
618 const JSONFormattable
& JSONFormattable::operator[](size_t index
) const
620 if (index
>= arr
.size()) {
621 return default_formattable
;
626 JSONFormattable
& JSONFormattable::operator[](const string
& name
)
628 auto i
= obj
.find(name
);
629 if (i
== obj
.end()) {
630 return default_formattable
;
635 JSONFormattable
& JSONFormattable::operator[](size_t index
)
637 if (index
>= arr
.size()) {
638 return default_formattable
;
643 bool JSONFormattable::exists(const string
& name
) const
645 auto i
= obj
.find(name
);
646 return (i
!= obj
.end());
649 bool JSONFormattable::exists(size_t index
) const
651 return (index
< arr
.size());
654 bool JSONFormattable::find(const string
& name
, string
*val
) const
656 auto i
= obj
.find(name
);
657 if (i
== obj
.end()) {
660 *val
= i
->second
.val();
664 int JSONFormattable::val_int() const {
665 return atoi(value
.str
.c_str());
668 long JSONFormattable::val_long() const {
669 return atol(value
.str
.c_str());
672 long long JSONFormattable::val_long_long() const {
673 return atoll(value
.str
.c_str());
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"));
683 string
JSONFormattable::def(const string
& def_val
) const {
684 if (type
== FMT_NONE
) {
690 int JSONFormattable::def(int def_val
) const {
691 if (type
== FMT_NONE
) {
697 bool JSONFormattable::def(bool def_val
) const {
698 if (type
== FMT_NONE
) {
704 string
JSONFormattable::get(const string
& name
, const string
& def_val
) const
706 return (*this)[name
].def(def_val
);
709 int JSONFormattable::get_int(const string
& name
, int def_val
) const
711 return (*this)[name
].def(def_val
);
714 bool JSONFormattable::get_bool(const string
& name
, bool def_val
) const
716 return (*this)[name
].def(def_val
);
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 */
726 explicit field_entity(const string
& n
) : is_obj(true), name(n
) {}
727 explicit field_entity(int i
) : is_obj(false), index(i
) {}
730 static int parse_entity(const string
& s
, vector
<field_entity
> *result
)
734 while (ofs
< s
.size()) {
735 size_t next_arr
= s
.find('[', ofs
);
736 if (next_arr
== string::npos
) {
740 result
->push_back(field_entity(s
));
743 if (next_arr
> ofs
) {
744 string field
= s
.substr(ofs
, next_arr
- ofs
);
745 result
->push_back(field_entity(field
));
748 size_t end_arr
= s
.find(']', next_arr
+ 1);
749 if (end_arr
== string::npos
) {
753 string index_str
= s
.substr(next_arr
+ 1, end_arr
- next_arr
- 1);
757 if (!index_str
.empty()) {
758 result
->push_back(field_entity(atoi(index_str
.c_str())));
762 result
->push_back(f
);
768 static bool is_numeric(const string
& val
)
771 boost::lexical_cast
<double>(val
);
772 } catch (const boost::bad_lexical_cast
& e
) {
778 int JSONFormattable::set(const string
& name
, const string
& val
)
780 boost::escaped_list_separator
<char> els('\\', '.', '"');
781 boost::tokenizer
<boost::escaped_list_separator
<char> > tok(name
, els
);
783 JSONFormattable
*f
= this;
787 bool is_valid_json
= jp
.parse(val
.c_str(), val
.size());
789 for (const auto& i
: tok
) {
790 vector
<field_entity
> v
;
791 int ret
= parse_entity(i
, &v
);
795 for (const auto& vi
: v
) {
796 if (f
->type
== FMT_NONE
) {
804 if (f
->type
== FMT_OBJ
) {
808 f
= &f
->obj
[vi
.name
];
809 } else if (f
->type
== FMT_ARRAY
) {
813 int index
= vi
.index
;
815 index
= f
->arr
.size();
816 } else if (index
< 0) {
817 index
= f
->arr
.size() + index
;
819 return -EINVAL
; /* out of bounds */
822 if ((size_t)index
>= f
->arr
.size()) {
823 f
->arr
.resize(index
+ 1);
834 f
->value
.set(val
, !is_numeric(val
));
840 int JSONFormattable::erase(const string
& name
)
842 boost::escaped_list_separator
<char> els('\\', '.', '"');
843 boost::tokenizer
<boost::escaped_list_separator
<char> > tok(name
, els
);
845 JSONFormattable
*f
= this;
846 JSONFormattable
*parent
= nullptr;
847 field_entity last_entity
;
849 for (auto& i
: tok
) {
850 vector
<field_entity
> v
;
851 int ret
= parse_entity(i
, &v
);
855 for (const auto& vi
: v
) {
856 if (f
->type
== FMT_NONE
||
857 f
->type
== FMT_VALUE
) {
867 if (f
->type
== FMT_OBJ
) {
871 auto iter
= f
->obj
.find(vi
.name
);
872 if (iter
== f
->obj
.end()) {
873 return 0; /* nothing to erase */
876 } else if (f
->type
== FMT_ARRAY
) {
880 int index
= vi
.index
;
882 index
= f
->arr
.size() + index
;
883 if (index
< 0) { /* out of bounds, nothing to remove */
887 if ((size_t)index
>= f
->arr
.size()) {
888 return 0; /* index beyond array boundaries */
897 *this = JSONFormattable(); /* erase everything */
899 if (last_entity
.is_obj
) {
900 parent
->obj
.erase(last_entity
.name
);
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()) {
906 parent
->arr
.erase(parent
->arr
.begin() + index
);
913 void JSONFormattable::derive_from(const JSONFormattable
& parent
)
915 for (auto& o
: parent
.obj
) {
916 if (obj
.find(o
.first
) == obj
.end()) {
917 obj
[o
.first
] = o
.second
;
922 void encode_json(const char *name
, const JSONFormattable
& v
, Formatter
*f
)
924 v
.encode_json(name
, f
);
927 void JSONFormattable::encode_json(const char *name
, Formatter
*f
) const
930 case JSONFormattable::FMT_VALUE
:
931 ::encode_json(name
, value
, f
);
933 case JSONFormattable::FMT_ARRAY
:
934 ::encode_json(name
, arr
, f
);
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
);
943 case JSONFormattable::FMT_NONE
:
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();
954 cur_enc
->set_type(JSONFormattable::FMT_OBJ
);
955 new_val
= &cur_enc
->obj
[string
{name
}];
957 new_val
->set_type(JSONFormattable::FMT_VALUE
);
958 new_val
->value
.set(s
, quoted
);
963 bool JSONFormattable::handle_open_section(std::string_view name
,
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
973 cur_enc
= &cur_enc
->obj
[string
{name
}];
975 enc_stack
.push_back(cur_enc
);
977 if (section_is_array
) {
978 cur_enc
->set_type(JSONFormattable::FMT_ARRAY
);
980 cur_enc
->set_type(JSONFormattable::FMT_OBJ
);
983 return false; /* continue processing */
986 bool JSONFormattable::handle_close_section() {
987 if (enc_stack
.size() <= 1) {
991 enc_stack
.pop_back();
992 cur_enc
= enc_stack
.back();
993 return false; /* continue processing */