json_common.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. //
  2. // json_common.h
  3. // json
  4. //
  5. // Created by Sam Jaffe on 4/22/16.
  6. //
  7. #pragma once
  8. #include <cstdint>
  9. #include <cstdlib>
  10. #include <stdexcept>
  11. #include <string>
  12. #include <errno.h>
  13. namespace json {
  14. using string_jt = std::string;
  15. using double_jt = double;
  16. using int_jt = int32_t;
  17. using uint_jt = uint32_t;
  18. using bool_jt = bool;
  19. class value;
  20. class malformed_json_exception :
  21. public std::domain_error {
  22. using std::domain_error::domain_error;
  23. };
  24. class unterminated_json_exception :
  25. public malformed_json_exception {
  26. using malformed_json_exception::malformed_json_exception;
  27. };
  28. class json_numeric_exception :
  29. public std::domain_error {
  30. using std::domain_error::domain_error;
  31. };
  32. class json_numeric_width_exception :
  33. public json_numeric_exception {
  34. using json_numeric_exception::json_numeric_exception;
  35. };
  36. namespace {
  37. const constexpr json::int_jt INT_JT_MAX = std::numeric_limits<json::int_jt>::max();
  38. const constexpr json::int_jt INT_JT_MAX_LAST_DIGIT = (INT_JT_MAX % 10);
  39. const constexpr json::int_jt INT_JT_MIN = std::numeric_limits<json::int_jt>::min();
  40. const constexpr json::uint_jt INT_JT_OVER = json::uint_jt(INT_JT_MAX) + 1;
  41. const constexpr json::uint_jt UINT_JT_MAX = json::uint_jt(0) - 1;
  42. // const constexpr json::uint_jt UINT_JT_MIN = 0;
  43. }
  44. }
  45. namespace json { namespace parser {
  46. enum options {
  47. allow_all = 0x00,
  48. disable_unknown_keys = 0x01,
  49. disable_concatenated_json_bodies = 0x02,
  50. disable_all = 0xFF,
  51. };
  52. } }
  53. namespace json { namespace helper {
  54. const char get_next_element(char const*& data);
  55. enum numeric_state {
  56. DOUBLE, INTEGER
  57. };
  58. struct numeric_token_info {
  59. numeric_token_info(char const * start);
  60. numeric_state parse_numeric();
  61. uint_jt val;
  62. char const * it;
  63. char const * end;
  64. bool is_double;
  65. bool is_negative;
  66. };
  67. numeric_token_info get_numeric_token_info(char const * it);
  68. /**
  69. * @throws json::malformed_json_exception
  70. */
  71. void advance_to_boundary(char const endtok, char const *& data);
  72. /**
  73. * @throws json::malformed_json_exception
  74. */
  75. std::string parse_string(char const * & data);
  76. template <typename T>
  77. void parse_string(T& json, char const * & data) {
  78. json = parse_string(data);
  79. }
  80. template <typename T>
  81. T parse_double_impl(char const * begin, char const * & end) {
  82. return std::strtod(begin, const_cast<char**>(&end));
  83. }
  84. template <>
  85. inline float parse_double_impl<float>(char const * begin, char const * & end) {
  86. return std::strtof(begin, const_cast<char**>(&end));
  87. }
  88. template <>
  89. inline long double parse_double_impl<long double>(char const * begin, char const * & end) {
  90. return std::strtold(begin, const_cast<char**>(&end));
  91. }
  92. template <typename T>
  93. void parse_double(T& json, char const * & data) {
  94. char const * begin = data;
  95. errno = 0;
  96. T tmp = parse_double_impl<T>(begin, data);
  97. if (errno != 0) {
  98. throw json::json_numeric_width_exception{"Number is out-of-range for floating-point type"};
  99. } else if ( begin == data ) {
  100. throw json::json_numeric_exception{"Expected numeric data"};
  101. }
  102. errno = 0;
  103. json = std::move(tmp);
  104. }
  105. template <typename J>
  106. void parse_numeric(J & json, char const * & data) {
  107. numeric_token_info info = data;
  108. if ( info.is_double || info.parse_numeric() == DOUBLE ) {
  109. if (std::is_integral<J>::value) {
  110. throw json::json_numeric_exception{"Expected integer, got double"};
  111. }
  112. helper::parse_double(json, data);
  113. } else {
  114. uint_jt const val = info.val;
  115. if (fls(val) > std::numeric_limits<J>::digits + info.is_negative) {
  116. throw json::json_numeric_width_exception{"Integer width too small for parsed value"};
  117. }
  118. if (info.is_negative) {
  119. if (!std::is_signed<J>::value) {
  120. throw json::json_numeric_exception{"Expected signed integer"};
  121. }
  122. if (val == INT_JT_OVER) {
  123. json = (J) INT_JT_MIN; // Cast suppresses error message, narrowing check above makes safe
  124. } else {
  125. json = -int_jt(val);
  126. }
  127. } else if (val <= uint_jt(INT_JT_MAX)) {
  128. json = int_jt(val);
  129. } else if (std::is_signed<J>::value) {
  130. throw json::json_numeric_exception{"Expected unsigned integer"};
  131. } else {
  132. json = val;
  133. }
  134. data = info.it;
  135. }
  136. }
  137. } }