24#include <boost/lexical_cast.hpp>
31const char*
const WHITESPACE =
" \b\f\n\r\t";
39 std::ostringstream ss;
196throwJSONError(
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());
234 return (
create(
static_cast<long long int>(i), pos));
239 return (
create(
static_cast<long long int>(i), pos));
278charIn(
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) {
289skipChars(std::istream& in,
const char* chars,
int& line,
int& pos) {
291 while (charIn(c, chars) && c != EOF) {
309skipTo(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);
344strFromStringstream(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);
446wordFromStringstream(std::istream& in,
int& pos) {
447 std::stringstream ss;
448 while (isalpha(in.peek())) {
449 ss << (char) in.get();
451 pos += ss.str().size();
456numberFromStringstream(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();
471fromStringstreamNumber(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()) {
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);
490 Element::Position(file, line, start_pos)));
491 }
catch (
const boost::bad_lexical_cast&) {
492 throwJSONError(std::string(
"Number overflow: ") + number, file,
500fromStringstreamBool(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") {
512 }
else if (word ==
"false") {
516 throwJSONError(std::string(
"Bad boolean value: ") + word, file,
523fromStringstreamNull(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") {
534 throwJSONError(std::string(
"Bad null value: ") + word, file,
541fromStringstreamString(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);
554fromStringstreamList(std::istream& in,
const std::string& file,
int& line,
561 skipChars(in, WHITESPACE, line, pos);
562 while (c != EOF && c !=
']') {
563 if (in.peek() !=
']') {
565 list->add(cur_list_element);
566 c = skipTo(in, file, line, pos,
",]", WHITESPACE);
576fromStringstreamMap(std::istream& in,
const std::string& file,
int& line,
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);
608 return (std::string(
"integer"));
610 return (std::string(
"real"));
612 return (std::string(
"boolean"));
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"));
630 if (type_name ==
"integer") {
632 }
else if (type_name ==
"real") {
634 }
else if (type_name ==
"boolean") {
636 }
else if (type_name ==
"string") {
638 }
else if (type_name ==
"list") {
640 }
else if (type_name ==
"map") {
642 }
else if (type_name ==
"named_set") {
644 }
else if (type_name ==
"null") {
646 }
else if (type_name ==
"any") {
656 int line = 1, pos = 1;
657 stringstream filtered;
670 int line = 1, pos = 1;
671 stringstream filtered;
675 return (
fromJSON(preproc ? filtered : in, file_name, line, pos));
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);
751 std::stringstream ss;
754 int line = 1, pos = 1;
755 stringstream filtered;
760 skipChars(ss, WHITESPACE, line, pos);
762 if (ss.peek() != EOF) {
763 throwJSONError(
"Extra data",
"<string>", line, pos);
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));
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);
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()) {
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);
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)));
920 std::stringstream ss;
922 int line = 0, pos = 0;
923 return (
fromJSON(ss,
"<wire>", line, pos));
938 int line = 0, pos = 0;
939 return (
fromJSON(in,
"<wire>", line, pos));
993 const size_t s =
size();
994 if (s != other.
size()) {
997 for (
size_t i = 0; i < s; ++i) {
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();
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);
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);
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();
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));
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()) {
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");
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) {
1263 if (element->empty()) {
1269 if (!element->get(0)) {
1272 int first_type = element->get(0)->getType();
1273 bool complex =
false;
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,
' ');
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;
1371 while (std::getline(in, line)) {
1374 if (!line.empty() && line[0] ==
'#') {
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown if a function is called in a prohibited way.
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
bool equals(const Element &other) const
bool equals(const Element &other) const
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
The Element class represents a piece of data, used by the command channel and configuration parts.
static ElementPtr create(const Position &pos=ZERO_POSITION())
virtual bool equals(const Element &other) const =0
virtual bool getValue(int64_t &t) const
static std::string typeToName(Element::types type)
Returns the name of the given type as a string.
virtual int64_t intValue() const
std::string str() const
Returns a string representing the Element and all its child elements; note that this is different fro...
virtual std::string stringValue() const
std::string toWire() const
Returns the wireformat for the Element and all its child elements.
static ElementPtr fromWire(std::stringstream &in, int length)
These function pparse the wireformat at the given stringstream (of the given length).
virtual bool setValue(const long long int v)
static ElementPtr fromJSONFile(const std::string &file_name, bool preproc=false)
Reads contents of specified file and interprets it as JSON.
virtual bool empty() const
Return true if there are no elements in the list.
virtual void remove(const int i)
Removes the element at the given position.
virtual bool contains(const std::string &name) const
Checks if there is data at the given key.
virtual ConstElementPtr find(const std::string &identifier) const
Recursively finds any data at the given identifier.
virtual size_t size() const
Returns the number of elements in the list.
virtual const std::map< std::string, ConstElementPtr > & mapValue() const
virtual void add(ElementPtr element)
Adds an ElementPtr to the list.
virtual const std::vector< ElementPtr > & listValue() const
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
virtual ConstElementPtr get(const int i) const
Returns the ElementPtr at the given index.
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
static Element::types nameToType(const std::string &type_name)
Converts the string to the corresponding type Throws a TypeError if the name is unknown.
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
virtual void toJSON(std::ostream &ss) const =0
Converts the Element to JSON format and appends it to the given stringstream.
virtual void set(const size_t i, ElementPtr element)
Sets the ElementPtr at the given index.
virtual double doubleValue() const
virtual bool boolValue() const
static void preprocess(std::istream &in, std::stringstream &out)
input text preprocessor
virtual ElementPtr getNonConst(const int i) const
returns element as non-const pointer
Notes: IntElement type is changed to int64_t.
bool equals(const Element &other) const
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
bool equals(const Element &other) const
ConstElementPtr find(const std::string &id) const
Recursively finds any data at the given identifier.
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
void set(const std::string &key, ConstElementPtr value)
Sets the ElementPtr at the given key.
bool equals(const Element &other) const
bool equals(const Element &other) const
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
bool equals(const Element &other) const
A standard Data module exception that is thrown if a function is called for an Element that has a wro...
#define throwTypeError(error)
Add the position to a TypeError message should be used in place of isc_throw(TypeError,...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
bool operator==(const Element &a, const Element &b)
void removeIdentical(ElementPtr a, ConstElementPtr b)
Remove all values from the first ElementPtr that are equal in the second.
void merge(ElementPtr element, ConstElementPtr other)
Merges the data from other into element.
bool isEquivalent(ConstElementPtr a, ConstElementPtr b)
Compares the data with other using unordered lists.
void prettyPrint(ConstElementPtr element, std::ostream &out, unsigned indent, unsigned step)
Pretty prints the data into stream.
boost::shared_ptr< const Element > ConstElementPtr
bool isNull(ConstElementPtr p)
Checks whether the given ElementPtr is a NULL pointer.
std::ostream & operator<<(std::ostream &out, const Element::Position &pos)
Insert Element::Position as a string into stream.
bool operator!=(const Element &a, const Element &b)
boost::shared_ptr< Element > ElementPtr
Defines the logger used by the top-level component of kea-dhcp-ddns.
Represents the position of the data element within a configuration string.
uint32_t pos_
Position within the line.
std::string str() const
Returns the position in the textual format.
uint32_t line_
Line number.
std::string file_
File name.