12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118 |
- // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- // $Id$
- #include "config.h"
- #include "data.h"
- #include <cassert>
- #include <cstdio>
- #include <iostream>
- #include <string>
- #include <sstream>
- #include <boost/algorithm/string.hpp> // for iequals
- using namespace std;
- namespace {
- const unsigned char PROTOCOL_VERSION[4] = { 0x53, 0x6b, 0x61, 0x6e };
- const unsigned char ITEM_BLOB = 0x01;
- const unsigned char ITEM_HASH = 0x02;
- const unsigned char ITEM_LIST = 0x03;
- const unsigned char ITEM_NULL = 0x04;
- const unsigned char ITEM_BOOL = 0x05;
- const unsigned char ITEM_INT = 0x06;
- const unsigned char ITEM_REAL = 0x07;
- const unsigned char ITEM_UTF8 = 0x08;
- const unsigned char ITEM_MASK = 0x0f;
- const unsigned char ITEM_LENGTH_32 = 0x00;
- const unsigned char ITEM_LENGTH_16 = 0x10;
- const unsigned char ITEM_LENGTH_8 = 0x20;
- const unsigned char ITEM_LENGTH_MASK = 0x30;
- }
- namespace isc {
- namespace data {
- //
- // The following methods are effectively empty, and their parameters are
- // unused. To silence compilers that warn unused function parameters,
- // we specify a (compiler dependent) special keyword when available.
- // It's defined in config.h, and to avoid including this header file from
- // installed files we define the methods here.
- //
- bool
- Element::getValue(int& t UNUSED_PARAM) {
- return false;
- }
- bool
- Element::getValue(double& t UNUSED_PARAM) {
- return false;
- }
- bool
- Element::getValue(bool& t UNUSED_PARAM) {
- return false;
- }
- bool
- Element::getValue(std::string& t UNUSED_PARAM) {
- return false;
- }
- bool
- Element::getValue(std::vector<ElementPtr>& t UNUSED_PARAM) {
- return false;
- }
- bool
- Element::getValue(std::map<std::string, ElementPtr>& t UNUSED_PARAM) {
- return false;
- }
- bool
- Element::setValue(const int v UNUSED_PARAM) {
- return false;
- }
- bool
- Element::setValue(const double v UNUSED_PARAM) {
- return false;
- }
- bool
- Element::setValue(const bool t UNUSED_PARAM) {
- return false;
- }
- bool
- Element::setValue(const std::string& v UNUSED_PARAM) {
- return false;
- }
- bool
- Element::setValue(const std::vector<ElementPtr>& v UNUSED_PARAM) {
- return false;
- }
- bool
- Element::setValue(const std::map<std::string, ElementPtr>& v UNUSED_PARAM)
- {
- return false;
- }
- ElementPtr
- Element::get(const int i UNUSED_PARAM) {
- isc_throw(TypeError, "get(int) called on a non-list Element");
- }
- void
- Element::set(const size_t i UNUSED_PARAM, ElementPtr element UNUSED_PARAM) {
- isc_throw(TypeError, "set(int, element) called on a non-list Element");
- }
- void
- Element::add(ElementPtr element UNUSED_PARAM) {
- isc_throw(TypeError, "add() called on a non-list Element");
- }
- void
- Element::remove(const int i UNUSED_PARAM) {
- isc_throw(TypeError, "remove(int) called on a non-list Element");
- }
- size_t
- Element::size() {
- isc_throw(TypeError, "size() called on a non-list Element");
- }
- ElementPtr
- Element::get(const std::string& name UNUSED_PARAM) {
- isc_throw(TypeError, "get(string) called on a non-map Element");
- }
- void
- Element::set(const std::string& name UNUSED_PARAM,
- ElementPtr element UNUSED_PARAM)
- {
- isc_throw(TypeError, "set(name, element) called on a non-map Element");
- }
- void
- Element::remove(const std::string& name UNUSED_PARAM) {
- isc_throw(TypeError, "remove(string) called on a non-map Element");
- }
- bool
- Element::contains(const std::string& name UNUSED_PARAM) {
- isc_throw(TypeError, "contains(string) called on a non-map Element");
- }
- ElementPtr
- Element::find(const std::string& identifier UNUSED_PARAM) {
- isc_throw(TypeError, "find(string) called on a non-map Element");
- }
- bool
- Element::find(const std::string& identifier UNUSED_PARAM,
- ElementPtr& t UNUSED_PARAM)
- {
- return false;
- }
- namespace {
- inline void
- throwParseError(const std::string& error, const std::string& file, int line = 0, int pos = 0)
- {
- if (line != 0 || pos != 0) {
- std::stringstream ss;
- ss << error << " in " + file + ":" << line << ":" << pos;
- throw ParseError(ss.str());
- } else {
- throw ParseError(error);
- }
- }
- }
- std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e) {
- return out << e->str();
- }
- bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b) {
- return a->equals(b);
- };
- //
- // factory functions
- //
- ElementPtr
- Element::create(const int i) {
- try {
- return ElementPtr(new IntElement(i));
- } catch (std::bad_alloc) {
- return ElementPtr();
- }
- }
- ElementPtr
- Element::create(const double d) {
- try {
- return ElementPtr(new DoubleElement(d));
- } catch (std::bad_alloc) {
- return ElementPtr();
- }
- }
- ElementPtr
- Element::create(const std::string& s) {
- try {
- return ElementPtr(new StringElement(s));
- } catch (std::bad_alloc) {
- return ElementPtr();
- }
- }
- ElementPtr
- Element::create(const bool b) {
- try {
- return ElementPtr(new BoolElement(b));
- } catch (std::bad_alloc) {
- return ElementPtr();
- }
- }
- ElementPtr
- Element::create(const std::vector<ElementPtr>& v) {
- try {
- return ElementPtr(new ListElement(v));
- } catch (std::bad_alloc) {
- return ElementPtr();
- }
- }
- ElementPtr
- Element::create(const std::map<std::string, ElementPtr>& m) {
- for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
- it != m.end(); ++it) {
- if ((*it).first.length() > 255) {
- isc_throw(TypeError, "Map tag is too long");
- }
- }
- try {
- return ElementPtr(new MapElement(m));
- } catch (std::bad_alloc) {
- return ElementPtr();
- }
- }
- //
- // helper functions for createFromString factory
- //
- namespace {
- bool
- char_in(const char c, const char *chars) {
- for (size_t i = 0; i < strlen(chars); ++i) {
- if (chars[i] == c) {
- return true;
- }
- }
- return false;
- }
- void
- skip_chars(std::istream &in, const char *chars, int& line, int& pos) {
- char c = in.peek();
- while (char_in(c, chars) && c != EOF) {
- if (c == '\n') {
- ++line;
- pos = 1;
- } else {
- ++pos;
- }
- in.get();
- c = in.peek();
- }
- }
- // skip on the input stream to one of the characters in chars
- // if another character is found this function returns false
- // unless that character is specified in the optional may_skip
- //
- // the character found is left on the stream
- void
- skip_to(std::istream &in, const std::string& file, int& line,
- int& pos, const char* chars, const char* may_skip="")
- {
- char c = in.get();
- ++pos;
- while (c != EOF) {
- if (c == '\n') {
- pos = 1;
- ++line;
- }
- if (char_in(c, may_skip)) {
- c = in.get();
- ++pos;
- } else if (char_in(c, chars)) {
- while(char_in(in.peek(), may_skip)) {
- if (in.peek() == '\n') {
- pos = 1;
- ++line;
- }
- in.get();
- ++pos;
- }
- in.putback(c);
- --pos;
- return;
- } else {
- throwParseError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
- }
- }
- throwParseError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
- }
- std::string
- str_from_stringstream(std::istream &in, const std::string& file, const int line,
- int& pos) throw (ParseError)
- {
- char c = 0;
- std::stringstream ss;
- c = in.get();
- ++pos;
- if (c == '"') {
- c = in.get();
- ++pos;
- } else {
- throwParseError("String expected", file, line, pos);
- }
- while (c != EOF && c != '"') {
- ss << c;
- if (c == '\\' && in.peek() == '"') {
- ss << in.get();
- ++pos;
- }
- c = in.get();
- ++pos;
- }
- return ss.str();
- }
- std::string
- word_from_stringstream(std::istream &in, int& pos) {
- std::stringstream ss;
- while (isalpha(in.peek())) {
- ss << (char) in.get();
- }
- pos += ss.str().size();
- return ss.str();
- }
- inline int
- count_chars_i(int i) {
- int result = 1;
- while (i > 10) {
- ++result;
- i = i / 10;
- }
- return result;
- }
- inline int
- count_chars_d(double d) {
- int result = 1;
- while (d < 1.0) {
- ++result;
- d = d * 10;
- }
- return result;
- }
- ElementPtr
- from_stringstream_int_or_double(std::istream &in, int &pos) {
- int i;
- in >> i;
- pos += count_chars_i(i);
- if (in.peek() == '.') {
- double d;
- in >> d;
- pos += count_chars_d(i);
- d += i;
- return Element::create(d);
- } else {
- return Element::create(i);
- }
- }
- ElementPtr
- from_stringstream_bool(std::istream &in, const std::string& file,
- const int line, int& pos)
- {
- const std::string word = word_from_stringstream(in, pos);
- if (boost::iequals(word, "True")) {
- return Element::create(true);
- } else if (boost::iequals(word, "False")) {
- return Element::create(false);
- } else {
- throwParseError(std::string("Bad boolean value: ") + word, file, line, pos);
- // above is a throw shortcur, return empty is never reached
- return ElementPtr();
- }
- }
- ElementPtr
- from_stringstream_string(std::istream& in, const std::string& file, int& line, int& pos)
- {
- return Element::create(str_from_stringstream(in, file, line, pos));
- }
- ElementPtr
- from_stringstream_list(std::istream &in, const std::string& file, int& line, int& pos)
- {
- char c = 0;
- std::vector<ElementPtr> v;
- ElementPtr cur_list_element;
- skip_chars(in, " \t\n", line, pos);
- while (c != EOF && c != ']') {
- if (in.peek() != ']') {
- cur_list_element = Element::createFromString(in, file, line, pos);
- v.push_back(cur_list_element);
- skip_to(in, file, line, pos, ",]", " \t\n");
- }
- c = in.get();
- pos++;
- }
- return Element::create(v);
- }
- ElementPtr
- from_stringstream_map(std::istream &in, const std::string& file, int& line,
- int& pos)
- {
- std::map<std::string, ElementPtr> m;
- skip_chars(in, " \t\n", line, pos);
- char c = in.peek();
- if (c == '}') {
- // empty map, skip closing curly
- c = in.get();
- } else {
- while (c != EOF && c != '}') {
- std::pair<std::string, ElementPtr> p;
- p.first = str_from_stringstream(in, file, line, pos);
- if (p.first.length() > 255) {
- // Map tag has one-byte length field in wire format, so the
- // length cannot exceed 255.
- throwParseError("Map tag is too long", file, line, pos);
- }
- skip_to(in, file, line, pos, ":", " \t\n");
- // skip the :
- in.get();
- pos++;
- p.second = Element::createFromString(in, file, line, pos);
- m.insert(p);
- skip_to(in, file, line, pos, ",}", " \t\n");
- c = in.get();
- pos++;
- }
- }
- return Element::create(m);
- }
- }
- ElementPtr
- Element::createFromString(std::istream& in) throw(ParseError) {
- int line = 1, pos = 1;
- return createFromString(in, "<istream>", line, pos);
- }
- ElementPtr
- Element::createFromString(std::istream& in, const std::string& file_name) throw(ParseError)
- {
- int line = 1, pos = 1;
- return createFromString(in, file_name, line, pos);
- }
- ElementPtr
- Element::createFromString(std::istream &in, const std::string& file, int& line, int& pos) throw(ParseError)
- {
- char c = 0;
- ElementPtr element;
- bool el_read = false;
- skip_chars(in, " \n\t", line, pos);
- while (c != EOF && !el_read) {
- c = in.get();
- pos++;
- switch(c) {
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '0':
- in.putback(c);
- element = from_stringstream_int_or_double(in, pos);
- el_read = true;
- break;
- case 't':
- case 'T':
- case 'f':
- case 'F':
- in.putback(c);
- element = from_stringstream_bool(in, file, line, pos);
- el_read = true;
- break;
- case '"':
- in.putback('"');
- element = from_stringstream_string(in, file, line, pos);
- el_read = true;
- break;
- case '[':
- element = from_stringstream_list(in, file, line, pos);
- el_read = true;
- break;
- case '{':
- element = from_stringstream_map(in, file, line, pos);
- el_read = true;
- break;
- case EOF:
- break;
- default:
- throwParseError(std::string("error: unexpected character ") + c, file, line, pos);
- break;
- }
- }
- if (el_read) {
- return element;
- } else {
- throw ParseError("nothing read");
- }
- }
- ElementPtr
- Element::createFromString(const std::string &in) {
- std::stringstream ss;
- ss << in;
- return createFromString(ss, "<string>");
- }
- //
- // a general to_str() function
- //
- std::string
- IntElement::str() {
- std::stringstream ss;
- ss << intValue();
- return ss.str();
- }
- std::string
- DoubleElement::str() {
- std::stringstream ss;
- ss << doubleValue();
- return ss.str();
- }
- std::string
- BoolElement::str() {
- if (b) {
- return "True";
- } else {
- return "False";
- }
- }
- std::string
- StringElement::str() {
- std::stringstream ss;
- ss << "\"";
- ss << stringValue();
- ss << "\"";
- return ss.str();
- }
- std::string
- ListElement::str() {
- std::stringstream ss;
- ss << "[ ";
- const std::vector<ElementPtr>& v = listValue();
- for (std::vector<ElementPtr>::const_iterator it = v.begin();
- it != v.end(); ++it) {
- if (it != v.begin()) {
- ss << ", ";
- }
- ss << (*it)->str();
- }
- ss << " ]";
- return ss.str();
- }
- std::string
- MapElement::str() {
- std::stringstream ss;
- ss << "{";
- const std::map<std::string, ElementPtr>& m = mapValue();
- for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
- it != m.end(); ++it) {
- if (it != m.begin()) {
- ss << ", ";
- }
- ss << "\"" << (*it).first << "\": ";
- if ((*it).second) {
- ss << (*it).second->str();
- } else {
- ss << "None";
- }
- }
- ss << "}";
- return ss.str();
- }
- // throws when one of the types in the path (except the one
- // we're looking for) is not a MapElement
- // returns 0 if it could simply not be found
- // should that also be an exception?
- ElementPtr
- MapElement::find(const std::string& id) {
- const size_t sep = id.find('/');
- if (sep == std::string::npos) {
- return get(id);
- } else {
- ElementPtr ce = get(id.substr(0, sep));
- if (ce) {
- // ignore trailing slash
- if (sep + 1 != id.size()) {
- return ce->find(id.substr(sep + 1));
- } else {
- return ce;
- }
- } else {
- return ElementPtr();
- }
- }
- }
- //
- // Decode from wire format.
- //
- namespace {
- ElementPtr decode_element(std::stringstream& in, int& in_length);
- unsigned char
- get_byte(std::stringstream& in) {
- const int c = in.get();
- if (c == EOF) {
- throw DecodeError("End of data while decoding wire format message");
- }
- return c;
- }
- std::string
- decode_tag(std::stringstream& in, int& item_length) {
- char buf[256];
- const int len = get_byte(in);
- item_length--;
- in.read(buf, len);
- if (in.fail()) {
- throw DecodeError();
- }
- buf[len] = 0;
- item_length -= len;
- return std::string(buf, len);
- }
- ElementPtr
- decode_bool(std::stringstream& in) {
- const char c = in.get();
-
- if (c == '1') {
- return Element::create(true);
- } else {
- return Element::create(false);
- }
- }
- ElementPtr
- decode_int(std::stringstream& in) {
- int me;
- return from_stringstream_int_or_double(in, me);
- }
- ElementPtr
- decode_real(std::stringstream& in) {
- int me;
- return from_stringstream_int_or_double(in, me);
- }
- ElementPtr
- decode_blob(std::stringstream& in, const int item_length) {
- vector<char> buf(item_length + 1);
- in.read(&buf[0], item_length);
- if (in.fail()) {
- throw DecodeError();
- }
- buf[item_length] = 0;
- return Element::create(std::string(&buf[0], item_length));
- }
- ElementPtr
- decode_hash(std::stringstream& in, int item_length) {
- std::map<std::string, ElementPtr> m;
- std::pair<std::string, ElementPtr> p;
- while (item_length > 0) {
- p.first = decode_tag(in, item_length);
- p.second = decode_element(in, item_length);
- m.insert(p);
- }
- return Element::create(m);
- }
- ElementPtr
- decode_list(std::stringstream& in, int item_length) {
- std::vector<ElementPtr> v;
- while (item_length > 0) {
- v.push_back(decode_element(in, item_length));
- }
- return Element::create(v);
- }
- ElementPtr
- decode_null() {
- return Element::create("NULL");
- }
- ElementPtr
- decode_element(std::stringstream& in, int& in_length) {
- ElementPtr element;
- const unsigned char type_and_length = get_byte(in);
- const unsigned char type = type_and_length & ITEM_MASK;
- const unsigned char lenbytes = type_and_length & ITEM_LENGTH_MASK;
- in_length--;
- int item_length = 0;
- switch (lenbytes) {
- case ITEM_LENGTH_32:
- item_length |= get_byte(in);
- item_length <<= 8;
- item_length |= get_byte(in);
- item_length <<= 8;
- in_length -= 2; // only 2 here, we will get more later
- case ITEM_LENGTH_16:
- item_length |= get_byte(in);
- item_length <<= 8;
- in_length--; // only 1 here
- case ITEM_LENGTH_8:
- item_length |= get_byte(in);
- in_length--;
- }
- in_length -= item_length;
- switch (type) {
- case ITEM_BOOL:
- element = decode_bool(in);
- break;
- case ITEM_INT:
- element = decode_int(in);
- break;
- case ITEM_REAL:
- element = decode_real(in);
- break;
- case ITEM_BLOB:
- element = decode_blob(in, item_length);
- break;
- case ITEM_UTF8:
- // XXXMLG currently identical to decode_blob
- element = decode_blob(in, item_length);
- break;
- case ITEM_HASH:
- element = decode_hash(in, item_length);
- break;
- case ITEM_LIST:
- element = decode_list(in, item_length);
- break;
- case ITEM_NULL:
- element = decode_null();
- break;
- }
- return (element);
- }
- }
- ElementPtr
- Element::fromWire(const std::string& s) {
- std::stringstream ss;
- ss << s;
- return fromWire(ss, s.length());
- }
- ElementPtr
- Element::fromWire(std::stringstream& in, int length) {
- //
- // Check protocol version
- //
- for (int i = 0 ; i < 4 ; ++i) {
- const unsigned char version_byte = get_byte(in);
- if (PROTOCOL_VERSION[i] != version_byte) {
- throw DecodeError("Protocol version incorrect");
- }
- }
- length -= 4;
- return (decode_hash(in, length));
- }
- //
- // Encode into wire format.
- //
- std::string
- encode_length(const unsigned int length, unsigned char type) {
- std::stringstream ss;
- if (length <= 0x000000ff) {
- const unsigned char val = (length & 0x000000ff);
- type |= ITEM_LENGTH_8;
- ss << type << val;
- } else if (length <= 0x0000ffff) {
- unsigned char val[2];
- val[0] = (length & 0x0000ff00) >> 8;
- val[1] = (length & 0x000000ff);
- type |= ITEM_LENGTH_16;
- ss << type << val[0] << val[1];
- } else {
- unsigned char val[4];
- val[0] = (length & 0xff000000) >> 24;
- val[1] = (length & 0x00ff0000) >> 16;
- val[2] = (length & 0x0000ff00) >> 8;
- val[3] = (length & 0x000000ff);
- type |= ITEM_LENGTH_32;
- ss << type << val[0] << val[1] << val[2] << val[3];
- }
- return ss.str();
- }
- std::string
- Element::toWire(const int omit_length) {
- std::stringstream ss;
- toWire(ss, omit_length);
- return ss.str();
- }
- void
- StringElement::toWire(std::stringstream& ss,
- const int omit_length UNUSED_PARAM)
- {
- unsigned int length = stringValue().length();
- ss << encode_length(length, ITEM_UTF8) << stringValue();
- }
- void
- IntElement::toWire(std::stringstream& ss,
- const int omit_length UNUSED_PARAM)
- {
- const std::string& s = str();
- ss << encode_length(s.length(), ITEM_INT) << s;
- }
- void
- BoolElement::toWire(std::stringstream& ss,
- const int omit_length UNUSED_PARAM)
- {
- ss << encode_length(1, ITEM_BOOL);
- if (boolValue()) {
- ss << 0x01;
- } else {
- ss << 0x00;
- }
- }
- void
- DoubleElement::toWire(std::stringstream& ss,
- const int omit_length UNUSED_PARAM)
- {
- std::stringstream text;
- text << str();
- const int length = text.str().length();
- ss << encode_length(length, ITEM_REAL) << text.str();
- }
- void
- ListElement::toWire(std::stringstream& ss, const int omit_length) {
- std::stringstream ss2;
- const std::vector<ElementPtr>& v = listValue();
- for (std::vector<ElementPtr>::const_iterator it = v.begin() ;
- it != v.end() ; ++it) {
- (*it)->toWire(ss2, 0);
- }
- if (omit_length) {
- stringbuf *ss2_buf = ss2.rdbuf();
- ss2_buf->pubseekpos(0);
- if (ss2_buf->in_avail() > 0) {
- ss << ss2_buf;
- }
- } else {
- stringbuf *ss2_buf = ss2.rdbuf();
- ss2_buf->pubseekpos(0);
- ss << encode_length(ss2_buf->in_avail(), ITEM_LIST);
- if (ss2_buf->in_avail() > 0) {
- ss << ss2_buf;
- }
- }
- }
- void
- MapElement::toWire(std::stringstream& ss, int omit_length) {
- std::stringstream ss2;
- //
- // If we don't want the length, we will want the protocol header
- //
- if (omit_length) {
- ss2 << PROTOCOL_VERSION[0] << PROTOCOL_VERSION[1];
- ss2 << PROTOCOL_VERSION[2] << PROTOCOL_VERSION[3];
- }
- const std::map<std::string, ElementPtr>& m = mapValue();
- for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
- it != m.end(); ++it) {
- const size_t taglen = (*it).first.length();
- assert(taglen <= 0xff);
- const unsigned char val = (taglen & 0x000000ff);
- ss2 << val << (*it).first;
- (*it).second->toWire(ss2, 0);
- }
- //
- // add length if needed
- //
- if (omit_length) {
- stringbuf *ss2_buf = ss2.rdbuf();
- ss2_buf->pubseekpos(0);
- if (ss2_buf->in_avail()) {
- ss << ss2_buf;
- }
- } else {
- stringbuf *ss2_buf = ss2.rdbuf();
- ss2_buf->pubseekpos(0);
- ss << encode_length(ss2_buf->in_avail(), ITEM_HASH);
- if (ss2_buf->in_avail()) {
- ss << ss2_buf;
- }
- }
- }
- bool
- MapElement::find(const std::string& id, ElementPtr& t) {
- try {
- ElementPtr p = find(id);
- if (p) {
- t = p;
- return true;
- }
- } catch (const TypeError& e) {
- // ignore
- }
- return false;
- }
- bool
- IntElement::equals(ElementPtr other) {
- return (other->getType() == Element::integer) &&
- (i == other->intValue());
- }
- bool
- DoubleElement::equals(ElementPtr other) {
- return (other->getType() == Element::real) &&
- (d == other->doubleValue());
- }
- bool
- BoolElement::equals(ElementPtr other) {
- return (other->getType() == Element::boolean) &&
- (b == other->boolValue());
- }
- bool
- StringElement::equals(ElementPtr other) {
- return (other->getType() == Element::string) &&
- (s == other->stringValue());
- }
- bool
- ListElement::equals(ElementPtr other) {
- if (other->getType() == Element::list) {
- const int s = size();
- if (s != other->size()) {
- return false;
- }
- for (int i = 0; i < s; ++i) {
- if (!get(i)->equals(other->get(i))) {
- return false;
- }
- }
- return true;
- } else {
- return false;
- }
- }
- bool
- MapElement::equals(ElementPtr other) {
- if (other->getType() == Element::map) {
- std::map<std::string, ElementPtr> m = mapValue();
- for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
- it != m.end() ; ++it) {
- if (other->contains((*it).first)) {
- if (!get((*it).first)->equals(other->get((*it).first))) {
- return false;
- }
- } else {
- return false;
- }
- }
- // quickly walk through the other map too, to see if there's
- // anything in there that we don't have. We don't need to
- // compare those elements; if one of them is missing we
- // differ (and if it's not missing the loop above has checked
- // it)
- m = other->mapValue();
- for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
- it != m.end() ; ++it) {
- if (!contains((*it).first)) {
- return false;
- }
- }
- return true;
- } else {
- return false;
- }
- }
- bool
- isNull(ElementPtr p) {
- return !p;
- }
- void
- removeIdentical(ElementPtr a, const ElementPtr b) {
- if (!b) {
- return;
- }
- if (a->getType() != Element::map || b->getType() != Element::map) {
- isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
- }
- std::map<std::string, ElementPtr> m = a->mapValue();
- for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
- it != m.end() ; ++it) {
- if (b->contains((*it).first)) {
- if (a->get((*it).first)->equals(b->get((*it).first))) {
- a->remove((*it).first);
- }
- }
- }
- }
- void
- merge(ElementPtr element, const ElementPtr other) {
- if (element->getType() != Element::map ||
- other->getType() != Element::map) {
- isc_throw(TypeError, "merge arguments not MapElements");
- }
-
- std::map<std::string, ElementPtr> m = other->mapValue();
- for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
- it != m.end() ; ++it) {
- if ((*it).second) {
- element->set((*it).first, (*it).second);
- } else if (element->contains((*it).first)) {
- element->remove((*it).first);
- }
- }
- }
- }
- }
|