mirror of https://github.com/PCSX2/pcsx2.git
Path: Make sanitize routine follow OS rules
This commit is contained in:
parent
22ed71cef4
commit
2b04f0b585
|
@ -61,16 +61,32 @@ static std::time_t ConvertFileTimeToUnixTime(const FILETIME& ft)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline bool FileSystemCharacterIsSane(char c, bool StripSlashes)
|
static inline bool FileSystemCharacterIsSane(char c, bool strip_slashes)
|
||||||
{
|
{
|
||||||
if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != ' ' &&
|
#ifdef _WIN32
|
||||||
c != '_' && c != '-' && c != '.')
|
// https://docs.microsoft.com/en-gb/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#naming-conventions
|
||||||
{
|
if ((c == U'/' || c == U'\\') && strip_slashes)
|
||||||
if (!StripSlashes && (c == '/' || c == '\\'))
|
return false;
|
||||||
return true;
|
|
||||||
|
|
||||||
|
if (c == U'<' || c == U'>' || c == U':' || c == U'"' || c == U'|' || c == U'?' || c == U'*' || c == 0 ||
|
||||||
|
c <= static_cast<char32_t>(31))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (c == '/' && strip_slashes)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// drop asterisks too, they make globbing annoying
|
||||||
|
if (c == '*')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// macos doesn't allow colons, apparently
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (c == U':')
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -118,39 +134,58 @@ static inline void PathAppendString(std::string& dst, const T& src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Path::SanitizeFileName(char* Destination, u32 cbDestination, const char* FileName, bool StripSlashes /* = true */)
|
std::string Path::SanitizeFileName(const std::string_view& str, bool strip_slashes /* = true */)
|
||||||
{
|
{
|
||||||
u32 i;
|
std::string ret;
|
||||||
u32 fileNameLength = static_cast<u32>(std::strlen(FileName));
|
ret.reserve(str.length());
|
||||||
|
|
||||||
if (FileName == Destination)
|
size_t pos = 0;
|
||||||
|
while (pos < str.length())
|
||||||
{
|
{
|
||||||
for (i = 0; i < fileNameLength; i++)
|
char32_t ch;
|
||||||
{
|
pos += StringUtil::DecodeUTF8(str, pos, &ch);
|
||||||
if (!FileSystemCharacterIsSane(FileName[i], StripSlashes))
|
ch = FileSystemCharacterIsSane(ch, strip_slashes) ? ch : U'_';
|
||||||
Destination[i] = '_';
|
StringUtil::EncodeAndAppendUTF8(ret, ch);
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 0; i < fileNameLength && i < cbDestination; i++)
|
|
||||||
{
|
|
||||||
if (FileSystemCharacterIsSane(FileName[i], StripSlashes))
|
|
||||||
Destination[i] = FileName[i];
|
|
||||||
else
|
|
||||||
Destination[i] = '_';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Windows: Can't end filename with a period.
|
||||||
|
if (ret.length() > 0 && ret.back() == '.')
|
||||||
|
ret.back() = '_';
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Path::SanitizeFileName(std::string& Destination, bool StripSlashes /* = true*/)
|
void Path::SanitizeFileName(std::string* str, bool strip_slashes /* = true */)
|
||||||
{
|
{
|
||||||
const std::size_t len = Destination.length();
|
const size_t len = str->length();
|
||||||
for (std::size_t i = 0; i < len; i++)
|
|
||||||
|
char small_buf[128];
|
||||||
|
std::unique_ptr<char[]> large_buf;
|
||||||
|
char* str_copy = small_buf;
|
||||||
|
if (len >= std::size(small_buf))
|
||||||
{
|
{
|
||||||
if (!FileSystemCharacterIsSane(Destination[i], StripSlashes))
|
large_buf = std::make_unique<char[]>(len + 1);
|
||||||
Destination[i] = '_';
|
str_copy = large_buf.get();
|
||||||
}
|
}
|
||||||
|
std::memcpy(str_copy, str->c_str(), sizeof(char) * (len + 1));
|
||||||
|
str->clear();
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
while (pos < len)
|
||||||
|
{
|
||||||
|
char32_t ch;
|
||||||
|
pos += StringUtil::DecodeUTF8(str_copy + pos, pos - len, &ch);
|
||||||
|
ch = FileSystemCharacterIsSane(ch, strip_slashes) ? ch : U'_';
|
||||||
|
StringUtil::EncodeAndAppendUTF8(*str, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Windows: Can't end filename with a period.
|
||||||
|
if (str->length() > 0 && str->back() == '.')
|
||||||
|
str->back() = '_';
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Path::IsAbsolute(const std::string_view& path)
|
bool Path::IsAbsolute(const std::string_view& path)
|
||||||
|
|
|
@ -38,8 +38,8 @@ namespace Path
|
||||||
void Canonicalize(std::string* path);
|
void Canonicalize(std::string* path);
|
||||||
|
|
||||||
/// Sanitizes a filename for use in a filesystem.
|
/// Sanitizes a filename for use in a filesystem.
|
||||||
void SanitizeFileName(char* Destination, u32 cbDestination, const char* FileName, bool StripSlashes /* = true */);
|
std::string SanitizeFileName(const std::string_view& str, bool strip_slashes = true);
|
||||||
void SanitizeFileName(std::string& Destination, bool StripSlashes = true);
|
void SanitizeFileName(std::string* str, bool strip_slashes = true);
|
||||||
|
|
||||||
/// Returns true if the specified path is an absolute path (C:\Path on Windows or /path on Unix).
|
/// Returns true if the specified path is an absolute path (C:\Path on Windows or /path on Unix).
|
||||||
bool IsAbsolute(const std::string_view& path);
|
bool IsAbsolute(const std::string_view& path);
|
||||||
|
|
|
@ -766,14 +766,14 @@ void GSRenderer::QueueSnapshot(const std::string& path, u32 gsdump_frames)
|
||||||
// append the game serial and title
|
// append the game serial and title
|
||||||
if (std::string name(GetDumpName()); !name.empty())
|
if (std::string name(GetDumpName()); !name.empty())
|
||||||
{
|
{
|
||||||
Path::SanitizeFileName(name);
|
Path::SanitizeFileName(&name);
|
||||||
if (name.length() > 219)
|
if (name.length() > 219)
|
||||||
name.resize(219);
|
name.resize(219);
|
||||||
m_snapshot += name;
|
m_snapshot += name;
|
||||||
}
|
}
|
||||||
if (std::string serial(GetDumpSerial()); !serial.empty())
|
if (std::string serial(GetDumpSerial()); !serial.empty())
|
||||||
{
|
{
|
||||||
Path::SanitizeFileName(serial);
|
Path::SanitizeFileName(&serial);
|
||||||
m_snapshot += '_';
|
m_snapshot += '_';
|
||||||
m_snapshot += serial;
|
m_snapshot += serial;
|
||||||
}
|
}
|
||||||
|
|
|
@ -357,8 +357,7 @@ void VMManager::ApplyGameFixes()
|
||||||
|
|
||||||
std::string VMManager::GetGameSettingsPath(const std::string_view& game_serial, u32 game_crc)
|
std::string VMManager::GetGameSettingsPath(const std::string_view& game_serial, u32 game_crc)
|
||||||
{
|
{
|
||||||
std::string sanitized_serial(game_serial);
|
std::string sanitized_serial(Path::SanitizeFileName(game_serial));
|
||||||
Path::SanitizeFileName(sanitized_serial);
|
|
||||||
|
|
||||||
return game_serial.empty() ?
|
return game_serial.empty() ?
|
||||||
Path::Combine(EmuFolders::GameSettings, fmt::format("{:08X}.ini", game_crc)) :
|
Path::Combine(EmuFolders::GameSettings, fmt::format("{:08X}.ini", game_crc)) :
|
||||||
|
|
Loading…
Reference in New Issue