json_common.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //
  2. // json_binder.cpp
  3. // json
  4. //
  5. // Created by Sam Jaffe on 4/23/16.
  6. //
  7. #include "json_common.hpp"
  8. #include <map>
  9. namespace json {
  10. namespace helper {
  11. namespace {
  12. std::string get_no_end_error(char expected, char found) {
  13. char str[64] = { '\0' };
  14. snprintf(str, sizeof(str),
  15. "Expected delimeter: ',' or '%c', got '%c' instead",
  16. expected, found);
  17. return str;
  18. }
  19. }
  20. namespace {
  21. std::map<numeric_token_info::parse_state, uint_jt> bases{
  22. { numeric_token_info::decimal, 10 },
  23. { numeric_token_info::octal, 8 },
  24. { numeric_token_info::hexadecimal, 16 }
  25. };
  26. std::map<numeric_token_info::parse_state, std::string> allowed{
  27. { numeric_token_info::decimal, "0123456789" },
  28. { numeric_token_info::octal, "01234567" },
  29. { numeric_token_info::hexadecimal, "0123456789aAbBcCdDeEfF" }
  30. };
  31. std::map<char, int_jt> values{
  32. { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 },
  33. { '4', 4 }, { '5', 5 }, { '6', 6 }, { '7', 7 },
  34. { '8', 8 }, { '9', 9 }, { 'a', 10 }, { 'A', 10 },
  35. { 'b', 11 }, { 'B', 11 }, { 'c', 12 }, { 'C', 12 },
  36. { 'd', 13 }, { 'D', 13 }, { 'e', 14 }, { 'E', 14 },
  37. { 'f', 15 }, { 'F', 15 }
  38. };
  39. std::map<numeric_token_info::parse_state, uint_jt> thresholds{
  40. { numeric_token_info::decimal, UINT_JT_MAX / 10 },
  41. { numeric_token_info::octal, UINT_JT_MAX / 8 },
  42. { numeric_token_info::hexadecimal, UINT_JT_MAX / 16 }
  43. };
  44. std::map<numeric_token_info::parse_state, int_jt> last_digits{
  45. { numeric_token_info::decimal, INT_JT_MAX % 10 },
  46. { numeric_token_info::octal, INT_JT_MAX % 8 },
  47. { numeric_token_info::hexadecimal, INT_JT_MAX % 16 }
  48. };
  49. }
  50. // TODO - parse hex and octal
  51. numeric_token_info::numeric_token_info(char const * start)
  52. : val(0)
  53. , base(decimal)
  54. , it(start)
  55. , end(start)
  56. , is_double(false)
  57. , is_negative(*start == '-') {
  58. if ( is_negative ) { ++it; ++end; }
  59. if ( *end == '0' ) {
  60. base = octal;
  61. ++end;
  62. if (strchr("xX", *end)) {
  63. base = hexadecimal;
  64. ++end;
  65. }
  66. }
  67. for (char c = *end;
  68. !strchr(",]}", c) && !isspace(c);
  69. c = *++end) {
  70. is_double |= !strchr(allowed[base].c_str(), c);
  71. }
  72. if ( is_negative && base != decimal ) {
  73. throw json_numeric_exception{"Only decimal numbers can be recorded as negative"};
  74. }
  75. if (end == it) {
  76. throw unterminated_json_exception("Expected any token, got nothing");
  77. }
  78. }
  79. numeric_state numeric_token_info::parse_numeric() {
  80. uint_jt const threshold = thresholds[base];
  81. uint_jt const last_digit = last_digits[base];
  82. val = 0;
  83. for (char c = *it; it != end; c = *++it) {
  84. int_jt digit = values[c];
  85. if (val > threshold ||
  86. ( val == threshold && ((it + 1) < end ||
  87. digit > last_digit))) {
  88. return DOUBLE;
  89. }
  90. val = (bases[base] * val) + digit;
  91. }
  92. return INTEGER;
  93. }
  94. const char get_next_element(char const*& data) {
  95. while (isspace(*data)) ++data;
  96. return *data;
  97. }
  98. void advance_to_boundary(char const endtok, char const*& data) {
  99. char const next = get_next_element(data);
  100. if (next == ',') {
  101. ++data;
  102. } else if (next != endtok) {
  103. throw json::unterminated_json_exception(get_no_end_error(endtok, *data));
  104. }
  105. }
  106. int reverse_count(char const * data, char val) {
  107. int i = 0;
  108. while (*data-- == val) { ++i; }
  109. return i;
  110. }
  111. std::string replace_all(std::string && str, std::string const & from, std::string const & to) {
  112. std::string::size_type start_pos = 0;
  113. while((start_pos = str.find(from, start_pos)) != std::string::npos) {
  114. str.replace(start_pos, from.length(), to);
  115. start_pos += to.length(); // ...
  116. }
  117. return std::move(str);
  118. }
  119. std::string parse_string(char const * & data) {
  120. char const* start = data;
  121. while (*++data) {
  122. if (*data == '"' && (reverse_count(data-1, '\\') % 2) == 0) {
  123. return replace_all(std::string(start+1, data++), "\\\"", "\"");
  124. }
  125. }
  126. throw json::unterminated_json_exception("Could not locate end of string");
  127. }
  128. }
  129. }