Commit c51d6c7b authored by Jelte Jansen's avatar Jelte Jansen

Data Elements fixups;

- isc::data::TypeError is now a subtype of isc::dns::Exception (which i think we should move to namespace isc::)
- isc::data::ParseError not yet; it is a subclass of std::runtime_error (due to the error in quiestion being constructed on the fly, can we add an equivalent of that to isc::[dns::]Exception?
- toWire() family of functions now writes directly to a stream, with a convenience function for Element that does return a std::string
- removed unused and unspecified toXML functions


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/parkinglot@699 e5f2f494-b856-4b98-b285-d166d9295462
parent 8ec49a35
......@@ -34,10 +34,8 @@ pyshared:
mkdir pyshared
mkdir pyshared/isc
ln -s ${abs_top_srcdir}/src/lib/config/python/isc/config pyshared/isc/config
cat ${abs_top_srcdir}/src/lib/config/python/isc/__init__.py >> pyshared/isc/__init__.py
ln -s ${abs_top_srcdir}/src/lib/cc/python/isc/cc pyshared/isc/cc
ln -s ${abs_top_srcdir}/src/lib/cc/python/isc/cc pyshared/isc/Util
cat ${abs_top_srcdir}/src/lib/cc/python/isc/__init__.py >> pyshared/isc/__init__.py
include:
mkdir include
......
SUBDIRS = cc config dns auth
SUBDIRS = dns cc config auth
AM_CPPFLAGS = -I$(top_srcdir)/src/lib/cc/cpp -I$(top_srcdir)/ext -Wall -Werror
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_srcdir)/ext -Wall -Werror
lib_LIBRARIES = libcc.a
libcc_a_SOURCES = data.cc data.h session.cc session.h
......@@ -7,9 +7,10 @@ TESTS =
if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = data_unittests.cc run_unittests.cc
run_unittests_CPPFLAGS = $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(GTEST_LDFLAGS)
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = libcc.a $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/dns/cpp/.libs/libdns.a
endif
noinst_PROGRAMS = $(TESTS)
// XXXMLG UTF-8 and binary are all encoded as UTF-8, and decoded as UTF-8.
// XXXMLG This will cause issues down the road, but for today it works.
// 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 "data.h"
......@@ -29,15 +42,20 @@ const unsigned char ITEM_LENGTH_16 = 0x10;
const unsigned char ITEM_LENGTH_8 = 0x20;
const unsigned char ITEM_LENGTH_MASK = 0x30;
std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e) {
return out << e->str();
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;
ss << error << "in " + file + ":" << line << ":" << pos;
throw ParseError(ss.str());
} else {
throw ParseError(error);
}
}
const char*
ParseError::what() const throw() {
stringstream ss;
ss << msg << " line " << line << " pos " << pos;
return ss.str().c_str();
std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e) {
return out << e->str();
}
//
......@@ -106,7 +124,6 @@ Element::create(const std::map<std::string, ElementPtr>& m)
//
// helper functions for createFromString factory
// these should probably also be moved to member functions
//
static bool
......@@ -142,7 +159,8 @@ skip_chars(std::istream &in, const char *chars, int& line, int& pos)
//
// the character found is left on the stream
static void
skip_to(std::istream &in, int& line, int& pos, const char* chars, const char* may_skip="")
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++;
......@@ -167,14 +185,14 @@ skip_to(std::istream &in, int& line, int& pos, const char* chars, const char* ma
pos--;
return;
} else {
throw ParseError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", line, pos);
throwParseError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
}
}
throw ParseError(std::string("EOF read, one of \"") + chars + "\" expected", line, pos);
throwParseError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
}
static std::string
str_from_stringstream(std::istream &in, int& line, int& pos) throw (ParseError)
str_from_stringstream(std::istream &in, const std::string& file, int& line, int& pos) throw (ParseError)
{
char c = 0;
std::stringstream ss;
......@@ -184,7 +202,7 @@ str_from_stringstream(std::istream &in, int& line, int& pos) throw (ParseError)
c = in.get();
pos++;
} else {
throw ParseError("String expected", line, pos);
throwParseError("String expected", file, line, pos);
}
while (c != EOF && c != '"') {
ss << c;
......@@ -249,7 +267,7 @@ from_stringstream_int_or_double(std::istream &in, int &line, int &pos)
}
static ElementPtr
from_stringstream_bool(std::istream &in, int& line, int& pos)
from_stringstream_bool(std::istream &in, const std::string& file, int& line, int& pos)
{
std::string word = word_from_stringstream(in, line, pos);
if (boost::iequals(word, "True")) {
......@@ -257,18 +275,20 @@ from_stringstream_bool(std::istream &in, int& line, int& pos)
} else if (boost::iequals(word, "False")) {
return Element::create(false);
} else {
throw ParseError(std::string("Bad boolean value: ") + word, line, pos);
throwParseError(std::string("Bad boolean value: ") + word, file, line, pos);
// above is a throw shortcur, return empty is never reached
return ElementPtr();
}
}
static ElementPtr
from_stringstream_string(std::istream &in, int& line, int& pos)
from_stringstream_string(std::istream &in, const std::string& file, int& line, int& pos)
{
return Element::create(str_from_stringstream(in, line, pos));
return Element::create(str_from_stringstream(in, file, line, pos));
}
static ElementPtr
from_stringstream_list(std::istream &in, int& line, int& pos)
from_stringstream_list(std::istream &in, const std::string& file, int& line, int& pos)
{
char c = 0;
std::vector<ElementPtr> v;
......@@ -277,9 +297,9 @@ from_stringstream_list(std::istream &in, int& line, int& pos)
skip_chars(in, " \t\n", line, pos);
while (c != EOF && c != ']') {
if (in.peek() != ']') {
cur_list_element = Element::createFromString(in, line, pos);
cur_list_element = Element::createFromString(in, file, line, pos);
v.push_back(cur_list_element);
skip_to(in, line, pos, ",]", " \t\n");
skip_to(in, file, line, pos, ",]", " \t\n");
}
c = in.get();
pos++;
......@@ -288,7 +308,7 @@ from_stringstream_list(std::istream &in, int& line, int& pos)
}
static ElementPtr
from_stringstream_map(std::istream &in, int& line, int& pos)
from_stringstream_map(std::istream &in, const std::string& file, int& line, int& pos)
{
char c = 0;
std::map<std::string, ElementPtr> m;
......@@ -297,14 +317,14 @@ from_stringstream_map(std::istream &in, int& line, int& pos)
ElementPtr cur_map_element;
skip_chars(in, " \t\n", line, pos);
while (c != EOF && c != '}') {
p.first = str_from_stringstream(in, line, pos);
skip_to(in, line, pos, ":", " \t\n");
p.first = str_from_stringstream(in, file, line, pos);
skip_to(in, file, line, pos, ":", " \t\n");
// skip the :
in.get();
pos++;
p.second = Element::createFromString(in, line, pos);
p.second = Element::createFromString(in, file, line, pos);
m.insert(p);
skip_to(in, line, pos, ",}", " \t\n");
skip_to(in, file, line, pos, ",}", " \t\n");
c = in.get();
pos++;
}
......@@ -315,11 +335,11 @@ ElementPtr
Element::createFromString(std::istream &in) throw(ParseError)
{
int line = 1, pos = 1;
return createFromString(in, line, pos);
return createFromString(in, "<unknown>", line, pos);
}
ElementPtr
Element::createFromString(std::istream &in, int& line, int& pos) throw(ParseError)
Element::createFromString(std::istream &in, const std::string& file, int& line, int& pos) throw(ParseError)
{
char c = 0;
ElementPtr element;
......@@ -348,26 +368,26 @@ Element::createFromString(std::istream &in, int& line, int& pos) throw(ParseErro
case 'f':
case 'F':
in.putback(c);
element = from_stringstream_bool(in, line, pos);
element = from_stringstream_bool(in, file, line, pos);
el_read = true;
break;
case '"':
in.putback('"');
element = from_stringstream_string(in, line, pos);
element = from_stringstream_string(in, file, line, pos);
el_read = true;
break;
case '[':
element = from_stringstream_list(in, line, pos);
element = from_stringstream_list(in, file, line, pos);
el_read = true;
break;
case '{':
element = from_stringstream_map(in, line, pos);
element = from_stringstream_map(in, file, line, pos);
el_read = true;
break;
case EOF:
break;
default:
throw ParseError(std::string("error: unexpected character ") + c, line, pos);
throwParseError(std::string("error: unexpected character ") + c, file, line, pos);
break;
}
}
......@@ -460,96 +480,6 @@ MapElement::str()
return ss.str();
}
//
// helpers for strXML() functions
//
// prefix with 'prefix' number of spaces
static void
pre(std::ostream &out, size_t prefix)
{
for (size_t i = 0; i < prefix; i++) {
out << " ";
}
}
std::string
IntElement::strXML(size_t prefix)
{
std::stringstream ss;
pre(ss, prefix);
ss << str();
return ss.str();
}
std::string
DoubleElement::strXML(size_t prefix)
{
std::stringstream ss;
pre(ss, prefix);
ss << str();
return ss.str();
}
std::string
BoolElement::strXML(size_t prefix)
{
std::stringstream ss;
pre(ss, prefix);
ss << str();
return ss.str();
}
std::string
StringElement::strXML(size_t prefix)
{
std::stringstream ss;
pre(ss, prefix);
ss << stringValue();
return ss.str();
}
std::string
ListElement::strXML(size_t prefix)
{
std::stringstream ss;
std::vector<ElementPtr> v;
pre(ss, prefix);
ss << "<list>" << endl;;
v = listValue();
for (std::vector<ElementPtr>::iterator it = v.begin(); it != v.end(); ++it) {
pre(ss, prefix + 4);
ss << "<listitem>" << endl;
ss << (*it)->strXML(prefix + 8) << endl;
pre(ss, prefix + 4);
ss << "</listitem>" << endl;
}
pre(ss, prefix);
ss << "</list>";
return ss.str();
}
std::string
MapElement::strXML(size_t prefix)
{
std::stringstream ss;
std::map<std::string, ElementPtr> m;
m = mapValue();
pre(ss, prefix);
ss << "<map>" << endl;
for (std::map<std::string, ElementPtr>::iterator it = m.begin(); it != m.end(); ++it) {
pre(ss, prefix + 4);
ss << "<mapitem name=\"" << (*it).first << "\">" << endl;
pre(ss, prefix);
ss << (*it).second->strXML(prefix+8) << endl;
pre(ss, prefix + 4);
ss << "</mapitem>" << endl;
}
pre(ss, prefix);
ss << "</map>";
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
......@@ -824,33 +754,33 @@ encode_length(unsigned int length, unsigned char type)
}
std::string
StringElement::toWire(int omit_length)
Element::toWire(int omit_length)
{
std::stringstream ss;
toWire(ss, omit_length);
return ss.str();
}
void
StringElement::toWire(std::stringstream& ss, int omit_length)
{
unsigned int length = stringValue().length();
ss << encode_length(length, ITEM_UTF8) << stringValue();
return ss.str();
}
std::string
IntElement::toWire(int omit_length)
void
IntElement::toWire(std::stringstream& ss, int omit_length)
{
std::stringstream ss;
std::stringstream text;
text << str();
int length = text.str().length();
ss << encode_length(length, ITEM_INT) << text.str();
return ss.str();
}
std::string
BoolElement::toWire(int omit_length)
void
BoolElement::toWire(std::stringstream& ss, int omit_length)
{
std::stringstream ss;
std::stringstream text;
text << str();
......@@ -861,87 +791,80 @@ BoolElement::toWire(int omit_length)
} else {
ss << 0x00;
}
return ss.str();
}
std::string
DoubleElement::toWire(int omit_length)
void
DoubleElement::toWire(std::stringstream& ss, int omit_length)
{
std::stringstream ss;
std::stringstream text;
text << str();
int length = text.str().length();
ss << encode_length(length, ITEM_REAL) << text.str();
return ss.str();
}
std::string
ListElement::toWire(int omit_length)
void
ListElement::toWire(std::stringstream& ss, int omit_length)
{
std::stringstream ss;
std::stringstream ss2;
std::vector<ElementPtr> v;
v = listValue();
for (std::vector<ElementPtr>::iterator it = v.begin() ;
it != v.end() ; ++it) {
ss << (*it)->toWire(0);
(*it)->toWire(ss2, 0);
}
if (omit_length) {
return ss.str();
ss << ss2.rdbuf();
} else {
std::stringstream ss_len;
ss_len << encode_length(ss.str().length(), ITEM_LIST);
ss_len << ss.str();
return ss_len.str();
stringbuf *ss2_buf = ss2.rdbuf();
ss2_buf->pubseekpos(0);
ss << encode_length(ss2_buf->in_avail(), ITEM_LIST);
ss << ss2_buf;
}
}
std::string
encode_tag(const std::string &s)
void
encode_tag(std::stringstream& ss, const std::string &s)
{
std::stringstream ss;
int length = s.length();
unsigned char val = length & 0x000000ff;
ss << val << s;
return ss.str();
}
std::string
MapElement::toWire(int omit_length)
void
MapElement::toWire(std::stringstream& ss, int omit_length)
{
std::stringstream ss;
std::stringstream ss2;
std::map<std::string, ElementPtr> m;
//
// If we don't want the length, we will want the protocol header
//
if (omit_length) {
ss << PROTOCOL_VERSION[0] << PROTOCOL_VERSION[1];
ss << PROTOCOL_VERSION[2] << PROTOCOL_VERSION[3];
ss2 << PROTOCOL_VERSION[0] << PROTOCOL_VERSION[1];
ss2 << PROTOCOL_VERSION[2] << PROTOCOL_VERSION[3];
}
m = mapValue();
for (std::map<std::string, ElementPtr>::iterator it = m.begin() ;
it != m.end() ; ++it) {
ss << encode_tag((*it).first);
ss << (*it).second->toWire(0);
encode_tag(ss2, (*it).first);
(*it).second->toWire(ss2, 0);
}
//
// add length if needed
//
if (omit_length) {
return ss.str();
ss << ss2.rdbuf();
} else {
std::stringstream ss_len;
ss_len << encode_length(ss.str().length(), ITEM_HASH);
ss_len << ss.str();
return ss_len.str();
stringbuf *ss2_buf = ss2.rdbuf();
ss2_buf->pubseekpos(0);
ss << encode_length(ss2_buf->in_avail(), ITEM_HASH);
ss << ss2_buf;
}
}
......
// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
// 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
......@@ -22,6 +22,7 @@
#include <map>
#include <boost/shared_ptr.hpp>
#include <stdexcept>
#include <dns/cpp/exceptions.h>
namespace isc { namespace data {
......@@ -35,28 +36,22 @@ typedef boost::shared_ptr<Element> ElementPtr;
/// ListElement)
///
// todo: include types and called function in the exception
class TypeError : public std::exception {
class TypeError : public isc::dns::Exception {
public:
TypeError(std::string m = "Attempt to use function on wrong Element type") : msg(m) {}
~TypeError() throw() {}
const char* what() const throw() { return msg.c_str(); }
private:
std::string msg;
TypeError(const char* file, size_t line, const char* what) :
isc::dns::Exception(file, line, what) {}
};
///
/// \brief A standard Data module exception that is thrown if a parse
/// error is encountered when constructing an Element from a string
///
class ParseError : public std::exception {
// i'd like to use Exception here but we need one that is derived from
// runtime_error (as this one is directly based on external data, and
// i want to add some values to any static data string that is provided)
class ParseError : public std::runtime_error {
public:
ParseError(std::string m = "Parse error in element data", int l = 0, int p = 0) : msg(m), line(l), pos(p) {}
~ParseError() throw() {}
const char* what() const throw();
private:
std::string msg;
int line;
int pos;
ParseError(const std::string &err) : std::runtime_error(err) {};
};
///
......@@ -120,22 +115,14 @@ public:
/// \return std::string containing the string representation
virtual std::string str() = 0;
/// Returns an xml representation for the Element and all its
/// child elements
///
/// \param prefix Every line of the xml string will be prefixed with
/// the number of spaces specified here
/// \return std::string containing the xml representation
// todo
virtual std::string strXML(size_t prefix = 0) = 0;
/// Returns the wireformat for the Element and all its child
/// elements.
///
/// \param omit_length If this is non-zero, the item length will
/// be omitted from the wire format
/// \return std::string containing the element in wire format
virtual std::string toWire(int omit_length = 1) = 0;
std::string toWire(int omit_length = 1);
virtual void toWire(std::stringstream& out, int omit_length = 1) = 0;
/// \name Type-specific getters
///
......@@ -146,12 +133,12 @@ public:
/// If you want an exception-safe getter method, use
/// getValue() below
//@{
virtual int intValue() { throw TypeError(); };
virtual double doubleValue() { throw TypeError(); };
virtual bool boolValue() { throw TypeError(); };
virtual std::string stringValue() { throw TypeError(); };
virtual const std::vector<boost::shared_ptr<Element> >& listValue() { throw TypeError(); }; // replace with real exception or empty vector?
virtual const std::map<std::string, boost::shared_ptr<Element> >& mapValue() { throw TypeError(); }; // replace with real exception or empty map?
virtual int intValue() { dns_throw(TypeError, "intValue() called on non-integer Element"); };
virtual double doubleValue() { dns_throw(TypeError, "doubleValue() called on non-double Element"); };
virtual bool boolValue() { dns_throw(TypeError, "boolValue() called on non-Bool Element"); };
virtual std::string stringValue() { dns_throw(TypeError, "stringValue() called on non-string Element"); };
virtual const std::vector<boost::shared_ptr<Element> >& listValue() { dns_throw(TypeError, "listValue() called on non-list Element"); }; // replace with real exception or empty vector?
virtual const std::map<std::string, boost::shared_ptr<Element> >& mapValue() { dns_throw(TypeError, "mapValue() called on non-map Element"); }; // replace with real exception or empty map?
//@}
/// \name Exception-safe getters
......@@ -198,21 +185,21 @@ public:
/// Returns the ElementPtr at the given index. If the index is out
/// of bounds, this function throws an std::out_of_range exception.
/// \param i The position of the ElementPtr to return
virtual ElementPtr get(const int i) { throw TypeError(); };
virtual ElementPtr get(const int i) { dns_throw(TypeError, "get(int) called on a non-list Element"); };
/// Sets the ElementPtr at the given index. If the index is out
/// of bounds, this function throws an std::out_of_range exception.
/// \param i The position of the ElementPtr to set
/// \param element The ElementPtr to set at the position
virtual void set(const size_t i, ElementPtr element) { throw TypeError(); };
virtual void set(const size_t i, ElementPtr element) { dns_throw(TypeError, "set(int, element) called on a non-list Element"); };
/// Adds an ElementPtr to the list
/// \param element The ElementPtr to add
virtual void add(ElementPtr element) { throw TypeError(); };
virtual void add(ElementPtr element) { dns_throw(TypeError, "add() called on a non-list Element"); };
/// Removes the element at the given position. If the index is out
/// of nothing happens.
/// \param i The index of the element to remove.
virtual void remove(const int i) { throw TypeError(); };
virtual void remove(const int i) { dns_throw(TypeError, "remove(int) called on a non-list Element"); };
/// Returns the number of elements in the list.
virtual size_t size() { throw TypeError(); };
virtual size_t size() { dns_throw(TypeError, "size() called on a non-list Element"); };
//@}
/// \name MapElement functions
......@@ -223,17 +210,17 @@ public:
/// Returns the ElementPtr at the given key
/// \param name The key of the Element to return
/// \return The ElementPtr at the given key
virtual ElementPtr get(const std::string& name) { throw TypeError(); } ;
virtual ElementPtr get(const std::string& name) { dns_throw(TypeError, "get(string) called on a non-map Element"); } ;
/// Sets the ElementPtr at the given key
/// \param name The key of the Element to set
virtual void set(const std::string& name, ElementPtr element) { throw TypeError(); };
virtual void set(const std::string& name, ElementPtr element) { dns_throw(TypeError, "set(name, element) called on a non-map Element"); };
/// Remove the ElementPtr at the given key
/// \param name The key of the Element to remove
virtual void remove(const std::string& name) { throw TypeError(); };
virtual void remove(const std::string& name) { dns_throw(TypeError, "remove(string) called on a non-map Element"); };
/// Checks if there is data at the given key
/// \param name The key of the Element to remove
/// \return true if there is data at the key, false if not.