// // json_binder.cpp // json // // Created by Sam Jaffe on 4/23/16. // #include "json_common.hpp" #include namespace json { namespace helper { namespace { std::string get_no_end_error(char expected, char found) { char str[64] = { '\0' }; snprintf(str, sizeof(str), "Expected delimeter: ',' or '%c', got '%c' instead", expected, found); return str; } } namespace { std::map bases{ { numeric_token_info::decimal, 10 }, { numeric_token_info::octal, 8 }, { numeric_token_info::hexadecimal, 16 } }; std::map allowed{ { numeric_token_info::decimal, "0123456789" }, { numeric_token_info::octal, "01234567" }, { numeric_token_info::hexadecimal, "0123456789aAbBcCdDeEfF" } }; std::map values{ { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 }, { '4', 4 }, { '5', 5 }, { '6', 6 }, { '7', 7 }, { '8', 8 }, { '9', 9 }, { 'a', 10 }, { 'A', 10 }, { 'b', 11 }, { 'B', 11 }, { 'c', 12 }, { 'C', 12 }, { 'd', 13 }, { 'D', 13 }, { 'e', 14 }, { 'E', 14 }, { 'f', 15 }, { 'F', 15 } }; std::map thresholds{ { numeric_token_info::decimal, UINT_JT_MAX / 10 }, { numeric_token_info::octal, UINT_JT_MAX / 8 }, { numeric_token_info::hexadecimal, UINT_JT_MAX / 16 } }; std::map last_digits{ { numeric_token_info::decimal, INT_JT_MAX % 10 }, { numeric_token_info::octal, INT_JT_MAX % 8 }, { numeric_token_info::hexadecimal, INT_JT_MAX % 16 } }; } // TODO - parse hex and octal numeric_token_info::numeric_token_info(char const * start) : val(0) , base(decimal) , it(start) , end(start) , is_double(false) , is_negative(*start == '-') { if ( is_negative ) { ++it; ++end; } if ( *end == '0' ) { base = octal; ++end; if (strchr("xX", *end)) { base = hexadecimal; ++end; } } for (char c = *end; !strchr(",]}", c) && !isspace(c); c = *++end) { is_double |= !strchr(allowed[base].c_str(), c); } if ( is_negative && base != decimal ) { throw json_numeric_exception{"Only decimal numbers can be recorded as negative"}; } if (end == it) { throw unterminated_json_exception("Expected any token, got nothing"); } } numeric_state numeric_token_info::parse_numeric() { uint_jt const threshold = thresholds[base]; uint_jt const last_digit = last_digits[base]; val = 0; for (char c = *it; it != end; c = *++it) { int_jt digit = values[c]; if (val > threshold || ( val == threshold && ((it + 1) < end || digit > last_digit))) { return DOUBLE; } val = (bases[base] * val) + digit; } return INTEGER; } const char get_next_element(char const*& data) { while (isspace(*data)) ++data; return *data; } void advance_to_boundary(char const endtok, char const*& data) { char const next = get_next_element(data); if (next == ',') { ++data; } else if (next != endtok) { throw json::unterminated_json_exception(get_no_end_error(endtok, *data)); } } int reverse_count(char const * data, char val) { int i = 0; while (*data-- == val) { ++i; } return i; } std::string replace_all(std::string str, std::string const & from, std::string const & to) { std::string::size_type start_pos = 0; while((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); // ... } return std::move(str); } std::string parse_string(char const * & data) { char const* start = data; while (*++data) { if (*data == '"' && (reverse_count(data-1, '\\') % 2) == 0) { return replace_all(std::string(start+1, data++), "\\\"", "\""); } } throw json::unterminated_json_exception("Could not locate end of string"); } } }