diff --git a/src/common/string.cpp b/src/common/string.cpp index c769245f57..bcd78b67bd 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -1633,20 +1633,34 @@ bool wxString::ToCLong(long *pVal, int base) const bool wxString::ToCULong(unsigned long *pVal, int base) const { - // We intentionally don't use std::from_chars() here because this function - // is supposed to be compatible with strtoul() and so _succeed_ for "-1", - // for example, instead of returning an error as from_chars() (much more - // logically) does. - wxCHECK_MSG( pVal, false, "null output pointer" ); - long l; - if ( !ToCLong(&l, base) ) + const wxScopedCharBuffer& buf = utf8_str(); + auto start = buf.data(); + const auto end = start + buf.length(); + + if ( !SetBaseAndSkipPrefix(base, start, end) ) return false; - *pVal = static_cast(l); + // Extra complication: for compatibility reasons, this function does accept + // "-1" as valid input (as strtoul() does!), but from_chars() doesn't, for + // unsigned values, so check for this separately. + if ( *start == '-' ) + { + long l; + const auto res = std::from_chars(start, end, l, base); - return true; + if ( res.ec != std::errc{} || res.ptr != end ) + return false; + + *pVal = static_cast(l); + + return true; + } + + const auto res = std::from_chars(start, end, *pVal, base); + + return res.ec == std::errc{} && res.ptr == end; } bool wxString::ToCDouble(double *pVal) const diff --git a/tests/strings/strings.cpp b/tests/strings/strings.cpp index 30e6082406..43afe86eba 100644 --- a/tests/strings/strings.cpp +++ b/tests/strings/strings.cpp @@ -607,6 +607,17 @@ static const struct ToLongData { wxT("0x11"), 17, Number_Ok, 0 }, { wxT("0x11"), 0, Number_Invalid, 8 }, { wxT("0x11"), 17, Number_Ok, 16 }, + + { +#if SIZEOF_LONG == 4 + wxT("0xffffffff"), +#elif SIZEOF_LONG == 8 + wxT("0xffffffffffffffff"), +#else + #error "Unknown sizeof(long)" +#endif + (TestValue_t)ULONG_MAX, Number_Unsigned, 0 + }, }; wxGCC_WARNING_RESTORE(missing-field-initializers)