Index: ps/trunk/source/ps/CStr.cpp =================================================================== --- ps/trunk/source/ps/CStr.cpp +++ ps/trunk/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 @@ 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 @@ double CStr::ToDouble() const { double ret = 0; - std::tstringstream str(*this); + std::tstringstream str(ParseableAsNumber(*this)); str >> ret; return ret; } Index: ps/trunk/source/ps/tests/test_CStr.h =================================================================== --- ps/trunk/source/ps/tests/test_CStr.h +++ ps/trunk/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 @@ 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 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 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("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); }