| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- //
- // json_binder.cpp
- // json
- //
- // Created by Sam Jaffe on 4/23/16.
- //
- #include "json_common.hpp"
- #include <map>
- 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<numeric_token_info::parse_state, uint_jt> bases{
- { numeric_token_info::decimal, 10 },
- { numeric_token_info::octal, 8 },
- { numeric_token_info::hexadecimal, 16 }
- };
- std::map<numeric_token_info::parse_state, std::string> allowed{
- { numeric_token_info::decimal, "0123456789" },
- { numeric_token_info::octal, "01234567" },
- { numeric_token_info::hexadecimal, "0123456789aAbBcCdDeEfF" }
- };
- std::map<char, uint_jt> 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<numeric_token_info::parse_state, uint_jt> 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<numeric_token_info::parse_state, uint_jt> 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) {
- uint_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");
- }
- }
- }
|