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
|
|
|
|
|
|
|
#include "data.h"
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
|
|
|
|
using namespace std;
|
2009-12-24 11:15:23 +00:00
|
|
|
using namespace isc::data;
|
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-02-02 14:14:52 +00:00
|
|
|
static 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;
|
2010-02-02 15:39:45 +00:00
|
|
|
ss << error << " in " + file + ":" << line << ":" << pos;
|
2010-02-02 14:14:52 +00:00
|
|
|
throw ParseError(ss.str());
|
|
|
|
} else {
|
|
|
|
throw ParseError(error);
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2009-10-30 17:28:17 +00:00
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
return ElementPtr(new MapElement(m));
|
|
|
|
} catch (std::bad_alloc) {
|
|
|
|
return ElementPtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
2009-12-24 11:30:19 +00:00
|
|
|
// helper functions for createFromString factory
|
2009-10-30 17:28:17 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
static bool
|
|
|
|
char_in(char c, const char *chars)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < strlen(chars); i++) {
|
|
|
|
if (chars[i] == c) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-11-04 13:41:12 +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') {
|
|
|
|
line++;
|
|
|
|
pos = 1;
|
|
|
|
} else {
|
|
|
|
pos++;
|
|
|
|
}
|
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
|
2009-11-04 13:41:12 +00:00
|
|
|
static 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();
|
2009-11-04 13:41:12 +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;
|
|
|
|
line++;
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
if (char_in(c, may_skip)) {
|
|
|
|
c = in.get();
|
2009-11-04 13:41:12 +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;
|
|
|
|
line++;
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
in.get();
|
2009-11-04 13:41:12 +00:00
|
|
|
pos++;
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
in.putback(c);
|
2009-11-04 13:41:12 +00:00
|
|
|
pos--;
|
|
|
|
return;
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
2010-02-02 14:14:52 +00:00
|
|
|
throwParseError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
2010-02-02 14:14:52 +00:00
|
|
|
throwParseError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static std::string
|
2010-02-02 14:14:52 +00:00
|
|
|
str_from_stringstream(std::istream &in, const std::string& file, int& line, int& pos) throw (ParseError)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
char c = 0;
|
|
|
|
std::stringstream ss;
|
|
|
|
c = in.get();
|
2009-11-04 13:41:12 +00:00
|
|
|
pos++;
|
2009-10-30 17:28:17 +00:00
|
|
|
if (c == '"') {
|
|
|
|
c = in.get();
|
2009-11-04 13:41:12 +00:00
|
|
|
pos++;
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
2010-02-02 14:14:52 +00:00
|
|
|
throwParseError("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();
|
2009-11-04 13:41:12 +00:00
|
|
|
pos++;
|
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
|
|
|
}
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string
|
2009-11-04 13:41:12 +00:00
|
|
|
word_from_stringstream(std::istream &in, int& line, 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-01-13 13:14:31 +00:00
|
|
|
static inline int
|
|
|
|
count_chars_i(int i)
|
|
|
|
{
|
|
|
|
int result = 1;
|
|
|
|
while (i > 10) {
|
|
|
|
result++;
|
|
|
|
i=i/10;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
count_chars_d(double d)
|
|
|
|
{
|
|
|
|
int result = 1;
|
|
|
|
while(d < 1.0) {
|
|
|
|
result++;
|
|
|
|
d = d * 10;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
|
|
|
|
static ElementPtr
|
2009-11-04 13:41:12 +00:00
|
|
|
from_stringstream_int_or_double(std::istream &in, int &line, int &pos)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
in >> i;
|
2010-01-13 13:14:31 +00:00
|
|
|
pos += count_chars_i(i);
|
2009-10-30 17:28:17 +00:00
|
|
|
if (in.peek() == '.') {
|
|
|
|
double d;
|
|
|
|
in >> d;
|
2010-01-13 13:14:31 +00:00
|
|
|
pos += count_chars_d(i);
|
2009-10-30 17:28:17 +00:00
|
|
|
d += i;
|
|
|
|
return Element::create(d);
|
|
|
|
} else {
|
|
|
|
return Element::create(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static ElementPtr
|
2010-02-02 14:14:52 +00:00
|
|
|
from_stringstream_bool(std::istream &in, const std::string& file, int& line, int& pos)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
2009-11-04 13:41:12 +00:00
|
|
|
std::string word = word_from_stringstream(in, line, 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-02-02 14:14:52 +00:00
|
|
|
throwParseError(std::string("Bad boolean value: ") + word, file, line, pos);
|
|
|
|
// above is a throw shortcur, return empty is never reached
|
|
|
|
return ElementPtr();
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static ElementPtr
|
2010-02-02 14:14:52 +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
|
|
|
}
|
|
|
|
|
|
|
|
static 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;
|
|
|
|
std::vector<ElementPtr> v;
|
|
|
|
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-02-02 14:14:52 +00:00
|
|
|
cur_list_element = Element::createFromString(in, file, line, pos);
|
2009-11-04 13:41:12 +00:00
|
|
|
v.push_back(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
|
|
|
}
|
|
|
|
return Element::create(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ElementPtr
|
2010-02-02 14:14:52 +00:00
|
|
|
from_stringstream_map(std::istream &in, const std::string& file, int& line, int& pos)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
char c = 0;
|
|
|
|
std::map<std::string, ElementPtr> m;
|
|
|
|
std::pair<std::string, ElementPtr> p;
|
|
|
|
std::string cur_map_key;
|
|
|
|
ElementPtr cur_map_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 != '}') {
|
2010-02-02 14:14:52 +00:00
|
|
|
p.first = str_from_stringstream(in, file, line, pos);
|
|
|
|
skip_to(in, file, line, pos, ":", " \t\n");
|
2009-11-04 13:41:12 +00:00
|
|
|
// skip the :
|
|
|
|
in.get();
|
|
|
|
pos++;
|
2010-02-02 14:14:52 +00:00
|
|
|
p.second = Element::createFromString(in, file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
m.insert(p);
|
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
|
|
|
}
|
|
|
|
return Element::create(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2009-12-24 11:30:19 +00:00
|
|
|
Element::createFromString(std::istream &in) throw(ParseError)
|
2009-11-04 13:41:12 +00:00
|
|
|
{
|
|
|
|
int line = 1, pos = 1;
|
2010-02-02 14:14:52 +00:00
|
|
|
return createFromString(in, "<unknown>", line, pos);
|
2009-11-04 13:41:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2010-02-02 14:14:52 +00:00
|
|
|
Element::createFromString(std::istream &in, const std::string& file, int& line, int& pos) throw(ParseError)
|
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);
|
2009-11-04 13:41:12 +00:00
|
|
|
element = from_stringstream_int_or_double(in, line, 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;
|
|
|
|
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-02-02 14:14:52 +00:00
|
|
|
throwParseError(std::string("error: unexpected character ") + c, file, line, pos);
|
2009-10-30 17:28:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (el_read) {
|
|
|
|
return element;
|
|
|
|
} else {
|
2009-11-04 13:41:12 +00:00
|
|
|
throw ParseError("nothing read");
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-03 13:07:00 +00:00
|
|
|
ElementPtr
|
2009-12-24 11:30:19 +00:00
|
|
|
Element::createFromString(const std::string &in)
|
2009-11-03 13:07:00 +00:00
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << in;
|
2009-12-24 11:30:19 +00:00
|
|
|
return createFromString(ss);
|
2009-11-03 13:07:00 +00:00
|
|
|
}
|
2010-01-13 13:14:31 +00:00
|
|
|
|
2009-10-30 17:28:17 +00:00
|
|
|
//
|
|
|
|
// a general to_str() function
|
|
|
|
//
|
|
|
|
std::string
|
|
|
|
IntElement::str()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
2009-12-24 11:30:19 +00:00
|
|
|
ss << intValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
DoubleElement::str()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
2009-12-24 11:30:19 +00:00
|
|
|
ss << doubleValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
BoolElement::str()
|
|
|
|
{
|
|
|
|
if (b) {
|
|
|
|
return "True";
|
|
|
|
} else {
|
|
|
|
return "False";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
StringElement::str()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "\"";
|
2009-12-24 11:30:19 +00:00
|
|
|
ss << stringValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
ss << "\"";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
ListElement::str()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
std::vector<ElementPtr> v;
|
|
|
|
ss << "[ ";
|
2009-12-24 11:30:19 +00:00
|
|
|
v = listValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
for (std::vector<ElementPtr>::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;
|
|
|
|
std::map<std::string, ElementPtr> m;
|
|
|
|
ss << "{";
|
2009-12-24 11:30:19 +00:00
|
|
|
m = mapValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
for (std::map<std::string, ElementPtr>::iterator it = m.begin(); it != m.end(); ++it) {
|
|
|
|
if (it != m.begin()) {
|
|
|
|
ss << ", ";
|
|
|
|
}
|
|
|
|
ss << "\"" << (*it).first << "\": ";
|
|
|
|
ss << (*it).second->str();
|
|
|
|
}
|
|
|
|
ss << "}";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
MapElement::find(const std::string& id)
|
|
|
|
{
|
|
|
|
size_t sep = id.find('/');
|
|
|
|
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
|
|
|
|
if (sep+1 != id.size()) {
|
|
|
|
return ce->find(id.substr(sep+1));
|
|
|
|
} else {
|
|
|
|
return ce;
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
|
|
|
return ElementPtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Decode from wire format.
|
|
|
|
//
|
|
|
|
|
|
|
|
ElementPtr decode_element(std::stringstream& in, int& in_length);
|
|
|
|
|
|
|
|
static unsigned char
|
|
|
|
get_byte(std::stringstream& in)
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-11-20 14:18:37 +00:00
|
|
|
ElementPtr
|
|
|
|
decode_bool(std::stringstream& in, int& item_length)
|
|
|
|
{
|
|
|
|
char c;
|
|
|
|
c = in.get();
|
2010-01-04 12:59:22 +00:00
|
|
|
|
|
|
|
if (c == '1') {
|
2009-11-20 14:18:37 +00:00
|
|
|
return Element::create(true);
|
|
|
|
} else {
|
|
|
|
return Element::create(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-23 09:35:36 +00:00
|
|
|
ElementPtr
|
|
|
|
decode_int(std::stringstream& in, int& item_length)
|
|
|
|
{
|
2009-12-24 10:00:34 +00:00
|
|
|
int skip, me;
|
|
|
|
return from_stringstream_int_or_double(in, skip, me);
|
2009-11-23 09:35:36 +00:00
|
|
|
}
|
|
|
|
|
2010-01-04 12:59:22 +00:00
|
|
|
ElementPtr
|
|
|
|
decode_real(std::stringstream& in, int& item_length)
|
|
|
|
{
|
|
|
|
int skip, me;
|
|
|
|
return from_stringstream_int_or_double(in, skip, me);
|
|
|
|
}
|
|
|
|
|
2009-10-30 17:28:17 +00:00
|
|
|
ElementPtr
|
2009-11-20 12:32:57 +00:00
|
|
|
decode_blob(std::stringstream& in, int& item_length)
|
|
|
|
{
|
|
|
|
char *buf = new char[item_length + 1];
|
|
|
|
|
|
|
|
in.read(buf, item_length);
|
|
|
|
if (in.fail()) {
|
|
|
|
throw DecodeError();
|
|
|
|
}
|
|
|
|
buf[item_length] = 0;
|
|
|
|
|
|
|
|
std::string s = std::string(buf, item_length);
|
|
|
|
item_length -= item_length;
|
|
|
|
|
|
|
|
delete [] buf;
|
|
|
|
return Element::create(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXXMLG currently identical to decode_blob
|
|
|
|
ElementPtr
|
|
|
|
decode_utf8(std::stringstream& in, int& item_length)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
char *buf = new char[item_length + 1];
|
|
|
|
|
|
|
|
in.read(buf, item_length);
|
|
|
|
if (in.fail()) {
|
|
|
|
throw DecodeError();
|
|
|
|
}
|
|
|
|
buf[item_length] = 0;
|
|
|
|
|
|
|
|
std::string s = std::string(buf, item_length);
|
|
|
|
item_length -= item_length;
|
|
|
|
|
|
|
|
delete [] buf;
|
|
|
|
return Element::create(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
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(std::stringstream& in, int& item_length)
|
|
|
|
{
|
|
|
|
return Element::create("NULL");
|
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
|
|
|
decode_element(std::stringstream& in, int& in_length)
|
|
|
|
{
|
|
|
|
ElementPtr element;
|
|
|
|
|
|
|
|
unsigned char type_and_length = get_byte(in);
|
|
|
|
unsigned char type = type_and_length & ITEM_MASK;
|
|
|
|
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) {
|
2009-11-20 14:18:37 +00:00
|
|
|
case ITEM_BOOL:
|
|
|
|
element = decode_bool(in, item_length);
|
|
|
|
break;
|
2009-11-23 09:35:36 +00:00
|
|
|
case ITEM_INT:
|
|
|
|
element = decode_int(in, item_length);
|
|
|
|
break;
|
2010-01-04 12:59:22 +00:00
|
|
|
case ITEM_REAL:
|
|
|
|
element = decode_real(in, item_length);
|
|
|
|
break;
|
2009-11-20 12:32:57 +00:00
|
|
|
case ITEM_BLOB:
|
|
|
|
element = decode_blob(in, item_length);
|
|
|
|
break;
|
|
|
|
case ITEM_UTF8:
|
|
|
|
element = decode_utf8(in, item_length);
|
2009-10-30 17:28:17 +00:00
|
|
|
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(in, item_length);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (element);
|
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2009-12-24 11:30:19 +00:00
|
|
|
Element::fromWire(const std::string& s)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << s;
|
2009-12-24 11:30:19 +00:00
|
|
|
return fromWire(ss, s.length());
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementPtr
|
2009-12-24 11:30:19 +00:00
|
|
|
Element::fromWire(std::stringstream& in, int length)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
//
|
|
|
|
// Check protocol version
|
|
|
|
//
|
|
|
|
for (int i = 0 ; i < 4 ; i++) {
|
|
|
|
unsigned char version_byte = get_byte(in);
|
|
|
|
if (PROTOCOL_VERSION[i] != version_byte) {
|
|
|
|
throw DecodeError("Protocol version incorrect");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
length -= 4;
|
|
|
|
|
|
|
|
ElementPtr element;
|
|
|
|
element = decode_hash(in, length);
|
|
|
|
return (element);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Encode into wire format.
|
|
|
|
//
|
|
|
|
|
|
|
|
std::string
|
|
|
|
encode_length(unsigned int length, unsigned char type)
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
|
|
|
|
if (length <= 0x000000ff) {
|
|
|
|
unsigned char val = (length & 0x000000ff);
|
|
|
|
type |= ITEM_LENGTH_8;
|
|
|
|
ss << type << val;
|
|
|
|
} else if (length <= 0x0000ffff) {
|
2010-01-04 12:59:22 +00:00
|
|
|
unsigned char val[2];
|
2009-10-30 17:28:17 +00:00
|
|
|
val[0] = (length & 0x0000ff00) >> 8;
|
|
|
|
val[1] = (length & 0x000000ff);
|
|
|
|
type |= ITEM_LENGTH_16;
|
2010-01-04 12:59:22 +00:00
|
|
|
ss << type << val[0] << val[1];
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
2010-01-04 12:59:22 +00:00
|
|
|
unsigned char val[4];
|
2009-10-30 17:28:17 +00:00
|
|
|
val[0] = (length & 0xff000000) >> 24;
|
|
|
|
val[1] = (length & 0x00ff0000) >> 16;
|
|
|
|
val[2] = (length & 0x0000ff00) >> 8;
|
|
|
|
val[3] = (length & 0x000000ff);
|
|
|
|
type |= ITEM_LENGTH_32;
|
2010-01-04 12:59:22 +00:00
|
|
|
ss << type << val[0] << val[1] << val[2] << val[3];
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
2010-02-02 14:14:52 +00:00
|
|
|
Element::toWire(int omit_length)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
std::stringstream ss;
|
2010-02-02 14:14:52 +00:00
|
|
|
toWire(ss, omit_length);
|
|
|
|
return ss.str();
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
|
2010-02-02 14:14:52 +00:00
|
|
|
void
|
|
|
|
StringElement::toWire(std::stringstream& ss, int omit_length)
|
|
|
|
{
|
2010-01-04 12:59:22 +00:00
|
|
|
unsigned int length = stringValue().length();
|
2009-12-24 11:30:19 +00:00
|
|
|
ss << encode_length(length, ITEM_UTF8) << stringValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-02-02 14:14:52 +00:00
|
|
|
void
|
|
|
|
IntElement::toWire(std::stringstream& ss, int omit_length)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
std::stringstream text;
|
|
|
|
|
|
|
|
text << str();
|
|
|
|
int length = text.str().length();
|
2009-11-23 09:35:36 +00:00
|
|
|
ss << encode_length(length, ITEM_INT) << text.str();
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-02-02 14:14:52 +00:00
|
|
|
void
|
|
|
|
BoolElement::toWire(std::stringstream& ss, int omit_length)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
std::stringstream text;
|
|
|
|
|
|
|
|
text << str();
|
2009-11-20 14:18:37 +00:00
|
|
|
int length = 1;
|
|
|
|
ss << encode_length(length, ITEM_BOOL);
|
2009-12-24 11:30:19 +00:00
|
|
|
if (boolValue()) {
|
2009-11-20 14:18:37 +00:00
|
|
|
ss << 0x01;
|
|
|
|
} else {
|
|
|
|
ss << 0x00;
|
|
|
|
}
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-02-02 14:14:52 +00:00
|
|
|
void
|
|
|
|
DoubleElement::toWire(std::stringstream& ss, int omit_length)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
std::stringstream text;
|
|
|
|
|
|
|
|
text << str();
|
|
|
|
int length = text.str().length();
|
2010-01-04 12:59:22 +00:00
|
|
|
ss << encode_length(length, ITEM_REAL) << text.str();
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2010-02-02 14:14:52 +00:00
|
|
|
void
|
|
|
|
ListElement::toWire(std::stringstream& ss, int omit_length)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
2010-02-02 14:14:52 +00:00
|
|
|
std::stringstream ss2;
|
2009-10-30 17:28:17 +00:00
|
|
|
std::vector<ElementPtr> v;
|
2009-12-24 11:30:19 +00:00
|
|
|
v = listValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
for (std::vector<ElementPtr>::iterator it = v.begin() ;
|
|
|
|
it != v.end() ; ++it) {
|
2010-02-02 14:14:52 +00:00
|
|
|
(*it)->toWire(ss2, 0);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (omit_length) {
|
2010-02-02 14:14:52 +00:00
|
|
|
ss << ss2.rdbuf();
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
2010-02-02 14:14:52 +00:00
|
|
|
stringbuf *ss2_buf = ss2.rdbuf();
|
|
|
|
ss2_buf->pubseekpos(0);
|
|
|
|
ss << encode_length(ss2_buf->in_avail(), ITEM_LIST);
|
|
|
|
ss << ss2_buf;
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-02 14:14:52 +00:00
|
|
|
void
|
|
|
|
encode_tag(std::stringstream& ss, const std::string &s)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
|
|
|
int length = s.length();
|
|
|
|
unsigned char val = length & 0x000000ff;
|
|
|
|
|
|
|
|
ss << val << s;
|
|
|
|
}
|
|
|
|
|
2010-02-02 14:14:52 +00:00
|
|
|
void
|
|
|
|
MapElement::toWire(std::stringstream& ss, int omit_length)
|
2009-10-30 17:28:17 +00:00
|
|
|
{
|
2010-02-02 14:14:52 +00:00
|
|
|
std::stringstream ss2;
|
2009-10-30 17:28:17 +00:00
|
|
|
std::map<std::string, ElementPtr> m;
|
|
|
|
|
|
|
|
//
|
|
|
|
// If we don't want the length, we will want the protocol header
|
|
|
|
//
|
|
|
|
if (omit_length) {
|
2010-02-02 14:14:52 +00:00
|
|
|
ss2 << PROTOCOL_VERSION[0] << PROTOCOL_VERSION[1];
|
|
|
|
ss2 << PROTOCOL_VERSION[2] << PROTOCOL_VERSION[3];
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
2009-12-24 11:30:19 +00:00
|
|
|
m = mapValue();
|
2009-10-30 17:28:17 +00:00
|
|
|
for (std::map<std::string, ElementPtr>::iterator it = m.begin() ;
|
|
|
|
it != m.end() ; ++it) {
|
2010-02-02 14:14:52 +00:00
|
|
|
encode_tag(ss2, (*it).first);
|
|
|
|
(*it).second->toWire(ss2, 0);
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// add length if needed
|
|
|
|
//
|
|
|
|
if (omit_length) {
|
2010-02-02 14:14:52 +00:00
|
|
|
ss << ss2.rdbuf();
|
2009-10-30 17:28:17 +00:00
|
|
|
} else {
|
2010-02-02 14:14:52 +00:00
|
|
|
|
|
|
|
stringbuf *ss2_buf = ss2.rdbuf();
|
|
|
|
ss2_buf->pubseekpos(0);
|
|
|
|
ss << encode_length(ss2_buf->in_avail(), ITEM_HASH);
|
|
|
|
ss << ss2_buf;
|
2009-10-30 17:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MapElement::find(const std::string& id, ElementPtr& t) {
|
|
|
|
ElementPtr p;
|
|
|
|
try {
|
|
|
|
p = find(id);
|
|
|
|
if (p) {
|
|
|
|
t = p;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} catch (TypeError e) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2009-12-18 17:41:23 +00:00
|
|
|
|
|
|
|
bool
|
2009-12-24 11:30:19 +00:00
|
|
|
isc::data::isNull(ElementPtr p)
|
2009-12-18 17:41:23 +00:00
|
|
|
{
|
|
|
|
return !p;
|
|
|
|
}
|
|
|
|
|