Merge pull request #11829 from lioncash/strutil

Common/StringUtil: Move some utilities into the Common namespace
This commit is contained in:
JosJuice 2023-05-17 09:13:36 +02:00 committed by GitHub
commit 11768e3dd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 53 additions and 48 deletions

View File

@ -77,7 +77,7 @@ std::string HexDump(const u8* data, size_t size)
if (row_start + i < size) if (row_start + i < size)
{ {
char c = static_cast<char>(data[row_start + i]); char c = static_cast<char>(data[row_start + i]);
out += IsPrintableCharacter(c) ? c : '.'; out += Common::IsPrintableCharacter(c) ? c : '.';
} }
} }
out += "\n"; out += "\n";
@ -656,6 +656,8 @@ std::string PathToString(const std::filesystem::path& path)
#endif #endif
} }
namespace Common
{
#ifdef _WIN32 #ifdef _WIN32
std::vector<std::string> CommandLineToUtf8Argv(const wchar_t* command_line) std::vector<std::string> CommandLineToUtf8Argv(const wchar_t* command_line)
{ {
@ -693,8 +695,6 @@ std::string GetEscapedHtml(std::string html)
return html; return html;
} }
namespace Common
{
void ToLower(std::string* str) void ToLower(std::string* str)
{ {
std::transform(str->begin(), str->end(), str->begin(), [](char c) { return Common::ToLower(c); }); std::transform(str->begin(), str->end(), str->begin(), [](char c) { return Common::ToLower(c); });

View File

@ -211,6 +211,34 @@ inline std::string UTF8ToTStr(std::string_view str)
std::filesystem::path StringToPath(std::string_view path); std::filesystem::path StringToPath(std::string_view path);
std::string PathToString(const std::filesystem::path& path); std::string PathToString(const std::filesystem::path& path);
namespace Common
{
/// Returns whether a character is printable, i.e. whether 0x20 <= c <= 0x7e is true.
/// Use this instead of calling std::isprint directly to ensure
/// the C locale is being used and to avoid possibly undefined behaviour.
inline bool IsPrintableCharacter(char c)
{
return std::isprint(c, std::locale::classic());
}
/// Returns whether a character is a letter, i.e. whether 'a' <= c <= 'z' || 'A' <= c <= 'Z'
/// is true. Use this instead of calling std::isalpha directly to ensure
/// the C locale is being used and to avoid possibly undefined behaviour.
inline bool IsAlpha(char c)
{
return std::isalpha(c, std::locale::classic());
}
inline char ToLower(char ch)
{
return std::tolower(ch, std::locale::classic());
}
inline char ToUpper(char ch)
{
return std::toupper(ch, std::locale::classic());
}
// Thousand separator. Turns 12345678 into 12,345,678 // Thousand separator. Turns 12345678 into 12,345,678
template <typename I> template <typename I>
std::string ThousandSeparate(I value, int spaces = 0) std::string ThousandSeparate(I value, int spaces = 0)
@ -230,38 +258,12 @@ std::string ThousandSeparate(I value, int spaces = 0)
#endif #endif
} }
/// Returns whether a character is printable, i.e. whether 0x20 <= c <= 0x7e is true.
/// Use this instead of calling std::isprint directly to ensure
/// the C locale is being used and to avoid possibly undefined behaviour.
inline bool IsPrintableCharacter(char c)
{
return std::isprint(c, std::locale::classic());
}
/// Returns whether a character is a letter, i.e. whether 'a' <= c <= 'z' || 'A' <= c <= 'Z'
/// is true. Use this instead of calling std::isalpha directly to ensure
/// the C locale is being used and to avoid possibly undefined behaviour.
inline bool IsAlpha(char c)
{
return std::isalpha(c, std::locale::classic());
}
#ifdef _WIN32 #ifdef _WIN32
std::vector<std::string> CommandLineToUtf8Argv(const wchar_t* command_line); std::vector<std::string> CommandLineToUtf8Argv(const wchar_t* command_line);
#endif #endif
std::string GetEscapedHtml(std::string html); std::string GetEscapedHtml(std::string html);
namespace Common
{
inline char ToLower(char ch)
{
return std::tolower(ch, std::locale::classic());
}
inline char ToUpper(char ch)
{
return std::toupper(ch, std::locale::classic());
}
void ToLower(std::string* str); void ToLower(std::string* str);
void ToUpper(std::string* str); void ToUpper(std::string* str);
bool CaseInsensitiveEquals(std::string_view a, std::string_view b); bool CaseInsensitiveEquals(std::string_view a, std::string_view b);

View File

@ -193,7 +193,7 @@ void DisplayMessage(std::string message, int time_in_ms)
return; return;
// Actually displaying non-ASCII could cause things to go pear-shaped // Actually displaying non-ASCII could cause things to go pear-shaped
if (!std::all_of(message.begin(), message.end(), IsPrintableCharacter)) if (!std::all_of(message.begin(), message.end(), Common::IsPrintableCharacter))
return; return;
OSD::AddMessage(std::move(message), time_in_ms); OSD::AddMessage(std::move(message), time_in_ms);

View File

@ -77,7 +77,7 @@ void FileLogger::Log(const DiscIO::Volume& volume, const DiscIO::Partition& part
if (m_previous_partition == partition && m_previous_file_offset == file_offset) if (m_previous_partition == partition && m_previous_file_offset == file_offset)
return; return;
const std::string size_string = ThousandSeparate(file_info->GetSize() / 1000, 7); const std::string size_string = Common::ThousandSeparate(file_info->GetSize() / 1000, 7);
const std::string path = file_info->GetPath(); const std::string path = file_info->GetPath();
const std::string log_string = fmt::format("{} kB {}", size_string, path); const std::string log_string = fmt::format("{} kB {}", size_string, path);
if (IsSoundFile(path)) if (IsSoundFile(path))

View File

@ -302,7 +302,7 @@ std::string TMDReader::GetGameID() const
std::memcpy(game_id, m_bytes.data() + offsetof(TMDHeader, title_id) + 4, 4); std::memcpy(game_id, m_bytes.data() + offsetof(TMDHeader, title_id) + 4, 4);
std::memcpy(game_id + 4, m_bytes.data() + offsetof(TMDHeader, group_id), 2); std::memcpy(game_id + 4, m_bytes.data() + offsetof(TMDHeader, group_id), 2);
if (std::all_of(std::begin(game_id), std::end(game_id), IsPrintableCharacter)) if (std::all_of(std::begin(game_id), std::end(game_id), Common::IsPrintableCharacter))
return std::string(game_id, sizeof(game_id)); return std::string(game_id, sizeof(game_id));
return fmt::format("{:016x}", GetTitleId()); return fmt::format("{:016x}", GetTitleId());
@ -313,7 +313,7 @@ std::string TMDReader::GetGameTDBID() const
const u8* begin = m_bytes.data() + offsetof(TMDHeader, title_id) + 4; const u8* begin = m_bytes.data() + offsetof(TMDHeader, title_id) + 4;
const u8* end = begin + 4; const u8* end = begin + 4;
if (std::all_of(begin, end, IsPrintableCharacter)) if (std::all_of(begin, end, Common::IsPrintableCharacter))
return std::string(begin, end); return std::string(begin, end);
return fmt::format("{:016x}", GetTitleId()); return fmt::format("{:016x}", GetTitleId());

View File

@ -474,8 +474,11 @@ ResultCode HostFileSystem::Format(Uid uid)
ResultCode HostFileSystem::CreateFileOrDirectory(Uid uid, Gid gid, const std::string& path, ResultCode HostFileSystem::CreateFileOrDirectory(Uid uid, Gid gid, const std::string& path,
FileAttribute attr, Modes modes, bool is_file) FileAttribute attr, Modes modes, bool is_file)
{ {
if (!IsValidNonRootPath(path) || !std::all_of(path.begin(), path.end(), IsPrintableCharacter)) if (!IsValidNonRootPath(path) ||
!std::all_of(path.begin(), path.end(), Common::IsPrintableCharacter))
{
return ResultCode::Invalid; return ResultCode::Invalid;
}
if (!is_file && std::count(path.begin(), path.end(), '/') > int(MaxPathDepth)) if (!is_file && std::count(path.begin(), path.end(), '/') > int(MaxPathDepth))
return ResultCode::TooManyPathComponents; return ResultCode::TooManyPathComponents;

View File

@ -87,7 +87,7 @@ void V4GetUSStringMessage::OnTransferComplete(s32 return_value) const
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
std::string message = memory.GetString(data_address); std::string message = memory.GetString(data_address);
std::replace_if(message.begin(), message.end(), std::not_fn(IsPrintableCharacter), '?'); std::replace_if(message.begin(), message.end(), std::not_fn(Common::IsPrintableCharacter), '?');
memory.CopyToEmu(data_address, message.c_str(), message.size()); memory.CopyToEmu(data_address, message.c_str(), message.size());
TransferCommand::OnTransferComplete(return_value); TransferCommand::OnTransferComplete(return_value);
} }

View File

@ -256,7 +256,7 @@ std::string VolumeWAD::GetMakerID(const Partition& partition) const
return "00"; return "00";
// Some weird channels use 0x0000 in place of the MakerID, so we need a check here // Some weird channels use 0x0000 in place of the MakerID, so we need a check here
if (!IsPrintableCharacter(temp[0]) || !IsPrintableCharacter(temp[1])) if (!Common::IsPrintableCharacter(temp[0]) || !Common::IsPrintableCharacter(temp[1]))
return "00"; return "00";
return DecodeString(temp); return DecodeString(temp);

View File

@ -316,7 +316,7 @@ int main(int argc, char* argv[])
#ifdef _WIN32 #ifdef _WIN32
int wmain(int, wchar_t*[], wchar_t*[]) int wmain(int, wchar_t*[], wchar_t*[])
{ {
std::vector<std::string> args = CommandLineToUtf8Argv(GetCommandLineW()); std::vector<std::string> args = Common::CommandLineToUtf8Argv(GetCommandLineW());
const int argc = static_cast<int>(args.size()); const int argc = static_cast<int>(args.size());
std::vector<char*> argv(args.size()); std::vector<char*> argv(args.size());
for (size_t i = 0; i < args.size(); ++i) for (size_t i = 0; i < args.size(); ++i)

View File

@ -168,7 +168,7 @@ void FilesystemWidget::PopulateDirectory(int partition_id, QStandardItem* root,
for (u32 i = 0; i < 4; i++) for (u32 i = 0; i < 4; i++)
{ {
char c = static_cast<char>(title_id.value() >> 8 * (3 - i)); char c = static_cast<char>(title_id.value() >> 8 * (3 - i));
if (IsPrintableCharacter(c)) if (Common::IsPrintableCharacter(c))
text += QLatin1Char(c); text += QLatin1Char(c);
else else
text += QLatin1Char('.'); text += QLatin1Char('.');

View File

@ -495,8 +495,8 @@ QString MemoryViewWidget::ValueToString(const Core::CPUThreadGuard& guard, u32 a
case Type::ASCII: case Type::ASCII:
{ {
const char value = accessors->ReadU8(guard, address); const char value = accessors->ReadU8(guard, address);
return IsPrintableCharacter(value) ? QString{QChar::fromLatin1(value)} : return Common::IsPrintableCharacter(value) ? QString{QChar::fromLatin1(value)} :
QString{QChar::fromLatin1('.')}; QString{QChar::fromLatin1('.')};
} }
case Type::Hex16: case Type::Hex16:
{ {

View File

@ -306,7 +306,7 @@ int main(int argc, char* argv[])
#ifdef _WIN32 #ifdef _WIN32
int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int) int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int)
{ {
std::vector<std::string> args = CommandLineToUtf8Argv(GetCommandLineW()); std::vector<std::string> args = Common::CommandLineToUtf8Argv(GetCommandLineW());
const int argc = static_cast<int>(args.size()); const int argc = static_cast<int>(args.size());
std::vector<char*> argv(args.size()); std::vector<char*> argv(args.size());
for (size_t i = 0; i < args.size(); ++i) for (size_t i = 0; i < args.size(); ++i)

View File

@ -54,7 +54,7 @@ int main(int argc, char* argv[])
#ifdef _WIN32 #ifdef _WIN32
int wmain(int, wchar_t*[], wchar_t*[]) int wmain(int, wchar_t*[], wchar_t*[])
{ {
std::vector<std::string> args = CommandLineToUtf8Argv(GetCommandLineW()); std::vector<std::string> args = Common::CommandLineToUtf8Argv(GetCommandLineW());
const int argc = static_cast<int>(args.size()); const int argc = static_cast<int>(args.size());
std::vector<char*> argv(args.size()); std::vector<char*> argv(args.size());
for (size_t i = 0; i < args.size(); ++i) for (size_t i = 0; i < args.size(); ++i)

View File

@ -43,7 +43,7 @@ std::string GetExpressionForControl(const std::string& control_name,
{ {
// If our expression contains any non-alpha characters // If our expression contains any non-alpha characters
// we should quote it // we should quote it
if (!std::all_of(expr.begin(), expr.end(), IsAlpha)) if (!std::all_of(expr.begin(), expr.end(), Common::IsAlpha))
expr = fmt::format("`{}`", expr); expr = fmt::format("`{}`", expr);
} }

View File

@ -118,7 +118,7 @@ std::string GenerateChangelog(const picojson::array& versions)
changelog += ver_obj["shortrev"].get<std::string>(); changelog += ver_obj["shortrev"].get<std::string>();
} }
const std::string escaped_description = const std::string escaped_description =
GetEscapedHtml(ver_obj["short_descr"].get<std::string>()); Common::GetEscapedHtml(ver_obj["short_descr"].get<std::string>());
changelog += " by <a href = \"" + ver_obj["author_url"].get<std::string>() + "\">" + changelog += " by <a href = \"" + ver_obj["author_url"].get<std::string>() + "\">" +
ver_obj["author"].get<std::string>() + "</a> &mdash; " + escaped_description; ver_obj["author"].get<std::string>() + "</a> &mdash; " + escaped_description;
} }

View File

@ -62,7 +62,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
return 0; return 0;
} }
std::vector<std::string> args = CommandLineToUtf8Argv(pCmdLine); std::vector<std::string> args = Common::CommandLineToUtf8Argv(pCmdLine);
return RunUpdater(args) ? 0 : 1; return RunUpdater(args) ? 0 : 1;
} }

View File

@ -86,7 +86,7 @@ TEST(StringUtil, GetEscapedHtml)
static constexpr auto no_escape_needed = static constexpr auto no_escape_needed =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
"!@#$%^*()-_=+,./?;:[]{}| \\\t\n"; "!@#$%^*()-_=+,./?;:[]{}| \\\t\n";
EXPECT_EQ(GetEscapedHtml(no_escape_needed), no_escape_needed); EXPECT_EQ(Common::GetEscapedHtml(no_escape_needed), no_escape_needed);
EXPECT_EQ(GetEscapedHtml("&<>'\""), "&amp;&lt;&gt;&apos;&quot;"); EXPECT_EQ(Common::GetEscapedHtml("&<>'\""), "&amp;&lt;&gt;&apos;&quot;");
EXPECT_EQ(GetEscapedHtml("&&&"), "&amp;&amp;&amp;"); EXPECT_EQ(Common::GetEscapedHtml("&&&"), "&amp;&amp;&amp;");
} }