Commit c5dd3881 authored by Jelte Jansen's avatar Jelte Jansen

rename ParseError to JSONError

check for overflow when parsing numbers


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac172@2114 e5f2f494-b856-4b98-b285-d166d9295462
parent b763a8e0
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <boost/algorithm/string.hpp> // for iequals #include <boost/algorithm/string.hpp> // for iequals
#include <cmath>
using namespace std; using namespace std;
namespace { namespace {
...@@ -201,14 +203,14 @@ Element::find(const std::string& identifier UNUSED_PARAM, ...@@ -201,14 +203,14 @@ Element::find(const std::string& identifier UNUSED_PARAM,
namespace { namespace {
inline void inline void
throwParseError(const std::string& error, const std::string& file, int line = 0, int pos = 0) throwJSONError(const std::string& error, const std::string& file, int line = 0, int pos = 0)
{ {
if (line != 0 || pos != 0) { if (line != 0 || pos != 0) {
std::stringstream ss; std::stringstream ss;
ss << error << " in " + file + ":" << line << ":" << pos; ss << error << " in " + file + ":" << line << ":" << pos;
throw ParseError(ss.str()); throw JSONError(ss.str());
} else { } else {
throw ParseError(error); throw JSONError(error);
} }
} }
} }
...@@ -321,17 +323,17 @@ skip_to(std::istream &in, const std::string& file, int& line, ...@@ -321,17 +323,17 @@ skip_to(std::istream &in, const std::string& file, int& line,
--pos; --pos;
return; return;
} else { } else {
throwParseError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos); throwJSONError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
} }
} }
throwParseError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos); throwJSONError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
} }
// TODO: Should we check for all other official escapes here (and // TODO: Should we check for all other official escapes here (and
// error on the rest)? // 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 (JSONError)
{ {
char c = 0; char c = 0;
std::stringstream ss; std::stringstream ss;
...@@ -341,7 +343,7 @@ str_from_stringstream(std::istream &in, const std::string& file, const int line, ...@@ -341,7 +343,7 @@ str_from_stringstream(std::istream &in, const std::string& file, const int line,
c = in.get(); c = in.get();
++pos; ++pos;
} else { } else {
throwParseError("String expected", file, line, pos); throwJSONError("String expected", file, line, pos);
} }
while (c != EOF && c != '"') { while (c != EOF && c != '"') {
ss << c; ss << c;
...@@ -375,7 +377,9 @@ count_chars_i(int i) { ...@@ -375,7 +377,9 @@ count_chars_i(int i) {
return result; return result;
} }
// TODO: range checks // 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)
ElementPtr ElementPtr
from_stringstream_number(std::istream &in, int &pos) { from_stringstream_number(std::istream &in, int &pos) {
int i, d_i; int i, d_i;
...@@ -384,43 +388,43 @@ from_stringstream_number(std::istream &in, int &pos) { ...@@ -384,43 +388,43 @@ from_stringstream_number(std::istream &in, int &pos) {
in >> i; in >> i;
pos += count_chars_i(i); pos += count_chars_i(i);
if (in.fail()) {
throw JSONError("Bad integer or overflow");
}
if (in.peek() == '.') { if (in.peek() == '.') {
is_double = true; is_double = true;
in.get(); in.get();
pos++; pos++;
in >> d_i; in >> d_i;
if (in.fail()) {
throw JSONError("Bad real or overflow");
}
d = i + (double)d_i / 10; d = i + (double)d_i / 10;
pos += count_chars_i(d_i); pos += count_chars_i(d_i);
} }
if (in.peek() == 'e' || in.peek() == 'E') { if (in.peek() == 'e' || in.peek() == 'E') {
int e; int e;
double p;
in.get(); in.get();
pos++; pos++;
in >> e; in >> e;
if (in.fail()) {
throw JSONError("Bad exponent or overflow");
}
pos += count_chars_i(e); pos += count_chars_i(e);
if (e == 0) { p = pow(10, e);
d = 1; if (p == HUGE_VAL) {
i = 1; throw JSONError("Bad exponent or overflow");
} else if (e < 0) { }
if (!is_double) { if (is_double) {
is_double = true; d = d * p;
d = i;
}
while (e < 0) {
d = d / 10;
e++;
}
} else { } else {
if (is_double) { if (p > 1.0) {
while (e > 0) { i = i * p;
d = d * 10;
e--;
}
} else { } else {
while (e > 0) { // negative exponent, so type becomes a double
i = i * 10; is_double = true;
e--; d = i * p;
}
} }
} }
} }
...@@ -442,7 +446,7 @@ from_stringstream_bool(std::istream &in, const std::string& file, ...@@ -442,7 +446,7 @@ from_stringstream_bool(std::istream &in, const std::string& file,
} else if (boost::iequals(word, "False")) { } else if (boost::iequals(word, "False")) {
return Element::create(false); return Element::create(false);
} else { } else {
throwParseError(std::string("Bad boolean value: ") + word, file, line, pos); throwJSONError(std::string("Bad boolean value: ") + word, file, line, pos);
// above is a throw shortcur, return empty is never reached // above is a throw shortcur, return empty is never reached
return ElementPtr(); return ElementPtr();
} }
...@@ -456,7 +460,7 @@ from_stringstream_null(std::istream &in, const std::string& file, ...@@ -456,7 +460,7 @@ from_stringstream_null(std::istream &in, const std::string& file,
if (boost::iequals(word, "null")) { if (boost::iequals(word, "null")) {
return Element::create(); return Element::create();
} else { } else {
throwParseError(std::string("Bad null value: ") + word, file, line, pos); throwJSONError(std::string("Bad null value: ") + word, file, line, pos);
return ElementPtr(); return ElementPtr();
} }
} }
...@@ -503,7 +507,7 @@ from_stringstream_map(std::istream &in, const std::string& file, int& line, ...@@ -503,7 +507,7 @@ from_stringstream_map(std::istream &in, const std::string& file, int& line,
if (key.length() > 255) { if (key.length() > 255) {
// Map tag has one-byte length field in wire format, so the // Map tag has one-byte length field in wire format, so the
// length cannot exceed 255. // length cannot exceed 255.
throwParseError("Map tag is too long", file, line, pos); throwJSONError("Map tag is too long", file, line, pos);
} }
skip_to(in, file, line, pos, ":", " \t\n"); skip_to(in, file, line, pos, ":", " \t\n");
...@@ -524,20 +528,20 @@ from_stringstream_map(std::istream &in, const std::string& file, int& line, ...@@ -524,20 +528,20 @@ from_stringstream_map(std::istream &in, const std::string& file, int& line,
} }
ElementPtr ElementPtr
Element::fromJSON(std::istream& in) throw(ParseError) { Element::fromJSON(std::istream& in) throw(JSONError) {
int line = 1, pos = 1; int line = 1, pos = 1;
return fromJSON(in, "<istream>", line, pos); return fromJSON(in, "<istream>", line, pos);
} }
ElementPtr ElementPtr
Element::fromJSON(std::istream& in, const std::string& file_name) throw(ParseError) Element::fromJSON(std::istream& in, const std::string& file_name) throw(JSONError)
{ {
int line = 1, pos = 1; int line = 1, pos = 1;
return fromJSON(in, file_name, line, pos); return fromJSON(in, file_name, line, pos);
} }
ElementPtr ElementPtr
Element::fromJSON(std::istream &in, const std::string& file, int& line, int& pos) throw(ParseError) Element::fromJSON(std::istream &in, const std::string& file, int& line, int& pos) throw(JSONError)
{ {
char c = 0; char c = 0;
ElementPtr element; ElementPtr element;
...@@ -590,14 +594,14 @@ Element::fromJSON(std::istream &in, const std::string& file, int& line, int& pos ...@@ -590,14 +594,14 @@ Element::fromJSON(std::istream &in, const std::string& file, int& line, int& pos
case EOF: case EOF:
break; break;
default: default:
throwParseError(std::string("error: unexpected character ") + c, file, line, pos); throwJSONError(std::string("error: unexpected character ") + c, file, line, pos);
break; break;
} }
} }
if (el_read) { if (el_read) {
return element; return element;
} else { } else {
throw ParseError("nothing read"); throw JSONError("nothing read");
} }
} }
......
...@@ -48,9 +48,9 @@ public: ...@@ -48,9 +48,9 @@ public:
// i'd like to use Exception here but we need one that is derived from // 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 // 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) // i want to add some values to any static data string that is provided)
class ParseError : public std::runtime_error { class JSONError : public std::runtime_error {
public: public:
ParseError(const std::string &err) : std::runtime_error(err) {}; JSONError(const std::string &err) : std::runtime_error(err) {};
}; };
/// ///
...@@ -298,7 +298,7 @@ public: ...@@ -298,7 +298,7 @@ public:
/// \brief These functions will parse the given string (JSON) /// \brief These functions will parse the given string (JSON)
/// representation of a compound element. If there is a parse /// representation of a compound element. If there is a parse
/// error, an exception of the type isc::data::ParseError is thrown. /// error, an exception of the type isc::data::JSONError is thrown.
//@{ //@{
/// Creates an Element from the given JSON string /// Creates an Element from the given JSON string
...@@ -313,8 +313,8 @@ public: ...@@ -313,8 +313,8 @@ public:
/// \param in The string to parse the element from /// \param in The string to parse the element from
/// \return An ElementPtr that contains the element(s) specified /// \return An ElementPtr that contains the element(s) specified
/// in the given input stream. /// in the given input stream.
static ElementPtr fromJSON(std::istream& in) throw(ParseError); static ElementPtr fromJSON(std::istream& in) throw(JSONError);
static ElementPtr fromJSON(std::istream& in, const std::string& file_name) throw(ParseError); static ElementPtr fromJSON(std::istream& in, const std::string& file_name) throw(JSONError);
/// Creates an Element from the given input stream, where we keep /// Creates an Element from the given input stream, where we keep
/// track of the location in the stream for error reporting. /// track of the location in the stream for error reporting.
...@@ -327,7 +327,7 @@ public: ...@@ -327,7 +327,7 @@ public:
/// \return An ElementPtr that contains the element(s) specified /// \return An ElementPtr that contains the element(s) specified
/// in the given input stream. /// in the given input stream.
// make this one private? // make this one private?
static ElementPtr fromJSON(std::istream& in, const std::string& file, int& line, int &pos) throw(ParseError); static ElementPtr fromJSON(std::istream& in, const std::string& file, int& line, int &pos) throw(JSONError);
//@} //@}
/// \name Wire format factory functions /// \name Wire format factory functions
......
...@@ -44,9 +44,10 @@ TEST(Element, type) { ...@@ -44,9 +44,10 @@ TEST(Element, type) {
EXPECT_EQ(list_el.getType(), Element::list); EXPECT_EQ(list_el.getType(), Element::list);
MapElement map_el = MapElement(); MapElement map_el = MapElement();
EXPECT_EQ(map_el.getType(), Element::map); EXPECT_EQ(map_el.getType(), Element::map);
} }
TEST(Element, from_and_to_str) { TEST(Element, from_and_to_json) {
// this test checks whether the str() method returns the same // this test checks whether the str() method returns the same
// string that was used for creation // string that was used for creation
ElementPtr el; ElementPtr el;
...@@ -73,7 +74,7 @@ TEST(Element, from_and_to_str) { ...@@ -73,7 +74,7 @@ TEST(Element, from_and_to_str) {
// some parse errors // some parse errors
try { try {
Element::fromJSON("{1}"); Element::fromJSON("{1}");
} catch (isc::data::ParseError pe) { } catch (isc::data::JSONError pe) {
std::string s = std::string(pe.what()); std::string s = std::string(pe.what());
EXPECT_EQ(s, "String expected in <string>:1:3"); EXPECT_EQ(s, "String expected in <string>:1:3");
} }
...@@ -89,7 +90,7 @@ TEST(Element, from_and_to_str) { ...@@ -89,7 +90,7 @@ TEST(Element, from_and_to_str) {
sv.push_back(""); sv.push_back("");
BOOST_FOREACH(std::string s, sv) { BOOST_FOREACH(std::string s, sv) {
EXPECT_THROW(el = Element::fromJSON(s), isc::data::ParseError); EXPECT_THROW(el = Element::fromJSON(s), isc::data::JSONError);
} }
// some json specific format tests, here the str() output is // some json specific format tests, here the str() output is
...@@ -102,6 +103,13 @@ TEST(Element, from_and_to_str) { ...@@ -102,6 +103,13 @@ TEST(Element, from_and_to_str) {
EXPECT_EQ("100", Element::fromJSON("1.0e2")->str()); EXPECT_EQ("100", Element::fromJSON("1.0e2")->str());
EXPECT_EQ("0.01", Element::fromJSON("1.0e-2")->str()); EXPECT_EQ("0.01", Element::fromJSON("1.0e-2")->str());
EXPECT_EQ("0.012", Element::fromJSON("1.2e-2")->str()); EXPECT_EQ("0.012", Element::fromJSON("1.2e-2")->str());
EXPECT_THROW(Element::fromJSON("12345678901234567890")->str(), JSONError);
EXPECT_THROW(Element::fromJSON("1.12345678901234567890")->str(), JSONError);
EXPECT_THROW(Element::fromJSON("1.1e12345678901234567890")->str(), JSONError);
EXPECT_THROW(Element::fromJSON("1e12345678901234567890")->str(), JSONError);
EXPECT_THROW(Element::fromJSON("1e50000")->str(), JSONError);
} }
TEST(Element, create_and_value_throws) { TEST(Element, create_and_value_throws) {
...@@ -231,7 +239,7 @@ TEST(Element, MapElement) { ...@@ -231,7 +239,7 @@ TEST(Element, MapElement) {
long_maptag.push_back('f'); long_maptag.push_back('f');
EXPECT_THROW(Element::fromJSON("{ \"" + long_maptag + EXPECT_THROW(Element::fromJSON("{ \"" + long_maptag +
"\": \"bar\"}"), "\": \"bar\"}"),
ParseError); JSONError);
EXPECT_THROW(el->set(long_maptag, Element::create("bar")), TypeError); EXPECT_THROW(el->set(long_maptag, Element::create("bar")), TypeError);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment