Module: sems Branch: master Commit: 9762fba26189e72dd6dcbafd8cb1dac2ae7da81b URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sems/?a=commit;h=9762fba26189e72dd6dcbafd8cb1dac2ae7da81b
Author: Stefan Sayer <[email protected]> Committer: Stefan Sayer <[email protected]> Date: Fri Jul 16 02:14:54 2010 +0200 core: json: add number with exp format parsing --- core/jsonxx.cpp | 230 +++++++++++++++++++++++++++++++++++++++++- core/tests/test_jsonarg.cpp | 53 ++++++++++ 2 files changed, 277 insertions(+), 6 deletions(-) diff --git a/core/jsonxx.cpp b/core/jsonxx.cpp index e3b307a..41cddf5 100644 --- a/core/jsonxx.cpp +++ b/core/jsonxx.cpp @@ -33,6 +33,10 @@ OTHER DEALINGS IN THE SOFTWARE. #include <iostream> #include <sstream> +#include <math.h> + +#include "log.h" + namespace jsonxx { void eat_whitespaces(std::istream& input) { @@ -125,6 +129,7 @@ bool parse_null(std::istream& input) { return false; } + /* bool parse_float(std::istream& input, double* value) { eat_whitespaces(input); char ch; @@ -160,6 +165,8 @@ bool parse_float(std::istream& input, double* value) { return false; } } + */ + bool parse_number(std::istream& input, long* value) { eat_whitespaces(input); @@ -188,27 +195,238 @@ bool parse_number(std::istream& input, long* value) { } } + bool parse_number(std::istream& input, int* value) { eat_whitespaces(input); char ch; std::string value_str; + std::string exp_str; // whole exp part + std::string exp_value_str; // value of exp part int sign = 1; + int e_sign = 1; + bool correct = true; + int e_value; + + enum { + p_number, + p_e, + p_enumber + } p_state = p_number; + if (match("-", input)) { sign = -1; } else { match("+", input); } + while(input && !input.eof()) { - input.get(ch); - if (!isdigit(ch)) { - input.putback(ch); - break; - } - value_str.push_back(ch); + input.get(ch); + switch (p_state) { + case p_number: { + // DBG("st = p_number, ch=%c\n",ch); + if (ch == 'E' || ch == 'e') { + exp_str.push_back(ch); + p_state = p_e; + continue; + } + if (!isdigit(ch)) { + input.putback(ch); + correct = false; + break; + } + value_str.push_back(ch); + } break; + + case p_e: { + // DBG("st = p_e, ch=%c\n",ch); + + if (ch == '+') { + exp_str.push_back(ch); + p_state = p_enumber; + } else if (ch == '-') { + e_sign = -1; + exp_str.push_back(ch); + p_state = p_enumber; + } else if (isdigit(ch)) { + exp_value_str.push_back(ch); + exp_str.push_back(ch); + p_state = p_enumber; + } else { + input.putback(ch); + correct = false; + } + } break; + + case p_enumber: { + // DBG("st = p_enumber, ch=%c\n",ch); + + if (isdigit(ch)) { + exp_value_str.push_back(ch); + exp_str.push_back(ch); + } else { + input.putback(ch); + correct = false; + } + } break; + + } + + if (!correct) + break; + } + + if (p_state == p_e) { + // todo: check also some other error states + for (std::string::reverse_iterator r_it= + exp_str.rbegin(); r_it != exp_str.rend(); r_it++) + input.putback(*r_it); + for (std::string::reverse_iterator r_it= + value_str.rbegin(); r_it != value_str.rend(); r_it++) + input.putback(*r_it); + return false; } + if (value_str.size() > 0) { std::istringstream(value_str) >> *value; *value*=sign; + + if (exp_value_str.size()) { + std::istringstream(exp_value_str) >> e_value; + + if (e_value && e_sign==-1) { + // should have been catched by parse_float + for (std::string::reverse_iterator r_it= + exp_str.rbegin(); r_it != exp_str.rend(); r_it++) + input.putback(*r_it); + for (std::string::reverse_iterator r_it= + value_str.rbegin(); r_it != value_str.rend(); r_it++) + input.putback(*r_it); + + return false; + } + *value *= pow(10, e_value); + } + + return true; + } else { + return false; + } +} + + +bool parse_float(std::istream& input, double* value) { + eat_whitespaces(input); + char ch; + std::string value_str; + std::string exp_str; // whole exp part + std::string exp_value_str; // value of exp part + int sign = 1; + int e_sign = 1; + bool correct = true; + int e_value; + bool has_dot = false; + + enum { + p_number, + p_e, + p_enumber + } p_state = p_number; + + if (match("-", input)) { + sign = -1; + } else { + match("+", input); + } + + while(input && !input.eof()) { + input.get(ch); + bool end = false; + switch (p_state) { + case p_number: { + // DBG("st = p_number, ch=%c\n",ch); + if (ch == 'E' || ch == 'e') { + exp_str.push_back(ch); + p_state = p_e; + continue; + } + if (ch == '.') { + if (has_dot) { + correct = false; + break; + } + has_dot = true; + value_str.push_back(ch); + continue; + } + + if (!isdigit(ch)) { + input.putback(ch); + end = true; + break; + } + value_str.push_back(ch); + } break; + + case p_e: { + // DBG("st = p_e, ch=%c\n",ch); + if (ch == '+') { + exp_str.push_back(ch); + p_state = p_enumber; + } else if (ch == '-') { + e_sign = -1; + exp_str.push_back(ch); + p_state = p_enumber; + } else if (isdigit(ch)) { + exp_value_str.push_back(ch); + exp_str.push_back(ch); + p_state = p_enumber; + } else { + input.putback(ch); + correct = false; + } + } break; + + case p_enumber: { + // DBG("st = p_enumber, ch=%c\n",ch); + + if (isdigit(ch)) { + exp_value_str.push_back(ch); + exp_str.push_back(ch); + } else { + input.putback(ch); + end = true; + } + } break; + + } + + if (end || !correct) + break; + } + + // DBG("correct = %s, has_dot = %s, e_sign = %d, exp_value_str.size() = %zd\n", + // correct?"true":"false",has_dot?"true":"false",e_sign,exp_value_str.size()); + if (!correct || (!has_dot && !(e_sign == -1 && exp_value_str.size())) || p_state == p_e) { + // todo: check also some other error states + for (std::string::reverse_iterator r_it= + exp_str.rbegin(); r_it != exp_str.rend(); r_it++) + input.putback(*r_it); + for (std::string::reverse_iterator r_it= + value_str.rbegin(); r_it != value_str.rend(); r_it++) + input.putback(*r_it); + return false; + } + + if (value_str.size() > 0) { + std::istringstream(value_str) >> *value; + *value*=sign; + + if (exp_value_str.size()) { + std::istringstream(exp_value_str) >> e_value; + + *value *= pow(10, e_sign*e_value); + } + return true; } else { return false; diff --git a/core/tests/test_jsonarg.cpp b/core/tests/test_jsonarg.cpp index 7de8533..2e25db8 100644 --- a/core/tests/test_jsonarg.cpp +++ b/core/tests/test_jsonarg.cpp @@ -49,4 +49,57 @@ FCTMF_SUITE_BGN(test_jsonarg) { fct_chk(rpc_params["result"][""].asInt()==1); } FCT_TEST_END(); + FCT_TEST_BGN(json_number_e_parse) { + string s = "{\"result\": 0E1}"; + // DBG("s.c_str() %s\n", s.c_str() ); + AmArg rpc_params; + fct_chk(json2arg(s.c_str(), rpc_params)); + fct_chk(isArgInt(rpc_params["result"]) && rpc_params["result"].asInt() == 0); + } FCT_TEST_END(); + + FCT_TEST_BGN(json_number_e_pow) { + string s = "{\"result\": 1E1}"; + // DBG("s.c_str() %s\n", s.c_str() ); + AmArg rpc_params; + fct_chk(json2arg(s.c_str(), rpc_params)); + fct_chk(isArgInt(rpc_params["result"]) && rpc_params["result"].asInt() == 10); + } FCT_TEST_END(); + + FCT_TEST_BGN(json_number_e_pow2) { + string s = "{\"result\": 5e0}"; + // DBG("s.c_str() %s\n", s.c_str() ); + AmArg rpc_params; + fct_chk(json2arg(s.c_str(), rpc_params)); + fct_chk(isArgInt(rpc_params["result"]) && rpc_params["result"].asInt() == 5); + } FCT_TEST_END(); + + FCT_TEST_BGN(json_number_e_wrong) { + string s = "{\"result\": 1E}"; + // DBG("s.c_str() %s\n", s.c_str() ); + AmArg rpc_params; + fct_chk(!json2arg(s.c_str(), rpc_params)); + } FCT_TEST_END(); + + FCT_TEST_BGN(json_number_e_powneg1) { + string s = "{\"result\": 1E-1}"; + // DBG("s.c_str() %s\n", s.c_str() ); + AmArg rpc_params; + fct_chk(json2arg(s.c_str(), rpc_params)); + // DBG("res: %s, type %d\n", AmArg::print(rpc_params["result"]).c_str(), rpc_params["result"].getType()); + + fct_chk(isArgDouble(rpc_params["result"])); + fct_chk(isArgDouble(rpc_params["result"]) && rpc_params["result"].asDouble() == 0.1); + } FCT_TEST_END(); + + FCT_TEST_BGN(json_number_float_parse) { + string s = "{\"result\": 1.21}"; + // DBG("s.c_str() %s\n", s.c_str() ); + AmArg rpc_params; + fct_chk(json2arg(s.c_str(), rpc_params)); + // DBG("res: %s, type %d\n", AmArg::print(rpc_params["result"]).c_str(), rpc_params["result"].getType()); + + fct_chk(isArgDouble(rpc_params["result"])); + fct_chk(isArgDouble(rpc_params["result"]) && rpc_params["result"].asDouble() == 1.21); + } FCT_TEST_END(); + } FCTMF_SUITE_END(); _______________________________________________ Semsdev mailing list [email protected] http://lists.iptel.org/mailman/listinfo/semsdev
