24 #include <boost/lexical_cast.hpp> 31 const char*
const WHITESPACE =
" \b\f\n\r\t";
38 Element::Position::str()
const {
39 std::ostringstream ss;
40 ss << file_ <<
":" << line_ <<
":" <<
pos_;
51 Element::str()
const {
58 Element::toWire()
const {
65 Element::toWire(std::ostream& ss)
const {
70 Element::getValue(int64_t&)
const {
75 Element::getValue(
double&)
const {
80 Element::getValue(
bool&)
const {
85 Element::getValue(std::string&)
const {
90 Element::getValue(std::vector<ElementPtr>&)
const {
95 Element::getValue(std::map<std::string, ConstElementPtr>&)
const {
100 Element::setValue(
const long long int) {
105 Element::setValue(
const double) {
110 Element::setValue(
const bool) {
115 Element::setValue(
const std::string&) {
120 Element::setValue(
const std::vector<ElementPtr>&) {
125 Element::setValue(
const std::map<std::string, ConstElementPtr>&) {
130 Element::get(
const int)
const {
135 Element::getNonConst(
const int)
const {
150 Element::remove(
const int) {
155 Element::size()
const {
160 Element::empty()
const {
165 Element::get(
const std::string&)
const {
175 Element::remove(
const std::string&) {
180 Element::contains(
const std::string&)
const {
185 Element::find(
const std::string&)
const {
196 throwJSONError(
const std::string& error,
const std::string& file,
int line,
199 std::stringstream ss;
200 ss << error <<
" in " + file +
":" << line <<
":" << pos;
207 return (out << e.
str());
228 Element::create(
const long long int i,
const Position& pos) {
233 Element::create(
const int i,
const Position& pos) {
234 return (create(static_cast<long long int>(i), pos));
238 Element::create(
const long int i,
const Position& pos) {
239 return (create(static_cast<long long int>(i), pos));
243 Element::create(
const double d,
const Position& pos) {
248 Element::create(
const bool b,
const Position& pos) {
253 Element::create(
const std::string& s,
const Position& pos) {
258 Element::create(
const char *s,
const Position& pos) {
259 return (create(std::string(s), pos));
278 charIn(
const int c,
const char* chars) {
279 const size_t chars_len = std::strlen(chars);
280 for (
size_t i = 0; i < chars_len; ++i) {
289 skipChars(std::istream& in,
const char* chars,
int& line,
int& pos) {
291 while (charIn(c, chars) && c != EOF) {
309 skipTo(std::istream& in,
const std::string& file,
int& line,
310 int& pos,
const char* chars,
const char* may_skip=
"")
319 if (charIn(c, may_skip)) {
322 }
else if (charIn(c, chars)) {
323 while (charIn(in.peek(), may_skip)) {
324 if (in.peek() ==
'\n') {
334 throwJSONError(std::string(
"'") + std::string(1, c) +
"' read, one of \"" + chars +
"\" expected", file, line, pos);
337 throwJSONError(std::string(
"EOF read, one of \"") + chars +
"\" expected", file, line, pos);
344 strFromStringstream(std::istream& in,
const std::string& file,
345 const int line,
int& pos)
347 std::stringstream ss;
354 throwJSONError(
"String expected", file, line, pos);
357 while (c != EOF && c !=
'"') {
392 throwJSONError(
"Unsupported unicode escape", file, line, pos);
399 throwJSONError(
"Unsupported unicode escape", file, line, pos - 2);
405 if ((d >=
'0') && (d <=
'9')) {
407 }
else if ((d >=
'A') && (d <=
'F')) {
408 c = (d -
'A' + 10) << 4;
409 }
else if ((d >=
'a') && (d <=
'f')) {
410 c = (d -
'a' + 10) << 4;
412 throwJSONError(
"Not hexadecimal in unicode escape", file, line, pos - 3);
418 if ((d >=
'0') && (d <=
'9')) {
420 }
else if ((d >=
'A') && (d <=
'F')) {
422 }
else if ((d >=
'a') && (d <=
'f')) {
425 throwJSONError(
"Not hexadecimal in unicode escape", file, line, pos - 4);
429 throwJSONError(
"Bad escape", file, line, pos);
440 throwJSONError(
"Unterminated string", file, line, pos);
446 wordFromStringstream(std::istream& in,
int& pos) {
447 std::stringstream ss;
448 while (isalpha(in.peek())) {
449 ss << (char) in.get();
451 pos += ss.str().size();
456 numberFromStringstream(std::istream& in,
int& pos) {
457 std::stringstream ss;
458 while (isdigit(in.peek()) || in.peek() ==
'+' || in.peek() ==
'-' ||
459 in.peek() ==
'.' || in.peek() ==
'e' || in.peek() ==
'E') {
460 ss << (char) in.get();
462 pos += ss.str().size();
471 fromStringstreamNumber(std::istream& in,
const std::string& file,
472 const int& line,
int& pos) {
475 const uint32_t start_pos = pos;
477 const std::string number = numberFromStringstream(in, pos);
479 if (number.find_first_of(
".eE") < number.size()) {
481 return (Element::create(boost::lexical_cast<double>(number),
482 Element::Position(file, line, start_pos)));
483 }
catch (
const boost::bad_lexical_cast&) {
484 throwJSONError(std::string(
"Number overflow: ") + number,
485 file, line, start_pos);
489 return (Element::create(boost::lexical_cast<int64_t>(number),
490 Element::Position(file, line, start_pos)));
491 }
catch (
const boost::bad_lexical_cast&) {
492 throwJSONError(std::string(
"Number overflow: ") + number, file,
500 fromStringstreamBool(std::istream& in,
const std::string& file,
501 const int line,
int& pos)
505 const uint32_t start_pos = pos;
507 const std::string word = wordFromStringstream(in, pos);
509 if (word ==
"true") {
510 return (Element::create(
true, Element::Position(file, line,
512 }
else if (word ==
"false") {
513 return (Element::create(
false, Element::Position(file, line,
516 throwJSONError(std::string(
"Bad boolean value: ") + word, file,
523 fromStringstreamNull(std::istream& in,
const std::string& file,
524 const int line,
int& pos)
528 const uint32_t start_pos = pos;
530 const std::string word = wordFromStringstream(in, pos);
531 if (word ==
"null") {
532 return (Element::create(Element::Position(file, line, start_pos)));
534 throwJSONError(std::string(
"Bad null value: ") + word, file,
541 fromStringstreamString(std::istream& in,
const std::string& file,
int& line,
546 const uint32_t start_pos = pos;
548 const std::string string_value = strFromStringstream(in, file, line, pos);
549 return (Element::create(string_value, Element::Position(file, line,
554 fromStringstreamList(std::istream& in,
const std::string& file,
int& line,
558 ElementPtr list = Element::createList(Element::Position(file, line, pos));
561 skipChars(in, WHITESPACE, line, pos);
562 while (c != EOF && c !=
']') {
563 if (in.peek() !=
']') {
564 cur_list_element = Element::fromJSON(in, file, line, pos);
565 list->add(cur_list_element);
566 c = skipTo(in, file, line, pos,
",]", WHITESPACE);
576 fromStringstreamMap(std::istream& in,
const std::string& file,
int& line,
579 ElementPtr map = Element::createMap(Element::Position(file, line, pos));
580 skipChars(in, WHITESPACE, line, pos);
583 throwJSONError(std::string(
"Unterminated map, <string> or } expected"), file, line, pos);
584 }
else if (c ==
'}') {
588 while (c != EOF && c !=
'}') {
589 std::string key = strFromStringstream(in, file, line, pos);
591 skipTo(in, file, line, pos,
":", WHITESPACE);
595 map->set(key, value);
597 c = skipTo(in, file, line, pos,
",}", WHITESPACE);
607 case Element::integer:
608 return (std::string(
"integer"));
610 return (std::string(
"real"));
611 case Element::boolean:
612 return (std::string(
"boolean"));
613 case Element::string:
614 return (std::string(
"string"));
616 return (std::string(
"list"));
618 return (std::string(
"map"));
620 return (std::string(
"null"));
622 return (std::string(
"any"));
624 return (std::string(
"unknown"));
629 Element::nameToType(
const std::string& type_name) {
630 if (type_name ==
"integer") {
631 return (Element::integer);
632 }
else if (type_name ==
"real") {
633 return (Element::real);
634 }
else if (type_name ==
"boolean") {
635 return (Element::boolean);
636 }
else if (type_name ==
"string") {
637 return (Element::string);
638 }
else if (type_name ==
"list") {
639 return (Element::list);
640 }
else if (type_name ==
"map") {
641 return (Element::map);
642 }
else if (type_name ==
"named_set") {
643 return (Element::map);
644 }
else if (type_name ==
"null") {
645 return (Element::null);
646 }
else if (type_name ==
"any") {
647 return (Element::any);
654 Element::fromJSON(std::istream& in,
bool preproc) {
656 int line = 1, pos = 1;
657 stringstream filtered;
659 preprocess(in, filtered);
662 ElementPtr value = fromJSON(preproc ? filtered : in,
"<istream>", line, pos);
668 Element::fromJSON(std::istream& in,
const std::string& file_name,
bool preproc)
670 int line = 1, pos = 1;
671 stringstream filtered;
673 preprocess(in, filtered);
675 return (fromJSON(preproc ? filtered : in, file_name, line, pos));
679 Element::fromJSON(std::istream& in,
const std::string& file,
int& line,
684 bool el_read =
false;
685 skipChars(in, WHITESPACE, line, pos);
686 while (c != EOF && !el_read) {
705 element = fromStringstreamNumber(in, file, line, pos);
712 element = fromStringstreamBool(in, file, line, pos);
718 element = fromStringstreamNull(in, file, line, pos);
724 element = fromStringstreamString(in, file, line, pos);
728 element = fromStringstreamList(in, file, line, pos);
732 element = fromStringstreamMap(in, file, line, pos);
738 throwJSONError(std::string(
"error: unexpected character ") + std::string(1, c), file, line, pos);
750 Element::fromJSON(
const std::string& in,
bool preproc) {
751 std::stringstream ss;
754 int line = 1, pos = 1;
755 stringstream filtered;
757 preprocess(ss, filtered);
759 ElementPtr result(fromJSON(preproc ? filtered : ss,
"<string>", line, pos));
760 skipChars(ss, WHITESPACE, line, pos);
762 if (ss.peek() != EOF) {
763 throwJSONError(
"Extra data",
"<string>", line, pos);
769 Element::fromJSONFile(
const std::string& file_name,
774 std::ifstream infile(file_name.c_str(), std::ios::in | std::ios::binary);
775 if (!infile.is_open())
777 const char* error = strerror(errno);
782 return (fromJSON(infile, file_name, preproc));
788 IntElement::toJSON(std::ostream& ss)
const {
793 DoubleElement::toJSON(std::ostream& ss)
const {
798 BoolElement::toJSON(std::ostream& ss)
const {
807 NullElement::toJSON(std::ostream& ss)
const {
812 StringElement::toJSON(std::ostream& ss)
const {
814 const std::string& str = stringValue();
815 for (
size_t i = 0; i < str.size(); ++i) {
816 const char c = str[i];
843 if (((c >= 0) && (c < 0x20)) || (c < 0) || (c >= 0x7f)) {
844 std::ostringstream esc;
849 << (static_cast<unsigned>(c) & 0xff);
860 ListElement::toJSON(std::ostream& ss)
const {
863 const std::vector<ElementPtr>& v = listValue();
864 for (std::vector<ElementPtr>::const_iterator it = v.begin();
865 it != v.end(); ++it) {
866 if (it != v.begin()) {
875 MapElement::toJSON(std::ostream& ss)
const {
878 const std::map<std::string, ConstElementPtr>& m = mapValue();
879 for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
880 it != m.end(); ++it) {
881 if (it != m.begin()) {
884 ss <<
"\"" << (*it).first <<
"\": ";
886 (*it).second->toJSON(ss);
899 MapElement::find(
const std::string&
id)
const {
900 const size_t sep =
id.find(
'/');
901 if (sep == std::string::npos) {
907 if (sep + 1 !=
id.size()) {
908 return (ce->find(
id.substr(sep + 1)));
919 Element::fromWire(
const std::string& s) {
920 std::stringstream ss;
922 int line = 0, pos = 0;
923 return (fromJSON(ss,
"<wire>", line, pos));
927 Element::fromWire(std::stringstream& in,
int) {
938 int line = 0, pos = 0;
939 return (fromJSON(in,
"<wire>", line, pos));
962 IntElement::equals(
const Element& other)
const {
963 return (other.
getType() == Element::integer) &&
968 DoubleElement::equals(
const Element& other)
const {
969 return (other.
getType() == Element::real) &&
974 BoolElement::equals(
const Element& other)
const {
975 return (other.
getType() == Element::boolean) &&
980 NullElement::equals(
const Element& other)
const {
981 return (other.
getType() == Element::null);
985 StringElement::equals(
const Element& other)
const {
986 return (other.
getType() == Element::string) &&
991 ListElement::equals(
const Element& other)
const {
992 if (other.
getType() == Element::list) {
993 const size_t s = size();
994 if (s != other.
size()) {
997 for (
size_t i = 0; i < s; ++i) {
998 if (!get(i)->equals(*other.
get(i))) {
1010 if (other.
getType() == Element::map) {
1011 const std::map<std::string, ConstElementPtr>& m = mapValue();
1012 for (std::map<std::string, ConstElementPtr>::const_iterator it =
1014 it != m.end() ; ++it) {
1016 if (!get((*it).first)->equals(*other.
get((*it).first))) {
1028 std::map<std::string, ConstElementPtr>::const_iterator it;
1029 for (it = other.
mapValue().begin();
1032 if (!contains((*it).first)) {
1052 if (a->getType() != Element::map || b->getType() != Element::map) {
1060 const std::map<std::string, ConstElementPtr>& m = b->mapValue();
1061 for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
1062 it != m.end() ; ++it) {
1063 if (a->contains((*it).first)) {
1064 if (a->get((*it).first)->equals(*b->get((*it).first))) {
1065 a->remove((*it).first);
1079 if (a->getType() != Element::map || b->getType() != Element::map) {
1083 const std::map<std::string, ConstElementPtr>& m = a->mapValue();
1084 for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
1085 it != m.end() ; ++it) {
1086 if (!b->contains((*it).first) ||
1087 !a->get((*it).first)->equals(*b->get((*it).first))) {
1088 result->set((*it).first, (*it).second);
1097 if (element->getType() != Element::map ||
1098 other->getType() != Element::map) {
1102 const std::map<std::string, ConstElementPtr>& m = other->mapValue();
1103 for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
1104 it != m.end() ; ++it) {
1105 if ((*it).second && (*it).second->getType() != Element::null) {
1106 element->set((*it).first, (*it).second);
1107 }
else if (element->contains((*it).first)) {
1108 element->remove((*it).first);
1118 int from_type = from->getType();
1119 if (from_type == Element::integer) {
1121 }
else if (from_type == Element::real) {
1123 }
else if (from_type == Element::boolean) {
1125 }
else if (from_type == Element::null) {
1127 }
else if (from_type == Element::string) {
1129 }
else if (from_type == Element::list) {
1131 typedef std::vector<ElementPtr> ListType;
1132 const ListType& value = from->listValue();
1133 for (ListType::const_iterator it = value.cbegin();
1134 it != value.cend(); ++it) {
1138 result->add(
copy(*it, level - 1));
1142 }
else if (from_type == Element::map) {
1144 typedef std::map<std::string, ConstElementPtr> MapType;
1145 const MapType& value = from->mapValue();
1146 for (MapType::const_iterator it = value.cbegin();
1147 it != value.cend(); ++it) {
1149 result->set(it->first, it->second);
1151 result->set(it->first,
copy(it->second, level - 1));
1169 "arguments include cycles");
1172 isc_throw(BadValue,
"isEquivalent got a null pointer");
1175 if (a->getType() != b->getType()) {
1178 if (a->getType() == Element::list) {
1181 return (b->empty());
1184 if (a->size() != b->size()) {
1189 const size_t s = a->size();
1190 typedef std::list<ConstElementPtr> ListType;
1192 for (
size_t i = 0; i < s; ++i) {
1193 l.push_back(b->get(i));
1197 for (
size_t i = 0; i < s; ++i) {
1201 for (ListType::iterator it = l.begin();
1202 it != l.end(); ++it) {
1204 if (isEquivalent0(item, *it, level - 1)) {
1218 isc_throw(Unexpected,
"isEquivalent internal error");
1221 }
else if (a->getType() == Element::map) {
1223 typedef std::map<std::string, ConstElementPtr> MapType;
1224 const MapType& ma = a->mapValue();
1225 for (MapType::const_iterator it = ma.begin();
1226 it != ma.end() ; ++it) {
1229 if (!item || !isEquivalent0(it->second, item, level - 1)) {
1234 const MapType& mb = b->mapValue();
1235 for (MapType::const_iterator it = mb.begin();
1236 it != mb.end() ; ++it) {
1238 if (!a->contains(it->first)) {
1244 return (a->equals(*b));
1252 return (isEquivalent0(a, b, 100));
1257 unsigned indent,
unsigned step) {
1261 if (element->getType() == Element::list) {
1263 if (element->empty()) {
1269 if (!element->get(0)) {
1272 int first_type = element->get(0)->getType();
1273 bool complex =
false;
1274 if ((first_type == Element::list) || (first_type == Element::map)) {
1277 std::string separator = complex ?
",\n" :
", ";
1280 out <<
"[" << (complex ?
"\n" :
" ");
1283 typedef std::vector<ElementPtr> ListType;
1284 const ListType& l = element->listValue();
1285 for (ListType::const_iterator it = l.begin();
1286 it != l.end(); ++it) {
1288 if (it != l.begin()) {
1293 out << std::string(indent + step,
' ');
1301 out <<
"\n" << std::string(indent,
' ');
1306 }
else if (element->getType() == Element::map) {
1308 if (element->size() == 0) {
1318 if (element->contains(
"comment")) {
1320 out << std::string(indent + step,
' ');
1322 out <<
"\"comment\": ";
1324 prettyPrint(element->get(
"comment"), out, indent + step, step);
1330 typedef std::map<std::string, ConstElementPtr> MapType;
1331 const MapType& m = element->mapValue();
1332 for (MapType::const_iterator it = m.begin();
1333 it != m.end(); ++it) {
1335 if (it->first ==
"comment") {
1345 out << std::string(indent + step,
' ');
1347 out <<
"\"" << it->first <<
"\": ";
1349 prettyPrint(it->second, out, indent + step, step);
1353 out <<
"\n" << std::string(indent,
' ') <<
"}";
1356 element->toJSON(out);
1362 std::stringstream ss;
1367 void Element::preprocess(std::istream& in, std::stringstream& out) {
1371 while (std::getline(in, line)) {
1374 if (!line.empty() && line[0] ==
'#') {
virtual std::string stringValue() const
std::string prettyPrint(ConstElementPtr element, unsigned indent, unsigned step)
Pretty prints the data into string.
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
bool operator!=(const Element &a, const Element &b)
virtual int64_t intValue() const
bool isEquivalent(ConstElementPtr a, ConstElementPtr b)
Compares the data with other using unordered lists.
boost::shared_ptr< Element > ElementPtr
#define throwTypeError(error)
Add the position to a TypeError message should be used in place of isc_throw(TypeError,...
bool isNull(ConstElementPtr p)
Checks whether the given ElementPtr is a NULL pointer.
virtual bool equals(const Element &other) const =0
bool operator==(const Element &a, const Element &b)
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
std::string str() const
Returns a string representing the Element and all its child elements; note that this is different fro...
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
ConstElementPtr removeIdentical(ConstElementPtr a, ConstElementPtr b)
Create a new ElementPtr from the first ElementPtr, removing all values that are equal in the second.
virtual const std::map< std::string, ConstElementPtr > & mapValue() const
Notes: IntElement type is changed to int64_t.
boost::shared_ptr< const Element > ConstElementPtr
virtual size_t size() const
Returns the number of elements in the list.
A standard Data module exception that is thrown if a function is called for an Element that has a wro...
Represents the position of the data element within a configuration string.
Defines the logger used by the top-level component of kea-dhcp-ddns.
std::ostream & operator<<(std::ostream &out, const Element &e)
Insert the Element as a string into stream.
std::string str() const
Returns the position in the textual format.
void merge(ElementPtr element, ConstElementPtr other)
Merges the data from other into element.
virtual double doubleValue() const
A generic exception that is thrown if a function is called in a prohibited way.
virtual ConstElementPtr get(const int i) const
Returns the ElementPtr at the given index.
The Element class represents a piece of data, used by the command channel and configuration parts.
uint16_t pos_
The position (offset from the beginning) in the buffer where the name starts.
virtual bool boolValue() const
virtual bool contains(const std::string &name) const
Checks if there is data at the given key.