Files
2025-05-18 13:04:45 +08:00

515 lines
10 KiB
C++

// Copyright 2011-2020 Molecular Matters GmbH, all rights reserved.
#if LC_VERSION == 1
// BEGIN EPIC MOD
//#include PCH_INCLUDE
// END EPIC MOD
#include "LC_StringUtil.h"
// BEGIN EPIC MOD
#if defined(__clang__) && defined(_MSC_VER) && _MSVC_LANG > 201402L && __clang_major__ < 13
// For reference: https://bugs.llvm.org/show_bug.cgi?id=41226#c16
#include <wchar.h>
#endif
#include "Windows/WindowsHWrapper.h"
// END EPIC MOD
namespace detail
{
static std::wstring ToWideString(const char* utf8Str, size_t length)
{
const int sizeNeeded = ::MultiByteToWideChar(CP_UTF8, 0, utf8Str, static_cast<int>(length), NULL, 0);
wchar_t* wstrTo = static_cast<wchar_t*>(_alloca(static_cast<size_t>(sizeNeeded) * sizeof(wchar_t)));
::MultiByteToWideChar(CP_UTF8, 0, utf8Str, static_cast<int>(length), wstrTo, sizeNeeded);
return std::wstring(wstrTo, static_cast<size_t>(sizeNeeded));
}
template <typename T>
static bool Matches(const T* str1, const T* str2)
{
unsigned int index = 0u;
T c1 = str1[index];
T c2 = str2[index];
while ((c1 != '\0') && (c2 != '\0'))
{
if (c1 != c2)
{
// at least one character is different
return false;
}
++index;
c1 = str1[index];
c2 = str2[index];
}
// reached the end of at least one string, but the string could be of different length
return (c1 == c2);
}
template <typename T>
static bool StartsWith(const T* str, const T* subString)
{
unsigned int index = 0u;
T c1 = str[index];
T c2 = subString[index];
while ((c1 != '\0') && (c2 != '\0'))
{
if (c1 != c2)
{
// at least one character is different
return false;
}
++index;
c1 = str[index];
c2 = subString[index];
}
// reached the end of at least one string.
// if str has ended but subString has not, it cannot be fully contained in str.
if ((c1 == '\0') && (c2 != '\0'))
{
return false;
}
return true;
}
// BEGIN EPIC MOD
template <typename T>
static const T* StartsWithEx(const T* str, const T* subString)
{
for (;;)
{
// Reached the end of the substring, return the remaining part of original string
T c2 = *subString++;
if (c2 == 0)
{
return str;
}
// If the characters don't match, we are done. We don't have to do a check specifically
// for 0 since we know that c2 must not be zero at this point.
T c1 = *str++;
if (c1 != c2)
{
return nullptr;
}
}
}
template <typename T>
bool MatchesWildcardRecursive(const T* target, const T* wildcard)
{
for (;;)
{
T w = *wildcard++;
// We have reached the end of the wildcard string, this is successful if have no more target string
if (w == 0)
{
return *target == 0;
}
// If we have a wildcard character, then
else if (w == '*')
{
// Skip any multiple wildcards
for (; *wildcard == '*'; ++wildcard)
{
}
w = *wildcard++;
// If wildcard is at the end of the wildcards, then we have a match
if (w == 0)
{
return true;
}
// Look through the target string for the given character.
// If we reach the end of the target string without finding a match
// then this is a failed match. If we find the character, recurse
// to match the remaining part of the string
for (;;)
{
T t = *target++;
if (t == 0)
{
return false;
}
else if (t == w && MatchesWildcardRecursive(target, wildcard))
{
return true;
}
}
}
// If we don't match the character, then we don't have a match
else if (w != *target++)
{
return false;
}
}
}
// Temporary replacement for std::wstring::find
static size_t WideFindOffset(const std::wstring& haystack, const std::wstring& needle)
{
#if defined(__clang__) && defined(_MSC_VER) && _MSVC_LANG > 201402L && __clang_major__ < 13
// For reference: https://bugs.llvm.org/show_bug.cgi?id=41226#c16
const wchar_t* found = ::wcsstr(haystack.c_str(), needle.c_str());
if (found)
{
return static_cast<size_t>(found - haystack.c_str());
}
else
{
return std::wstring::npos;
}
#else
return haystack.find(needle);
#endif
}
// END EPIC MOD
}
namespace string
{
std::wstring ToWideString(const char* utf8Str)
{
return detail::ToWideString(utf8Str, strlen(utf8Str));
}
std::wstring ToWideString(const char* utf8Str, size_t count)
{
size_t length = 0u;
// BEGIN EPIC MOD - PVS FIX
while ((length < count) && (utf8Str[length] != '\0'))
// END EPIC MOD
{
// find null-terminator
++length;
}
return detail::ToWideString(utf8Str, length);
}
std::wstring ToWideString(const std::string& str)
{
return detail::ToWideString(str.c_str(), str.length());
}
std::wstring Replace(const std::wstring& str, const std::wstring& from, const std::wstring& to)
{
std::wstring result = str;
// BEGIN EPIC MOD
size_t startPos = detail::WideFindOffset(str, from);
// END EPIC MOD
if (startPos == std::wstring::npos)
return result;
result.replace(startPos, from.length(), to);
return result;
}
std::string Replace(const std::string& str, const std::string& from, const std::string& to)
{
std::string result = str;
size_t startPos = str.find(from);
if (startPos == std::string::npos)
return result;
result.replace(startPos, from.length(), to);
return result;
}
std::string ReplaceAll(const std::string& str, const std::string& from, const std::string& to)
{
std::string result(str);
for (;;)
{
const size_t pos = result.find(from);
if (pos == std::string::npos)
{
return result;
}
result.replace(pos, from.length(), to);
}
}
std::wstring ReplaceAll(const std::wstring& str, const std::wstring& from, const std::wstring& to)
{
std::wstring result(str);
for (;;)
{
// BEGIN EPIC MOD
const size_t pos = detail::WideFindOffset(result, from);
// END EPIC MOD
if (pos == std::wstring::npos)
{
return result;
}
result.replace(pos, from.length(), to);
}
}
std::string EraseAll(const std::string& str, const std::string& subString)
{
const size_t subStringLength = subString.length();
std::string result(str);
for (;;)
{
const size_t pos = result.find(subString);
if (pos == std::string::npos)
{
return result;
}
result.erase(pos, subStringLength);
}
}
std::wstring EraseAll(const std::wstring& str, const std::wstring& subString)
{
const size_t subStringLength = subString.length();
std::wstring result(str);
for (;;)
{
// BEGIN EPIC MOD
const size_t pos = detail::WideFindOffset(result, subString);
// END EPIC MOD
if (pos == std::wstring::npos)
{
return result;
}
result.erase(pos, subStringLength);
}
}
char* Find(char* str, const char* subString)
{
return strstr(str, subString);
}
wchar_t* Find(wchar_t* str, const wchar_t* subString)
{
return wcsstr(str, subString);
}
const char* Find(const char* str, const char* subString)
{
return strstr(str, subString);
}
const wchar_t* Find(const wchar_t* str, const wchar_t* subString)
{
return wcsstr(str, subString);
}
const wchar_t* Find(const wchar_t* str, size_t strLength, const wchar_t* subString, size_t subStringLength)
{
const wchar_t* end = str + strLength;
while (str < end - subStringLength)
{
size_t i = 0;
for (; i < subStringLength; ++i)
{
if (str[i] != subString[i])
break;
}
if (i == subStringLength)
return str;
++str;
}
return nullptr;
}
bool Matches(const char* str1, const char* str2)
{
return detail::Matches(str1, str2);
}
bool Matches(const wchar_t* str1, const wchar_t* str2)
{
return detail::Matches(str1, str2);
}
bool Contains(const char* str, const char* subString)
{
return Find(str, subString) != nullptr;
}
bool Contains(const wchar_t* str, const wchar_t* subString)
{
return Find(str, subString) != nullptr;
}
bool StartsWith(const char* str, const char* subString)
{
return detail::StartsWith(str, subString);
}
bool StartsWith(const wchar_t* str, const wchar_t* subString)
{
return detail::StartsWith(str, subString);
}
// BEGIN EPIC MOD
const char* StartsWithEx(const char* str, const char* subString)
{
return detail::StartsWithEx(str, subString);
}
const wchar_t* StartsWithEx(const wchar_t* str, const wchar_t* subString)
{
return detail::StartsWithEx(str, subString);
}
bool MatchWildcard(const char* target, const char* wildcard)
{
return detail::MatchesWildcardRecursive(target, wildcard);
}
bool MatchWildcard(const wchar_t* target, const wchar_t* wildcard)
{
return detail::MatchesWildcardRecursive(target, wildcard);
}
// END EPIC MOD
std::string ToUpper(const char* str)
{
std::string upperStr(str);
char* dest = &upperStr[0];
for (size_t i = 0u; i < upperStr.size(); ++i)
{
dest[i] = static_cast<char>(::toupper(dest[i]));
}
return upperStr;
}
std::string ToUpper(const std::string& str)
{
return ToUpper(str.c_str());
}
std::wstring ToUpper(const wchar_t* str)
{
std::wstring upperStr(str);
wchar_t* dest = &upperStr[0];
for (size_t i = 0u; i < upperStr.size(); ++i)
{
dest[i] = static_cast<wchar_t>(::towupper(dest[i]));
}
return upperStr;
}
std::wstring ToUpper(const std::wstring& str)
{
return ToUpper(str.c_str());
}
std::wstring ToLower(const wchar_t* str)
{
std::wstring lowerStr(str);
wchar_t* dest = &lowerStr[0];
for (size_t i = 0u; i < lowerStr.size(); ++i)
{
dest[i] = static_cast<wchar_t>(::towlower(dest[i]));
}
return lowerStr;
}
std::wstring ToLower(const std::wstring& str)
{
return ToLower(str.c_str());
}
std::wstring MakeSafeName(const std::wstring& name)
{
std::wstring safeName(name);
const size_t length = name.length();
for (size_t i = 0u; i < length; ++i)
{
if ((name[i] == '\\') ||
(name[i] == '/') ||
(name[i] == '*') ||
(name[i] == '?') ||
(name[i] == '"') ||
(name[i] == '<') ||
(name[i] == '>') ||
(name[i] == '|') ||
(name[i] == ':') ||
(name[i] == ';') ||
(name[i] == ',') ||
(name[i] == '.'))
{
safeName[i] = '_';
}
}
return safeName;
}
}
#endif // LC_VERSION