From 9699535801adc521f5da3a17f635b619e68c4fca Mon Sep 17 00:00:00 2001 From: Mykola Bilochub Date: Sat, 3 Jun 2017 02:40:59 +0300 Subject: [PATCH] parser: fix parsing of big integer values Implement additional function for parsing integer values which cannot be parsed using standard library functions. Refs: https://github.com/metarhia/jstp/issues/175 PR-URL: https://github.com/metarhia/jstp/pull/208 Reviewed-By: Denys Otrishko Reviewed-By: Alexey Orlenko --- src/jsrs_parser.cc | 43 +++++++++++++++++++++++++++++++++++++++++-- src/jsrs_parser.h | 9 +++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/jsrs_parser.cc b/src/jsrs_parser.cc index 7273099..967b80c 100644 --- a/src/jsrs_parser.cc +++ b/src/jsrs_parser.cc @@ -4,8 +4,10 @@ #include "jsrs_parser.h" #include +#include #include #include +#include #include #include #include @@ -28,6 +30,7 @@ using std::size_t; using std::strncmp; using std::strncpy; using std::strtol; +using std::toupper; using v8::Array; using v8::False; @@ -379,12 +382,48 @@ Local ParseIntegerNumber(Isolate* isolate, int base, bool negate_result) { char* number_end; - int32_t value = strtol(begin, &number_end, base); + long long value = strtoll(begin, &number_end, base); + if (errno == ERANGE) { + errno = 0; + return ParseBigIntegerNumber(isolate, begin, end, size, + base, negate_result); + } if (negate_result) { value = -value; } *size = static_cast(number_end - begin); - return Integer::New(isolate, value); + if (value > INT32_MIN && value < INT32_MAX) { + return Integer::New(isolate, value); + } else { + return Number::New(isolate, value); + } +} + +Local ParseBigIntegerNumber(Isolate* isolate, + const char* begin, + const char* end, + size_t* size, + int base, + bool negate_result) { + *size = end - begin; + double result = 0.0; + char current_digit; + double current_digit_value; + char base_digit_count = base > 10 ? 10 : base; + char base_alpha_count = base > 10 ? base - 10 : 0; + for (size_t i = 0; i < *size; i++) { + current_digit = toupper(begin[i]); + if ((current_digit < '0' || current_digit >= '0' + base_digit_count) && + (current_digit < 'A' || current_digit >= 'A' + base_alpha_count)) { + *size = i; + break; + } + current_digit_value = current_digit <= '9' ? current_digit - '0' : + current_digit - 'A' + 10; + result *= base; + result += current_digit_value; + } + return Number::New(isolate, negate_result ? -result : result); } static bool GetControlChar(Isolate* isolate, diff --git a/src/jsrs_parser.h b/src/jsrs_parser.h index 5399696..502358d 100644 --- a/src/jsrs_parser.h +++ b/src/jsrs_parser.h @@ -118,6 +118,15 @@ v8::Local ParseIntegerNumber(v8::Isolate* isolate, int base, bool negate_result); +// Parses an integer number, which is too big to be parsed using +// ParseIntegerNumber, in arbitrary base without prefixes. +v8::Local ParseBigIntegerNumber(v8::Isolate* isolate, + const char* begin, + const char* end, + std::size_t* size, + int base, + bool negate_result); + } // namespace internal } // namespace parser