From 43eb6e20fab73f541f34d15211bc7e712316b5a6 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 15 Mar 2024 15:21:06 +1000 Subject: [PATCH] System: Improve screenshot naming --- src/common-tests/path_tests.cpp | 10 ++++++++++ src/common/file_system.cpp | 19 +++++++++++++++++++ src/common/path.h | 4 ++++ src/core/gpu.cpp | 3 ++- src/core/system.cpp | 24 +++++++++++++++--------- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/common-tests/path_tests.cpp b/src/common-tests/path_tests.cpp index 1af1a6cea..8b6372c56 100644 --- a/src/common-tests/path_tests.cpp +++ b/src/common-tests/path_tests.cpp @@ -243,6 +243,16 @@ TEST(Path, SanitizeFileName) ASSERT_EQ(Path::SanitizeFileName("foo/bar", false), "foo/bar"); } +TEST(Path, RemoveLengthLimits) +{ +#ifdef _WIN32 + ASSERT_EQ(Path::RemoveLengthLimits("C:\\foo"), "\\\\?\\C:\\foo"); + ASSERT_EQ(Path::RemoveLengthLimits("\\\\foo\\bar\\baz"), "\\\\?\\\\\\foo\\bar\\baz"); +#else + ASSERT_EQ(Path::RemoveLengthLimits("/foo/bar/baz"), "/foo/bar/baz"); +#endif +} + #if 0 // Relies on presence of files. diff --git a/src/common/file_system.cpp b/src/common/file_system.cpp index e22039dcf..ef78acc04 100644 --- a/src/common/file_system.cpp +++ b/src/common/file_system.cpp @@ -182,6 +182,25 @@ void Path::SanitizeFileName(std::string* str, bool strip_slashes /* = true */) #endif } +std::string Path::RemoveLengthLimits(std::string_view str) +{ + std::string ret; +#ifdef _WIN32 + ret.reserve(str.length() + 4); +#endif + ret.append(str); + RemoveLengthLimits(&ret); + return ret; +} + +void Path::RemoveLengthLimits(std::string* path) +{ + DebugAssert(IsAbsolute(*path)); +#ifdef _WIN32 + path->insert(0, "\\\\?\\"); +#endif +} + bool Path::IsAbsolute(const std::string_view& path) { #ifdef _WIN32 diff --git a/src/common/path.h b/src/common/path.h index dff7a04eb..e0303791b 100644 --- a/src/common/path.h +++ b/src/common/path.h @@ -28,6 +28,10 @@ void Canonicalize(std::string* path); std::string SanitizeFileName(const std::string_view& str, bool strip_slashes = true); void SanitizeFileName(std::string* str, bool strip_slashes = true); +/// Mutates the path to remove any MAX_PATH limits (for Windows). +std::string RemoveLengthLimits(std::string_view str); +void RemoveLengthLimits(std::string* path); + /// 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); diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 0fed53027..829567104 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -2209,7 +2209,8 @@ bool GPU::RenderScreenshotToFile(std::string filename, DisplayScreenshotMode mod return false; } - auto fp = FileSystem::OpenManagedCFile(filename.c_str(), "wb"); + // These filenames tend to be fairly long, so remove any MAX_PATH limit. + auto fp = FileSystem::OpenManagedCFile(Path::RemoveLengthLimits(filename).c_str(), "wb"); if (!fp) { Log_ErrorPrintf("Can't open file '%s': errno %d", filename.c_str(), errno); diff --git a/src/core/system.cpp b/src/core/system.cpp index 2da03ad51..88ab90480 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -239,7 +239,7 @@ static time_t s_discord_presence_time_epoch; static TinyString GetTimestampStringForFileName() { - return TinyString::from_format("{:%Y-%m-%d_%H-%M-%S}", fmt::localtime(std::time(nullptr))); + return TinyString::from_format("{:%Y-%m-%d-%H-%M-%S}", fmt::localtime(std::time(nullptr))); } bool System::Internal::ProcessStartup() @@ -4348,17 +4348,23 @@ bool System::SaveScreenshot(const char* filename, DisplayScreenshotMode mode, Di std::string auto_filename; if (!filename) { - const auto& code = System::GetGameSerial(); + const std::string& name = System::GetGameTitle(); const char* extension = Settings::GetDisplayScreenshotFormatExtension(format); - if (code.empty()) - { - auto_filename = - Path::Combine(EmuFolders::Screenshots, fmt::format("{}.{}", GetTimestampStringForFileName(), extension)); - } + std::string basename; + if (name.empty()) + basename = fmt::format("{}", GetTimestampStringForFileName()); else + basename = fmt::format("{} {}", name, GetTimestampStringForFileName()); + + auto_filename = fmt::format("{}" FS_OSPATH_SEPARATOR_STR "{}.{}", EmuFolders::Screenshots, basename, extension); + + // handle quick screenshots to the same filename + u32 next_suffix = 1; + while (FileSystem::FileExists(Path::RemoveLengthLimits(auto_filename).c_str())) { - auto_filename = Path::Combine(EmuFolders::Screenshots, - fmt::format("{}_{}.{}", code, GetTimestampStringForFileName(), extension)); + auto_filename = fmt::format("{}" FS_OSPATH_SEPARATOR_STR "{} ({}).{}", EmuFolders::Screenshots, basename, + next_suffix, extension); + next_suffix++; } filename = auto_filename.c_str();