From febb8560b54e2a9b05924a14c1119161bf3f9599 Mon Sep 17 00:00:00 2001 From: Patrik Juvonen Date: Tue, 28 Apr 2020 12:10:58 +0300 Subject: [PATCH] Revert "Revert "Fix #1258: Add mixed hex and RGB(A) parsing to XMLColorToInt (#1261)"" This reverts commit 3f39bb5b387c35f93e04d000a54a19dbdebec6cd. Signed-off-by: Patrik Juvonen --- Server/mods/deathmatch/logic/CVehicle.cpp | 26 ++--- Server/mods/deathmatch/logic/Utils.cpp | 120 ++++++++++++++++++++-- Server/mods/deathmatch/logic/Utils.h | 5 + 3 files changed, 125 insertions(+), 26 deletions(-) diff --git a/Server/mods/deathmatch/logic/CVehicle.cpp b/Server/mods/deathmatch/logic/CVehicle.cpp index dda1b2ca2d..135817e062 100644 --- a/Server/mods/deathmatch/logic/CVehicle.cpp +++ b/Server/mods/deathmatch/logic/CVehicle.cpp @@ -304,28 +304,20 @@ bool CVehicle::ReadSpecialData(const int iLine) char szTemp[256]; if (GetCustomDataString("color", szTemp, 256, true)) { - uchar ucValues[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - char* sz1 = strtok(szTemp, ", "); - if (sz1) - ucValues[0] = atoi(sz1); + std::vector vecColors; + unsigned char ucCount; - int i; - for (i = 1; i < 12; i++) + if (ColorStringToRGB(szTemp, SColorRGBA(0, 0, 0, 0), vecColors, ucCount)) { - char* szn = strtok(NULL, ", "); - if (!szn) - break; - ucValues[i] = atoi(szn); - } - - if (i == 3 || i == 6 || i == 9 || i == 12) - { - m_Color.SetRGBColors(SColorRGBA(ucValues[0], ucValues[1], ucValues[2], 0), SColorRGBA(ucValues[3], ucValues[4], ucValues[5], 0), - SColorRGBA(ucValues[6], ucValues[7], ucValues[8], 0), SColorRGBA(ucValues[9], ucValues[10], ucValues[11], 0)); + if (ucCount % 3 == 0) + m_Color.SetRGBColors(vecColors[0], vecColors[1], vecColors[2], vecColors[3]); + else + m_Color.SetPaletteColors(vecColors[0].R, vecColors[0].G, vecColors[0].B, vecColors[1].R); } else { - m_Color.SetPaletteColors(ucValues[0], ucValues[1], ucValues[2], ucValues[3]); + CLogger::ErrorPrintf("Bad 'color' value specified in (line %u)\n", iLine); + return false; } } diff --git a/Server/mods/deathmatch/logic/Utils.cpp b/Server/mods/deathmatch/logic/Utils.cpp index 2fdf04779e..3a9939882b 100644 --- a/Server/mods/deathmatch/logic/Utils.cpp +++ b/Server/mods/deathmatch/logic/Utils.cpp @@ -535,18 +535,120 @@ bool XMLColorToInt(const char* szColor, unsigned long& ulColor) bool XMLColorToInt(const char* szColor, unsigned char& ucRed, unsigned char& ucGreen, unsigned char& ucBlue, unsigned char& ucAlpha) { - // Convert it to an integer first - unsigned long ulColor; - if (!XMLColorToInt(szColor, ulColor)) - { + // If we're empty, let's just stop right away + if (!szColor || strlen(szColor) == 0) return false; + + std::vector vecColors; + unsigned char ucCount; + + if (ColorStringToRGBA(szColor, SColorRGBA(ucRed, ucGreen, ucBlue, ucAlpha), vecColors, ucCount)) + { + ucRed = vecColors[0].R; + ucGreen = vecColors[0].G; + ucBlue = vecColors[0].B; + ucAlpha = vecColors[0].A; + + return true; + } + + return false; +} + +bool ColorStringToRGBA(const char* szColor, SColorRGBA defaultColor, std::vector& vecColors, unsigned char& ucCount, bool bIgnoreAlpha) +{ + std::stringstream ss(szColor); + SColorRGBA color = defaultColor; + bool bPreviousWasHex = false; + unsigned int uiRGBAIndex = 0; + unsigned long ulColor; + unsigned char ucValue; + unsigned char ucLength = bIgnoreAlpha ? 3 : 4; + + while (ss.good()) + { + // Ambiguous value before a comma + SString strValue; + getline(ss, strValue, ','); + + // Remove spaces + ReplaceOccurrencesInString(strValue, " ", ""); + + // Is the value looking like a hexadecimal? + if (strValue[0] == '#') + { + // Try converting it to an integer + if (XMLColorToInt(strValue.c_str(), ulColor)) + { + // If a previous RGBA wasn't finished, let's finish it now + if (!bPreviousWasHex && uiRGBAIndex != 0) + { + vecColors.push_back(color); + ucCount += ucLength - uiRGBAIndex; + color = defaultColor; + } + + color.R = static_cast(ulColor); + color.G = static_cast(ulColor >> 8); + color.B = static_cast(ulColor >> 16); + + if (!bIgnoreAlpha) + color.A = static_cast(ulColor >> 24); + + bPreviousWasHex = true; + ucCount += ucLength; + } + else + return false; + } + // It looks like we have an empty value, let's skip the value but treat it as RGB + else if (strValue.empty()) + { + if (bPreviousWasHex || uiRGBAIndex % ucLength == 0) + { + bPreviousWasHex = false; + uiRGBAIndex = 0; + } + + uiRGBAIndex++; + ucCount++; + + if (uiRGBAIndex % ucLength != 0 && ss.good()) + continue; + } + // It looks like a plain number so let's treat it as a RGBA value + else if (strValue.find_first_not_of("0123456789") == std::string::npos) + { + ucValue = atoi(strValue.c_str()); + + if (bPreviousWasHex || uiRGBAIndex % ucLength == 0) + { + color.R = ucValue; + bPreviousWasHex = false; + uiRGBAIndex = 0; + } + else if (uiRGBAIndex % ucLength == 1) + color.G = ucValue; + else if (uiRGBAIndex % ucLength == 2) + color.B = ucValue; + else if (uiRGBAIndex % ucLength == 3) + color.A = ucValue; + + uiRGBAIndex++; + ucCount++; + + if (uiRGBAIndex % ucLength != 0 && ss.good()) + continue; + } + else + return false; + + // We have a color, so let's push it + vecColors.push_back(color); + color = defaultColor; + uiRGBAIndex = 0; } - // Convert it to red, green, blue and alpha - ucRed = static_cast(ulColor); - ucGreen = static_cast(ulColor >> 8); - ucBlue = static_cast(ulColor >> 16); - ucAlpha = static_cast(ulColor >> 24); return true; } diff --git a/Server/mods/deathmatch/logic/Utils.h b/Server/mods/deathmatch/logic/Utils.h index 07419e5106..f2a253520b 100644 --- a/Server/mods/deathmatch/logic/Utils.h +++ b/Server/mods/deathmatch/logic/Utils.h @@ -57,6 +57,11 @@ bool IsValidOrganizationPath(const char* szPath); unsigned int HexToInt(const char* szHex); bool XMLColorToInt(const char* szColor, unsigned long& ulColor); bool XMLColorToInt(const char* szColor, unsigned char& ucRed, unsigned char& ucGreen, unsigned char& ucBlue, unsigned char& ucAlpha); +bool ColorStringToRGBA(const char* szColor, SColorRGBA defaultColor, std::vector& vecColors, unsigned char& ucCount, bool bIgnoreAlpha = false); +inline bool ColorStringToRGB(const char* szColor, SColorRGBA defaultColor, std::vector& vecColors, unsigned char& ucCount) +{ + return ColorStringToRGBA(szColor, defaultColor, vecColors, ucCount, true); +} inline float WrapAround(float fValue, float fHigh) {