mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-01-09 06:23:21 +08:00
* Move a bunch of path logic into Core/Util/PathUtil.cpp/h . * Move GameImageView out from SaveDataScreen * More cleanup, add a translation string
212 lines
6.4 KiB
C++
212 lines
6.4 KiB
C++
#include <string_view>
|
|
|
|
#include "Common/File/Path.h"
|
|
#include "Common/File/FileUtil.h"
|
|
#include "Common/StringUtils.h"
|
|
#include "Common/System/System.h"
|
|
#include "Common/Log.h"
|
|
#include "Core/Util/PathUtil.h"
|
|
#include "Core/Config.h"
|
|
#include "Common/VR/PPSSPPVR.h"
|
|
|
|
Path FindConfigFile(const Path &searchPath, std::string_view baseFilename, bool *exists) {
|
|
// Don't search for an absolute path.
|
|
if (baseFilename.size() > 1 && baseFilename[0] == '/') {
|
|
Path path(baseFilename);
|
|
*exists = File::Exists(path);
|
|
return path;
|
|
}
|
|
#ifdef _WIN32
|
|
// Handle paths starting with a drive letter.
|
|
if (baseFilename.size() > 3 && baseFilename[1] == ':' && (baseFilename[2] == '/' || baseFilename[2] == '\\')) {
|
|
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();
|
|
|
|
// We try to create the path and ignore if it fails (already exists).
|
|
if (parent != GetSysDirectory(DIRECTORY_SYSTEM)) {
|
|
File::CreateFullPath(parent);
|
|
}
|
|
return filename;
|
|
}
|
|
|
|
Path GetSysDirectory(PSPDirectories directoryType) {
|
|
const Path &memStickDirectory = g_Config.memStickDirectory;
|
|
Path pspDirectory;
|
|
if (!strcasecmp(memStickDirectory.GetFilename().c_str(), "PSP")) {
|
|
// Let's strip this off, to easily allow choosing a root directory named "PSP" on Android.
|
|
pspDirectory = memStickDirectory;
|
|
} else {
|
|
pspDirectory = memStickDirectory / "PSP";
|
|
}
|
|
|
|
switch (directoryType) {
|
|
case DIRECTORY_PSP:
|
|
return pspDirectory;
|
|
case DIRECTORY_CHEATS:
|
|
return pspDirectory / "Cheats";
|
|
case DIRECTORY_GAME:
|
|
return pspDirectory / "GAME";
|
|
case DIRECTORY_SAVEDATA:
|
|
return pspDirectory / "SAVEDATA";
|
|
case DIRECTORY_SCREENSHOT:
|
|
return pspDirectory / "SCREENSHOT";
|
|
case DIRECTORY_SYSTEM:
|
|
return pspDirectory / "SYSTEM";
|
|
case DIRECTORY_PAUTH:
|
|
return memStickDirectory / "PAUTH"; // This one's at the root...
|
|
case DIRECTORY_EXDATA:
|
|
return memStickDirectory / "EXDATA"; // This one's traditionally at the root...
|
|
case DIRECTORY_DUMP:
|
|
return pspDirectory / "SYSTEM/DUMP";
|
|
case DIRECTORY_SAVESTATE:
|
|
return pspDirectory / "PPSSPP_STATE";
|
|
case DIRECTORY_CACHE:
|
|
return pspDirectory / "SYSTEM/CACHE";
|
|
case DIRECTORY_TEXTURES:
|
|
return pspDirectory / "TEXTURES";
|
|
case DIRECTORY_PLUGINS:
|
|
return pspDirectory / "PLUGINS";
|
|
case DIRECTORY_APP_CACHE:
|
|
if (!g_Config.appCacheDirectory.empty()) {
|
|
return g_Config.appCacheDirectory;
|
|
}
|
|
return pspDirectory / "SYSTEM/CACHE";
|
|
case DIRECTORY_VIDEO:
|
|
return pspDirectory / "VIDEO";
|
|
case DIRECTORY_AUDIO:
|
|
return pspDirectory / "AUDIO";
|
|
case DIRECTORY_CUSTOM_SHADERS:
|
|
return pspDirectory / "shaders";
|
|
case DIRECTORY_CUSTOM_THEMES:
|
|
return pspDirectory / "themes";
|
|
|
|
case DIRECTORY_MEMSTICK_ROOT:
|
|
return g_Config.memStickDirectory;
|
|
// Just return the memory stick root if we run into some sort of problem.
|
|
default:
|
|
ERROR_LOG(Log::FileSystem, "Unknown directory type.");
|
|
return g_Config.memStickDirectory;
|
|
}
|
|
}
|
|
|
|
bool CreateSysDirectories() {
|
|
#if PPSSPP_PLATFORM(ANDROID)
|
|
const bool createNoMedia = true;
|
|
#else
|
|
const bool createNoMedia = false;
|
|
#endif
|
|
|
|
Path pspDir = GetSysDirectory(DIRECTORY_PSP);
|
|
INFO_LOG(Log::IO, "Creating '%s' and subdirs:", pspDir.c_str());
|
|
File::CreateFullPath(pspDir);
|
|
if (!File::Exists(pspDir)) {
|
|
INFO_LOG(Log::IO, "Not a workable memstick directory. Giving up");
|
|
return false;
|
|
}
|
|
|
|
// Create the default directories that a real PSP creates. Good for homebrew so they can
|
|
// expect a standard environment. Skipping THEME though, that's pointless.
|
|
static const PSPDirectories sysDirs[] = {
|
|
DIRECTORY_CHEATS,
|
|
DIRECTORY_SAVEDATA,
|
|
DIRECTORY_SAVESTATE,
|
|
DIRECTORY_GAME,
|
|
DIRECTORY_SYSTEM,
|
|
DIRECTORY_TEXTURES,
|
|
DIRECTORY_PLUGINS,
|
|
DIRECTORY_CACHE,
|
|
};
|
|
|
|
for (auto dir : sysDirs) {
|
|
Path path = GetSysDirectory(dir);
|
|
File::CreateFullPath(path);
|
|
if (createNoMedia) {
|
|
// Create a nomedia file in each specified subdirectory.
|
|
File::CreateEmptyFile(path / ".nomedia");
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Path GetGameConfigFilePath(const Path &searchPath, std::string_view gameId, bool *exists) {
|
|
std::string_view ppssppIniFilename = IsVREnabled() ? "_ppssppvr.ini" : "_ppsspp.ini";
|
|
std::string iniFileName = join(gameId, ppssppIniFilename);
|
|
Path iniFileNameFull = FindConfigFile(searchPath, iniFileName, exists);
|
|
return iniFileNameFull;
|
|
}
|
|
|
|
// On iOS, the path to the app documents directory changes on each launch.
|
|
// Example path:
|
|
// /var/mobile/Containers/Data/Application/0E0E89DE-8D8E-485A-860C-700D8BC87B86/Documents/PSP/GAME/SuicideBarbie
|
|
// The GUID part changes on each launch.
|
|
bool TryUpdateSavedPath(Path *path) {
|
|
#if PPSSPP_PLATFORM(IOS)
|
|
// DEBUG_LOG(Log::Loader, "Original path: %s", path->c_str());
|
|
std::string pathStr = path->ToString();
|
|
|
|
const std::string_view applicationRoot = "/var/mobile/Containers/Data/Application/";
|
|
if (startsWith(pathStr, applicationRoot)) {
|
|
size_t documentsPos = pathStr.find("/Documents/");
|
|
if (documentsPos == std::string::npos) {
|
|
return false;
|
|
}
|
|
std::string memstick = g_Config.memStickDirectory.ToString();
|
|
size_t memstickDocumentsPos = memstick.find("/Documents"); // Note: No trailing slash, or we won't find it.
|
|
*path = Path(memstick.substr(0, memstickDocumentsPos) + pathStr.substr(documentsPos));
|
|
return true;
|
|
} else {
|
|
// Path can't be auto-updated.
|
|
return false;
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
Path GetFailedBackendsDir() {
|
|
Path failedBackendsDir;
|
|
if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) {
|
|
failedBackendsDir = GetSysDirectory(DIRECTORY_APP_CACHE);
|
|
} else {
|
|
failedBackendsDir = GetSysDirectory(DIRECTORY_SYSTEM);
|
|
}
|
|
return failedBackendsDir;
|
|
}
|
|
|
|
std::string GetFriendlyPath(Path path, Path aliasMatch, std::string_view aliasDisplay) {
|
|
// Show relative to memstick root if there.
|
|
if (path.StartsWith(aliasMatch)) {
|
|
std::string p;
|
|
if (aliasMatch.ComputePathTo(path, p)) {
|
|
return join(aliasDisplay, p);
|
|
}
|
|
std::string str = path.ToString();
|
|
if (aliasMatch.size() < str.length()) {
|
|
return join(aliasDisplay, str.substr(aliasMatch.size()));
|
|
} else {
|
|
return std::string(aliasDisplay);
|
|
}
|
|
}
|
|
|
|
std::string str = path.ToString();
|
|
#if !PPSSPP_PLATFORM(ANDROID) && (PPSSPP_PLATFORM(LINUX) || PPSSPP_PLATFORM(MAC))
|
|
char *home = getenv("HOME");
|
|
if (home != nullptr && !strncmp(str.c_str(), home, strlen(home))) {
|
|
return std::string("~") + str.substr(strlen(home));
|
|
}
|
|
#endif
|
|
return path.ToVisualString();
|
|
}
|