json_common.cpp 4.4 KB

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