diff --git a/src/fios.cpp b/src/fios.cpp index 26024efd07..e111546a0a 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -17,12 +17,12 @@ #include "network/network_content.h" #include "screenshot.h" #include "string_func.h" +#include "string_func_extra.h" #include "strings_func.h" #include "tar_type.h" #include #include #include "3rdparty/optional/ottd_optional.h" -#include #ifndef _WIN32 # include @@ -780,7 +780,7 @@ FiosNumberedSaveName::FiosNumberedSaveName(const std::string &prefix) : prefix(p _savegame_sort_order = order; std::string_view name = list.begin()->title; - std::from_chars(name.data() + this->prefix.size(), name.data() + name.size(), this->number); + IntFromChars(name.data() + this->prefix.size(), name.data() + name.size(), this->number); } } diff --git a/src/network/network.cpp b/src/network/network.cpp index 4352efdce9..1a193d4bbb 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -36,7 +36,7 @@ #include "../gfx_func.h" #include "../error.h" #include "../core/checksum_func.hpp" -#include +#include "../string_func_extra.h" #include #include @@ -496,8 +496,8 @@ std::string_view ParseCompanyFromConnectionString(const std::string &connection_ ip = ip.substr(0, offset); uint8 company_value; - auto [_, err] = std::from_chars(company_string.data(), company_string.data() + company_string.size(), company_value); - if (err == std::errc()) { + bool success = IntFromChars(company_string.data(), company_string.data() + company_string.size(), company_value); + if (success) { if (company_value != COMPANY_NEW_COMPANY && company_value != COMPANY_SPECTATOR) { if (company_value > MAX_COMPANIES || company_value == 0) { *company_id = COMPANY_SPECTATOR; @@ -538,7 +538,7 @@ std::string_view ParseFullConnectionString(const std::string &connection_string, if (port_offset != std::string::npos && (ipv6_close == std::string::npos || ipv6_close < port_offset)) { std::string_view port_string = ip.substr(port_offset + 1); ip = ip.substr(0, port_offset); - std::from_chars(port_string.data(), port_string.data() + port_string.size(), port); + IntFromChars(port_string.data(), port_string.data() + port_string.size(), port); } return ip; } diff --git a/src/settings.cpp b/src/settings.cpp index 4362e03eab..22269dfe8b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -23,7 +23,6 @@ #include "stdafx.h" #include -#include #include #include "currency.h" #include "screenshot.h" @@ -77,6 +76,7 @@ #include "gui.h" #include "statusbar_gui.h" #include "graph_gui.h" +#include "string_func_extra.h" #include "void_map.h" #include "station_base.h" @@ -1982,7 +1982,7 @@ static IniFileVersion LoadVersionFromConfig(IniFile &ini) if (version_number == nullptr || !version_number->value.has_value()) return IFV_0; uint32 version = 0; - std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version); + IntFromChars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version); return static_cast(version); } diff --git a/src/string_func_extra.h b/src/string_func_extra.h index 430f3f6f99..1dc21dd9bb 100644 --- a/src/string_func_extra.h +++ b/src/string_func_extra.h @@ -10,6 +10,7 @@ #include "string_func.h" #include +#include static inline void StrMakeValidInPlace(std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK) { @@ -34,5 +35,45 @@ inline void ProcessLineByLine(char *buf, F line_functor) if (p < p2) line_functor(p); } +/* + * Cut down version of std::from_chars, base is fixed at 10. + * Returns true on success + */ +template +inline bool IntFromChars(const char* first, const char* last, T& value) +{ + static_assert(std::is_integral::value && !std::is_same::value, "T must be an integer"); + + bool negative = false; + if (std::is_signed::value) { + if (first != last && *first == '-') { + first++; + negative = true; + } + } + + T out = 0; + const char * const start = first; + while (first != last) { + const char c = *first; + if (c >= '0' && c <= '9') { +#ifdef WITH_OVERFLOW_BUILTINS + if (unlikely(__builtin_mul_overflow(out, 10, &out))) return false; + if (unlikely(__builtin_add_overflow(out, c - '0', &out))) return false; +#else + if (unlikely(out > std::numeric_limits::max() / 10)) return false; + out *= 10; + if (unlikely(out > (std::numeric_limits::max() - (c - '0')))) return false; + out += (c - '0'); +#endif + first++; + } else { + break; + } + } + if (start == first) return false; + value = negative ? -out : out; + return true; +} #endif /* STRING_FUNC_EXTRA_H */