mirror of
https://github.com/izzy2lost/ppsspp.git
synced 2026-03-10 12:43:04 -07:00
Merge pull request #19676 from hrydgard/file-system-perf-part-4
File system perf part 4, fix save deletion regression
This commit is contained in:
@@ -162,7 +162,7 @@ static std::string EscapeHash(std::string_view value) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void ParsedIniLine::ParseFrom(std::string_view line) {
|
||||
ParsedIniLine::ParsedIniLine(std::string_view line) {
|
||||
line = StripSpaces(line);
|
||||
if (line.empty()) {
|
||||
key.clear();
|
||||
@@ -534,7 +534,7 @@ bool IniFile::Load(std::istream &in) {
|
||||
while (!(in.eof() || in.fail()))
|
||||
{
|
||||
in.getline(templine, MAX_BYTES);
|
||||
std::string line = templine;
|
||||
std::string_view line = templine;
|
||||
|
||||
// Remove UTF-8 byte order marks.
|
||||
if (line.substr(0, 3) == "\xEF\xBB\xBF") {
|
||||
@@ -543,8 +543,8 @@ bool IniFile::Load(std::istream &in) {
|
||||
|
||||
#ifndef _WIN32
|
||||
// Check for CRLF eol and convert it to LF
|
||||
if (!line.empty() && line.at(line.size()-1) == '\r') {
|
||||
line.erase(line.size()-1);
|
||||
if (!line.empty() && line.at(line.size() - 1) == '\r') {
|
||||
line = line.substr(line.size() - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -556,7 +556,7 @@ bool IniFile::Load(std::istream &in) {
|
||||
|
||||
if (sectionNameEnd != std::string::npos) {
|
||||
// New section!
|
||||
std::string sub = line.substr(1, sectionNameEnd - 1);
|
||||
std::string_view sub = line.substr(1, sectionNameEnd - 1);
|
||||
sections.push_back(std::make_unique<Section>(sub));
|
||||
|
||||
if (sectionNameEnd + 1 < line.size()) {
|
||||
@@ -566,9 +566,7 @@ bool IniFile::Load(std::istream &in) {
|
||||
if (sections.empty()) {
|
||||
sections.push_back(std::make_unique<Section>(""));
|
||||
}
|
||||
ParsedIniLine parsedLine;
|
||||
parsedLine.ParseFrom(line);
|
||||
sections.back()->lines_.push_back(parsedLine);
|
||||
sections.back()->lines_.emplace_back(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ class VFSInterface;
|
||||
|
||||
class ParsedIniLine {
|
||||
public:
|
||||
ParsedIniLine() {}
|
||||
explicit ParsedIniLine(std::string_view line);
|
||||
|
||||
ParsedIniLine(std::string_view key, std::string_view value) {
|
||||
this->key = key;
|
||||
this->value = value;
|
||||
@@ -32,8 +33,6 @@ public:
|
||||
return ParsedIniLine(std::string_view(), std::string_view(), comment);
|
||||
}
|
||||
|
||||
// Comments only come from "ParseFrom".
|
||||
void ParseFrom(std::string_view line);
|
||||
void Reconstruct(std::string *output) const;
|
||||
|
||||
// Having these as views allows a more efficient internal representation, like one joint string.
|
||||
|
||||
@@ -131,9 +131,7 @@ Path I18NRepo::GetIniPath(const std::string &languageID) const {
|
||||
|
||||
bool I18NRepo::IniExists(const std::string &languageID) const {
|
||||
File::FileInfo info;
|
||||
if (!g_VFS.GetFileInfo(GetIniPath(languageID).ToString().c_str(), &info))
|
||||
return false;
|
||||
if (!info.exists)
|
||||
if (!g_VFS.Exists(GetIniPath(languageID).ToString().c_str()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ void Android_StorageSetNativeActivity(jobject nativeActivity) {
|
||||
void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj) {
|
||||
openContentUri = env->GetMethodID(env->GetObjectClass(obj), "openContentUri", "(Ljava/lang/String;Ljava/lang/String;)I");
|
||||
_dbg_assert_(openContentUri);
|
||||
listContentUriDir = env->GetMethodID(env->GetObjectClass(obj), "listContentUriDir", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
|
||||
listContentUriDir = env->GetMethodID(env->GetObjectClass(obj), "listContentUriDir", "(Ljava/lang/String;)[Ljava/lang/String;");
|
||||
_dbg_assert_(listContentUriDir);
|
||||
contentUriCreateDirectory = env->GetMethodID(env->GetObjectClass(obj), "contentUriCreateDirectory", "(Ljava/lang/String;Ljava/lang/String;)I");
|
||||
_dbg_assert_(contentUriCreateDirectory);
|
||||
@@ -233,8 +233,7 @@ std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri, const
|
||||
double start = time_now_d();
|
||||
|
||||
jstring param = env->NewStringUTF(uri.c_str());
|
||||
jstring filter = prefix.empty() ? nullptr : env->NewStringUTF(prefix.c_str());
|
||||
jobject retval = env->CallObjectMethod(g_nativeActivity, listContentUriDir, param, filter);
|
||||
jobject retval = env->CallObjectMethod(g_nativeActivity, listContentUriDir, param);
|
||||
|
||||
jobjectArray fileList = (jobjectArray)retval;
|
||||
std::vector<File::FileInfo> items;
|
||||
@@ -251,6 +250,7 @@ std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri, const
|
||||
} else if (ParseFileInfo(line, &info)) {
|
||||
// We can just reconstruct the URI.
|
||||
info.fullName = Path(uri) / info.name;
|
||||
INFO_LOG(Log::FileSystem, "%s", info.name.c_str());
|
||||
items.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ static uint64_t FiletimeToStatTime(FILETIME ft) {
|
||||
|
||||
bool GetFileInfo(const Path &path, FileInfo * fileInfo) {
|
||||
if (LOG_IO) {
|
||||
INFO_LOG(Log::System, "GetFileInfo %s", path.c_str());
|
||||
INFO_LOG(Log::System, "GetFileInfo %s", path.ToVisualString().c_str());
|
||||
}
|
||||
if (SIMULATE_SLOW_IO) {
|
||||
sleep_ms(300, "slow-io-sim");
|
||||
@@ -178,12 +178,14 @@ std::vector<File::FileInfo> ApplyFilter(std::vector<File::FileInfo> files, const
|
||||
}
|
||||
|
||||
auto pred = [&](const File::FileInfo &info) {
|
||||
// WARNING: Keep in mind that if we return true here, the files is REMOVED from the list.
|
||||
// It's not retain_if.
|
||||
if (!startsWith(info.name, prefix)) {
|
||||
return true;
|
||||
}
|
||||
if (info.isDirectory || !extensionFilter)
|
||||
return false;
|
||||
std::string ext = info.fullName.GetFileExtension();
|
||||
if (!startsWith(info.name, prefix)) {
|
||||
return false;
|
||||
}
|
||||
return filters.find(ext) == filters.end();
|
||||
};
|
||||
files.erase(std::remove_if(files.begin(), files.end(), pred), files.end());
|
||||
@@ -192,7 +194,7 @@ std::vector<File::FileInfo> ApplyFilter(std::vector<File::FileInfo> files, const
|
||||
|
||||
bool GetFilesInDir(const Path &directory, std::vector<FileInfo> *files, const char *filter, int flags, std::string_view prefix) {
|
||||
if (LOG_IO) {
|
||||
INFO_LOG(Log::System, "GetFilesInDir %s (ext %s, prefix %.*s)", directory.c_str(), filter, (int)prefix.size(), prefix.data());
|
||||
INFO_LOG(Log::System, "GetFilesInDir '%s' (ext %s, prefix %.*s)", directory.ToVisualString().c_str(), filter, (int)prefix.size(), prefix.data());
|
||||
}
|
||||
if (SIMULATE_SLOW_IO) {
|
||||
sleep_ms(300, "slow-io-sim");
|
||||
@@ -202,8 +204,10 @@ bool GetFilesInDir(const Path &directory, std::vector<FileInfo> *files, const ch
|
||||
bool exists = false;
|
||||
// TODO: Move prefix filtering over to the Java side for more speed.
|
||||
std::vector<File::FileInfo> fileList = Android_ListContentUri(directory.ToString(), std::string(prefix), &exists);
|
||||
*files = ApplyFilter(fileList, filter, "");
|
||||
int beforeFilter = (int)fileList.size();
|
||||
*files = ApplyFilter(fileList, filter, prefix);
|
||||
std::sort(files->begin(), files->end());
|
||||
DEBUG_LOG(Log::System, "GetFilesInDir: Found %d entries (%d before filter)", (int)files->size(), beforeFilter);
|
||||
return exists;
|
||||
}
|
||||
|
||||
@@ -276,12 +280,9 @@ bool GetFilesInDir(const Path &directory, std::vector<FileInfo> *files, const ch
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
if (SIMULATE_SLOW_IO) {
|
||||
INFO_LOG(Log::System, "GetFilesInDir item %s", virtualName.c_str());
|
||||
sleep_ms(50, "slow-io-sim");
|
||||
if (LOG_IO) {
|
||||
// INFO_LOG(Log::System, "GetFilesInDir item %s", virtualName.c_str());
|
||||
}
|
||||
*/
|
||||
|
||||
FileInfo info;
|
||||
info.name = virtualName;
|
||||
|
||||
@@ -420,7 +420,7 @@ bool ExistsInDir(const Path &path, const std::string &filename) {
|
||||
|
||||
bool Exists(const Path &path) {
|
||||
if (LOG_IO) {
|
||||
INFO_LOG(Log::System, "Exists %s", path.c_str());
|
||||
INFO_LOG(Log::System, "Exists %s", path.ToVisualString().c_str());
|
||||
}
|
||||
if (SIMULATE_SLOW_IO) {
|
||||
sleep_ms(200, "slow-io-sim");
|
||||
@@ -631,7 +631,7 @@ bool CreateDir(const Path &path) {
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const Path &path) {
|
||||
if (File::Exists(path)) {
|
||||
DEBUG_LOG(Log::Common, "CreateFullPath: path exists %s", path.c_str());
|
||||
DEBUG_LOG(Log::Common, "CreateFullPath: path exists %s", path.ToVisualString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -640,7 +640,7 @@ bool CreateFullPath(const Path &path) {
|
||||
case PathType::CONTENT_URI:
|
||||
break; // OK
|
||||
default:
|
||||
ERROR_LOG(Log::Common, "CreateFullPath(%s): Not yet supported", path.c_str());
|
||||
ERROR_LOG(Log::Common, "CreateFullPath(%s): Not yet supported", path.ToVisualString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -665,9 +665,7 @@ bool CreateFullPath(const Path &path) {
|
||||
Path curPath = root;
|
||||
for (auto part : parts) {
|
||||
curPath /= part;
|
||||
if (!File::Exists(curPath)) {
|
||||
File::CreateDir(curPath);
|
||||
}
|
||||
File::CreateDir(curPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -32,6 +32,11 @@ bool DirectoryReader::GetFileInfo(const char *path, File::FileInfo *info) {
|
||||
return File::GetFileInfo(new_path, info);
|
||||
}
|
||||
|
||||
bool DirectoryReader::Exists(const char *path) {
|
||||
Path new_path = Path(path).StartsWith(path_) ? Path(path) : path_ / path;
|
||||
return File::Exists(new_path);
|
||||
}
|
||||
|
||||
class DirectoryReaderFileReference : public VFSFileReference {
|
||||
public:
|
||||
Path path;
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
|
||||
bool GetFileListing(const char *path, std::vector<File::FileInfo> *listing, const char *filter) override;
|
||||
bool GetFileInfo(const char *path, File::FileInfo *info) override;
|
||||
bool Exists(const char *path) override;
|
||||
std::string toString() const override {
|
||||
return path_.ToString();
|
||||
}
|
||||
|
||||
@@ -118,3 +118,29 @@ bool VFS::GetFileInfo(const char *path, File::FileInfo *info) {
|
||||
} // Otherwise, the file was just missing. No need to log.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VFS::Exists(const char *path) {
|
||||
if (IsLocalAbsolutePath(path)) {
|
||||
// Local path, not VFS.
|
||||
// INFO_LOG(Log::IO, "Not a VFS path: %s . Getting local file info.", path);
|
||||
return File::Exists(Path(std::string(path)));
|
||||
}
|
||||
|
||||
bool fileSystemFound = false;
|
||||
int fn_len = (int)strlen(path);
|
||||
for (const auto &entry : entries_) {
|
||||
int prefix_len = (int)strlen(entry.prefix);
|
||||
if (prefix_len >= fn_len) continue;
|
||||
if (0 == memcmp(path, entry.prefix, prefix_len)) {
|
||||
fileSystemFound = true;
|
||||
if (entry.reader->Exists(path + prefix_len))
|
||||
return true;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!fileSystemFound) {
|
||||
ERROR_LOG(Log::IO, "Missing filesystem for '%s'", path);
|
||||
} // Otherwise, the file was just missing. No need to log.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,10 @@ public:
|
||||
|
||||
// Filter support is optional but nice to have
|
||||
virtual bool GetFileInfo(const char *path, File::FileInfo *info) = 0;
|
||||
virtual bool Exists(const char *path) {
|
||||
File::FileInfo info{};
|
||||
return GetFileInfo(path, &info) && info.exists;
|
||||
}
|
||||
|
||||
virtual std::string toString() const = 0;
|
||||
};
|
||||
@@ -70,14 +74,10 @@ public:
|
||||
// Always allocates an extra zero byte at the end, so that it
|
||||
// can be used for text like shader sources.
|
||||
uint8_t *ReadFile(const char *filename, size_t *size) override;
|
||||
bool GetFileInfo(const char *filename, File::FileInfo *fileInfo);
|
||||
bool GetFileListing(const char *path, std::vector<File::FileInfo> *listing, const char *filter = nullptr) override;
|
||||
|
||||
// Shortcut for cleaner code
|
||||
bool Exists(const char *path) {
|
||||
File::FileInfo info{};
|
||||
return GetFileInfo(path, &info);
|
||||
}
|
||||
bool GetFileInfo(const char *filename, File::FileInfo *fileInfo);
|
||||
bool Exists(const char *path);
|
||||
|
||||
private:
|
||||
struct VFSEntry {
|
||||
|
||||
@@ -44,7 +44,7 @@ ZipFileReader *ZipFileReader::Create(const Path &zipFile, const char *inZipPath,
|
||||
if (!path.empty() && path.back() != '/') {
|
||||
path.push_back('/');
|
||||
}
|
||||
return new ZipFileReader(zip_file, path);
|
||||
return new ZipFileReader(zip_file, zipFile, path);
|
||||
}
|
||||
|
||||
ZipFileReader::~ZipFileReader() {
|
||||
|
||||
@@ -36,15 +36,21 @@ public:
|
||||
bool GetFileListing(const char *path, std::vector<File::FileInfo> *listing, const char *filter) override;
|
||||
bool GetFileInfo(const char *path, File::FileInfo *info) override;
|
||||
std::string toString() const override {
|
||||
return inZipPath_;
|
||||
std::string retval = zipPath_.ToVisualString();
|
||||
if (!inZipPath_.empty()) {
|
||||
retval += ": ";
|
||||
retval += inZipPath_;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
private:
|
||||
ZipFileReader(zip *zip_file, const std::string &inZipPath) : zip_file_(zip_file), inZipPath_(inZipPath) {}
|
||||
ZipFileReader(zip *zip_file, const Path &zipPath, const std::string &inZipPath) : zip_file_(zip_file), zipPath_(zipPath), inZipPath_(inZipPath) {}
|
||||
// Path has to be either an empty string, or a string ending with a /.
|
||||
bool GetZipListings(const std::string &path, std::set<std::string> &files, std::set<std::string> &directories);
|
||||
|
||||
zip *zip_file_ = nullptr;
|
||||
std::mutex lock_;
|
||||
std::string inZipPath_;
|
||||
Path zipPath_;
|
||||
};
|
||||
|
||||
@@ -258,7 +258,7 @@ void LogManager::LogLine(LogLevel level, Log type, const char *file, int line, c
|
||||
const char *threadName;
|
||||
#if PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(MAC)
|
||||
const char *hostThreadName = GetCurrentThreadName();
|
||||
if (strcmp(hostThreadName, "EmuThread") != 0 || !hleCurrentThreadName) {
|
||||
if (hostThreadName && strcmp(hostThreadName, "EmuThread") != 0 || !hleCurrentThreadName) {
|
||||
// Use the host thread name.
|
||||
threadName = hostThreadName;
|
||||
} else {
|
||||
|
||||
@@ -1090,10 +1090,11 @@ void Config::Reload() {
|
||||
void Config::UpdateIniLocation(const char *iniFileName, const char *controllerIniFilename) {
|
||||
const bool useIniFilename = iniFileName != nullptr && strlen(iniFileName) > 0;
|
||||
const char *ppssppIniFilename = IsVREnabled() ? "ppssppvr.ini" : "ppsspp.ini";
|
||||
iniFilename_ = FindConfigFile(useIniFilename ? iniFileName : ppssppIniFilename);
|
||||
bool exists;
|
||||
iniFilename_ = FindConfigFile(useIniFilename ? iniFileName : ppssppIniFilename, &exists);
|
||||
const bool useControllerIniFilename = controllerIniFilename != nullptr && strlen(controllerIniFilename) > 0;
|
||||
const char *controlsIniFilename = IsVREnabled() ? "controlsvr.ini" : "controls.ini";
|
||||
controllerIniFilename_ = FindConfigFile(useControllerIniFilename ? controllerIniFilename : controlsIniFilename);
|
||||
controllerIniFilename_ = FindConfigFile(useControllerIniFilename ? controllerIniFilename : controlsIniFilename, &exists);
|
||||
}
|
||||
|
||||
bool Config::LoadAppendedConfig() {
|
||||
@@ -1660,22 +1661,27 @@ void Config::SetSearchPath(const Path &searchPath) {
|
||||
searchPath_ = searchPath;
|
||||
}
|
||||
|
||||
const Path Config::FindConfigFile(const std::string &baseFilename) {
|
||||
const Path Config::FindConfigFile(const std::string &baseFilename, bool *exists) {
|
||||
// Don't search for an absolute path.
|
||||
if (baseFilename.size() > 1 && baseFilename[0] == '/') {
|
||||
return Path(baseFilename);
|
||||
Path path(baseFilename);
|
||||
*exists = File::Exists(path);
|
||||
return path;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (baseFilename.size() > 3 && baseFilename[1] == ':' && (baseFilename[2] == '/' || baseFilename[2] == '\\')) {
|
||||
return Path(baseFilename);
|
||||
Path path(baseFilename);
|
||||
*exists = File::Exists(path);
|
||||
return path;
|
||||
}
|
||||
#endif
|
||||
|
||||
Path filename = searchPath_ / baseFilename;
|
||||
if (File::Exists(filename)) {
|
||||
*exists = true;
|
||||
return filename;
|
||||
}
|
||||
|
||||
*exists = false;
|
||||
// Make sure at least the directory it's supposed to be in exists.
|
||||
Path parent = filename.NavigateUp();
|
||||
|
||||
@@ -1711,8 +1717,9 @@ void Config::RestoreDefaults(RestoreSettingsBits whatToRestore) {
|
||||
}
|
||||
|
||||
bool Config::hasGameConfig(const std::string &pGameId) {
|
||||
Path fullIniFilePath = getGameConfigFile(pGameId);
|
||||
return File::Exists(fullIniFilePath);
|
||||
bool exists = false;
|
||||
Path fullIniFilePath = getGameConfigFile(pGameId, &exists);
|
||||
return exists;
|
||||
}
|
||||
|
||||
void Config::changeGameSpecific(const std::string &pGameId, const std::string &title) {
|
||||
@@ -1724,9 +1731,11 @@ void Config::changeGameSpecific(const std::string &pGameId, const std::string &t
|
||||
}
|
||||
|
||||
bool Config::createGameConfig(const std::string &pGameId) {
|
||||
Path fullIniFilePath = getGameConfigFile(pGameId);
|
||||
bool exists;
|
||||
Path fullIniFilePath = getGameConfigFile(pGameId, &exists);
|
||||
|
||||
if (hasGameConfig(pGameId)) {
|
||||
if (exists) {
|
||||
INFO_LOG(Log::System, "Game config already exists");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1735,16 +1744,19 @@ bool Config::createGameConfig(const std::string &pGameId) {
|
||||
}
|
||||
|
||||
bool Config::deleteGameConfig(const std::string& pGameId) {
|
||||
Path fullIniFilePath = Path(getGameConfigFile(pGameId));
|
||||
bool exists;
|
||||
Path fullIniFilePath = Path(getGameConfigFile(pGameId, &exists));
|
||||
|
||||
File::Delete(fullIniFilePath);
|
||||
if (exists) {
|
||||
File::Delete(fullIniFilePath);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Path Config::getGameConfigFile(const std::string &pGameId) {
|
||||
Path Config::getGameConfigFile(const std::string &pGameId, bool *exists) {
|
||||
const char *ppssppIniFilename = IsVREnabled() ? "_ppssppvr.ini" : "_ppsspp.ini";
|
||||
std::string iniFileName = pGameId + ppssppIniFilename;
|
||||
Path iniFileNameFull = FindConfigFile(iniFileName);
|
||||
Path iniFileNameFull = FindConfigFile(iniFileName, exists);
|
||||
|
||||
return iniFileNameFull;
|
||||
}
|
||||
@@ -1754,7 +1766,8 @@ bool Config::saveGameConfig(const std::string &pGameId, const std::string &title
|
||||
return false;
|
||||
}
|
||||
|
||||
Path fullIniFilePath = getGameConfigFile(pGameId);
|
||||
bool exists;
|
||||
Path fullIniFilePath = getGameConfigFile(pGameId, &exists);
|
||||
|
||||
IniFile iniFile;
|
||||
|
||||
@@ -1791,9 +1804,9 @@ bool Config::saveGameConfig(const std::string &pGameId, const std::string &title
|
||||
}
|
||||
|
||||
bool Config::loadGameConfig(const std::string &pGameId, const std::string &title) {
|
||||
Path iniFileNameFull = getGameConfigFile(pGameId);
|
||||
|
||||
if (!hasGameConfig(pGameId)) {
|
||||
bool exists;
|
||||
Path iniFileNameFull = getGameConfigFile(pGameId, &exists);
|
||||
if (!exists) {
|
||||
DEBUG_LOG(Log::Loader, "No game-specific settings found in %s. Using global defaults.", iniFileNameFull.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -585,11 +585,11 @@ public:
|
||||
bool loadGameConfig(const std::string &game_id, const std::string &title);
|
||||
bool saveGameConfig(const std::string &pGameId, const std::string &title);
|
||||
void unloadGameConfig();
|
||||
Path getGameConfigFile(const std::string &gameId);
|
||||
Path getGameConfigFile(const std::string &gameId, bool *exists);
|
||||
bool hasGameConfig(const std::string &game_id);
|
||||
|
||||
void SetSearchPath(const Path &path);
|
||||
const Path FindConfigFile(const std::string &baseFilename);
|
||||
const Path FindConfigFile(const std::string &baseFilename, bool *exists);
|
||||
|
||||
void UpdateIniLocation(const char *iniFileName = nullptr, const char *controllerIniFilename = nullptr);
|
||||
|
||||
|
||||
@@ -1558,12 +1558,20 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param)
|
||||
|
||||
// get and stock file info for each file
|
||||
int realCount = 0;
|
||||
|
||||
// TODO: Filter away non-directories directly?
|
||||
std::vector<PSPFileInfo> allSaves = pspFileSystem.GetDirListing(savePath);
|
||||
|
||||
bool fetchedAllSaves = false;
|
||||
std::string gameName = GetGameName(param);
|
||||
|
||||
for (int i = 0; i < saveDataListCount; i++) {
|
||||
// "<>" means saveName can be anything...
|
||||
if (strncmp(saveNameListData[i], "<>", ARRAY_SIZE(saveNameListData[i])) == 0) {
|
||||
// TODO:Maybe we need a way to reorder the files?
|
||||
auto allSaves = pspFileSystem.GetDirListing(savePath);
|
||||
std::string gameName = GetGameName(param);
|
||||
if (!fetchedAllSaves) {
|
||||
fetchedAllSaves = true;
|
||||
}
|
||||
for (auto it = allSaves.begin(); it != allSaves.end(); ++it) {
|
||||
if (it->name.compare(0, gameName.length(), gameName) == 0) {
|
||||
std::string saveName = it->name.substr(gameName.length());
|
||||
@@ -1590,13 +1598,30 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param)
|
||||
|
||||
const std::string thisSaveName = FixedToString(saveNameListData[i], ARRAY_SIZE(saveNameListData[i]));
|
||||
|
||||
std::string fileDataDir = savePath + GetGameName(param) + thisSaveName;
|
||||
PSPFileInfo info = GetSaveInfo(fileDataDir);
|
||||
if (info.exists) {
|
||||
SetFileInfo(realCount, info, thisSaveName);
|
||||
INFO_LOG(Log::sceUtility, "Save data exists: %s = %s", thisSaveName.c_str(), fileDataDir.c_str());
|
||||
realCount++;
|
||||
} else {
|
||||
const std::string folderName = gameName + thisSaveName;
|
||||
|
||||
// Check if thisSaveName is in the list before processing.
|
||||
// This is hopefully faster than doing file I/O.
|
||||
bool found = false;
|
||||
for (int i = 0; i < allSaves.size(); i++) {
|
||||
if (allSaves[i].name == folderName) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string fileDataDir = savePath + gameName + thisSaveName;
|
||||
if (found) {
|
||||
PSPFileInfo info = GetSaveInfo(fileDataDir);
|
||||
if (info.exists) {
|
||||
SetFileInfo(realCount, info, thisSaveName);
|
||||
INFO_LOG(Log::sceUtility, "Save data exists: %s = %s", thisSaveName.c_str(), fileDataDir.c_str());
|
||||
realCount++;
|
||||
} else {
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) { // NOTE: May be changed above, can't merge with the expression
|
||||
if (listEmptyFile) {
|
||||
ClearFileInfo(saveDataList[realCount], thisSaveName);
|
||||
INFO_LOG(Log::sceUtility, "Listing missing save data: %s = %s", thisSaveName.c_str(), fileDataDir.c_str());
|
||||
@@ -2002,7 +2027,7 @@ int SavedataParam::GetSaveCryptMode(const SceUtilitySavedataParam *param, const
|
||||
|
||||
bool SavedataParam::IsInSaveDataList(const std::string &saveName, int count) {
|
||||
for(int i = 0; i < count; ++i) {
|
||||
if(strcmp(saveDataList[i].saveName.c_str(),saveName.c_str()) == 0)
|
||||
if (saveDataList[i].saveName == saveName)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -155,12 +155,7 @@ bool LocalFileLoader::Exists() {
|
||||
return true;
|
||||
#endif
|
||||
|
||||
File::FileInfo info;
|
||||
if (File::GetFileInfo(filename_, &info)) {
|
||||
return info.exists;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return File::Exists(filename_);
|
||||
}
|
||||
|
||||
bool LocalFileLoader::IsDirectory() {
|
||||
|
||||
@@ -2466,6 +2466,7 @@ static u32 sceIoDopen(const char *path) {
|
||||
"TEXTURES",
|
||||
"DUMP",
|
||||
"SHADERS",
|
||||
"DRIVERS",
|
||||
};
|
||||
std::vector<PSPFileInfo> filtered;
|
||||
for (const auto &entry : dir->listing) {
|
||||
|
||||
@@ -801,26 +801,24 @@ namespace SaveState
|
||||
|
||||
std::string GetSlotDateAsString(const Path &gameFilename, int slot) {
|
||||
Path fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION);
|
||||
if (File::Exists(fn)) {
|
||||
tm time;
|
||||
if (File::GetModifTime(fn, time)) {
|
||||
char buf[256];
|
||||
// TODO: Use local time format? Americans and some others might not like ISO standard :)
|
||||
switch (g_Config.iDateFormat) {
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD:
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &time);
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_MMDDYYYY:
|
||||
strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &time);
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY:
|
||||
strftime(buf, sizeof(buf), "%d-%m-%Y %H:%M:%S", &time);
|
||||
break;
|
||||
default: // Should never happen
|
||||
return "";
|
||||
}
|
||||
return std::string(buf);
|
||||
tm time;
|
||||
if (File::GetModifTime(fn, time)) {
|
||||
char buf[256];
|
||||
// TODO: Use local time format? Americans and some others might not like ISO standard :)
|
||||
switch (g_Config.iDateFormat) {
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD:
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &time);
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_MMDDYYYY:
|
||||
strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &time);
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY:
|
||||
strftime(buf, sizeof(buf), "%d-%m-%Y %H:%M:%S", &time);
|
||||
break;
|
||||
default: // Should never happen
|
||||
return "";
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -101,7 +101,6 @@ ReplacedTexture::~ReplacedTexture() {
|
||||
if (threadWaitable_) {
|
||||
SetState(ReplacementState::CANCEL_INIT);
|
||||
|
||||
std::unique_lock<std::mutex> lock(lock_);
|
||||
threadWaitable_->WaitAndRelease();
|
||||
threadWaitable_ = nullptr;
|
||||
}
|
||||
@@ -225,7 +224,7 @@ void ReplacedTexture::Prepare(VFSBackend *vfs) {
|
||||
VFSFileReference *fileRef = vfs_->GetFile(desc_.filenames[i].c_str());
|
||||
if (!fileRef) {
|
||||
if (i == 0) {
|
||||
INFO_LOG(Log::G3D, "Texture replacement file '%s' not found", desc_.filenames[i].c_str());
|
||||
INFO_LOG(Log::G3D, "Texture replacement file '%s' not found in %s", desc_.filenames[i].c_str(), vfs_->toString().c_str());
|
||||
// No file at all. Mark as NOT_FOUND.
|
||||
SetState(ReplacementState::NOT_FOUND);
|
||||
return;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user