diff options
author | Jaeseung Ha <ipknhama@gmail.com> | 2017-12-25 15:30:06 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-25 15:30:06 +0900 |
commit | 01cc7a3508013dda0a14d594a9f03f991cef812a (patch) | |
tree | 45463dba3c0f3d53b7c60c0cd6a8fe508ed52b3f /include | |
parent | 49bd1c27975ec3e21ba74887584e3419f71e8111 (diff) | |
parent | ecbbd0ebf2204bae8ca968007c7408b6e2ae2a75 (diff) | |
download | crow-01cc7a3508013dda0a14d594a9f03f991cef812a.tar.gz crow-01cc7a3508013dda0a14d594a9f03f991cef812a.zip |
Merge pull request #258 from erikaldsund/fix_handling_of_big_integers
Fix handling of big integers
Diffstat (limited to 'include')
-rw-r--r-- | include/crow/json.h | 126 |
1 files changed, 106 insertions, 20 deletions
diff --git a/include/crow/json.h b/include/crow/json.h index d8dbace..1f28af5 100644 --- a/include/crow/json.h +++ b/include/crow/json.h @@ -96,6 +96,13 @@ namespace crow } } + enum class num_type : char { + Signed_integer, + Unsigned_integer, + Floating_point, + Null + }; + class rvalue; rvalue load(const char* data, size_t size); @@ -216,13 +223,16 @@ namespace crow : start_{s}, end_{e}, t_{t} - {} + { + determine_num_type(); + } rvalue(const rvalue& r) : start_(r.start_), end_(r.end_), key_(r.key_), t_(r.t_), + nt_(r.nt_), option_(r.option_) { copy_l(r); @@ -240,6 +250,7 @@ namespace crow key_ = r.key_; copy_l(r); t_ = r.t_; + nt_ = r.nt_; option_ = r.option_; return *this; } @@ -252,6 +263,7 @@ namespace crow lsize_ = r.lsize_; lremain_ = r.lremain_; t_ = r.t_; + nt_ = r.nt_; option_ = r.option_; return *this; } @@ -287,6 +299,17 @@ namespace crow return t_; } + num_type nt() const + { +#ifndef CROW_JSON_NO_ERROR_CHECK + if (option_ & error_bit) + { + throw std::runtime_error("invalid json object"); + } +#endif + return nt_; + } + int64_t i() const { #ifndef CROW_JSON_NO_ERROR_CHECK @@ -591,6 +614,28 @@ namespace crow lremain_ --; } + // determines num_type from the string + void determine_num_type() + { + if (t_ != type::Number) + { + nt_ = num_type::Null; + return; + } + + const std::size_t len = end_ - start_; + const bool has_minus = std::memchr(start_, '-', len) != nullptr; + const bool has_e = std::memchr(start_, 'e', len) != nullptr + || std::memchr(start_, 'E', len) != nullptr; + const bool has_dec_sep = std::memchr(start_, '.', len) != nullptr; + if (has_dec_sep || has_e) + nt_ = num_type::Floating_point; + else if (has_minus) + nt_ = num_type::Signed_integer; + else + nt_ = num_type::Unsigned_integer; + } + mutable char* start_; mutable char* end_; detail::r_string key_; @@ -598,6 +643,7 @@ namespace crow uint32_t lsize_; uint16_t lremain_; type t_; + num_type nt_{num_type::Null}; mutable uint8_t option_{0}; friend rvalue load_nocopy_internal(char* data, size_t size); @@ -610,7 +656,17 @@ namespace crow case type::Null: os << "null"; break; case type::False: os << "false"; break; case type::True: os << "true"; break; - case type::Number: os << r.d(); break; + case type::Number: + { + switch (r.nt()) + { + case num_type::Floating_point: os << r.d(); break; + case num_type::Signed_integer: os << r.i(); break; + case num_type::Unsigned_integer: os << r.u(); break; + case num_type::Null: throw std::runtime_error("Number with num_type Null"); + } + } + break; case type::String: os << '"' << r.s() << '"'; break; case type::List: { @@ -1092,7 +1148,12 @@ namespace crow type t() const { return t_; } private: type t_{type::Null}; - double d {}; + num_type nt{num_type::Null}; + union { + double d; + int64_t si; + uint64_t ui {}; + } num; std::string s; std::unique_ptr<std::vector<wvalue>> l; std::unique_ptr<std::unordered_map<std::string, wvalue>> o; @@ -1110,7 +1171,13 @@ namespace crow case type::True: return; case type::Number: - d = r.d(); + nt = r.nt(); + if (nt == num_type::Floating_point) + num.d = r.d(); + else if (nt == num_type::Signed_integer) + num.si = r.i(); + else + num.ui = r.u(); return; case type::String: s = r.s(); @@ -1140,7 +1207,7 @@ namespace crow wvalue& operator = (wvalue&& r) { t_ = r.t_; - d = r.d; + num = r.num; s = std::move(r.s); l = std::move(r.l); o = std::move(r.o); @@ -1149,9 +1216,7 @@ namespace crow void clear() { - t_ = type::Null; - l.reset(); - o.reset(); + reset(); } void reset() @@ -1180,7 +1245,8 @@ namespace crow { reset(); t_ = type::Number; - d = value; + num.d = value; + nt = num_type::Floating_point; return *this; } @@ -1188,7 +1254,8 @@ namespace crow { reset(); t_ = type::Number; - d = (double)value; + num.ui = value; + nt = num_type::Unsigned_integer; return *this; } @@ -1196,7 +1263,8 @@ namespace crow { reset(); t_ = type::Number; - d = (double)value; + num.si = value; + nt = num_type::Signed_integer; return *this; } @@ -1204,7 +1272,8 @@ namespace crow { reset(); t_ = type::Number; - d = (double)value; + num.si = value; + nt = num_type::Signed_integer; return *this; } @@ -1212,7 +1281,8 @@ namespace crow { reset(); t_ = type::Number; - d = (double)value; + num.si = value; + nt = num_type::Signed_integer; return *this; } @@ -1220,7 +1290,8 @@ namespace crow { reset(); t_ = type::Number; - d = (double)value; + num.si = value; + nt = num_type::Signed_integer; return *this; } @@ -1228,7 +1299,8 @@ namespace crow { reset(); t_ = type::Number; - d = (double)value; + num.ui = value; + nt = num_type::Unsigned_integer; return *this; } @@ -1236,7 +1308,8 @@ namespace crow { reset(); t_ = type::Number; - d = (double)value; + num.ui = value; + nt = num_type::Unsigned_integer; return *this; } @@ -1244,7 +1317,8 @@ namespace crow { reset(); t_ = type::Number; - d = (double)value; + num.ui = value; + nt = num_type::Unsigned_integer; return *this; } @@ -1406,11 +1480,23 @@ namespace crow { char outbuf[128]; #ifdef _MSC_VER - sprintf_s(outbuf, 128, "%g", v.d); +#define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf_s((BUFFER_PTR), 128, (FORMAT_PTR), (VALUE)) #else - sprintf(outbuf, "%g", v.d); +#define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf((BUFFER_PTR), (FORMAT_PTR), (VALUE)) #endif - + if (v.nt == num_type::Floating_point) + { + MSC_COMPATIBLE_SPRINTF(outbuf, "%g", v.num.d); + } + else if (v.nt == num_type::Signed_integer) + { + MSC_COMPATIBLE_SPRINTF(outbuf, "%lld", v.num.si); + } + else + { + MSC_COMPATIBLE_SPRINTF(outbuf, "%llu", v.num.ui); + } +#undef MSC_COMPATIBLE_SPRINTF out += outbuf; } break; |