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,
198 std::stringstream ss;
199 ss <<
error <<
" in " + file +
":" << line <<
":" << pos;
206 return (out << e.
str());
252 return (
create(
static_cast<long long int>(i), pos));
257 return (
create(
static_cast<long long int>(i), pos));
277 return (
create(std::string(s), pos));
296charIn(
const int c,
const char* chars) {
297 const size_t chars_len = std::strlen(chars);
298 for (
size_t i = 0; i < chars_len; ++i) {
307skipChars(std::istream& in,
const char* chars,
int& line,
int& pos) {
309 while (charIn(c, chars) && c != EOF) {
327skipTo(std::istream& in,
const std::string& file,
int& line,
int& pos,
328 const char* chars,
const char* may_skip=
"") {
336 if (charIn(c, may_skip)) {
339 }
else if (charIn(c, chars)) {
340 while (charIn(in.peek(), may_skip)) {
341 if (in.peek() ==
'\n') {
351 throwJSONError(std::string(
"'") + std::string(1, c) +
"' read, one of \"" + chars +
"\" expected", file, line, pos);
354 throwJSONError(std::string(
"EOF read, one of \"") + chars +
"\" expected", file, line, pos);
361strFromStringstream(std::istream& in,
const std::string& file,
362 const int line,
int& pos) {
363 std::stringstream ss;
370 throwJSONError(
"String expected", file, line, pos);
373 while (c != EOF && c !=
'"') {
408 throwJSONError(
"Unsupported unicode escape", file, line, pos);
415 throwJSONError(
"Unsupported unicode escape", file, line, pos - 2);
421 if ((d >=
'0') && (d <=
'9')) {
423 }
else if ((d >=
'A') && (d <=
'F')) {
424 c = (d -
'A' + 10) << 4;
425 }
else if ((d >=
'a') && (d <=
'f')) {
426 c = (d -
'a' + 10) << 4;
428 throwJSONError(
"Not hexadecimal in unicode escape", file, line, pos - 3);
434 if ((d >=
'0') && (d <=
'9')) {
436 }
else if ((d >=
'A') && (d <=
'F')) {
438 }
else if ((d >=
'a') && (d <=
'f')) {
441 throwJSONError(
"Not hexadecimal in unicode escape", file, line, pos - 4);
445 throwJSONError(
"Bad escape", file, line, pos);
456 throwJSONError(
"Unterminated string", file, line, pos);
462wordFromStringstream(std::istream& in,
int& pos) {
463 std::stringstream ss;
464 while (isalpha(in.peek())) {
465 ss << (char) in.get();
467 pos += ss.str().size();
472numberFromStringstream(std::istream& in,
int& pos) {
473 std::stringstream ss;
474 while (isdigit(in.peek()) || in.peek() ==
'+' || in.peek() ==
'-' ||
475 in.peek() ==
'.' || in.peek() ==
'e' || in.peek() ==
'E') {
476 ss << (char) in.get();
478 pos += ss.str().size();
487fromStringstreamNumber(std::istream& in,
const std::string& file,
488 const int line,
int& pos) {
491 const uint32_t start_pos = pos;
493 const std::string number = numberFromStringstream(in, pos);
495 if (number.find_first_of(
".eE") < number.size()) {
498 Element::Position(file, line, start_pos)));
499 }
catch (
const boost::bad_lexical_cast&) {
500 throwJSONError(std::string(
"Number overflow: ") + number,
501 file, line, start_pos);
506 Element::Position(file, line, start_pos)));
507 }
catch (
const boost::bad_lexical_cast&) {
508 throwJSONError(std::string(
"Number overflow: ") + number, file,
516fromStringstreamBool(std::istream& in,
const std::string& file,
517 const int line,
int& pos) {
520 const uint32_t start_pos = pos;
522 const std::string word = wordFromStringstream(in, pos);
524 if (word ==
"true") {
527 }
else if (word ==
"false") {
531 throwJSONError(std::string(
"Bad boolean value: ") + word, file,
538fromStringstreamNull(std::istream& in,
const std::string& file,
539 const int line,
int& pos) {
542 const uint32_t start_pos = pos;
544 const std::string word = wordFromStringstream(in, pos);
545 if (word ==
"null") {
548 throwJSONError(std::string(
"Bad null value: ") + word, file,
555fromStringstreamString(std::istream& in,
const std::string& file,
int& line,
559 const uint32_t start_pos = pos;
561 const std::string string_value = strFromStringstream(in, file, line, pos);
567fromStringstreamList(std::istream& in,
const std::string& file,
int& line,
573 skipChars(in, WHITESPACE, line, pos);
574 while (c != EOF && c !=
']') {
575 if (in.peek() !=
']') {
577 list->add(cur_list_element);
578 c = skipTo(in, file, line, pos,
",]", WHITESPACE);
588fromStringstreamMap(std::istream& in,
const std::string& file,
int& line,
591 skipChars(in, WHITESPACE, line, pos);
594 throwJSONError(std::string(
"Unterminated map, <string> or } expected"), file, line, pos);
595 }
else if (c ==
'}') {
599 while (c != EOF && c !=
'}') {
600 std::string key = strFromStringstream(in, file, line, pos);
602 skipTo(in, file, line, pos,
":", WHITESPACE);
606 map->set(key, value);
608 c = skipTo(in, file, line, pos,
",}", WHITESPACE);
619 return (std::string(
"integer"));
621 return (std::string(
"real"));
623 return (std::string(
"boolean"));
625 return (std::string(
"string"));
627 return (std::string(
"list"));
629 return (std::string(
"map"));
631 return (std::string(
"null"));
633 return (std::string(
"any"));
635 return (std::string(
"unknown"));
641 if (type_name ==
"integer") {
643 }
else if (type_name ==
"real") {
645 }
else if (type_name ==
"boolean") {
647 }
else if (type_name ==
"string") {
649 }
else if (type_name ==
"list") {
651 }
else if (type_name ==
"map") {
653 }
else if (type_name ==
"named_set") {
655 }
else if (type_name ==
"null") {
657 }
else if (type_name ==
"any") {
667 int line = 1, pos = 1;
668 stringstream filtered;
680 int line = 1, pos = 1;
681 stringstream filtered;
685 return (
fromJSON(preproc ? filtered : in, file_name, line, pos));
693 bool el_read =
false;
694 skipChars(in, WHITESPACE, line, pos);
695 while (c != EOF && !el_read) {
714 element = fromStringstreamNumber(in, file, line, pos);
721 element = fromStringstreamBool(in, file, line, pos);
727 element = fromStringstreamNull(in, file, line, pos);
733 element = fromStringstreamString(in, file, line, pos);
737 element = fromStringstreamList(in, file, line, pos);
741 element = fromStringstreamMap(in, file, line, pos);
747 throwJSONError(std::string(
"error: unexpected character ") + std::string(1, c), file, line, pos);
760 std::stringstream ss;
763 int line = 1, pos = 1;
764 stringstream filtered;
769 skipChars(ss, WHITESPACE, line, pos);
771 if (ss.peek() != EOF) {
772 throwJSONError(
"Extra data",
"<string>", line, pos);
782 std::ifstream infile(file_name.c_str(), std::ios::in | std::ios::binary);
783 if (!infile.is_open()) {
784 const char*
error = strerror(errno);
789 return (
fromJSON(infile, file_name, preproc));
807 ostringstream val_ss;
810 if (val_ss.str().find_first_of(
'.') == string::npos) {
833 for (
size_t i = 0; i <
str.size(); ++i) {
834 const char c =
str[i];
861 if (((c >= 0) && (c < 0x20)) || (c < 0) || (c >= 0x7f)) {
862 std::ostringstream esc;
867 << (
static_cast<unsigned>(c) & 0xff);
881 const std::vector<ElementPtr>& v =
listValue();
882 for (
auto it = v.begin(); it != v.end(); ++it) {
883 if (it != v.begin()) {
895 const std::map<std::string, ConstElementPtr>& m =
mapValue();
896 for (
auto it = m.begin(); it != m.end(); ++it) {
897 if (it != m.begin()) {
900 ss <<
"\"" << (*it).first <<
"\": ";
902 (*it).second->toJSON(ss);
916 const size_t sep =
id.find(
'/');
917 if (sep == std::string::npos) {
923 if (sep + 1 !=
id.
size()) {
924 return (ce->find(
id.substr(sep + 1)));
936 std::stringstream ss;
938 int line = 0, pos = 0;
939 return (
fromJSON(ss,
"<wire>", line, pos));
954 int line = 0, pos = 0;
955 return (
fromJSON(in,
"<wire>", line, pos));
1009 const size_t s =
size();
1010 if (s != other.
size()) {
1013 for (
size_t i = 0; i < s; ++i) {
1030 int const t(l.at(0)->getType());
1033 if (index.empty()) {
1044 }
else if (t ==
list) {
1049 if (!index.empty()) {
1057 std::sort(l.begin(), l.end(), comparator);
1067 auto key = kv.first;
1100 for (
auto kv : b->mapValue()) {
1101 auto key = kv.first;
1102 if (a->contains(key)) {
1103 if (a->get(key)->equals(*b->get(key))) {
1122 for (
auto kv : a->mapValue()) {
1123 auto key = kv.first;
1124 if (!b->contains(key) ||
1125 !a->get(key)->equals(*b->get(key))) {
1126 result->set(key, kv.second);
1140 for (
auto kv : other->mapValue()) {
1141 auto key = kv.first;
1142 auto value = kv.second;
1144 element->set(key, value);
1145 }
else if (element->contains(key)) {
1146 element->remove(key);
1156 int from_type = from->getType();
1169 for (
auto elem : from->listValue()) {
1173 result->add(
copy(elem, level - 1));
1179 for (
auto kv : from->mapValue()) {
1180 auto key = kv.first;
1181 auto value = kv.second;
1183 result->set(key, value);
1185 result->set(key,
copy(value, level - 1));
1202 "arguments include cycles");
1205 isc_throw(BadValue,
"isEquivalent got a null pointer");
1208 if (a->getType() != b->getType()) {
1214 return (b->empty());
1217 if (a->size() != b->size()) {
1222 const size_t s = a->size();
1223 std::list<ConstElementPtr> l;
1224 for (
size_t i = 0; i < s; ++i) {
1225 l.push_back(b->get(i));
1229 for (
size_t i = 0; i < s; ++i) {
1233 for (
auto it = l.begin(); it != l.end(); ++it) {
1235 if (isEquivalent0(item, *it, level - 1)) {
1249 isc_throw(Unexpected,
"isEquivalent internal error");
1254 if (a->size() != b->size()) {
1258 for (
auto kv : a->mapValue()) {
1261 if (!item || !isEquivalent0(kv.second, item, level - 1)) {
1267 return (a->equals(*b));
1275 return (isEquivalent0(a, b, 100));
1280 unsigned indent,
unsigned step) {
1286 if (element->empty()) {
1292 if (!element->get(0)) {
1295 int first_type = element->get(0)->getType();
1296 bool complex =
false;
1300 std::string separator = complex ?
",\n" :
", ";
1303 out <<
"[" << (complex ?
"\n" :
" ");
1306 const auto& l = element->listValue();
1307 for (
auto it = l.begin(); it != l.end(); ++it) {
1309 if (it != l.begin()) {
1314 out << std::string(indent + step,
' ');
1322 out <<
"\n" << std::string(indent,
' ');
1329 if (element->size() == 0) {
1338 const auto& m = element->mapValue();
1340 for (
auto it = m.begin(); it != m.end(); ++it) {
1348 out << std::string(indent + step,
' ');
1350 out <<
"\"" << it->first <<
"\": ";
1352 prettyPrint(it->second, out, indent + step, step);
1356 out <<
"\n" << std::string(indent,
' ') <<
"}";
1359 element->toJSON(out);
1365 std::stringstream ss;
1374 while (std::getline(in, line)) {
1377 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 sort(std::string const &index=std::string())
Sorts the elements inside the list.
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 override
Recursively finds any data at the given identifier.
void set(const std::string &key, ConstElementPtr value) override
Sets the ElementPtr at the given key.
bool equals(const Element &other) const override
void toJSON(std::ostream &ss) const override
Converts the Element to JSON format and appends it to the given stringstream.
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 operator<(Element const &a, Element const &b)
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-lfc.
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.