2010-02-02 14:14:52 +00:00
|
|
|
// 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$
|
2009-10-30 17:28:17 +00:00
|
|
|
|
2010-03-19 19:58:38 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2009-10-30 17:28:17 +00:00
|
|
|
#include "data.h"
|
|
|
|
|
2010-04-01 00:38:56 +00:00
|
|
|
#include <cassert>
|
2009-10-30 17:28:17 +00:00
|
|
|
#include <cstdio>
|
|
|
|
#include <iostream>
|
2010-03-15 04:52:16 +00:00
|
|
|
#include <string>
|
2009-10-30 17:28:17 +00:00
|
|
|
#include <sstream>
|
|
|
|
|
2010-03-15 04:52:16 +00:00
|
|
|
#include <boost/algorithm/string.hpp> // for iequals
|
2009-10-30 17:28:17 +00:00
|
|
|
|
2010-06-15 13:37:41 +00:00
|
|
|
#include <cmath>
|
|
|
|
|
2009-10-30 17:28:17 +00:00
|
|
|
using namespace std;
|
|
|
|
|
2010-03-19 19:58:38 +00:00
|
|
|
namespace {
|
2009-10-30 17:28:17 +00:00
|
|
|
const unsigned char PROTOCOL_VERSION[4] = { 0x53, 0x6b, 0x61, 0x6e };
|
|
|
|
|
2009-11-20 12:32:57 +00:00
|
|
|
const unsigned char ITEM_BLOB = 0x01;
|
2009-10-30 17:28:17 +00:00
|
|
|
const unsigned char ITEM_HASH = 0x02;
|
|
|
|
const unsigned char ITEM_LIST = 0x03;
|
|
|
|
const unsigned char ITEM_NULL = 0x04;
|
2009-11-20 14:18:37 +00:00
|
|
|
const unsigned char ITEM_BOOL = 0x05;
|
2009-11-23 09:35:36 +00:00
|
|
|
const unsigned char ITEM_INT = 0x06;
|
2010-01-04 12:59:22 +00:00
|
|
|
const unsigned char ITEM_REAL = 0x07;
|
2009-11-20 12:32:57 +00:00
|
|
|
const unsigned char ITEM_UTF8 = 0x08;
|
2009-10-30 17:28:17 +00:00
|
|
|
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;
|
2010-03-19 19:58:38 +00:00
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
namespace isc {
|
|
|
|
namespace data {
|
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
std::string
|
|
|
|
Element::str()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
toJSON(ss);
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
Element::toWire()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
toJSON(ss);
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Element::toWire(std::stringstream& ss)
|
|
|
|
{
|
|
|
|
toJSON(ss);
|
|
|
|
}
|
|
|
|
|
2010-03-19 19:58:38 +00:00
|
|
|
//
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
namespace {
|
|
|
|
inline void
|
2010-06-15 13:37:41 +00:00
|
|
|
throwJSONError(const std::string& error, const std::string& file, int line = 0, int pos = 0)
|
2010-02-02 14:14:52 +00:00
|
|
|
{
|
|
|
|
if (line != 0 || pos != 0) {
|
|
|
|
std::stringstream ss;
|
2010-02-02 15:39:45 +00:00
|
|
|
ss << error << " in " + file + ":" << line << ":" << pos;
|
2010-06-15 13:37:41 +00:00
|
|
|
throw JSONError(ss.str());
|
2010-02-02 14:14:52 +00:00
|
|
|
} else {
|
2010-06-15 13:37:41 +00:00
|
|
|
throw JSONError(error);
|
2010-02-02 14:14:52 +00:00
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
2010-03-15 08:35:45 +00:00
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
|
2010-02-02 14:14:52 +00:00
|
|
|
std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e) {
|
|
|
|
return out << e->str();
|
2009-11-04 13:41:12 +00:00
|
|
|
}
|
|
|
|
|
2010-03-15 08:24:50 +00:00
|
|
|
bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b) {
|
2010-02-28 20:00:49 +00:00
|
|
|
return a->equals(b);
|
|
|
|
};
|
|
|
|
|
2009-10-30 17:28:17 +00:00
|
|
|
//
|
|
|
|
// factory functions
|
|
|
|
//
|
2010-06-15 10:11:48 +00:00
|
|
|
ElementPtr
|
|
|
|
Element::create() {
|
|
|
|
return ElementPtr(new NullElement());
|
|
|
|
}
|
|
|
|
|
2009-10-30 17:28:17 +00:00
|
|
|
ElementPtr
|
2010-03-15 08:24:50 +00:00
|
|
|
Element::create(const int i) {
|
2010-05-20 09:15:36 +00:00
|
|
|
return ElementPtr(new IntElement(i));
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-03-15 08:24:50 +00:00
|
|
|
Element::create(const double d) {
|
2010-05-20 09:15:36 +00:00
|
|
|
return ElementPtr(new DoubleElement(d));
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-03-15 08:24:50 +00:00
|
|
|
Element::create(const std::string& s) {
|
2010-05-20 09:15:36 +00:00
|
|
|
return ElementPtr(new StringElement(s));
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-03-15 08:24:50 +00:00
|
|
|
Element::create(const bool b) {
|
2010-05-20 09:15:36 +00:00
|
|
|
return ElementPtr(new BoolElement(b));
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-06-15 12:38:55 +00:00
|
|
|
Element::createList() {
|
|
|
|
return ElementPtr(new ListElement());
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-06-15 12:38:55 +00:00
|
|
|
Element::createMap() {
|
|
|
|
return ElementPtr(new MapElement());
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
2010-06-15 13:02:26 +00:00
|
|
|
// helper functions for fromJSON factory
|
2009-10-30 17:28:17 +00:00
|
|
|
//
|
2010-03-15 08:35:45 +00:00
|
|
|
namespace {
|
|
|
|
bool
|
2010-03-15 08:24:50 +00:00
|
|
|
char_in(const char c, const char *chars) {
|
|
|
|
for (size_t i = 0; i < strlen(chars); ++i) {
|
2009-10-30 17:28:17 +00:00
|
|
|
if (chars[i] == c) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
void
|
2010-03-15 08:24:50 +00:00
|
|
|
skip_chars(std::istream &in, const char *chars, int& line, int& pos) {
|
2009-10-30 17:28:17 +00:00
|
|
|
char c = in.peek();
|
|
|
|
while (char_in(c, chars) && c != EOF) {
|
2009-11-04 13:41:12 +00:00
|
|
|
if (c == '\n') {
|
2010-03-15 08:24:50 +00:00
|
|
|
++line;
|
2009-11-04 13:41:12 +00:00
|
|
|
pos = 1;
|
|
|
|
} else {
|
2010-03-15 08:24:50 +00:00
|
|
|
++pos;
|
2009-11-04 13:41:12 +00:00
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
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
|
2010-01-16 07:37:40 +00:00
|
|
|
// unless that character is specified in the optional may_skip
|
2009-10-30 17:28:17 +00:00
|
|
|
//
|
|
|
|
// the character found is left on the stream
|
2010-03-15 08:35:45 +00:00
|
|
|
void
|
2010-02-02 14:14:52 +00:00
|
|
|
skip_to(std::istream &in, const std::string& file, int& line,
|
|
|
|
int& pos, const char* chars, const char* may_skip="")
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
char c = in.get();
|
2010-03-15 08:24:50 +00:00
|
|
|
++pos;
|
2009-10-30 17:28:17 +00:00
|
|
|
while (c != EOF) {
|
2009-11-04 13:41:12 +00:00
|
|
|
if (c == '\n') {
|
|
|
|
pos = 1;
|
2010-03-15 08:24:50 +00:00
|
|
|
++line;
|
2009-11-04 13:41:12 +00:00
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
if (char_in(c, may_skip)) {
|
|
|
|
c = in.get();
|
2010-03-15 08:24:50 +00:00
|
|
|
++pos;
|
2009-10-30 17:28:17 +00:00
|
|
|
} else if (char_in(c, chars)) {
|
|
|
|
while(char_in(in.peek(), may_skip)) {
|
2009-11-04 13:41:12 +00:00
|
|
|
if (in.peek() == '\n') {
|
|
|
|
pos = 1;
|
2010-03-15 08:24:50 +00:00
|
|
|
++line;
|
2009-11-04 13:41:12 +00:00
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
in.get();
|
2010-03-15 08:24:50 +00:00
|
|
|
++pos;
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
in.putback(c);
|
2010-03-15 08:24:50 +00:00
|
|
|
--pos;
|
2009-11-04 13:41:12 +00:00
|
|
|
return;
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
2010-06-15 13:37:41 +00:00
|
|
|
throwJSONError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-15 13:37:41 +00:00
|
|
|
throwJSONError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
// TODO: Should we check for all other official escapes here (and
|
|
|
|
// error on the rest)?
|
2010-03-15 08:35:45 +00:00
|
|
|
std::string
|
2010-03-31 19:35:20 +00:00
|
|
|
str_from_stringstream(std::istream &in, const std::string& file, const int line,
|
2010-06-15 13:37:41 +00:00
|
|
|
int& pos) throw (JSONError)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
char c = 0;
|
|
|
|
std::stringstream ss;
|
|
|
|
c = in.get();
|
2010-03-15 08:24:50 +00:00
|
|
|
++pos;
|
2009-10-30 17:28:17 +00:00
|
|
|
if (c == '"') {
|
|
|
|
c = in.get();
|
2010-03-15 08:24:50 +00:00
|
|
|
++pos;
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
2010-06-15 13:37:41 +00:00
|
|
|
throwJSONError("String expected", file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
while (c != EOF && c != '"') {
|
|
|
|
ss << c;
|
|
|
|
if (c == '\\' && in.peek() == '"') {
|
|
|
|
ss << in.get();
|
2010-03-15 08:24:50 +00:00
|
|
|
++pos;
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
c = in.get();
|
2010-03-15 08:24:50 +00:00
|
|
|
++pos;
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
std::string
|
2010-03-31 19:35:20 +00:00
|
|
|
word_from_stringstream(std::istream &in, int& pos) {
|
2009-10-30 17:28:17 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
while (isalpha(in.peek())) {
|
|
|
|
ss << (char) in.get();
|
|
|
|
}
|
2009-11-04 13:41:12 +00:00
|
|
|
pos += ss.str().size();
|
2009-10-30 17:28:17 +00:00
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
inline int
|
2010-03-15 08:24:50 +00:00
|
|
|
count_chars_i(int i) {
|
2010-01-13 13:14:31 +00:00
|
|
|
int result = 1;
|
|
|
|
while (i > 10) {
|
2010-03-15 08:24:50 +00:00
|
|
|
++result;
|
|
|
|
i = i / 10;
|
2010-01-13 13:14:31 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-06-15 13:37:41 +00:00
|
|
|
// Should we change from IntElement and DoubleElement to NumberElement
|
|
|
|
// that can also hold an e value? (and have specific getters if the
|
|
|
|
// value is larger than an int can handle)
|
2010-03-15 08:35:45 +00:00
|
|
|
ElementPtr
|
2010-06-15 10:11:48 +00:00
|
|
|
from_stringstream_number(std::istream &in, int &pos) {
|
|
|
|
int i, d_i;
|
|
|
|
double d = 0.0;
|
|
|
|
bool is_double = false;
|
|
|
|
|
2009-10-30 17:28:17 +00:00
|
|
|
in >> i;
|
2010-01-13 13:14:31 +00:00
|
|
|
pos += count_chars_i(i);
|
2010-06-15 13:37:41 +00:00
|
|
|
if (in.fail()) {
|
|
|
|
throw JSONError("Bad integer or overflow");
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
if (in.peek() == '.') {
|
2010-06-15 10:11:48 +00:00
|
|
|
is_double = true;
|
|
|
|
in.get();
|
|
|
|
pos++;
|
|
|
|
in >> d_i;
|
2010-06-15 13:37:41 +00:00
|
|
|
if (in.fail()) {
|
|
|
|
throw JSONError("Bad real or overflow");
|
|
|
|
}
|
2010-06-15 10:11:48 +00:00
|
|
|
d = i + (double)d_i / 10;
|
|
|
|
pos += count_chars_i(d_i);
|
|
|
|
}
|
|
|
|
if (in.peek() == 'e' || in.peek() == 'E') {
|
|
|
|
int e;
|
2010-06-15 13:37:41 +00:00
|
|
|
double p;
|
2010-06-15 10:11:48 +00:00
|
|
|
in.get();
|
|
|
|
pos++;
|
|
|
|
in >> e;
|
2010-06-15 13:37:41 +00:00
|
|
|
if (in.fail()) {
|
|
|
|
throw JSONError("Bad exponent or overflow");
|
|
|
|
}
|
2010-06-15 10:11:48 +00:00
|
|
|
pos += count_chars_i(e);
|
2010-06-15 13:37:41 +00:00
|
|
|
p = pow(10, e);
|
|
|
|
if (p == HUGE_VAL) {
|
|
|
|
throw JSONError("Bad exponent or overflow");
|
|
|
|
}
|
|
|
|
if (is_double) {
|
|
|
|
d = d * p;
|
2010-06-15 10:11:48 +00:00
|
|
|
} else {
|
2010-06-15 13:37:41 +00:00
|
|
|
if (p > 1.0) {
|
|
|
|
i = i * p;
|
2010-06-15 10:11:48 +00:00
|
|
|
} else {
|
2010-06-15 13:37:41 +00:00
|
|
|
// negative exponent, so type becomes a double
|
|
|
|
is_double = true;
|
|
|
|
d = i * p;
|
2010-06-15 10:11:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_double) {
|
2009-10-30 17:28:17 +00:00
|
|
|
return Element::create(d);
|
|
|
|
} else {
|
|
|
|
return Element::create(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
ElementPtr
|
2010-03-31 19:35:20 +00:00
|
|
|
from_stringstream_bool(std::istream &in, const std::string& file,
|
|
|
|
const int line, int& pos)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
2010-03-31 19:35:20 +00:00
|
|
|
const std::string word = word_from_stringstream(in, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
if (boost::iequals(word, "True")) {
|
|
|
|
return Element::create(true);
|
|
|
|
} else if (boost::iequals(word, "False")) {
|
|
|
|
return Element::create(false);
|
|
|
|
} else {
|
2010-06-15 13:37:41 +00:00
|
|
|
throwJSONError(std::string("Bad boolean value: ") + word, file, line, pos);
|
2010-02-02 14:14:52 +00:00
|
|
|
// above is a throw shortcur, return empty is never reached
|
|
|
|
return ElementPtr();
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
ElementPtr
|
|
|
|
from_stringstream_null(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, "null")) {
|
|
|
|
return Element::create();
|
|
|
|
} else {
|
2010-06-15 13:37:41 +00:00
|
|
|
throwJSONError(std::string("Bad null value: ") + word, file, line, pos);
|
2010-06-15 10:11:48 +00:00
|
|
|
return ElementPtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
ElementPtr
|
2010-03-15 08:24:50 +00:00
|
|
|
from_stringstream_string(std::istream& in, const std::string& file, int& line, int& pos)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
2010-02-02 14:14:52 +00:00
|
|
|
return Element::create(str_from_stringstream(in, file, line, pos));
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
ElementPtr
|
2010-02-02 14:14:52 +00:00
|
|
|
from_stringstream_list(std::istream &in, const std::string& file, int& line, int& pos)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
char c = 0;
|
2010-06-15 12:38:55 +00:00
|
|
|
ElementPtr list = Element::createList();
|
2009-10-30 17:28:17 +00:00
|
|
|
ElementPtr cur_list_element;
|
|
|
|
|
2009-11-04 13:41:12 +00:00
|
|
|
skip_chars(in, " \t\n", line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
while (c != EOF && c != ']') {
|
2009-11-04 13:41:12 +00:00
|
|
|
if (in.peek() != ']') {
|
2010-06-15 13:02:26 +00:00
|
|
|
cur_list_element = Element::fromJSON(in, file, line, pos);
|
2010-06-15 12:38:55 +00:00
|
|
|
list->add(cur_list_element);
|
2010-02-02 14:14:52 +00:00
|
|
|
skip_to(in, file, line, pos, ",]", " \t\n");
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
c = in.get();
|
2009-11-04 13:41:12 +00:00
|
|
|
pos++;
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
2010-06-15 12:38:55 +00:00
|
|
|
return list;
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
ElementPtr
|
2010-03-31 23:55:26 +00:00
|
|
|
from_stringstream_map(std::istream &in, const std::string& file, int& line,
|
|
|
|
int& pos)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
2010-06-15 12:38:55 +00:00
|
|
|
ElementPtr map = Element::createMap();
|
2009-11-04 13:41:12 +00:00
|
|
|
skip_chars(in, " \t\n", line, pos);
|
2010-03-31 23:55:26 +00:00
|
|
|
char c = in.peek();
|
2010-02-03 11:38:38 +00:00
|
|
|
if (c == '}') {
|
|
|
|
// empty map, skip closing curly
|
2009-10-30 17:28:17 +00:00
|
|
|
c = in.get();
|
2010-02-03 11:38:38 +00:00
|
|
|
} else {
|
|
|
|
while (c != EOF && c != '}') {
|
2010-06-15 12:38:55 +00:00
|
|
|
std::string key = str_from_stringstream(in, file, line, pos);
|
|
|
|
if (key.length() > 255) {
|
2010-03-31 23:55:26 +00:00
|
|
|
// Map tag has one-byte length field in wire format, so the
|
|
|
|
// length cannot exceed 255.
|
2010-06-15 13:37:41 +00:00
|
|
|
throwJSONError("Map tag is too long", file, line, pos);
|
2010-03-31 23:55:26 +00:00
|
|
|
}
|
|
|
|
|
2010-02-03 11:38:38 +00:00
|
|
|
skip_to(in, file, line, pos, ":", " \t\n");
|
|
|
|
// skip the :
|
|
|
|
in.get();
|
|
|
|
pos++;
|
2010-06-15 12:38:55 +00:00
|
|
|
|
2010-06-15 13:02:26 +00:00
|
|
|
ElementPtr value = Element::fromJSON(in, file, line, pos);
|
2010-06-15 12:38:55 +00:00
|
|
|
map->set(key, value);
|
|
|
|
|
2010-02-03 11:38:38 +00:00
|
|
|
skip_to(in, file, line, pos, ",}", " \t\n");
|
|
|
|
c = in.get();
|
|
|
|
pos++;
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
2010-06-15 12:38:55 +00:00
|
|
|
return map;
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
2010-03-15 08:35:45 +00:00
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
|
|
|
|
ElementPtr
|
2010-06-15 13:37:41 +00:00
|
|
|
Element::fromJSON(std::istream& in) throw(JSONError) {
|
2009-11-04 13:41:12 +00:00
|
|
|
int line = 1, pos = 1;
|
2010-06-15 13:02:26 +00:00
|
|
|
return fromJSON(in, "<istream>", line, pos);
|
2010-02-03 11:38:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-06-15 13:37:41 +00:00
|
|
|
Element::fromJSON(std::istream& in, const std::string& file_name) throw(JSONError)
|
2010-02-03 11:38:38 +00:00
|
|
|
{
|
|
|
|
int line = 1, pos = 1;
|
2010-06-15 13:02:26 +00:00
|
|
|
return fromJSON(in, file_name, line, pos);
|
2009-11-04 13:41:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-06-15 13:37:41 +00:00
|
|
|
Element::fromJSON(std::istream &in, const std::string& file, int& line, int& pos) throw(JSONError)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
char c = 0;
|
|
|
|
ElementPtr element;
|
|
|
|
bool el_read = false;
|
2009-11-04 13:41:12 +00:00
|
|
|
skip_chars(in, " \n\t", line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
while (c != EOF && !el_read) {
|
|
|
|
c = in.get();
|
2009-11-04 13:41:12 +00:00
|
|
|
pos++;
|
2009-10-30 17:28:17 +00:00
|
|
|
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);
|
2010-06-15 10:11:48 +00:00
|
|
|
element = from_stringstream_number(in, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
el_read = true;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
case 'T':
|
|
|
|
case 'f':
|
|
|
|
case 'F':
|
|
|
|
in.putback(c);
|
2010-02-02 14:14:52 +00:00
|
|
|
element = from_stringstream_bool(in, file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
el_read = true;
|
|
|
|
break;
|
2010-06-15 10:11:48 +00:00
|
|
|
case 'n':
|
|
|
|
in.putback(c);
|
|
|
|
element = from_stringstream_null(in, file, line, pos);
|
|
|
|
el_read = true;
|
|
|
|
break;
|
2009-10-30 17:28:17 +00:00
|
|
|
case '"':
|
|
|
|
in.putback('"');
|
2010-02-02 14:14:52 +00:00
|
|
|
element = from_stringstream_string(in, file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
el_read = true;
|
|
|
|
break;
|
|
|
|
case '[':
|
2010-02-02 14:14:52 +00:00
|
|
|
element = from_stringstream_list(in, file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
el_read = true;
|
|
|
|
break;
|
|
|
|
case '{':
|
2010-02-02 14:14:52 +00:00
|
|
|
element = from_stringstream_map(in, file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
el_read = true;
|
|
|
|
break;
|
2009-11-04 13:41:12 +00:00
|
|
|
case EOF:
|
|
|
|
break;
|
2009-10-30 17:28:17 +00:00
|
|
|
default:
|
2010-06-15 13:37:41 +00:00
|
|
|
throwJSONError(std::string("error: unexpected character ") + c, file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (el_read) {
|
|
|
|
return element;
|
|
|
|
} else {
|
2010-06-15 13:37:41 +00:00
|
|
|
throw JSONError("nothing read");
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-03 13:07:00 +00:00
|
|
|
ElementPtr
|
2010-06-15 13:02:26 +00:00
|
|
|
Element::fromJSON(const std::string &in) {
|
2009-11-03 13:07:00 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
ss << in;
|
2010-06-15 13:02:26 +00:00
|
|
|
return fromJSON(ss, "<string>");
|
2009-11-03 13:07:00 +00:00
|
|
|
}
|
2010-01-13 13:14:31 +00:00
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
// to JSON format
|
|
|
|
|
|
|
|
void
|
|
|
|
IntElement::toJSON(std::stringstream& ss)
|
|
|
|
{
|
2009-12-24 11:30:19 +00:00
|
|
|
ss << intValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
void
|
|
|
|
DoubleElement::toJSON(std::stringstream& ss)
|
|
|
|
{
|
2009-12-24 11:30:19 +00:00
|
|
|
ss << doubleValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
void
|
|
|
|
BoolElement::toJSON(std::stringstream& ss)
|
|
|
|
{
|
2009-10-30 17:28:17 +00:00
|
|
|
if (b) {
|
2010-06-15 10:11:48 +00:00
|
|
|
ss << "true";
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
2010-06-15 10:11:48 +00:00
|
|
|
ss << "false";
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
void
|
|
|
|
NullElement::toJSON(std::stringstream& ss)
|
|
|
|
{
|
|
|
|
ss << "null";
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
StringElement::toJSON(std::stringstream& ss)
|
|
|
|
{
|
2009-10-30 17:28:17 +00:00
|
|
|
ss << "\"";
|
2009-12-24 11:30:19 +00:00
|
|
|
ss << stringValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
ss << "\"";
|
|
|
|
}
|
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
void
|
|
|
|
ListElement::toJSON(std::stringstream& ss)
|
|
|
|
{
|
2009-10-30 17:28:17 +00:00
|
|
|
ss << "[ ";
|
2010-03-15 08:24:50 +00:00
|
|
|
|
|
|
|
const std::vector<ElementPtr>& v = listValue();
|
|
|
|
for (std::vector<ElementPtr>::const_iterator it = v.begin();
|
|
|
|
it != v.end(); ++it) {
|
2009-10-30 17:28:17 +00:00
|
|
|
if (it != v.begin()) {
|
|
|
|
ss << ", ";
|
|
|
|
}
|
2010-06-15 10:11:48 +00:00
|
|
|
(*it)->toJSON(ss);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
ss << " ]";
|
|
|
|
}
|
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
void
|
|
|
|
MapElement::toJSON(std::stringstream& ss)
|
|
|
|
{
|
|
|
|
ss << "{ ";
|
2010-03-15 08:24:50 +00:00
|
|
|
|
|
|
|
const std::map<std::string, ElementPtr>& m = mapValue();
|
|
|
|
for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
|
|
|
|
it != m.end(); ++it) {
|
2009-10-30 17:28:17 +00:00
|
|
|
if (it != m.begin()) {
|
|
|
|
ss << ", ";
|
|
|
|
}
|
|
|
|
ss << "\"" << (*it).first << "\": ";
|
2010-02-22 12:42:15 +00:00
|
|
|
if ((*it).second) {
|
2010-06-15 10:11:48 +00:00
|
|
|
(*it).second->toJSON(ss);
|
2010-02-22 12:42:15 +00:00
|
|
|
} else {
|
|
|
|
ss << "None";
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
2010-06-15 10:11:48 +00:00
|
|
|
ss << " }";
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-01-04 12:59:22 +00:00
|
|
|
// throws when one of the types in the path (except the one
|
2009-10-30 17:28:17 +00:00
|
|
|
// we're looking for) is not a MapElement
|
|
|
|
// returns 0 if it could simply not be found
|
|
|
|
// should that also be an exception?
|
|
|
|
ElementPtr
|
2010-03-15 08:24:50 +00:00
|
|
|
MapElement::find(const std::string& id) {
|
|
|
|
const size_t sep = id.find('/');
|
2009-10-30 17:28:17 +00:00
|
|
|
if (sep == std::string::npos) {
|
|
|
|
return get(id);
|
|
|
|
} else {
|
|
|
|
ElementPtr ce = get(id.substr(0, sep));
|
|
|
|
if (ce) {
|
2009-12-18 17:41:23 +00:00
|
|
|
// ignore trailing slash
|
2010-03-15 08:24:50 +00:00
|
|
|
if (sep + 1 != id.size()) {
|
|
|
|
return ce->find(id.substr(sep + 1));
|
2009-12-18 17:41:23 +00:00
|
|
|
} else {
|
|
|
|
return ce;
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
|
|
|
return ElementPtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-03-15 08:24:50 +00:00
|
|
|
Element::fromWire(const std::string& s) {
|
2009-10-30 17:28:17 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
ss << s;
|
2010-06-15 10:11:48 +00:00
|
|
|
int line = 0, pos = 0;
|
2010-06-15 13:02:26 +00:00
|
|
|
return fromJSON(ss, "<wire>", line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-03-15 08:24:50 +00:00
|
|
|
Element::fromWire(std::stringstream& in, int length) {
|
2009-10-30 17:28:17 +00:00
|
|
|
//
|
|
|
|
// Check protocol version
|
|
|
|
//
|
2010-06-15 10:11:48 +00:00
|
|
|
//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;
|
|
|
|
int line = 0, pos = 0;
|
2010-06-15 13:02:26 +00:00
|
|
|
return fromJSON(in, "<wire>", line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-06-15 12:38:55 +00:00
|
|
|
void
|
|
|
|
MapElement::set(const std::string& key, ElementPtr value) {
|
|
|
|
if (key.length() <= 255) {
|
|
|
|
m[key] = value;
|
|
|
|
} else {
|
|
|
|
isc_throw(TypeError, "Map key too long");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-30 17:28:17 +00:00
|
|
|
bool
|
|
|
|
MapElement::find(const std::string& id, ElementPtr& t) {
|
|
|
|
try {
|
2010-02-02 15:47:51 +00:00
|
|
|
ElementPtr p = find(id);
|
2009-10-30 17:28:17 +00:00
|
|
|
if (p) {
|
|
|
|
t = p;
|
|
|
|
return true;
|
|
|
|
}
|
2010-03-15 08:24:50 +00:00
|
|
|
} catch (const TypeError& e) {
|
2009-10-30 17:28:17 +00:00
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2009-12-18 17:41:23 +00:00
|
|
|
|
2010-02-28 20:00:49 +00:00
|
|
|
bool
|
2010-03-15 08:24:50 +00:00
|
|
|
IntElement::equals(ElementPtr other) {
|
2010-02-28 20:00:49 +00:00
|
|
|
return (other->getType() == Element::integer) &&
|
|
|
|
(i == other->intValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-03-15 08:24:50 +00:00
|
|
|
DoubleElement::equals(ElementPtr other) {
|
2010-02-28 20:00:49 +00:00
|
|
|
return (other->getType() == Element::real) &&
|
|
|
|
(d == other->doubleValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-03-15 08:24:50 +00:00
|
|
|
BoolElement::equals(ElementPtr other) {
|
2010-02-28 20:00:49 +00:00
|
|
|
return (other->getType() == Element::boolean) &&
|
|
|
|
(b == other->boolValue());
|
|
|
|
}
|
|
|
|
|
2010-06-15 10:11:48 +00:00
|
|
|
bool
|
|
|
|
NullElement::equals(ElementPtr other) {
|
|
|
|
return other->getType() == Element::null;
|
|
|
|
}
|
|
|
|
|
2010-02-28 20:00:49 +00:00
|
|
|
bool
|
2010-03-15 08:24:50 +00:00
|
|
|
StringElement::equals(ElementPtr other) {
|
2010-02-28 20:00:49 +00:00
|
|
|
return (other->getType() == Element::string) &&
|
|
|
|
(s == other->stringValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-03-15 08:24:50 +00:00
|
|
|
ListElement::equals(ElementPtr other) {
|
2010-02-28 20:00:49 +00:00
|
|
|
if (other->getType() == Element::list) {
|
2010-03-15 08:24:50 +00:00
|
|
|
const int s = size();
|
2010-02-28 20:00:49 +00:00
|
|
|
if (s != other->size()) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-03-15 08:24:50 +00:00
|
|
|
for (int i = 0; i < s; ++i) {
|
2010-02-28 20:00:49 +00:00
|
|
|
if (!get(i)->equals(other->get(i))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-03-15 08:24:50 +00:00
|
|
|
MapElement::equals(ElementPtr other) {
|
2010-02-28 20:00:49 +00:00
|
|
|
if (other->getType() == Element::map) {
|
|
|
|
std::map<std::string, ElementPtr> m = mapValue();
|
2010-03-15 08:24:50 +00:00
|
|
|
for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
|
2010-02-28 20:00:49 +00:00
|
|
|
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();
|
2010-03-15 08:24:50 +00:00
|
|
|
for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
|
2010-02-28 20:00:49 +00:00
|
|
|
it != m.end() ; ++it) {
|
|
|
|
if (!contains((*it).first)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-18 17:41:23 +00:00
|
|
|
bool
|
2010-03-15 08:35:45 +00:00
|
|
|
isNull(ElementPtr p) {
|
2009-12-18 17:41:23 +00:00
|
|
|
return !p;
|
|
|
|
}
|
|
|
|
|
2010-02-28 20:00:49 +00:00
|
|
|
void
|
2010-03-15 08:35:45 +00:00
|
|
|
removeIdentical(ElementPtr a, const ElementPtr b) {
|
2010-02-28 20:33:42 +00:00
|
|
|
if (!b) {
|
|
|
|
return;
|
|
|
|
}
|
2010-02-28 20:00:49 +00:00
|
|
|
if (a->getType() != Element::map || b->getType() != Element::map) {
|
2010-03-07 07:06:42 +00:00
|
|
|
isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
|
2010-02-28 20:00:49 +00:00
|
|
|
}
|
2010-02-28 20:33:42 +00:00
|
|
|
|
2010-02-28 20:00:49 +00:00
|
|
|
std::map<std::string, ElementPtr> m = a->mapValue();
|
2010-03-15 08:24:50 +00:00
|
|
|
for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
|
2010-02-28 20:00:49 +00:00
|
|
|
it != m.end() ; ++it) {
|
|
|
|
if (b->contains((*it).first)) {
|
|
|
|
if (a->get((*it).first)->equals(b->get((*it).first))) {
|
|
|
|
a->remove((*it).first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-02-28 20:33:42 +00:00
|
|
|
}
|
2010-02-28 20:00:49 +00:00
|
|
|
|
2010-02-28 20:33:42 +00:00
|
|
|
void
|
2010-03-15 08:35:45 +00:00
|
|
|
merge(ElementPtr element, const ElementPtr other) {
|
2010-02-28 20:33:42 +00:00
|
|
|
if (element->getType() != Element::map ||
|
|
|
|
other->getType() != Element::map) {
|
2010-03-07 07:06:42 +00:00
|
|
|
isc_throw(TypeError, "merge arguments not MapElements");
|
2010-02-28 20:33:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::map<std::string, ElementPtr> m = other->mapValue();
|
2010-03-15 08:24:50 +00:00
|
|
|
for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
|
2010-02-28 20:33:42 +00:00
|
|
|
it != m.end() ; ++it) {
|
|
|
|
if ((*it).second) {
|
|
|
|
element->set((*it).first, (*it).second);
|
|
|
|
} else if (element->contains((*it).first)) {
|
|
|
|
element->remove((*it).first);
|
|
|
|
}
|
|
|
|
}
|
2010-02-28 20:00:49 +00:00
|
|
|
}
|
2010-02-28 20:33:42 +00:00
|
|
|
|
2010-03-15 08:35:45 +00:00
|
|
|
}
|
|
|
|
}
|