// Copyright 2014 The Crashpad Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "util/stdlib/string_number_conversion.h" #include #include #include #include #include #include namespace { template struct StringToIntegerTraits { using IntType = TIntType; using LongType = TLongType; static void TypeCheck() { static_assert(std::numeric_limits::is_integer && std::numeric_limits::is_integer, "IntType and LongType must be integer"); static_assert(std::numeric_limits::is_signed == std::numeric_limits::is_signed, "IntType and LongType signedness must agree"); static_assert(std::numeric_limits::min() >= std::numeric_limits::min() && std::numeric_limits::min() < std::numeric_limits::max(), "IntType min must be in LongType range"); static_assert(std::numeric_limits::max() > std::numeric_limits::min() && std::numeric_limits::max() <= std::numeric_limits::max(), "IntType max must be in LongType range"); } }; template struct StringToSignedIntegerTraits : public StringToIntegerTraits { static void TypeCheck() { static_assert(std::numeric_limits::is_signed, "StringToSignedTraits IntType must be signed"); return super::TypeCheck(); } static bool IsNegativeOverflow(TLongType value) { return value < std::numeric_limits::min(); } private: using super = StringToIntegerTraits; }; template struct StringToUnsignedIntegerTraits : public StringToIntegerTraits { static void TypeCheck() { static_assert(!std::numeric_limits::is_signed, "StringToUnsignedTraits IntType must be unsigned"); return super::TypeCheck(); } static bool IsNegativeOverflow(TLongType value) { return false; } private: using super = StringToIntegerTraits; }; struct StringToIntTraits : public StringToSignedIntegerTraits { static LongType Convert(const char* str, char** end, int base) { return strtol(str, end, base); } }; struct StringToUnsignedIntTraits : public StringToUnsignedIntegerTraits { static LongType Convert(const char* str, char** end, int base) { if (str[0] == '-') { *end = const_cast(str); return 0; } return strtoul(str, end, base); } }; struct StringToLongTraits : public StringToSignedIntegerTraits { static LongType Convert(const char* str, char** end, int base) { return strtoll(str, end, base); } }; struct StringToUnsignedLongTraits : public StringToUnsignedIntegerTraits { static LongType Convert(const char* str, char** end, int base) { if (str[0] == '-') { *end = const_cast(str); return 0; } return strtoull(str, end, base); } }; struct StringToLongLongTraits : public StringToSignedIntegerTraits { static LongType Convert(const char* str, char** end, int base) { return strtoll(str, end, base); } }; struct StringToUnsignedLongLongTraits : public StringToUnsignedIntegerTraits { static LongType Convert(const char* str, char** end, int base) { if (str[0] == '-') { *end = const_cast(str); return 0; } return strtoull(str, end, base); } }; template bool StringToIntegerInternal(const std::string& string, typename Traits::IntType* number) { using IntType = typename Traits::IntType; using LongType = typename Traits::LongType; Traits::TypeCheck(); if (string.empty() || isspace(string[0])) { return false; } errno = 0; char* end; LongType result = Traits::Convert(string.data(), &end, 0); if (Traits::IsNegativeOverflow(result) || result > std::numeric_limits::max() || errno == ERANGE || end != string.data() + string.length()) { return false; } *number = static_cast(result); return true; } } // namespace namespace crashpad { bool StringToNumber(const std::string& string, int* number) { return StringToIntegerInternal(string, number); } bool StringToNumber(const std::string& string, unsigned int* number) { return StringToIntegerInternal(string, number); } bool StringToNumber(const std::string& string, long* number) { return StringToIntegerInternal(string, number); } bool StringToNumber(const std::string& string, unsigned long* number) { return StringToIntegerInternal(string, number); } bool StringToNumber(const std::string& string, long long* number) { return StringToIntegerInternal(string, number); } bool StringToNumber(const std::string& string, unsigned long long* number) { return StringToIntegerInternal(string, number); } } // namespace crashpad