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.
This commit is contained in:
Unknown W. Brackets 2019-03-17 06:32:55 -07:00
parent d6d6dbb772
commit a99549c451
4 changed files with 57 additions and 42 deletions

View File

@ -110,27 +110,11 @@ bool GameInfo::Delete() {
}
}
static int64_t GetDirectoryRecursiveSize(const std::string &path) {
std::vector<FileInfo> 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();

View File

@ -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<FileLoader>(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<const SavedataButton *>(v1);
const SavedataButton *b2 = static_cast<const SavedataButton *>(v2);
std::shared_ptr<GameInfo> g1info = g_gameInfoCache->GetInfo(nullptr, b1->GamePath(), GAMEINFO_WANTSIZE);
std::shared_ptr<GameInfo> 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<FileLoader>(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<const SavedataButton *>(v1);
const SavedataButton *b2 = static_cast<const SavedataButton *>(v2);
auto getDateSeconds = [&](const SavedataButton *b) {
std::shared_ptr<GameInfo> 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() {

View File

@ -297,6 +297,22 @@ size_t getFilesInDir(const char *directory, std::vector<FileInfo> *files, const
return foundEntries;
}
int64_t getDirectoryRecursiveSize(const std::string &path, const char *filter, int flags) {
std::vector<FileInfo> 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<std::string> getWindowsDrives()

View File

@ -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<FileInfo> *files, const char *filter = 0, int flags = 0);
size_t getFilesInDir(const char *directory, std::vector<FileInfo> *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<std::string> getWindowsDrives();