Commit 2568b6c2 authored by Jelte Jansen's avatar Jelte Jansen
Browse files

created toJSON functions (which are mostly the old str() ones, str() is now a...

created toJSON functions (which are mostly the old str() ones, str() is now a general Element function that calls toJSON)
toWire now also simply calls toJSON(), so str() and toWire are the same for now (in the future we could add formatting to str version)
Added NullElement, and support for reading of exponent format
updated tests


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac172@2110 e5f2f494-b856-4b98-b285-d166d9295462
parent cc99c8a3
...@@ -272,42 +272,41 @@ class BoB: ...@@ -272,42 +272,41 @@ class BoB:
if self.verbose: if self.verbose:
sys.stdout.write("[bind10] ccsession started\n") sys.stdout.write("[bind10] ccsession started\n")
## TODO: UNCOMMENT (commented out, doing json for python first) # start the xfrout before auth-server, to make sure every xfr-query can
# # start the xfrout before auth-server, to make sure every xfr-query can # be processed properly.
# # be processed properly. xfrout_args = ['b10-xfrout']
# xfrout_args = ['b10-xfrout'] if self.verbose:
# if self.verbose: sys.stdout.write("[bind10] Starting b10-xfrout\n")
# sys.stdout.write("[bind10] Starting b10-xfrout\n") xfrout_args += ['-v']
# xfrout_args += ['-v'] try:
# try: xfrout = ProcessInfo("b10-xfrout", xfrout_args,
# xfrout = ProcessInfo("b10-xfrout", xfrout_args, c_channel_env )
# c_channel_env ) except Exception as e:
# except Exception as e: c_channel.process.kill()
# c_channel.process.kill() bind_cfgd.process.kill()
# bind_cfgd.process.kill() return "Unable to start b10-xfrout; " + str(e)
# return "Unable to start b10-xfrout; " + str(e) self.processes[xfrout.pid] = xfrout
# self.processes[xfrout.pid] = xfrout if self.verbose:
# if self.verbose: sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % xfrout.pid)
# sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % xfrout.pid)
# # start b10-auth
# # start b10-auth # XXX: this must be read from the configuration manager in the future
# # XXX: this must be read from the configuration manager in the future authargs = ['b10-auth', '-p', str(self.auth_port)]
# authargs = ['b10-auth', '-p', str(self.auth_port)] if self.verbose:
# if self.verbose: sys.stdout.write("[bind10] Starting b10-auth using port %d\n" %
# sys.stdout.write("[bind10] Starting b10-auth using port %d\n" % self.auth_port)
# self.auth_port) authargs += ['-v']
# authargs += ['-v'] try:
# try: auth = ProcessInfo("b10-auth", authargs,
# auth = ProcessInfo("b10-auth", authargs, c_channel_env)
# c_channel_env) except Exception as e:
# except Exception as e: c_channel.process.kill()
# c_channel.process.kill() bind_cfgd.process.kill()
# bind_cfgd.process.kill() xfrout.process.kill()
# xfrout.process.kill() return "Unable to start b10-auth; " + str(e)
# return "Unable to start b10-auth; " + str(e) self.processes[auth.pid] = auth
# self.processes[auth.pid] = auth if self.verbose:
# if self.verbose: sys.stdout.write("[bind10] Started b10-auth (PID %d)\n" % auth.pid)
# sys.stdout.write("[bind10] Started b10-auth (PID %d)\n" % auth.pid)
# start b10-xfrin # start b10-xfrin
xfrin_args = ['b10-xfrin'] xfrin_args = ['b10-xfrin']
......
...@@ -50,6 +50,28 @@ const unsigned char ITEM_LENGTH_MASK = 0x30; ...@@ -50,6 +50,28 @@ const unsigned char ITEM_LENGTH_MASK = 0x30;
namespace isc { namespace isc {
namespace data { namespace data {
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);
}
// //
// The following methods are effectively empty, and their parameters are // The following methods are effectively empty, and their parameters are
// unused. To silence compilers that warn unused function parameters, // unused. To silence compilers that warn unused function parameters,
...@@ -202,6 +224,11 @@ bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b) { ...@@ -202,6 +224,11 @@ bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b) {
// //
// factory functions // factory functions
// //
ElementPtr
Element::create() {
return ElementPtr(new NullElement());
}
ElementPtr ElementPtr
Element::create(const int i) { Element::create(const int i) {
return ElementPtr(new IntElement(i)); return ElementPtr(new IntElement(i));
...@@ -306,6 +333,8 @@ skip_to(std::istream &in, const std::string& file, int& line, ...@@ -306,6 +333,8 @@ skip_to(std::istream &in, const std::string& file, int& line,
throwParseError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos); throwParseError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
} }
// TODO: Should we check for all other official escapes here (and
// error on the rest)?
std::string std::string
str_from_stringstream(std::istream &in, const std::string& file, const int line, str_from_stringstream(std::istream &in, const std::string& file, const int line,
int& pos) throw (ParseError) int& pos) throw (ParseError)
...@@ -352,26 +381,57 @@ count_chars_i(int i) { ...@@ -352,26 +381,57 @@ count_chars_i(int i) {
return result; return result;
} }
inline int // TODO: range checks
count_chars_d(double d) {
int result = 1;
while (d < 1.0) {
++result;
d = d * 10;
}
return result;
}
ElementPtr ElementPtr
from_stringstream_int_or_double(std::istream &in, int &pos) { from_stringstream_number(std::istream &in, int &pos) {
int i; int i, d_i;
double d = 0.0;
bool is_double = false;
in >> i; in >> i;
pos += count_chars_i(i); pos += count_chars_i(i);
if (in.peek() == '.') { if (in.peek() == '.') {
double d; is_double = true;
in >> d; in.get();
pos += count_chars_d(i); pos++;
d += i; in >> d_i;
d = i + (double)d_i / 10;
pos += count_chars_i(d_i);
}
if (in.peek() == 'e' || in.peek() == 'E') {
int e;
in.get();
pos++;
in >> e;
pos += count_chars_i(e);
if (e == 0) {
d = 1;
i = 1;
} else if (e < 0) {
if (!is_double) {
is_double = true;
d = i;
}
while (e < 0) {
d = d / 10;
e++;
}
} else {
if (is_double) {
while (e > 0) {
d = d * 10;
e--;
}
} else {
while (e > 0) {
i = i * 10;
e--;
}
}
}
}
if (is_double) {
return Element::create(d); return Element::create(d);
} else { } else {
return Element::create(i); return Element::create(i);
...@@ -394,6 +454,19 @@ from_stringstream_bool(std::istream &in, const std::string& file, ...@@ -394,6 +454,19 @@ from_stringstream_bool(std::istream &in, const std::string& file,
} }
} }
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 {
throwParseError(std::string("Bad null value: ") + word, file, line, pos);
return ElementPtr();
}
}
ElementPtr ElementPtr
from_stringstream_string(std::istream& in, const std::string& file, int& line, int& pos) from_stringstream_string(std::istream& in, const std::string& file, int& line, int& pos)
{ {
...@@ -491,7 +564,7 @@ Element::createFromString(std::istream &in, const std::string& file, int& line, ...@@ -491,7 +564,7 @@ Element::createFromString(std::istream &in, const std::string& file, int& line,
case '9': case '9':
case '0': case '0':
in.putback(c); in.putback(c);
element = from_stringstream_int_or_double(in, pos); element = from_stringstream_number(in, pos);
el_read = true; el_read = true;
break; break;
case 't': case 't':
...@@ -502,6 +575,11 @@ Element::createFromString(std::istream &in, const std::string& file, int& line, ...@@ -502,6 +575,11 @@ Element::createFromString(std::istream &in, const std::string& file, int& line,
element = from_stringstream_bool(in, file, line, pos); element = from_stringstream_bool(in, file, line, pos);
el_read = true; el_read = true;
break; break;
case 'n':
in.putback(c);
element = from_stringstream_null(in, file, line, pos);
el_read = true;
break;
case '"': case '"':
in.putback('"'); in.putback('"');
element = from_stringstream_string(in, file, line, pos); element = from_stringstream_string(in, file, line, pos);
...@@ -536,44 +614,47 @@ Element::createFromString(const std::string &in) { ...@@ -536,44 +614,47 @@ Element::createFromString(const std::string &in) {
return createFromString(ss, "<string>"); return createFromString(ss, "<string>");
} }
// // to JSON format
// a general to_str() function
// void
std::string IntElement::toJSON(std::stringstream& ss)
IntElement::str() { {
std::stringstream ss;
ss << intValue(); ss << intValue();
return ss.str();
} }
std::string void
DoubleElement::str() { DoubleElement::toJSON(std::stringstream& ss)
std::stringstream ss; {
ss << doubleValue(); ss << doubleValue();
return ss.str();
} }
std::string void
BoolElement::str() { BoolElement::toJSON(std::stringstream& ss)
{
if (b) { if (b) {
return "True"; ss << "true";
} else { } else {
return "False"; ss << "false";
} }
} }
std::string void
StringElement::str() { NullElement::toJSON(std::stringstream& ss)
std::stringstream ss; {
ss << "null";
}
void
StringElement::toJSON(std::stringstream& ss)
{
ss << "\""; ss << "\"";
ss << stringValue(); ss << stringValue();
ss << "\""; ss << "\"";
return ss.str();
} }
std::string void
ListElement::str() { ListElement::toJSON(std::stringstream& ss)
std::stringstream ss; {
ss << "[ "; ss << "[ ";
const std::vector<ElementPtr>& v = listValue(); const std::vector<ElementPtr>& v = listValue();
...@@ -582,16 +663,15 @@ ListElement::str() { ...@@ -582,16 +663,15 @@ ListElement::str() {
if (it != v.begin()) { if (it != v.begin()) {
ss << ", "; ss << ", ";
} }
ss << (*it)->str(); (*it)->toJSON(ss);
} }
ss << " ]"; ss << " ]";
return ss.str();
} }
std::string void
MapElement::str() { MapElement::toJSON(std::stringstream& ss)
std::stringstream ss; {
ss << "{"; ss << "{ ";
const std::map<std::string, ElementPtr>& m = mapValue(); const std::map<std::string, ElementPtr>& m = mapValue();
for (std::map<std::string, ElementPtr>::const_iterator it = m.begin(); for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
...@@ -601,13 +681,12 @@ MapElement::str() { ...@@ -601,13 +681,12 @@ MapElement::str() {
} }
ss << "\"" << (*it).first << "\": "; ss << "\"" << (*it).first << "\": ";
if ((*it).second) { if ((*it).second) {
ss << (*it).second->str(); (*it).second->toJSON(ss);
} else { } else {
ss << "None"; ss << "None";
} }
} }
ss << "}"; ss << " }";
return ss.str();
} }
// throws when one of the types in the path (except the one // throws when one of the types in the path (except the one
...@@ -634,169 +713,12 @@ MapElement::find(const std::string& id) { ...@@ -634,169 +713,12 @@ MapElement::find(const std::string& id) {
} }
} }
//
// 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 ElementPtr
Element::fromWire(const std::string& s) { Element::fromWire(const std::string& s) {
std::stringstream ss; std::stringstream ss;
ss << s; ss << s;
return fromWire(ss, s.length()); int line = 0, pos = 0;
return createFromString(ss, "<wire>", line, pos);
} }
ElementPtr ElementPtr
...@@ -804,159 +726,15 @@ Element::fromWire(std::stringstream& in, int length) { ...@@ -804,159 +726,15 @@ Element::fromWire(std::stringstream& in, int length) {
// //
// Check protocol version // Check protocol version
// //
for (int i = 0 ; i < 4 ; ++i) { //for (int i = 0 ; i < 4 ; ++i) {
const unsigned char version_byte = get_byte(in); // const unsigned char version_byte = get_byte(in);
if (PROTOCOL_VERSION[i] != version_byte) { // if (PROTOCOL_VERSION[i] != version_byte) {
throw DecodeError("Protocol version incorrect"); // throw DecodeError("Protocol version incorrect");
} // }
} //}
length -= 4; //length -= 4;
int line = 0, pos = 0;
return (decode_hash(in, length)); return createFromString(in, "<wire>", line, pos);
}
//
// 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];