From a99549c4515aeb772fbc35e81a940f242c1362aa Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 17 Mar 2019 06:32:55 -0700 Subject: [PATCH] UI: Avoid using game info cache in savedata sort. It can change mid-sort causing the sorting results to be inconsistent, which will crash many implementations of std::stable_sort. Also, fix an issue where it kept resorting after it didn't need to and make it strictly ordered for equal dates/sizes. Fixes #11892. --- UI/GameInfoCache.cpp | 18 +--------- UI/SavedataScreen.cpp | 62 +++++++++++++++++++++-------------- ext/native/file/file_util.cpp | 16 +++++++++ ext/native/file/file_util.h | 3 +- 4 files changed, 57 insertions(+), 42 deletions(-) diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 05558dd2b9..eec7f6f340 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -110,27 +110,11 @@ bool GameInfo::Delete() { } } -static int64_t GetDirectoryRecursiveSize(const std::string &path) { - std::vector fileInfo; - getFilesInDir(path.c_str(), &fileInfo); - int64_t sizeSum = 0; - // Note: getFileInDir does not fill in fileSize properly. - for (size_t i = 0; i < fileInfo.size(); i++) { - FileInfo finfo; - getFileInfo(fileInfo[i].fullName.c_str(), &finfo); - if (!finfo.isDirectory) - sizeSum += finfo.size; - else - sizeSum += GetDirectoryRecursiveSize(finfo.fullName); - } - return sizeSum; -} - u64 GameInfo::GetGameSizeInBytes() { switch (fileType) { case IdentifiedFileType::PSP_PBP_DIRECTORY: case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: - return GetDirectoryRecursiveSize(ResolvePBPDirectory(filePath_)); + return getDirectoryRecursiveSize(ResolvePBPDirectory(filePath_), nullptr, GETFILES_GETHIDDEN); default: return GetFileLoader()->FileSize(); diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index a017aa540d..735b57d5ed 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -132,8 +132,9 @@ public: : UI::LinearLayout(orientation, layoutParams) { } - void SetCompare(CompareFunc lessFunc, DoneFunc) { + void SetCompare(CompareFunc lessFunc, DoneFunc doneFunc) { lessFunc_ = lessFunc; + doneFunc_ = doneFunc; } void Update() override; @@ -336,43 +337,56 @@ bool SavedataBrowser::ByFilename(const UI::View *v1, const UI::View *v2) { return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0; } +static time_t GetTotalSize(const SavedataButton *b) { + auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath())); + tm datetm; + bool success; + switch (Identify_File(fileLoader.get())) { + case IdentifiedFileType::PSP_PBP_DIRECTORY: + case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: + return getDirectoryRecursiveSize(ResolvePBPDirectory(b->GamePath()), nullptr, GETFILES_GETHIDDEN); + + default: + return fileLoader->FileSize(); + } +} + bool SavedataBrowser::BySize(const UI::View *v1, const UI::View *v2) { const SavedataButton *b1 = static_cast(v1); const SavedataButton *b2 = static_cast(v2); - std::shared_ptr g1info = g_gameInfoCache->GetInfo(nullptr, b1->GamePath(), GAMEINFO_WANTSIZE); - std::shared_ptr g2info = g_gameInfoCache->GetInfo(nullptr, b2->GamePath(), GAMEINFO_WANTSIZE); + if (GetTotalSize(b1) > GetTotalSize(b2)) + return true; + return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0; +} - // They might be zero, but that's fine. - return g1info->gameSize > g2info->gameSize; +static time_t GetDateSeconds(const SavedataButton *b) { + auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath())); + tm datetm; + bool success; + if (Identify_File(fileLoader.get()) == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) { + success = File::GetModifTime(b->GamePath() + "/PARAM.SFO", datetm); + } else { + success = File::GetModifTime(b->GamePath(), datetm); + } + + if (success) { + return mktime(&datetm); + } + return (time_t)0; } bool SavedataBrowser::ByDate(const UI::View *v1, const UI::View *v2) { const SavedataButton *b1 = static_cast(v1); const SavedataButton *b2 = static_cast(v2); - auto getDateSeconds = [&](const SavedataButton *b) { - std::shared_ptr ginfo = g_gameInfoCache->GetInfo(nullptr, b->GamePath(), 0); - tm datetm; - bool success; - if (ginfo && ginfo->fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) { - success = File::GetModifTime(b->GamePath() + "/PARAM.SFO", datetm); - } else { - success = File::GetModifTime(b->GamePath(), datetm); - } - - if (success) { - return mktime(&datetm); - } - return (time_t)0; - }; - - return getDateSeconds(b1) > getDateSeconds(b2); + if (GetDateSeconds(b1) > GetDateSeconds(b2)) + return true; + return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0; } bool SavedataBrowser::SortDone() { - PrioritizedWorkQueue *wq = g_gameInfoCache->WorkQueue(); - return wq->Done(); + return true; } void SavedataBrowser::Refresh() { diff --git a/ext/native/file/file_util.cpp b/ext/native/file/file_util.cpp index 0882213e9b..2d6c6df33c 100644 --- a/ext/native/file/file_util.cpp +++ b/ext/native/file/file_util.cpp @@ -297,6 +297,22 @@ size_t getFilesInDir(const char *directory, std::vector *files, const return foundEntries; } +int64_t getDirectoryRecursiveSize(const std::string &path, const char *filter, int flags) { + std::vector fileInfo; + getFilesInDir(path.c_str(), &fileInfo, filter, flags); + int64_t sizeSum = 0; + // Note: getFileInDir does not fill in fileSize properly. + for (size_t i = 0; i < fileInfo.size(); i++) { + FileInfo finfo; + getFileInfo(fileInfo[i].fullName.c_str(), &finfo); + if (!finfo.isDirectory) + sizeSum += finfo.size; + else + sizeSum += getDirectoryRecursiveSize(finfo.fullName, filter, flags); + } + return sizeSum; +} + #ifdef _WIN32 // Returns a vector with the device names std::vector getWindowsDrives() diff --git a/ext/native/file/file_util.h b/ext/native/file/file_util.h index 587b7b93fc..b6c414139b 100644 --- a/ext/native/file/file_util.h +++ b/ext/native/file/file_util.h @@ -34,7 +34,8 @@ FILE *openCFile(const std::string &filename, const char *mode); enum { GETFILES_GETHIDDEN = 1 }; -size_t getFilesInDir(const char *directory, std::vector *files, const char *filter = 0, int flags = 0); +size_t getFilesInDir(const char *directory, std::vector *files, const char *filter = nullptr, int flags = 0); +int64_t getDirectoryRecursiveSize(const std::string &path, const char *filter = nullptr, int flags = 0); #ifdef _WIN32 std::vector getWindowsDrives();