diff --git a/source/ps/CStr.cpp b/source/ps/CStr.cpp index 82fafbf13b..87d15753c4 100644 --- a/source/ps/CStr.cpp +++ b/source/ps/CStr.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,6 +31,7 @@ #include "lib/byte_order.h" #include "network/Serialization.h" +#include #include #include @@ -154,10 +155,24 @@ unsigned long CStr::ToULong() const return ret; } +/** + * libc++ and libstd++ differ on how they handle string-to-number parsing for floating-points numbers. + * See https://trac.wildfiregames.com/ticket/2780#comment:4 for details. + * To prevent this, only consider [0-9.-+], replace the others in-place with a neutral character. + */ +CStr ParseableAsNumber(CStr cleaned_copy) +{ + for (tchar& c : cleaned_copy) + if (!std::isdigit(c) && c != '.' && c != '-' && c != '+') + c = ' '; + + return cleaned_copy; +} + float CStr::ToFloat() const { float ret = 0; - std::tstringstream str(*this); + std::tstringstream str(ParseableAsNumber(*this)); str >> ret; return ret; } @@ -165,7 +180,7 @@ float CStr::ToFloat() const double CStr::ToDouble() const { double ret = 0; - std::tstringstream str(*this); + std::tstringstream str(ParseableAsNumber(*this)); str >> ret; return ret; } diff --git a/source/ps/tests/test_CStr.h b/source/ps/tests/test_CStr.h index 4e7562ec20..1f630e7f68 100644 --- a/source/ps/tests/test_CStr.h +++ b/source/ps/tests/test_CStr.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -123,21 +123,35 @@ public: TS_ASSERT_EQUALS(str1.ToLong(), 1); TS_ASSERT_EQUALS(str1.ToULong(), 1u); - CStr8 str2("bogus"); - TS_ASSERT_EQUALS(str2.ToFloat(), 0.0f); - TS_ASSERT_EQUALS(str2.ToDouble(), 0.0); - TS_ASSERT_EQUALS(str2.ToInt(), 0); - TS_ASSERT_EQUALS(str2.ToUInt(), 0u); - TS_ASSERT_EQUALS(str2.ToLong(), 0); - TS_ASSERT_EQUALS(str2.ToULong(), 0u); + CStr8 str2("+1,234"); + TS_ASSERT_DELTA(str2.ToFloat(), 1.f, 0.0001f); + TS_ASSERT_DELTA(str2.ToDouble(), 1., 0.0001); + TS_ASSERT_EQUALS(str2.ToInt(), 1); + TS_ASSERT_EQUALS(str2.ToUInt(), 1u); + TS_ASSERT_EQUALS(str2.ToLong(), 1); + TS_ASSERT_EQUALS(str2.ToULong(), 1u); - CStr8 str3("3bogus"); - TS_ASSERT_EQUALS(str3.ToFloat(), 3.0f); - TS_ASSERT_EQUALS(str3.ToDouble(), 3.0); - TS_ASSERT_EQUALS(str3.ToInt(), 3); - TS_ASSERT_EQUALS(str3.ToUInt(), 3u); - TS_ASSERT_EQUALS(str3.ToLong(), 3); - TS_ASSERT_EQUALS(str3.ToULong(), 3u); + CStr8 str3("bogus"); + TS_ASSERT_EQUALS(str3.ToFloat(), 0.0f); + TS_ASSERT_EQUALS(str3.ToDouble(), 0.0); + TS_ASSERT_EQUALS(str3.ToInt(), 0); + TS_ASSERT_EQUALS(str3.ToUInt(), 0u); + TS_ASSERT_EQUALS(str3.ToLong(), 0); + TS_ASSERT_EQUALS(str3.ToULong(), 0u); + + CStr8 str4("3bogus"); + TS_ASSERT_DELTA(str4.ToFloat(), 3.0f, 0.0001f); + TS_ASSERT_DELTA(str4.ToDouble(), 3.0, 0.0001); + TS_ASSERT_EQUALS(str4.ToInt(), 3); + TS_ASSERT_EQUALS(str4.ToUInt(), 3u); + TS_ASSERT_EQUALS(str4.ToLong(), 3); + TS_ASSERT_EQUALS(str4.ToULong(), 3u); + + CStr8 str5("-3bogus"); + TS_ASSERT_DELTA(str5.ToFloat(), -3.0f, 0.0001f); + TS_ASSERT_DELTA(str5.ToDouble(), -3.0, 0.0001); + TS_ASSERT_EQUALS(str5.ToInt(), -3); + TS_ASSERT_EQUALS(str5.ToLong(), -3); setlocale(LC_NUMERIC, old); }