From 2e16e83159996edd72c3625e2815fb1f64965dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 9 May 2021 18:38:48 +0200 Subject: [PATCH] It never ends... --- Common/File/Path.cpp | 75 ++++++++++++++++++---- Common/File/Path.h | 9 ++- Common/StringUtils.cpp | 16 ----- Common/StringUtils.h | 2 - Core/Config.cpp | 5 +- Core/FileLoaders/DiskCachingFileLoader.cpp | 24 +++---- Core/FileLoaders/DiskCachingFileLoader.h | 12 ++-- Core/FileLoaders/HTTPFileLoader.cpp | 6 +- Core/FileLoaders/HTTPFileLoader.h | 7 +- Core/FileLoaders/LocalFileLoader.cpp | 12 ++-- Core/FileLoaders/LocalFileLoader.h | 11 ++-- Core/FileSystems/BlobFileSystem.cpp | 2 +- Core/FileSystems/VirtualDiscFileSystem.cpp | 11 +--- Core/FileSystems/VirtualDiscFileSystem.h | 2 +- Core/HLE/sceUmd.cpp | 2 +- Core/HLE/sceUmd.h | 4 +- Core/Loaders.cpp | 62 ++++++++---------- Core/Loaders.h | 21 +++--- Core/PSPLoaders.cpp | 37 ++++------- Core/Reporting.cpp | 15 ++--- Core/Reporting.h | 7 +- Core/SaveState.cpp | 8 +-- Core/System.cpp | 4 +- Core/Util/GameManager.cpp | 34 ++++++---- Core/Util/GameManager.h | 14 ++-- UI/GameInfoCache.cpp | 18 +++--- UI/GameScreen.cpp | 6 +- UI/InstallZipScreen.cpp | 4 +- UI/InstallZipScreen.h | 4 +- UI/MainScreen.cpp | 10 +-- UI/MiscScreens.h | 2 +- UI/NativeApp.cpp | 11 ++-- UI/ReportScreen.cpp | 8 +-- UI/SavedataScreen.cpp | 6 +- UWP/StorageFileLoader.cpp | 2 +- UWP/StorageFileLoader.h | 5 +- Windows/MainWindowMenu.cpp | 3 +- android/jni/app-android.cpp | 7 +- headless/Compare.cpp | 43 ++++++------- headless/Compare.h | 11 ++-- headless/Headless.cpp | 10 +-- headless/StubHost.h | 6 +- unittest/UnitTest.cpp | 11 +++- 43 files changed, 292 insertions(+), 277 deletions(-) diff --git a/Common/File/Path.cpp b/Common/File/Path.cpp index b653a1e87c..8c8595eaf8 100644 --- a/Common/File/Path.cpp +++ b/Common/File/Path.cpp @@ -1,6 +1,6 @@ #include "Common/File/Path.h" #include "Common/StringUtils.h" - +#include "Common/Log.h" #include "Common/Data/Encoding/Utf8.h" Path::Path(const std::string &str) { @@ -39,10 +39,22 @@ void Path::Init(const std::string &str) { } } +// We always use forward slashes internally, we convert to backslash only when +// converted to a wstring. Path Path::operator /(const std::string &subdir) const { - // We always use forward slashes internally, we convert to backslash only when - // converted to a wstring. - return Path(path_ + "/" + subdir); + if (subdir.empty()) { + return Path(path_); + } + std::string fullPath = path_; + if (subdir.front() != '/') { + fullPath += "/"; + } + fullPath += subdir; + // Prevent adding extra slashes. + if (fullPath.back() == '/') { + fullPath.pop_back(); + } + return Path(fullPath); } void Path::operator /=(const std::string &subdir) { @@ -50,18 +62,40 @@ void Path::operator /=(const std::string &subdir) { } Path Path::WithExtraExtension(const std::string &ext) const { - return Path(path_ + "." + ext); + _dbg_assert_(!ext.empty() && ext[0] == '.'); + return Path(path_ + ext); } Path Path::WithReplacedExtension(const std::string &oldExtension, const std::string &newExtension) const { - if (endsWithNoCase(path_, "." + oldExtension)) { - std::string newPath = path_.substr(0, path_.size() - oldExtension.size() - 1); - return Path(newPath + "." + newExtension); + _dbg_assert_(!oldExtension.empty() && oldExtension[0] == '.'); + _dbg_assert_(!newExtension.empty() && newExtension[0] == '.'); + if (endsWithNoCase(path_, oldExtension)) { + std::string newPath = path_.substr(0, path_.size() - oldExtension.size()); + return Path(newPath + newExtension); } else { return Path(*this); } } +Path Path::WithReplacedExtension(const std::string &newExtension) const { + _dbg_assert_(!newExtension.empty() && newExtension[0] == '.'); + if (path_.empty()) { + return Path(*this); + } + std::string extension = GetFileExtension(); + std::string newPath = path_.substr(0, path_.size() - extension.size()) + newExtension; + return Path(newPath); +} + +std::string Path::GetFilename() const { + size_t pos = path_.rfind('/'); + if (pos != std::string::npos) { + return path_.substr(pos + 1); + } + // No directory components, just return the full path. + return path_; +} + std::string Path::GetFileExtension() const { size_t pos = path_.rfind("."); if (pos == std::string::npos) { @@ -72,17 +106,27 @@ std::string Path::GetFileExtension() const { // Don't want to detect "df/file" from "/as.df/file" return ""; } - std::string ext = path_.substr(pos + 1); + std::string ext = path_.substr(pos); for (size_t i = 0; i < ext.size(); i++) { ext[i] = tolower(ext[i]); } return ext; } -Path Path::Directory() const { - std::string directory; - SplitPath(path_, &directory, nullptr, nullptr); - return Path(directory); +std::string Path::GetDirectory() const { + size_t pos = path_.rfind('/'); + if (pos != std::string::npos) { + return path_.substr(0, pos); + } else { + // There could be a ':', too. Unlike the slash, let's include that + // in the returned directory. + size_t c_pos = path_.rfind(':'); + if (c_pos != std::string::npos) { + return path_.substr(0, c_pos + 1); + } + } + // No directory components, just return the full path. + return path_; } bool Path::FilePathContains(const std::string &needle) const { @@ -125,6 +169,11 @@ bool Path::CanNavigateUp() const { return true; } +Path Path::NavigateUp() const { + std::string dir = GetDirectory(); + return Path(dir); +} + bool Path::IsAbsolute() const { if (path_.empty()) return true; diff --git a/Common/File/Path.h b/Common/File/Path.h index cc0f6de42b..b406892ba8 100644 --- a/Common/File/Path.h +++ b/Common/File/Path.h @@ -59,11 +59,12 @@ public: // File extension manipulation. Path WithExtraExtension(const std::string &ext) const; Path WithReplacedExtension(const std::string &oldExtension, const std::string &newExtension) const; + Path WithReplacedExtension(const std::string &newExtension) const; // Removes the last component. - Path Directory() const; - - std::string GetFileExtension() const; + std::string GetFilename() const; // Really, GetLastComponent. Could be a file or directory. + std::string GetFileExtension() const; // Always lowercase return. Includes the dot. + std::string GetDirectory() const; const std::string &ToString() const; @@ -74,6 +75,8 @@ public: std::string ToVisualString() const; bool CanNavigateUp() const; + Path NavigateUp() const; + bool operator ==(const Path &other) const { return path_ == other.path_ && type_ == other.type_; } diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index ee0159f662..f54b2e975f 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -125,22 +125,6 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ return true; } -std::string GetFilenameFromPath(std::string full_path) { - size_t pos; -#ifdef _WIN32 - pos = full_path.rfind('\\'); - if (pos != std::string::npos) { - return full_path.substr(pos + 1); - } -#endif - pos = full_path.rfind('/'); - if (pos != std::string::npos) { - return full_path.substr(pos + 1); - } - // No directory components, just return the full path. - return full_path; -} - std::string LineNumberString(const std::string &str) { std::stringstream input(str); std::stringstream output; diff --git a/Common/StringUtils.h b/Common/StringUtils.h index b5a3c28b4d..89127be810 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -101,5 +101,3 @@ inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) // "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); - -std::string GetFilenameFromPath(std::string full_path); diff --git a/Core/Config.cpp b/Core/Config.cpp index 61fa6b3dbf..6c350a9dcc 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1536,7 +1536,7 @@ void Config::RemoveRecent(const std::string &file) { void Config::CleanRecent() { std::vector cleanedRecent; for (size_t i = 0; i < recentIsos.size(); i++) { - FileLoader *loader = ConstructFileLoader(recentIsos[i]); + FileLoader *loader = ConstructFileLoader(Path(recentIsos[i])); if (loader->ExistsFast()) { // Make sure we don't have any redundant items. auto duplicate = std::find(cleanedRecent.begin(), cleanedRecent.end(), recentIsos[i]); @@ -1577,7 +1577,8 @@ const Path Config::FindConfigFile(const std::string &baseFilename) { const Path filename = defaultPath_ / baseFilename; if (!File::Exists(filename)) { - Path path = filename.Directory(); + // Make sure at least the directory it's supposed to be in exists. + Path path = filename.NavigateUp(); if (createdPath_ != path) { File::CreateFullPath(path); createdPath_ = path; diff --git a/Core/FileLoaders/DiskCachingFileLoader.cpp b/Core/FileLoaders/DiskCachingFileLoader.cpp index eedb6471d3..275ce11cb6 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.cpp +++ b/Core/FileLoaders/DiskCachingFileLoader.cpp @@ -45,7 +45,7 @@ static const u32 CACHE_SPACE_FLEX = 4; Path DiskCachingFileLoaderCache::cacheDir_; -std::map DiskCachingFileLoader::caches_; +std::map DiskCachingFileLoader::caches_; std::mutex DiskCachingFileLoader::cachesMutex_; // Takes ownership of backend. @@ -118,11 +118,11 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, return readSize; } -std::vector DiskCachingFileLoader::GetCachedPathsInUse() { +std::vector DiskCachingFileLoader::GetCachedPathsInUse() { std::lock_guard guard(cachesMutex_); // This is on the file loader so that it can manage the caches_. - std::vector files; + std::vector files; for (auto it : caches_) { files.push_back(it.first); @@ -134,7 +134,7 @@ std::vector DiskCachingFileLoader::GetCachedPathsInUse() { void DiskCachingFileLoader::InitCache() { std::lock_guard guard(cachesMutex_); - std::string path = ProxiedFileLoader::GetPath(); + Path path = ProxiedFileLoader::GetPath(); auto &entry = caches_[path]; if (!entry) { entry = new DiskCachingFileLoaderCache(path, filesize_); @@ -155,7 +155,7 @@ void DiskCachingFileLoader::ShutdownCache() { cache_ = nullptr; } -DiskCachingFileLoaderCache::DiskCachingFileLoaderCache(const std::string &path, u64 filesize) +DiskCachingFileLoaderCache::DiskCachingFileLoaderCache(const Path &path, u64 filesize) : filesize_(filesize), origPath_(path) { InitCache(path); } @@ -164,7 +164,7 @@ DiskCachingFileLoaderCache::~DiskCachingFileLoaderCache() { ShutdownCache(); } -void DiskCachingFileLoaderCache::InitCache(const std::string &filename) { +void DiskCachingFileLoaderCache::InitCache(const Path &filename) { cacheSize_ = 0; indexCount_ = 0; oldestGeneration_ = 0; @@ -172,7 +172,7 @@ void DiskCachingFileLoaderCache::InitCache(const std::string &filename) { flags_ = 0; generation_ = 0; - const Path cacheFilePath = Path(MakeCacheFilePath(filename)); + const Path cacheFilePath = MakeCacheFilePath(filename); bool fileLoaded = LoadCacheFile(cacheFilePath); // We do some basic locking to protect against two things: crashes and concurrency. @@ -409,9 +409,9 @@ u32 DiskCachingFileLoaderCache::AllocateBlock(u32 indexPos) { return INVALID_BLOCK; } -std::string DiskCachingFileLoaderCache::MakeCacheFilename(const std::string &path) { +std::string DiskCachingFileLoaderCache::MakeCacheFilename(const Path &path) { static const char *const invalidChars = "?*:/\\^|<>\"'"; - std::string filename = path; + std::string filename = path.ToString(); for (size_t i = 0; i < filename.size(); ++i) { int c = filename[i]; if (strchr(invalidChars, c) != nullptr) { @@ -421,7 +421,7 @@ std::string DiskCachingFileLoaderCache::MakeCacheFilename(const std::string &pat return filename + ".ppdc"; } -::Path DiskCachingFileLoaderCache::MakeCacheFilePath(const std::string &filename) { +::Path DiskCachingFileLoaderCache::MakeCacheFilePath(const Path &filename) { Path dir = cacheDir_; if (dir.empty()) { dir = GetSysDirectory(DIRECTORY_CACHE); @@ -801,9 +801,9 @@ u32 DiskCachingFileLoaderCache::CountCachedFiles() { void DiskCachingFileLoaderCache::GarbageCollectCacheFiles(u64 goalBytes) { // We attempt to free up at least enough files from the cache to get goalBytes more space. - const std::vector usedPaths = DiskCachingFileLoader::GetCachedPathsInUse(); + const std::vector usedPaths = DiskCachingFileLoader::GetCachedPathsInUse(); std::set used; - for (std::string path : usedPaths) { + for (const Path &path : usedPaths) { used.insert(MakeCacheFilename(path)); } diff --git a/Core/FileLoaders/DiskCachingFileLoader.h b/Core/FileLoaders/DiskCachingFileLoader.h index 1732ac2f8c..8dafab9c4f 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.h +++ b/Core/FileLoaders/DiskCachingFileLoader.h @@ -42,7 +42,7 @@ public: } size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; - static std::vector GetCachedPathsInUse(); + static std::vector GetCachedPathsInUse(); private: void Prepare(); @@ -55,13 +55,13 @@ private: // We don't support concurrent disk cache access (we use memory cached indexes.) // So we have to ensure there's only one of these per. - static std::map caches_; + static std::map caches_; static std::mutex cachesMutex_; }; class DiskCachingFileLoaderCache { public: - DiskCachingFileLoaderCache(const std::string &path, u64 filesize); + DiskCachingFileLoaderCache(const Path &path, u64 filesize); ~DiskCachingFileLoaderCache(); bool IsValid() { @@ -87,7 +87,7 @@ public: bool HasData() const; private: - void InitCache(const std::string &path); + void InitCache(const Path &path); void ShutdownCache(); bool MakeCacheSpaceFor(size_t blocks); void RebalanceGenerations(); @@ -99,8 +99,8 @@ private: void WriteIndexData(u32 indexPos, BlockInfo &info); s64 GetBlockOffset(u32 block); - ::Path MakeCacheFilePath(const std::string &filename); - std::string MakeCacheFilename(const std::string &path); + Path MakeCacheFilePath(const Path &filename); + std::string MakeCacheFilename(const Path &path); bool LoadCacheFile(const Path &path); void LoadCacheIndex(); void CreateCacheFile(const Path &path); diff --git a/Core/FileLoaders/HTTPFileLoader.cpp b/Core/FileLoaders/HTTPFileLoader.cpp index d9497fccc0..5078dcc4a3 100644 --- a/Core/FileLoaders/HTTPFileLoader.cpp +++ b/Core/FileLoaders/HTTPFileLoader.cpp @@ -23,8 +23,8 @@ #include "Core/Config.h" #include "Core/FileLoaders/HTTPFileLoader.h" -HTTPFileLoader::HTTPFileLoader(const std::string &filename) - : url_(filename), progress_(&cancel_), filename_(filename) { +HTTPFileLoader::HTTPFileLoader(const ::Path &filename) + : url_(filename.ToString()), progress_(&cancel_), filename_(filename) { } void HTTPFileLoader::Prepare() { @@ -172,7 +172,7 @@ s64 HTTPFileLoader::FileSize() { return filesize_; } -std::string HTTPFileLoader::GetPath() const { +Path HTTPFileLoader::GetPath() const { return filename_; } diff --git a/Core/FileLoaders/HTTPFileLoader.h b/Core/FileLoaders/HTTPFileLoader.h index 345ffd147f..84a4361097 100644 --- a/Core/FileLoaders/HTTPFileLoader.h +++ b/Core/FileLoaders/HTTPFileLoader.h @@ -20,6 +20,7 @@ #include #include +#include "Common/File/Path.h" #include "Common/Net/HTTPClient.h" #include "Common/Net/Resolve.h" #include "Common/Net/URL.h" @@ -28,7 +29,7 @@ class HTTPFileLoader : public FileLoader { public: - HTTPFileLoader(const std::string &filename); + HTTPFileLoader(const ::Path &filename); virtual ~HTTPFileLoader() override; bool IsRemote() override { @@ -38,7 +39,7 @@ public: virtual bool ExistsFast() override; virtual bool IsDirectory() override; virtual s64 FileSize() override; - virtual std::string GetPath() const override; + virtual Path GetPath() const override; virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { return ReadAt(absolutePos, bytes * count, data, flags) / bytes; @@ -71,7 +72,7 @@ private: Url url_; http::Client client_; http::RequestProgress progress_; - std::string filename_; + ::Path filename_; bool connected_ = false; bool cancel_ = false; const char *latestError_ = ""; diff --git a/Core/FileLoaders/LocalFileLoader.cpp b/Core/FileLoaders/LocalFileLoader.cpp index 644ab68f4c..df3593c585 100644 --- a/Core/FileLoaders/LocalFileLoader.cpp +++ b/Core/FileLoaders/LocalFileLoader.cpp @@ -32,7 +32,7 @@ #endif #ifndef _WIN32 -LocalFileLoader::LocalFileLoader(int fd, const std::string &filename) : fd_(fd), filename_(filename), isOpenedByFd_(fd != -1) { +LocalFileLoader::LocalFileLoader(int fd, const Path &filename) : fd_(fd), filename_(filename), isOpenedByFd_(fd != -1) { if (fd != -1) { DetectSizeFd(); } @@ -51,7 +51,7 @@ void LocalFileLoader::DetectSizeFd() { } #endif -LocalFileLoader::LocalFileLoader(const std::string &filename) +LocalFileLoader::LocalFileLoader(const Path &filename) : filesize_(0), filename_(filename), isOpenedByFd_(false) { if (filename.empty()) { ERROR_LOG(FILESYS, "LocalFileLoader can't load empty filenames"); @@ -70,9 +70,9 @@ LocalFileLoader::LocalFileLoader(const std::string &filename) const DWORD access = GENERIC_READ, share = FILE_SHARE_READ, mode = OPEN_EXISTING, flags = FILE_ATTRIBUTE_NORMAL; #if PPSSPP_PLATFORM(UWP) - handle_ = CreateFile2(ConvertUTF8ToWString(filename).c_str(), access, share, mode, nullptr); + handle_ = CreateFile2(filename.ToWString().c_str(), access, share, mode, nullptr); #else - handle_ = CreateFile(ConvertUTF8ToWString(filename).c_str(), access, share, nullptr, mode, flags, nullptr); + handle_ = CreateFile(filename.ToWString().c_str(), access, share, nullptr, mode, flags, nullptr); #endif if (handle_ == INVALID_HANDLE_VALUE) { return; @@ -130,10 +130,6 @@ s64 LocalFileLoader::FileSize() { return filesize_; } -std::string LocalFileLoader::GetPath() const { - return filename_.ToString(); -} - size_t LocalFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags) { if (bytes == 0) return 0; diff --git a/Core/FileLoaders/LocalFileLoader.h b/Core/FileLoaders/LocalFileLoader.h index a4d7487c7f..9ed9b185fa 100644 --- a/Core/FileLoaders/LocalFileLoader.h +++ b/Core/FileLoaders/LocalFileLoader.h @@ -23,21 +23,22 @@ #include "Common/File/Path.h" #include "Core/Loaders.h" - #ifdef _WIN32 typedef void *HANDLE; #endif class LocalFileLoader : public FileLoader { public: - LocalFileLoader(const std::string &filename); - LocalFileLoader(const int fd, const std::string &filename); + LocalFileLoader(const Path &filename); + LocalFileLoader(const int fd, const Path &filename); virtual ~LocalFileLoader(); virtual bool Exists() override; virtual bool IsDirectory() override; virtual s64 FileSize() override; - virtual std::string GetPath() const override; + virtual Path GetPath() const override { + return filename_; + } virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; private: @@ -48,7 +49,7 @@ private: HANDLE handle_; #endif u64 filesize_; - ::Path filename_; + Path filename_; std::mutex readLock_; bool isOpenedByFd_; }; diff --git a/Core/FileSystems/BlobFileSystem.cpp b/Core/FileSystems/BlobFileSystem.cpp index 425724c40b..8ab517da7c 100644 --- a/Core/FileSystems/BlobFileSystem.cpp +++ b/Core/FileSystems/BlobFileSystem.cpp @@ -129,7 +129,7 @@ bool BlobFileSystem::RemoveFile(const std::string &filename) { } bool BlobFileSystem::GetHostPath(const std::string &inpath, Path &outpath) { - outpath = Path(fileLoader_->GetPath()); + outpath = fileLoader_->GetPath(); return true; } diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp index a79794af08..99c2180421 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.cpp +++ b/Core/FileSystems/VirtualDiscFileSystem.cpp @@ -50,8 +50,8 @@ const std::string INDEX_FILENAME = ".ppsspp-index.lst"; -VirtualDiscFileSystem::VirtualDiscFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) - : basePath(_basePath),currentBlockIndex(0) { +VirtualDiscFileSystem::VirtualDiscFileSystem(IHandleAllocator *_hAlloc, const Path &_basePath) + : basePath(_basePath), currentBlockIndex(0) { hAlloc = _hAlloc; LoadFileListIndex(); } @@ -78,13 +78,6 @@ void VirtualDiscFileSystem::LoadFileListIndex() { return; } - /* - in.open(filename.c_str(), std::ios::in); - if (in.fail()) { ->>>>>>> 52a34c2de (Introduce Path, start using it all over the place.) - return; - }*/ - std::string buf; static const int MAX_LINE_SIZE = 2048; char linebuf[MAX_LINE_SIZE]{}; diff --git a/Core/FileSystems/VirtualDiscFileSystem.h b/Core/FileSystems/VirtualDiscFileSystem.h index c7f4d6ce11..927700fe2a 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.h +++ b/Core/FileSystems/VirtualDiscFileSystem.h @@ -27,7 +27,7 @@ class VirtualDiscFileSystem: public IFileSystem { public: - VirtualDiscFileSystem(IHandleAllocator *_hAlloc, std::string _basePath); + VirtualDiscFileSystem(IHandleAllocator *_hAlloc, const Path &_basePath); ~VirtualDiscFileSystem(); void DoState(PointerWrap &p) override; diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 8692bd8e1b..8ad8a5196a 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -482,7 +482,7 @@ static u32 sceUmdGetErrorStat() return umdErrorStat; } -void __UmdReplace(std::string filepath) { +void __UmdReplace(Path filepath) { std::string error = ""; if (!UmdReplace(filepath, error)) { ERROR_LOG(SCEIO, "UMD Replace failed: %s", error.c_str()); diff --git a/Core/HLE/sceUmd.h b/Core/HLE/sceUmd.h index 1fdf4bbc28..91e9bcafd6 100644 --- a/Core/HLE/sceUmd.h +++ b/Core/HLE/sceUmd.h @@ -17,6 +17,8 @@ #pragma once +#include "Common/File/Path.h" + enum pspUmdState { PSP_UMD_INIT = 0x00, PSP_UMD_NOT_PRESENT = 0x01, @@ -41,7 +43,7 @@ enum pspUmdType { void __UmdInit(); void __UmdDoState(PointerWrap &p); -void __UmdReplace(std::string filepath); +void __UmdReplace(Path filepath); bool getUMDReplacePermit(); void Register_sceUmdUser(); diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index c3dc361a86..42b9297417 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -40,8 +40,8 @@ void RegisterFileLoaderFactory(std::string prefix, std::unique_ptrConstructFileLoader(filename); } } @@ -73,7 +73,7 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) { return IdentifiedFileType::ERROR_IDENTIFYING; } - std::string extension = File::GetFileExtension(fileLoader->GetPath()); + std::string extension = fileLoader->GetPath().GetFileExtension(); if (extension == ".iso") { // may be a psx iso, they have 2352 byte sectors. You never know what some people try to open if ((fileLoader->FileSize() % 2352) == 0) { @@ -143,9 +143,9 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) { } if (id == 'FLE\x7F') { - std::string filename = fileLoader->GetPath(); + Path filename = fileLoader->GetPath(); // There are a few elfs misnamed as pbp (like Trig Wars), accept that. - if (extension == ".plf" || strstr(filename.c_str(), "BOOT.BIN") || + if (extension == ".plf" || strstr(filename.GetFilename().c_str(), "BOOT.BIN") || extension == ".elf" || extension == ".prx" || extension == ".pbp") { return IdentifiedFileType::PSP_ELF; } @@ -176,14 +176,13 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) { // Let's check if we got pointed to a PBP within such a directory. // If so we just move up and return the directory itself as the game. - std::string path = File::GetDir(fileLoader->GetPath()); // If loading from memstick... - size_t pos = path.find("PSP/GAME/"); - if (pos != std::string::npos) { + if (fileLoader->GetPath().FilePathContains("PSP/GAME/")) { return IdentifiedFileType::PSP_PBP_DIRECTORY; } return IdentifiedFileType::PSP_PBP; - } else if (extension == ".pbp") { + } + else if (extension == ".pbp") { ERROR_LOG(LOADER, "A PBP with the wrong magic number?"); return IdentifiedFileType::PSP_PBP; } else if (extension == ".bin") { @@ -205,7 +204,7 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) { FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader) { IdentifiedFileType type = Identify_File(fileLoader); if (type == IdentifiedFileType::PSP_PBP_DIRECTORY) { - const std::string ebootFilename = ResolvePBPFile(fileLoader->GetPath()); + const Path ebootFilename = ResolvePBPFile(fileLoader->GetPath()); if (ebootFilename != fileLoader->GetPath()) { // Switch fileLoader to the actual EBOOT. delete fileLoader; @@ -215,28 +214,20 @@ FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader) { return fileLoader; } -std::string ResolvePBPDirectory(const std::string &filename) { - bool hasPBP = endsWith(filename, "/EBOOT.PBP"); -#ifdef _WIN32 - hasPBP = hasPBP || endsWith(filename, "\\EBOOT.PBP"); -#endif - - if (hasPBP) { - return filename.substr(0, filename.length() - strlen("/EBOOT.PBP")); +Path ResolvePBPDirectory(const Path &filename) { + if (filename.GetFilename() == "EBOOT.PBP") { + return filename.NavigateUp(); + } else { + return filename; } - return filename; } -std::string ResolvePBPFile(const std::string &filename) { - bool hasPBP = endsWith(filename, "/EBOOT.PBP"); -#ifdef _WIN32 - hasPBP = hasPBP || endsWith(filename, "\\EBOOT.PBP"); -#endif - - if (!hasPBP) { - return filename + "/EBOOT.PBP"; +Path ResolvePBPFile(const Path &filename) { + if (filename.GetFilename() != "EBOOT.PBP") { + return filename / "EBOOT.PBP"; + } else { + return filename; } - return filename; } bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { @@ -260,11 +251,12 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { coreState = CORE_BOOT_ERROR; return false; } - std::string path = fileLoader->GetPath(); - size_t pos = path.find("PSP/GAME/"); + + std::string dir = fileLoader->GetPath().GetDirectory(); + size_t pos = dir.find("PSP/GAME/"); if (pos != std::string::npos) { - path = ResolvePBPDirectory(path); - pspFileSystem.SetStartingDirectory("ms0:/" + path.substr(pos)); + dir = ResolvePBPDirectory(Path(dir)).ToString(); + pspFileSystem.SetStartingDirectory("ms0:/" + dir.substr(pos)); } return Load_PSP_ELF_PBP(fileLoader, error_string); } else { @@ -355,7 +347,7 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { return false; } -bool UmdReplace(std::string filepath, std::string &error) { +bool UmdReplace(const Path &filepath, std::string &error) { IFileSystem* currentUMD = pspFileSystem.GetSystem("disc0:"); if (!currentUMD) { @@ -367,7 +359,7 @@ bool UmdReplace(std::string filepath, std::string &error) { if (!loadedFile->Exists()) { delete loadedFile; - error = loadedFile->GetPath() + " doesn't exist"; + error = loadedFile->GetPath().ToVisualString() + " doesn't exist"; return false; } UpdateLoadedFile(loadedFile); diff --git a/Core/Loaders.h b/Core/Loaders.h index 959ec628cb..cbf4329547 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -21,6 +21,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/File/Path.h" enum class IdentifiedFileType { ERROR_IDENTIFYING, @@ -74,15 +75,15 @@ public: } virtual bool IsDirectory() = 0; virtual s64 FileSize() = 0; - virtual std::string GetPath() const = 0; + virtual Path GetPath() const = 0; + virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) = 0; virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) { return ReadAt(absolutePos, 1, bytes, data, flags); } // Cancel any operations that might block, if possible. - virtual void Cancel() { - } + virtual void Cancel() {} virtual std::string LatestError() const { return ""; @@ -112,7 +113,7 @@ public: s64 FileSize() override { return backend_->FileSize(); } - std::string GetPath() const override { + Path GetPath() const override { return backend_->GetPath(); } void Cancel() override { @@ -136,23 +137,23 @@ inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) { return (u32)a & (u32)b; } -FileLoader *ConstructFileLoader(const std::string &filename); +FileLoader *ConstructFileLoader(const Path &filename); // Resolve to the target binary, ISO, or other file (e.g. from a directory.) FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader); -std::string ResolvePBPDirectory(const std::string &filename); -std::string ResolvePBPFile(const std::string &filename); +Path ResolvePBPDirectory(const Path &filename); +Path ResolvePBPFile(const Path &filename); IdentifiedFileType Identify_File(FileLoader *fileLoader); class FileLoaderFactory { public: virtual ~FileLoaderFactory() {} - virtual FileLoader *ConstructFileLoader(const std::string &filename) = 0; + virtual FileLoader *ConstructFileLoader(const Path &filename) = 0; }; -void RegisterFileLoaderFactory(std::string name, std::unique_ptr factory); +void RegisterFileLoaderFactory(std::string prefix, std::unique_ptr factory); // Can modify the string filename, as it calls IdentifyFile above. bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string); -bool UmdReplace(std::string filepath, std::string &error); +bool UmdReplace(const Path &filepath, std::string &error); diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index 652ce845d8..869c6f8492 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -375,16 +375,10 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { pspFileSystem.Mount("umd:", blockSystem); } } - - std::string full_path = fileLoader->GetPath(); - std::string path, file, extension; - SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); - if (!path.empty() && path.back() == '/') - path.resize(path.size() - 1); -#ifdef _WIN32 - if (!path.empty() && path.back() == '\\') - path.resize(path.size() - 1); -#endif + Path full_path = fileLoader->GetPath(); + std::string path = full_path.GetDirectory(); + std::string extension = full_path.GetFileExtension(); + std::string file = full_path.GetFilename(); size_t pos = path.find("PSP/GAME/"); std::string ms_path; @@ -396,11 +390,6 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { ms_path = "umd0:/"; } -#ifdef _WIN32 - // Turn the slashes back to the Windows way. - path = ReplaceAll(path, "/", "\\"); -#endif - if (!PSP_CoreParameter().mountRoot.empty()) { // We don't want to worry about .. and cwd and such. const Path rootNorm = NormalizePath(PSP_CoreParameter().mountRoot); @@ -425,7 +414,7 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { DirectoryFileSystem *fs = new DirectoryFileSystem(&pspFileSystem, Path(path), FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD); pspFileSystem.Mount("umd0:", fs); - std::string finalName = ms_path + file + extension; + std::string finalName = ms_path + file; std::string homebrewName = PSP_CoreParameter().fileToStart.ToVisualString(); std::size_t lslash = homebrewName.find_last_of("/"); @@ -449,14 +438,14 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { Path oldNamePrefix = savestateDir / StringFromFormat("%s_%d", homebrewName.c_str(), i); Path oldIDPrefix = savestateDir / StringFromFormat("%s_1.00_%d", madeUpID.c_str(), i); - if (oldIDPrefix != newPrefix && File::Exists(oldIDPrefix.WithExtraExtension("ppst"))) - File::Rename(oldIDPrefix.WithExtraExtension("ppst"), newPrefix.WithExtraExtension("ppst")); - else if (File::Exists(oldNamePrefix.WithExtraExtension("ppst"))) - File::Rename(oldNamePrefix.WithExtraExtension("ppst"), newPrefix.WithExtraExtension("ppst")); - if (oldIDPrefix != newPrefix && File::Exists(oldIDPrefix.WithExtraExtension("jpg"))) - File::Rename(oldIDPrefix.WithExtraExtension("jpg"), newPrefix.WithExtraExtension("jpg")); - else if (File::Exists(oldNamePrefix.WithExtraExtension("jpg"))) - File::Rename(oldNamePrefix.WithExtraExtension("jpg"), newPrefix.WithExtraExtension("jpg")); + if (oldIDPrefix != newPrefix && File::Exists(oldIDPrefix.WithExtraExtension(".ppst"))) + File::Rename(oldIDPrefix.WithExtraExtension(".ppst"), newPrefix.WithExtraExtension(".ppst")); + else if (File::Exists(oldNamePrefix.WithExtraExtension(".ppst"))) + File::Rename(oldNamePrefix.WithExtraExtension(".ppst"), newPrefix.WithExtraExtension(".ppst")); + if (oldIDPrefix != newPrefix && File::Exists(oldIDPrefix.WithExtraExtension(".jpg"))) + File::Rename(oldIDPrefix.WithExtraExtension(".jpg"), newPrefix.WithExtraExtension(".jpg")); + else if (File::Exists(oldNamePrefix.WithExtraExtension(".jpg"))) + File::Rename(oldNamePrefix.WithExtraExtension(".jpg"), newPrefix.WithExtraExtension(".jpg")); } PSPLoaders_Shutdown(); diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 0b846f3c6c..91b31da54e 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -101,8 +101,8 @@ namespace Reporting static std::mutex crcLock; static std::condition_variable crcCond; - static std::string crcFilename; - static std::map crcResults; + static Path crcFilename; + static std::map crcResults; static volatile bool crcPending = false; static volatile bool crcCancel = false; static std::thread crcThread; @@ -126,11 +126,10 @@ namespace Reporting crcResults[crcFilename] = crc; crcPending = false; crcCond.notify_one(); - return 0; } - void QueueCRC(const std::string &gamePath) { + void QueueCRC(const Path &gamePath) { std::lock_guard guard(crcLock); auto it = crcResults.find(gamePath); @@ -151,12 +150,12 @@ namespace Reporting crcThread = std::thread(CalculateCRCThread); } - bool HasCRC(const std::string &gamePath) { + bool HasCRC(const Path &gamePath) { std::lock_guard guard(crcLock); return crcResults.find(gamePath) != crcResults.end(); } - uint32_t RetrieveCRC(const std::string &gamePath) { + uint32_t RetrieveCRC(const Path &gamePath) { QueueCRC(gamePath); std::unique_lock guard(crcLock); @@ -173,11 +172,11 @@ namespace Reporting static uint32_t RetrieveCRCUnlessPowerSaving(const Path &gamePath) { // It's okay to use it if we have it already. - if (Core_GetPowerSaving() && !HasCRC(gamePath.ToString())) { + if (Core_GetPowerSaving() && !HasCRC(gamePath)) { return 0; } - return RetrieveCRC(gamePath.ToString()); + return RetrieveCRC(gamePath); } static void PurgeCRC() { diff --git a/Core/Reporting.h b/Core/Reporting.h index 3aa20e4eb9..a1b04ab86f 100644 --- a/Core/Reporting.h +++ b/Core/Reporting.h @@ -21,6 +21,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/File/Path.h" #include "Common/Log.h" #define DEBUG_LOG_REPORT(t,...) do { DEBUG_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false) @@ -88,14 +89,14 @@ namespace Reporting std::vector CompatibilitySuggestions(); // Queues game for CRC hash if needed. - void QueueCRC(const std::string &gamePath); + void QueueCRC(const Path &gamePath); // Returns true if the hash is available, does not queue if not. - bool HasCRC(const std::string &gamePath); + bool HasCRC(const Path &gamePath); // Blocks until the CRC hash is available for game, and returns it. // To avoid stalling, call HasCRC() in update() or similar and call this if it returns true. - uint32_t RetrieveCRC(const std::string &gamePath); + uint32_t RetrieveCRC(const Path &gamePath); // Returns true if that identifier has not been logged yet. bool ShouldLogNTimes(const char *identifier, int n); diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 0a0d8a7629..fdba84d11f 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -463,7 +463,7 @@ namespace SaveState } static void SwapIfExists(const Path &from, const Path &to) { - Path temp = from.WithExtraExtension("tmp"); + Path temp = from.WithExtraExtension(".tmp"); if (File::Exists(from)) { File::Rename(from, temp); File::Rename(to, from); @@ -486,7 +486,7 @@ namespace SaveState } else { DeleteIfExists(fn); } - File::Rename(fn.WithExtraExtension("tmp"), fn); + File::Rename(fn.WithExtraExtension(".tmp"), fn); } if (callback) { callback(status, message, data); @@ -498,7 +498,7 @@ namespace SaveState RenameIfExists(shot, shotUndo); } SaveScreenshot(shot, Callback(), 0); - Save(fn.WithExtraExtension("tmp"), slot, renameCallback, cbUserData); + Save(fn.WithExtraExtension(".tmp"), slot, renameCallback, cbUserData); } else { auto sy = GetI18NCategory("System"); if (callback) @@ -532,7 +532,7 @@ namespace SaveState bool HasUndoSaveInSlot(const std::string &gameFilename, int slot) { Path fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION); - return File::Exists(fn.WithExtraExtension("undo")); + return File::Exists(fn.WithExtraExtension(".undo")); } bool HasScreenshotInSlot(const std::string &gameFilename, int slot) diff --git a/Core/System.cpp b/Core/System.cpp index 1d1ea8bbfa..607b1b3819 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -231,7 +231,7 @@ bool CPU_Init() { Memory::g_PSPModel = g_Config.iPSPModel; Path filename = coreParameter.fileToStart; - loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename.ToString())); + loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename)); #if PPSSPP_ARCH(AMD64) if (g_Config.bCacheFullIsoInRam) { loadedFile = new RamCachingFileLoader(loadedFile); @@ -241,7 +241,7 @@ bool CPU_Init() { // TODO: Put this somewhere better? if (!coreParameter.mountIso.empty()) { - coreParameter.mountIsoLoader = ConstructFileLoader(coreParameter.mountIso.ToString()); + coreParameter.mountIsoLoader = ConstructFileLoader(coreParameter.mountIso); } MIPSAnalyst::Reset(); diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index c844ed7cfa..e20cbed323 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -15,6 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "ppsspp_config.h" + #include #include #include @@ -137,7 +139,7 @@ void GameManager::Update() { return; } // Game downloaded to temporary file - install it! - InstallGameOnThread(curDownload_->url(), fileName.ToString(), true); + InstallGameOnThread(Path(curDownload_->url()), fileName, true); } else { ERROR_LOG(HLE, "Expected HTTP status code 200, got status code %d. Install cancelled, deleting partial file '%s'", curDownload_->ResultCode(), fileName.c_str()); @@ -169,7 +171,7 @@ static void countSlashes(const std::string &fileName, int *slashLocation, int *s } } -ZipFileContents DetectZipFileContents(std::string fileName, ZipFileInfo *info) { +ZipFileContents DetectZipFileContents(const Path &fileName, ZipFileInfo *info) { int error = 0; struct zip *z = zip_open(fileName.c_str(), 0, &error); if (!z) { @@ -254,7 +256,8 @@ ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info) { } } -bool GameManager::InstallGame(const std::string &url, const std::string &fileName, bool deleteAfter) { +// Parameters need to be by value, since this is a thread func. +bool GameManager::InstallGame(Path url, Path fileName, bool deleteAfter) { if (installInProgress_) { ERROR_LOG(HLE, "Cannot have two installs in progress at the same time"); return false; @@ -265,10 +268,11 @@ bool GameManager::InstallGame(const std::string &url, const std::string &fileNam return false; } + std::string extension = url.GetFileExtension(); // Examine the URL to guess out what we're installing. - if (endsWithNoCase(url, ".cso") || endsWithNoCase(url, ".iso")) { + if (extension == "cso" || extension == "iso") { // It's a raw ISO or CSO file. We just copy it to the destination. - std::string shortFilename = GetFilenameFromPath(url); + std::string shortFilename = Path(url).GetFilename(); return InstallRawISO(fileName, shortFilename, deleteAfter); } @@ -278,6 +282,8 @@ bool GameManager::InstallGame(const std::string &url, const std::string &fileNam Path pspGame = GetSysDirectory(DIRECTORY_GAME); Path dest = pspGame; int error = 0; + + // TODO(scoped): zip_open ain't gonna work. zip_fdopen though.. struct zip *z = zip_open(fileName.c_str(), 0, &error); if (!z) { ERROR_LOG(HLE, "Failed to open ZIP file '%s', error code=%i", fileName.c_str(), error); @@ -351,7 +357,7 @@ bool GameManager::DetectTexturePackDest(struct zip *z, int iniIndex, Path &dest) if (games.size() > 1) { // Check for any supported game on their recent list and use that instead. for (const std::string &path : g_Config.recentIsos) { - std::string recentID = GetGameID(path); + std::string recentID = GetGameID(Path(path)); if (games.find(recentID) != games.end()) { gameID = recentID; break; @@ -371,7 +377,7 @@ void GameManager::SetInstallError(const std::string &err) { InstallDone(); } -std::string GameManager::GetGameID(const std::string &path) const { +std::string GameManager::GetGameID(const Path &path) const { auto loader = ConstructFileLoader(path); std::string id; @@ -495,7 +501,7 @@ bool GameManager::ExtractFile(struct zip *z, int file_index, const Path &outFile } // TODO(scoped): This one will be slightly tricky. -bool GameManager::InstallMemstickGame(struct zip *z, const std::string &zipfile, const std::string &dest, const ZipFileInfo &info, bool allowRoot, bool deleteAfter) { +bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const std::string &dest, const ZipFileInfo &info, bool allowRoot, bool deleteAfter) { size_t allBytes = 0; size_t bytesCopied = 0; @@ -591,7 +597,7 @@ bail: return false; } -bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, std::string zipfile, bool deleteAfter) { +bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter) { // Let's place the output file in the currently selected Games directory. std::string fn = zip_get_name(z, isoFileIndex, 0); @@ -614,7 +620,7 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, std::string } zip_close(z); if (deleteAfter) { - File::Delete(Path(zipfile)); + File::Delete(zipfile); } z = 0; @@ -625,7 +631,7 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, std::string return true; } -bool GameManager::InstallGameOnThread(std::string url, std::string fileName, bool deleteAfter) { +bool GameManager::InstallGameOnThread(const Path &url, const Path &fileName, bool deleteAfter) { if (installInProgress_) { return false; } @@ -633,12 +639,12 @@ bool GameManager::InstallGameOnThread(std::string url, std::string fileName, boo return true; } -bool GameManager::InstallRawISO(const std::string &file, const std::string &originalName, bool deleteAfter) { +bool GameManager::InstallRawISO(const Path &file, const std::string &originalName, bool deleteAfter) { Path destPath = Path(g_Config.currentDirectory) / originalName; // TODO: To save disk space, we should probably attempt a move first. - if (File::Copy(Path(file), destPath)) { + if (File::Copy(file, destPath)) { if (deleteAfter) { - File::Delete(Path(file)); + File::Delete(file); } } installProgress_ = 1.0f; diff --git a/Core/Util/GameManager.h b/Core/Util/GameManager.h index 1481d2df75..6b7acd8b3d 100644 --- a/Core/Util/GameManager.h +++ b/Core/Util/GameManager.h @@ -73,20 +73,20 @@ public: } // Only returns false if there's already an installation in progress. - bool InstallGameOnThread(std::string url, std::string tempFileName, bool deleteAfter); + bool InstallGameOnThread(const Path &url, const Path &tempFileName, bool deleteAfter); private: - bool InstallGame(const std::string &url, const std::string &tempFileName, bool deleteAfter); - bool InstallMemstickGame(struct zip *z, const std::string &zipFile, const std::string &pspGame, const ZipFileInfo &info, bool allowRoot, bool deleteAfter); - bool InstallZippedISO(struct zip *z, int isoFileIndex, std::string zipfile, bool deleteAfter); - bool InstallRawISO(const std::string &zipFile, const std::string &originalName, bool deleteAfter); + bool InstallGame(Path url, Path tempFileName, bool deleteAfter); + bool InstallMemstickGame(struct zip *z, const Path &zipFile, const std::string &pspGame, const ZipFileInfo &info, bool allowRoot, bool deleteAfter); + bool InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter); + bool InstallRawISO(const Path &zipFile, const std::string &originalName, bool deleteAfter); void InstallDone(); bool ExtractFile(struct zip *z, int file_index, const Path &outFilename, size_t *bytesCopied, size_t allBytes); bool DetectTexturePackDest(struct zip *z, int iniIndex, Path &dest); void SetInstallError(const std::string &err); std::string GetTempFilename() const; - std::string GetGameID(const std::string &path) const; + std::string GetGameID(const Path &path) const; std::string GetPBPGameID(FileLoader *loader) const; std::string GetISOGameID(FileLoader *loader) const; std::shared_ptr curDownload_; @@ -115,4 +115,4 @@ struct ZipFileInfo { }; ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info); -ZipFileContents DetectZipFileContents(std::string fileName, ZipFileInfo *info); +ZipFileContents DetectZipFileContents(const Path &fileName, ZipFileInfo *info); diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 985f4f30a6..d2ddd36381 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -71,7 +71,7 @@ bool GameInfo::Delete() { case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: { // TODO: This could be handled by Core/Util/GameManager too somehow. - Path directoryToRemove = Path(ResolvePBPDirectory(filePath_.ToString())); + Path directoryToRemove = ResolvePBPDirectory(filePath_); INFO_LOG(SYSTEM, "Deleting %s", directoryToRemove.c_str()); if (!File::DeleteDirRecursively(directoryToRemove)) { ERROR_LOG(SYSTEM, "Failed to delete file"); @@ -115,7 +115,7 @@ u64 GameInfo::GetGameSizeInBytes() { switch (fileType) { case IdentifiedFileType::PSP_PBP_DIRECTORY: case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: - return File::GetDirectoryRecursiveSize(Path(ResolvePBPDirectory(filePath_.ToString())), nullptr, File::GETFILES_GETHIDDEN); + return File::GetDirectoryRecursiveSize(ResolvePBPDirectory(filePath_), nullptr, File::GETFILES_GETHIDDEN); default: return GetFileLoader()->FileSize(); @@ -201,7 +201,7 @@ bool GameInfo::LoadFromPath(const Path &gamePath) { std::lock_guard guard(lock); // No need to rebuild if we already have it loaded. if (filePath_ != gamePath) { - fileLoader.reset(ConstructFileLoader(gamePath.ToString())); + fileLoader.reset(ConstructFileLoader(gamePath)); if (!fileLoader) return false; filePath_ = gamePath; @@ -220,7 +220,7 @@ std::shared_ptr GameInfo::GetFileLoader() { return fileLoader; } if (!fileLoader) { - fileLoader.reset(ConstructFileLoader(filePath_.ToString())); + fileLoader.reset(ConstructFileLoader(filePath_)); } return fileLoader; } @@ -361,9 +361,9 @@ public: { auto pbpLoader = info_->GetFileLoader(); if (info_->fileType == IdentifiedFileType::PSP_PBP_DIRECTORY) { - Path ebootPath = Path(ResolvePBPFile(gamePath_.ToString())); + Path ebootPath = ResolvePBPFile(gamePath_); if (ebootPath != gamePath_) { - pbpLoader.reset(ConstructFileLoader(ebootPath.ToString())); + pbpLoader.reset(ConstructFileLoader(ebootPath)); } } @@ -372,7 +372,7 @@ public: if (pbp.IsELF()) { goto handleELF; } - ERROR_LOG(LOADER, "invalid pbp %s\n", pbpLoader->GetPath().c_str()); + ERROR_LOG(LOADER, "invalid pbp '%s'\n", pbpLoader->GetPath().c_str()); info_->pending = false; info_->working = false; return; @@ -466,7 +466,7 @@ handleELF: case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: { SequentialHandleAllocator handles; - VirtualDiscFileSystem umd(&handles, gamePath_.c_str()); + VirtualDiscFileSystem umd(&handles, gamePath_); // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; @@ -507,7 +507,7 @@ handleELF: { info_->fileType = IdentifiedFileType::PSP_ISO; SequentialHandleAllocator handles; - VirtualDiscFileSystem umd(&handles, gamePath_.c_str()); + VirtualDiscFileSystem umd(&handles, gamePath_); // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index fc1148a199..a9fdffa0b4 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -96,7 +96,7 @@ void GameScreen::CreateViews() { tvRegion_->SetShadow(true); tvCRC_ = infoLayout->Add(new TextView("", ALIGN_LEFT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); tvCRC_->SetShadow(true); - tvCRC_->SetVisibility(Reporting::HasCRC(gamePath_.ToString()) ? V_VISIBLE : V_GONE); + tvCRC_->SetVisibility(Reporting::HasCRC(gamePath_) ? V_VISIBLE : V_GONE); } else { tvTitle_ = nullptr; tvGameSize_ = nullptr; @@ -240,9 +240,9 @@ void GameScreen::render() { } } - if (tvCRC_ && Reporting::HasCRC(gamePath_.ToString())) { + if (tvCRC_ && Reporting::HasCRC(gamePath_)) { auto rp = GetI18NCategory("Reporting"); - std::string crc = StringFromFormat("%08X", Reporting::RetrieveCRC(gamePath_.ToString())); + std::string crc = StringFromFormat("%08X", Reporting::RetrieveCRC(gamePath_)); tvCRC_->SetText(ReplaceAll(rp->T("FeedbackCRCValue", "Disc CRC: [VALUE]"), "[VALUE]", crc)); tvCRC_->SetVisibility(UI::V_VISIBLE); } diff --git a/UI/InstallZipScreen.cpp b/UI/InstallZipScreen.cpp index ab34f66faa..7db798ea08 100644 --- a/UI/InstallZipScreen.cpp +++ b/UI/InstallZipScreen.cpp @@ -29,7 +29,7 @@ void InstallZipScreen::CreateViews() { using namespace UI; File::FileInfo fileInfo; - bool success = File::GetFileInfo(Path(zipPath_), &fileInfo); + bool success = File::GetFileInfo(zipPath_, &fileInfo); auto di = GetI18NCategory("Dialog"); auto iz = GetI18NCategory("InstallZip"); @@ -43,7 +43,7 @@ void InstallZipScreen::CreateViews() { root_->Add(leftColumn); root_->Add(rightColumnItems); - std::string shortFilename = GetFilenameFromPath(zipPath_); + std::string shortFilename = zipPath_.GetFilename(); // TODO: Do in the background? ZipFileInfo zipInfo; diff --git a/UI/InstallZipScreen.h b/UI/InstallZipScreen.h index e8e8d05701..daf7d4ae88 100644 --- a/UI/InstallZipScreen.h +++ b/UI/InstallZipScreen.h @@ -26,7 +26,7 @@ class InstallZipScreen : public UIDialogScreenWithBackground { public: - InstallZipScreen(std::string zipPath) : zipPath_(zipPath) {} + InstallZipScreen(const Path &zipPath) : zipPath_(zipPath) {} virtual void update() override; virtual bool key(const KeyInput &key) override; @@ -40,7 +40,7 @@ private: UI::Choice *backChoice_ = nullptr; UI::ProgressBar *progressBar_ = nullptr; UI::TextView *doneView_ = nullptr; - std::string zipPath_; + Path zipPath_; bool returnToHomebrew_ = true; bool installStarted_ = false; bool deleteZipFile_ = false; diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 9f558094e9..dfc5cef75f 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -69,7 +69,7 @@ bool MainScreen::showHomebrewTab = false; bool LaunchFile(ScreenManager *screenManager, const Path &path) { // Depending on the file type, we don't want to launch EmuScreen at all. - auto loader = ConstructFileLoader(path.ToString()); + auto loader = ConstructFileLoader(path); if (!loader) { return false; } @@ -79,7 +79,7 @@ bool LaunchFile(ScreenManager *screenManager, const Path &path) { switch (type) { case IdentifiedFileType::ARCHIVE_ZIP: - screenManager->push(new InstallZipScreen(path.ToString())); + screenManager->push(new InstallZipScreen(path)); break; default: // Let the EmuScreen take care of it. @@ -620,7 +620,7 @@ static bool IsValidPBP(const Path &path, bool allowHomebrew) { if (!File::Exists(path)) return false; - std::unique_ptr loader(ConstructFileLoader(path.ToString())); + std::unique_ptr loader(ConstructFileLoader(path)); PBPReader pbp(loader.get()); std::vector sfoData; if (!pbp.GetSubFile(PBP_PARAM_SFO, &sfoData)) @@ -1509,7 +1509,7 @@ void UmdReplaceScreen::update() { } UI::EventReturn UmdReplaceScreen::OnGameSelected(UI::EventParams &e) { - __UmdReplace(e.s); + __UmdReplace(Path(e.s)); TriggerFinish(DR_OK); return UI::EVENT_DONE; } @@ -1525,7 +1525,7 @@ UI::EventReturn UmdReplaceScreen::OnGameSettings(UI::EventParams &e) { } UI::EventReturn UmdReplaceScreen::OnGameSelectedInstant(UI::EventParams &e) { - __UmdReplace(e.s); + __UmdReplace(Path(e.s)); TriggerFinish(DR_OK); return UI::EVENT_DONE; } diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 57d2fc8d9d..4ceee02c2f 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -29,7 +29,7 @@ struct ShaderInfo; struct TextureShaderInfo; -extern std::string boot_filename; +extern Path boot_filename; void UIBackgroundInit(UIContext &dc); void UIBackgroundShutdown(); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 5a1b4016db..295b99f07a 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -207,7 +207,7 @@ int Win32Mix(short *buffer, int numSamples, int bits, int rate, int channels) { // globals static LogListener *logger = nullptr; -std::string boot_filename = ""; +Path boot_filename; void NativeHost::InitSound() { #if PPSSPP_PLATFORM(IOS) @@ -559,7 +559,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch bool gotBootFilename = false; bool gotoGameSettings = false; bool gotoTouchScreenTest = false; - boot_filename = ""; + boot_filename.clear(); // Parse command line LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO; @@ -644,10 +644,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch } } if (okToLoad) { - boot_filename = argv[i]; -#ifdef _WIN32 - boot_filename = ReplaceAll(boot_filename, "\\", "/"); -#endif + boot_filename = Path(std::string(argv[i])); skipLogo = true; } if (okToLoad && okToCheck) { @@ -758,7 +755,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch screenManager->switchScreen(new MainScreen()); screenManager->push(new TouchTestScreen()); } else if (skipLogo) { - screenManager->switchScreen(new EmuScreen(Path(boot_filename))); + screenManager->switchScreen(new EmuScreen(boot_filename)); } else { screenManager->switchScreen(new LogoScreen()); } diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index 610ccbcd44..3aa52b1365 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -270,7 +270,7 @@ void ReportScreen::CreateViews() { } #ifdef MOBILE_DEVICE - if (!Core_GetPowerSaving() && !Reporting::HasCRC(gamePath_.ToString())) { + if (!Core_GetPowerSaving() && !Reporting::HasCRC(gamePath_)) { auto crcWarning = new TextView(rp->T("FeedbackIncludeCRC", "Note: Battery will be used to send a disc CRC"), FLAG_WRAP_TEXT, false, new LinearLayoutParams(Margins(12, 5, 0, 5))); crcWarning->SetShadow(true); crcWarning->SetEnabledPtr(&enableReporting_); @@ -334,8 +334,8 @@ void ReportScreen::UpdateCRCInfo() { auto rp = GetI18NCategory("Reporting"); std::string updated; - if (Reporting::HasCRC(gamePath_.ToString())) { - std::string crc = StringFromFormat("%08X", Reporting::RetrieveCRC(gamePath_.ToString())); + if (Reporting::HasCRC(gamePath_)) { + std::string crc = StringFromFormat("%08X", Reporting::RetrieveCRC(gamePath_)); updated = ReplaceAll(rp->T("FeedbackCRCValue", "Disc CRC: [VALUE]"), "[VALUE]", crc); } else if (showCRC_) { updated = rp->T("FeedbackCRCCalculating", "Disc CRC: Calculating..."); @@ -395,7 +395,7 @@ EventReturn ReportScreen::HandleBrowser(EventParams &e) { } EventReturn ReportScreen::HandleShowCRC(EventParams &e) { - Reporting::QueueCRC(gamePath_.ToString()); + Reporting::QueueCRC(gamePath_); showCRC_ = true; return EVENT_DONE; } diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index 3b237e2ca5..b47ce5b45e 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -426,11 +426,11 @@ bool SavedataBrowser::ByFilename(const UI::View *v1, const UI::View *v2) { } static time_t GetTotalSize(const SavedataButton *b) { - auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath().ToString())); + auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath())); switch (Identify_File(fileLoader.get())) { case IdentifiedFileType::PSP_PBP_DIRECTORY: case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: - return File::GetDirectoryRecursiveSize(Path(ResolvePBPDirectory(b->GamePath().ToString())), nullptr, File::GETFILES_GETHIDDEN); + return File::GetDirectoryRecursiveSize(ResolvePBPDirectory(b->GamePath()), nullptr, File::GETFILES_GETHIDDEN); default: return fileLoader->FileSize(); @@ -447,7 +447,7 @@ bool SavedataBrowser::BySize(const UI::View *v1, const UI::View *v2) { } static time_t GetDateSeconds(const SavedataButton *b) { - auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath().ToString())); + auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath())); tm datetm; bool success; if (Identify_File(fileLoader.get()) == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) { diff --git a/UWP/StorageFileLoader.cpp b/UWP/StorageFileLoader.cpp index 8679673765..0fb95697d0 100644 --- a/UWP/StorageFileLoader.cpp +++ b/UWP/StorageFileLoader.cpp @@ -175,6 +175,6 @@ size_t StorageFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, vo } } -FileLoader *StorageFileLoaderFactory::ConstructFileLoader(const std::string &filename) { +FileLoader *StorageFileLoaderFactory::ConstructFileLoader(const Path &filename) { return file_ ? new StorageFileLoader(file_) : nullptr; } diff --git a/UWP/StorageFileLoader.h b/UWP/StorageFileLoader.h index f44368853a..d6da51acb9 100644 --- a/UWP/StorageFileLoader.h +++ b/UWP/StorageFileLoader.h @@ -9,6 +9,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/File/Path.h" #include "Core/Loaders.h" // This thing is a terrible abomination that wraps asynchronous file access behind a synchronous interface, @@ -24,7 +25,7 @@ public: bool IsDirectory() override; s64 FileSize() override; - std::string GetPath() const override; + Path GetPath() const override; size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; @@ -73,7 +74,7 @@ private: class StorageFileLoaderFactory : public FileLoaderFactory { public: StorageFileLoaderFactory(Windows::Storage::StorageFile ^file, IdentifiedFileType fileType) : file_(file), fileType_(fileType) { } - FileLoader *ConstructFileLoader(const std::string &filename) override; + FileLoader *ConstructFileLoader(const Path &filename) override; private: Windows::Storage::StorageFile ^file_; diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index d05f2743c9..39a48fe8a0 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -450,8 +450,7 @@ namespace MainWindow { } if (W32Util::BrowseForFileName(true, GetHWND(), L"Switch UMD", 0, ConvertUTF8ToWString(filter).c_str(), L"*.pbp;*.elf;*.iso;*.cso;", fn)) { - fn = ReplaceAll(fn, "\\", "/"); - __UmdReplace(fn); + __UmdReplace(Path(fn)); } } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 8f72f6cd23..2fad162248 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -60,6 +60,7 @@ struct JNIEnv {}; #include "Common/System/NativeApp.h" #include "Common/System/System.h" #include "Common/Thread/ThreadUtil.h" +#include "Common/File/Path.h" #include "Common/File/VFS/VFS.h" #include "Common/File/VFS/AssetReader.h" #include "Common/Input/InputState.h" @@ -248,9 +249,9 @@ int Android_OpenContentUriFd(const std::string &filename) { class ContentURIFileLoader : public ProxiedFileLoader { public: - ContentURIFileLoader(const std::string &filename) + ContentURIFileLoader(const Path &filename) : ProxiedFileLoader(nullptr) { // we overwrite the nullptr below - int fd = Android_OpenContentUriFd(filename); + int fd = Android_OpenContentUriFd(filename.ToString()); INFO_LOG(SYSTEM, "Fd %d for content URI: '%s'", fd, filename.c_str()); backend_ = new LocalFileLoader(fd, filename); } @@ -267,7 +268,7 @@ public: class AndroidContentLoaderFactory : public FileLoaderFactory { public: AndroidContentLoaderFactory() {} - FileLoader *ConstructFileLoader(const std::string &filename) override { + FileLoader *ConstructFileLoader(const Path &filename) override { return new ContentURIFileLoader(filename); } }; diff --git a/headless/Compare.cpp b/headless/Compare.cpp index 327aa56bb7..b80b1b2dcd 100644 --- a/headless/Compare.cpp +++ b/headless/Compare.cpp @@ -168,24 +168,17 @@ protected: size_t pos_ = 0; }; -std::string ExpectedFromFilename(const std::string &bootFilename) { - size_t pos = bootFilename.find_last_of('.'); - if (pos == bootFilename.npos) { - return bootFilename + ".expected"; +Path ExpectedScreenshotFromFilename(const Path &bootFilename) { + std::string extension = bootFilename.GetFileExtension(); + if (extension.empty()) { + return bootFilename.WithExtraExtension(".bmp"); } - return bootFilename.substr(0, pos) + ".expected"; -} -std::string ExpectedScreenshotFromFilename(const std::string &bootFilename) { - size_t pos = bootFilename.find_last_of('.'); - if (pos == bootFilename.npos) { - return bootFilename + ".bmp"; - } // Let's use pngs as the default for ppdmp tests. - if (bootFilename.substr(pos) == ".ppdmp") { - return bootFilename.substr(0, pos) + ".png"; + if (extension == ".ppdmp") { + return bootFilename.WithReplacedExtension(".png"); } - return bootFilename.substr(0, pos) + ".expected.bmp"; + return bootFilename.WithReplacedExtension(".expected.bmp"); } static std::string ChopFront(std::string s, std::string front) @@ -209,14 +202,14 @@ static std::string ChopEnd(std::string s, std::string end) return s; } -std::string GetTestName(const std::string &bootFilename) +std::string GetTestName(const Path &bootFilename) { // Kinda ugly, trying to guesstimate the test name from filename... - return ChopEnd(ChopFront(ChopFront(bootFilename, "tests/"), "pspautotests/tests/"), ".prx"); + return ChopEnd(ChopFront(ChopFront(bootFilename.ToString(), "tests/"), "pspautotests/tests/"), ".prx"); } -bool CompareOutput(const std::string &bootFilename, const std::string &output, bool verbose) { - std::string expect_filename = ExpectedFromFilename(bootFilename); +bool CompareOutput(const Path &bootFilename, const std::string &output, bool verbose) { + Path expect_filename = bootFilename.WithReplacedExtension("prx", "expected"); std::unique_ptr expect_loader(ConstructFileLoader(expect_filename)); if (expect_loader->Exists()) { @@ -372,7 +365,7 @@ std::vector TranslateDebugBufferToCompare(const GPUDebugBuffer *buffer, u32 return data; } -double CompareScreenshot(const std::vector &pixels, u32 stride, u32 w, u32 h, const std::string& screenshotFilename, std::string &error) +double CompareScreenshot(const std::vector &pixels, u32 stride, u32 w, u32 h, const Path& screenshotFilename, std::string &error) { if (pixels.size() < stride * h) { @@ -388,7 +381,7 @@ double CompareScreenshot(const std::vector &pixels, u32 stride, u32 w, u32 if (loader->Exists()) { uint8_t header[2]; if (loader->ReadAt(0, 2, header) != 2) { - error = "Unable to read screenshot data: " + screenshotFilename; + error = "Unable to read screenshot data: " + screenshotFilename.ToVisualString(); return -1.0f; } @@ -397,7 +390,7 @@ double CompareScreenshot(const std::vector &pixels, u32 stride, u32 w, u32 asBitmap = true; // The bitmap header is 14 + 40 bytes. We could validate it but the test would fail either way. if (reference && loader->ReadAt(14 + 40, sizeof(u32), stride * h, reference) != stride * h) { - error = "Unable to read screenshot data: " + screenshotFilename; + error = "Unable to read screenshot data: " + screenshotFilename.ToVisualString(); return -1.0f; } } else { @@ -405,23 +398,23 @@ double CompareScreenshot(const std::vector &pixels, u32 stride, u32 w, u32 std::vector compressed; compressed.resize(loader->FileSize()); if (loader->ReadAt(0, compressed.size(), &compressed[0]) != compressed.size()) { - error = "Unable to read screenshot data: " + screenshotFilename; + error = "Unable to read screenshot data: " + screenshotFilename.ToVisualString(); return -1.0f; } int width, height; if (!pngLoadPtr(&compressed[0], compressed.size(), &width, &height, (unsigned char **)&reference)) { - error = "Unable to read screenshot data: " + screenshotFilename; + error = "Unable to read screenshot data: " + screenshotFilename.ToVisualString(); return -1.0f; } } } else { - error = "Unable to read screenshot: " + screenshotFilename; + error = "Unable to read screenshot: " + screenshotFilename.ToVisualString(); return -1.0f; } if (!reference) { - error = "Unable to allocate screenshot data: " + screenshotFilename; + error = "Unable to allocate screenshot data: " + screenshotFilename.ToVisualString(); return -1.0f; } diff --git a/headless/Compare.h b/headless/Compare.h index fb2da13e81..f1f30f5375 100644 --- a/headless/Compare.h +++ b/headless/Compare.h @@ -19,6 +19,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/File/Path.h" struct GPUDebugBuffer; @@ -27,10 +28,10 @@ extern std::string currentTestName; void TeamCityPrint(const char *fmt, ...); void GitHubActionsPrint(const char *type, const char *fmt, ...); -std::string ExpectedFromFilename(const std::string &bootFilename); -std::string ExpectedScreenshotFromFilename(const std::string &bootFilename); -std::string GetTestName(const std::string &bootFilename); +Path ExpectedFromFilename(const Path &bootFilename); +Path ExpectedScreenshotFromFilename(const Path &bootFilename); +std::string GetTestName(const Path &bootFilename); -bool CompareOutput(const std::string &bootFilename, const std::string &output, bool verbose); +bool CompareOutput(const Path &bootFilename, const std::string &output, bool verbose); std::vector TranslateDebugBufferToCompare(const GPUDebugBuffer *buffer, u32 stride, u32 h); -double CompareScreenshot(const std::vector &pixels, u32 stride, u32 w, u32 h, const std::string& screenshotFilename, std::string &error); +double CompareScreenshot(const std::vector &pixels, u32 stride, u32 w, u32 h, const Path &screenshotFilename, std::string &error); diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 28db565418..dd19ac5536 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -152,7 +152,7 @@ static HeadlessHost *getHost(GPUCore gpuCore) { bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, bool autoCompare, bool verbose, double timeout) { // Kinda ugly, trying to guesstimate the test name from filename... - currentTestName = GetTestName(coreParameter.fileToStart.ToString()); + currentTestName = GetTestName(coreParameter.fileToStart); std::string output; if (autoCompare) @@ -172,7 +172,7 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, bool host->BootDone(); if (autoCompare) - headlessHost->SetComparisonScreenshot(ExpectedScreenshotFromFilename(coreParameter.fileToStart.ToString())); + headlessHost->SetComparisonScreenshot(ExpectedScreenshotFromFilename(coreParameter.fileToStart)); bool passed = true; // TODO: We must have some kind of stack overflow or we're not following the ABI right. @@ -221,7 +221,7 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, bool headlessHost->FlushDebugOutput(); if (autoCompare && passed) - passed = CompareOutput(coreParameter.fileToStart.ToString(), output, verbose); + passed = CompareOutput(coreParameter.fileToStart, output, verbose); TeamCityPrint("testFinished name='%s'", currentTestName.c_str()); @@ -423,7 +423,7 @@ int main(int argc, const char* argv[]) g_Config.flash0Directory = Path(File::GetExeDirectory()) / "assets/flash0"; if (screenshotFilename != 0) - headlessHost->SetComparisonScreenshot(screenshotFilename); + headlessHost->SetComparisonScreenshot(Path(std::string(screenshotFilename))); #ifdef __ANDROID__ // For some reason the debugger installs it with this name? @@ -456,7 +456,7 @@ int main(int argc, const char* argv[]) bool passed = RunAutoTest(headlessHost, coreParameter, autoCompare, verbose, timeout); if (autoCompare) { - std::string testName = GetTestName(coreParameter.fileToStart.ToString()); + std::string testName = GetTestName(coreParameter.fileToStart); if (passed) { passedTests.push_back(testName); diff --git a/headless/StubHost.h b/headless/StubHost.h index 571444ce0b..c914f025b2 100644 --- a/headless/StubHost.h +++ b/headless/StubHost.h @@ -17,6 +17,8 @@ #pragma once +#include "Common/File/Path.h" + #include "Core/CoreParameter.h" #include "Core/Host.h" #include "Core/Debugger/SymbolMap.h" @@ -66,7 +68,7 @@ public: } } - virtual void SetComparisonScreenshot(const std::string &filename) { + virtual void SetComparisonScreenshot(const Path &filename) { comparisonScreenshot_ = filename; } @@ -80,7 +82,7 @@ public: protected: void SendOrCollectDebugOutput(const std::string &output); - std::string comparisonScreenshot_; + Path comparisonScreenshot_; std::string debugOutputBuffer_; GPUCore gpuCore_; GraphicsContext *gfx_ = nullptr; diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index bcdaa116c8..24d013bb0c 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -588,13 +588,18 @@ static bool TestPath() { EXPECT_EQ_STR(path.ToString(), std::string("/asdf/jkl")); Path path2("/asdf/jkl"); - EXPECT_EQ_STR(path2.ToString(), std::string("/asdf/jkl")); + EXPECT_EQ_STR(path2.NavigateUp().ToString(), std::string("/asdf")); Path path3 = path2 / "foo/bar"; - EXPECT_EQ_STR(path3.WithExtraExtension("txt").ToString(), std::string("/asdf/jkl/foo/bar.txt")); + EXPECT_EQ_STR(path3.WithExtraExtension(".txt").ToString(), std::string("/asdf/jkl/foo/bar.txt")); EXPECT_EQ_STR(Path("foo.bar/hello").GetFileExtension(), std::string("")); - EXPECT_EQ_STR(Path("foo.bar/hello.txt").WithReplacedExtension("txt", "html").ToString(), std::string("foo.bar/hello.html")); + EXPECT_EQ_STR(Path("foo.bar/hello.txt").WithReplacedExtension(".txt", ".html").ToString(), std::string("foo.bar/hello.html")); + + EXPECT_EQ_STR(Path("C:\\Yo").GetDirectory(), std::string("C:")); + EXPECT_EQ_STR(Path("C:\\Yo").GetFilename(), std::string("Yo")); + EXPECT_EQ_STR(Path("C:\\Yo\\Lo").GetDirectory(), std::string("C:/Yo")); + EXPECT_EQ_STR(Path("C:\\Yo\\Lo").GetFilename(), std::string("Lo")); return true; }