diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index 0002e5377e..92d317756a 100644 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -1687,7 +1687,7 @@ void CGUI::Xeromyces_ReadEffects(XMBElement Element, CXeromyces* pFile, SGUIImag if (attr_name == "add_color") { CColor color; - if (!GUI::ParseColor(attr_value, color, 0.f)) + if (!GUI::ParseColor(attr_value, color, 0)) LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str()); else effects.m_AddColor = color; } @@ -1933,7 +1933,7 @@ void CGUI::Xeromyces_ReadColor(XMBElement Element, CXeromyces* pFile) if (! value.empty()) { // Try setting color to value - if (!color.ParseString(value, 255.f)) + if (!color.ParseString(value)) { LOGERROR(L"GUI: Unable to create custom color '%hs'. Invalid color syntax.", name.c_str()); } diff --git a/source/gui/GUIutil.cpp b/source/gui/GUIutil.cpp index c1efceadc3..d41f5b9474 100644 --- a/source/gui/GUIutil.cpp +++ b/source/gui/GUIutil.cpp @@ -99,7 +99,7 @@ bool __ParseString(const CStrW& Value, CClientArea &Output) } template <> -bool GUI::ParseColor(const CStrW& Value, CColor &Output, float DefaultAlpha) +bool GUI::ParseColor(const CStrW& Value, CColor &Output, int DefaultAlpha) { // First, check our database in g_GUI for pre-defined colors // If we find anything, we'll ignore DefaultAlpha @@ -119,7 +119,7 @@ bool __ParseString(const CStrW& Value, CColor &Output) if (g_GUI->GetPreDefinedColor(Value.ToUTF8(), Output)) return true; - return Output.ParseString(Value.ToUTF8(), 255.f); + return Output.ParseString(Value.ToUTF8()); } template <> diff --git a/source/gui/GUIutil.h b/source/gui/GUIutil.h index 32cd980823..417c139317 100644 --- a/source/gui/GUIutil.h +++ b/source/gui/GUIutil.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -235,7 +235,7 @@ public: return __ParseString(Value, tOutput); } - static bool ParseColor(const CStrW& Value, CColor &tOutput, float DefaultAlpha); + static bool ParseColor(const CStrW& Value, CColor &tOutput, int DefaultAlpha); private: diff --git a/source/ps/Overlay.cpp b/source/ps/Overlay.cpp index c9b2449f07..579bfc4435 100644 --- a/source/ps/Overlay.cpp +++ b/source/ps/Overlay.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,31 +24,49 @@ Overlay.cpp #include #include "Overlay.h" -#include "Parser.h" +#include "CLogger.h" +#include "CStr.h" - -bool CColor::ParseString(const CStr8& Value, float DefaultAlpha) +/** + * Try to parse @p Value as a color. Returns true on success, false otherwise. + * @param Value Should be "r g b" or "r g b a" where each value is an integer in [0,255]. + * @param DefaultAlpha The alpha value that is used if the format of @p Value is "r g b". + */ +bool CColor::ParseString(const CStr8& Value, int DefaultAlpha) { - // Use the parser to parse the values - CParser& parser (CParserCache::Get("_[-$arg(_minus)]$value_[-$arg(_minus)]$value_[-$arg(_minus)]$value_[[-$arg(_minus)]$value_]")); - - std::string str = Value; - - CParserLine line; - line.ParseString(parser, str); - if (!line.m_ParseOK) + unsigned int NUM_VALS= 4; + int values[NUM_VALS] = { 0, 0, 0, DefaultAlpha }; + std::stringstream stream; + stream.str(Value); + // Parse each value + size_t i; + for (i = 0; i < NUM_VALS; ++i) { - // TODO Gee: Parsing failed - return false; - } - float values[4] = { 0, 0, 0, DefaultAlpha }; - for (int i=0; i<(int)line.GetArgCount(); ++i) - { - if (!line.GetArgFloat(i, values[i])) + if (stream.eof()) + break; + + stream >> values[i]; + if ((stream.rdstate() & std::stringstream::failbit) != 0) { - // Parsing failed + LOGWARNING(L"Unable to parse CColor parameters. Your input: '%s'", Value.c_str()); return false; } + if (values[i] < 0 || values[i] > 255) + { + LOGWARNING(L"Invalid value (<0 or >255) when parsing CColor parameters. Your input: '%s'", Value.c_str()); + return false; + } + } + + if (i < 3) + { + LOGWARNING(L"Not enough parameters when parsing as CColor. Your input: '%s'", Value.c_str()); + return false; + } + if (!stream.eof()) + { + LOGWARNING(L"Too many parameters when parsing as CColor. Your input: '%s'", Value.c_str()); + return false; } r = values[0]/255.f; diff --git a/source/ps/Overlay.h b/source/ps/Overlay.h index e0bb1929bb..e9eb8f9c1a 100644 --- a/source/ps/Overlay.h +++ b/source/ps/Overlay.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,7 +36,7 @@ struct CColor CColor() : r(-1.f), g(-1.f), b(-1.f), a(1.f) {} CColor(float cr,float cg,float cb,float ca) : r(cr), g(cg), b(cb), a(ca) {} - bool ParseString(const CStr8& Value, float DefaultAlpha); + bool ParseString(const CStr8& Value, int DefaultAlpha = 255); bool operator == (const CColor &color) const; diff --git a/source/ps/tests/test_CColor.h b/source/ps/tests/test_CColor.h new file mode 100644 index 0000000000..32d1d0f775 --- /dev/null +++ b/source/ps/tests/test_CColor.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2014 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "lib/self_test.h" + +#include "ps/Overlay.h" +#include "ps/CLogger.h" + +class TestCColor : public CxxTest::TestSuite +{ +public: + void test_parse() + { + TestLogger nolog; +#define CHECK_CCOLOR_EQUAL(v,r,g,b,a) \ + { \ + CStr str = v; \ + CColor c; \ + TS_ASSERT(c.ParseString(str, 255)); \ + CColor c_(r/255.f,g/255.f,b/255.f,a/255.f); \ + TS_ASSERT_EQUALS(c, c_); \ + } + + CHECK_CCOLOR_EQUAL("0 0 0 0", 0, 0, 0, 0); + CHECK_CCOLOR_EQUAL("255 0 255 0", 255, 0, 255, 0); + CHECK_CCOLOR_EQUAL("0 123 0 0", 0, 123, 0, 0); + CHECK_CCOLOR_EQUAL("0 0 0 55", 0, 0, 0, 55); + CHECK_CCOLOR_EQUAL("76 24 0", 76, 24, 0, 255); + CHECK_CCOLOR_EQUAL("159 98 24", 159, 98, 24, 255); +#undef CHECK_CCOLOR_EQUAL + } + + void test_parse_failure() + { + TestLogger nolog; + +#define CHECK_CCOLOR_FAIL(v) \ + { \ + CStr str = v; \ + CColor a; \ + TS_ASSERT(!a.ParseString(str, 255)); \ + } + + CHECK_CCOLOR_FAIL("abc"); + CHECK_CCOLOR_FAIL("0.123 1 2 3"); + CHECK_CCOLOR_FAIL("0 0 0 0 adfasd"); + CHECK_CCOLOR_FAIL("0 a0 b0 ax"); + CHECK_CCOLOR_FAIL("-124dsaf"); + CHECK_CCOLOR_FAIL("\0"); + CHECK_CCOLOR_FAIL("1 2 xxxx"); + + // Not enough parameters + CHECK_CCOLOR_FAIL(""); + CHECK_CCOLOR_FAIL("124"); + CHECK_CCOLOR_FAIL("0 55"); + + // More parameters than allowed + CHECK_CCOLOR_FAIL("0 5 1 5 6"); + + // Out of bounds + CHECK_CCOLOR_FAIL("-1 0 0"); + CHECK_CCOLOR_FAIL("256 0 0 0"); + CHECK_CCOLOR_FAIL("255 256 -1 0"); +#undef CHECK_CCLOLO_FAIL + } +};