diff --git a/Common/File/AndroidStorage.cpp b/Common/File/AndroidStorage.cpp index c1b42836513a..ec8248947bcb 100644 --- a/Common/File/AndroidStorage.cpp +++ b/Common/File/AndroidStorage.cpp @@ -206,11 +206,13 @@ bool Android_FileExists(const std::string &fileUri) { return exists; } -std::vector Android_ListContentUri(const std::string &path) { +std::vector Android_ListContentUri(const std::string &path, bool *exists) { if (!g_nativeActivity) { + *exists = false; return std::vector(); } auto env = getEnv(); + *exists = true; double start = time_now_d(); @@ -224,8 +226,12 @@ std::vector Android_ListContentUri(const std::string &path) { jstring str = (jstring)env->GetObjectArrayElement(fileList, i); const char *charArray = env->GetStringUTFChars(str, 0); if (charArray) { // paranoia + std::string line = charArray; File::FileInfo info; - if (ParseFileInfo(std::string(charArray), &info)) { + if (line == "X") { + // Indicates an exception thrown, path doesn't exist. + *exists = false; + } else if (ParseFileInfo(line, &info)) { // We can just reconstruct the URI. info.fullName = Path(path) / info.name; items.push_back(info); @@ -238,7 +244,7 @@ std::vector Android_ListContentUri(const std::string &path) { double elapsed = time_now_d() - start; if (elapsed > 0.1) { - INFO_LOG(FILESYS, "Listing directory on content URI took %0.3f s (%d files)", elapsed, (int)size); + INFO_LOG(FILESYS, "Listing directory on content URI took %0.3f s (%d files)", elapsed, (int)items.size()); } return items; } diff --git a/Common/File/AndroidStorage.h b/Common/File/AndroidStorage.h index a9a88055d141..1b4585f7755b 100644 --- a/Common/File/AndroidStorage.h +++ b/Common/File/AndroidStorage.h @@ -55,7 +55,7 @@ int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath); bool Android_IsExternalStoragePreservedLegacy(); const char *Android_ErrorToString(StorageError error); -std::vector Android_ListContentUri(const std::string &uri); +std::vector Android_ListContentUri(const std::string &uri, bool *exists); void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj); @@ -78,7 +78,8 @@ inline int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) { return inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; } inline bool Android_IsExternalStoragePreservedLegacy() { return false; } inline const char *Android_ErrorToString(StorageError error) { return ""; } -inline std::vector Android_ListContentUri(const std::string &uri) { +inline std::vector Android_ListContentUri(const std::string &uri, bool *exists) { + *exists = false; return std::vector(); } diff --git a/Common/File/DirListing.cpp b/Common/File/DirListing.cpp index 2f7178847b34..d17a4f22417b 100644 --- a/Common/File/DirListing.cpp +++ b/Common/File/DirListing.cpp @@ -171,10 +171,11 @@ std::vector ApplyFilter(std::vector files, const bool GetFilesInDir(const Path &directory, std::vector *files, const char *filter, int flags) { if (directory.Type() == PathType::CONTENT_URI) { - std::vector fileList = Android_ListContentUri(directory.ToString()); + bool exists = false; + std::vector fileList = Android_ListContentUri(directory.ToString(), &exists); *files = ApplyFilter(fileList, filter); std::sort(files->begin(), files->end()); - return true; + return exists; } std::set filters; @@ -219,7 +220,7 @@ bool GetFilesInDir(const Path &directory, std::vector *files, const ch HANDLE hFind = FindFirstFileEx((directory.ToWString() + L"\\*").c_str(), FindExInfoStandard, &ffd, FindExSearchNameMatch, NULL, 0); #endif if (hFind == INVALID_HANDLE_VALUE) { - return 0; + return false; } do { const std::string virtualName = ConvertWStringToUTF8(ffd.cFileName); @@ -266,7 +267,7 @@ bool GetFilesInDir(const Path &directory, std::vector *files, const ch struct dirent *result = NULL; DIR *dirp = opendir(directory.c_str()); if (!dirp) - return 0; + return false; while ((result = readdir(dirp))) { const std::string virtualName(result->d_name); // check for "." and ".." diff --git a/Core/Dialog/PSPGamedataInstallDialog.cpp b/Core/Dialog/PSPGamedataInstallDialog.cpp index 3bbe9442f1dd..30da2953c6c9 100644 --- a/Core/Dialog/PSPGamedataInstallDialog.cpp +++ b/Core/Dialog/PSPGamedataInstallDialog.cpp @@ -206,12 +206,9 @@ void PSPGamedataInstallDialog::CloseCurrentFile() { void PSPGamedataInstallDialog::WriteSfoFile() { ParamSFOData sfoFile; std::string sfopath = GetGameDataInstallFileName(&request, SFO_FILENAME); - PSPFileInfo sfoInfo = pspFileSystem.GetFileInfo(sfopath); - if (sfoInfo.exists) { - std::vector sfoData; - if (pspFileSystem.ReadEntireFile(sfopath, sfoData) >= 0) { - sfoFile.ReadSFO(sfoData); - } + std::vector sfoFileData; + if (pspFileSystem.ReadEntireFile(sfopath, sfoFileData) >= 0) { + sfoFile.ReadSFO(sfoFileData); } // Update based on the just-saved data. diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 8ab80a4761a4..91994d3f3628 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -56,6 +56,29 @@ const static int SAVEDATA_DIALOG_SIZE_V1 = 1480; const static int SAVEDATA_DIALOG_SIZE_V2 = 1500; const static int SAVEDATA_DIALOG_SIZE_V3 = 1536; +static bool IsNotVisibleAction(SceUtilitySavedataType type) { + switch (type) { + case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD: + case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE: + case SCE_UTILITY_SAVEDATA_TYPE_SIZES: + case SCE_UTILITY_SAVEDATA_TYPE_LIST: + case SCE_UTILITY_SAVEDATA_TYPE_FILES: + case SCE_UTILITY_SAVEDATA_TYPE_GETSIZE: + case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE: + case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATA: + case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE: + case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA: + case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: + case SCE_UTILITY_SAVEDATA_TYPE_READDATA: + case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA: + case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE: + return true; + + default: + break; + } + return false; +} PSPSaveDialog::PSPSaveDialog(UtilityDialogType type) : PSPDialog(type) { param.SetPspParam(0); @@ -87,6 +110,8 @@ int PSPSaveDialog::Init(int paramAddr) Memory::Memcpy(&request, requestAddr, size); Memory::Memcpy(&originalRequest, requestAddr, size); + param.SetIgnoreTextures(IsNotVisibleAction((SceUtilitySavedataType)(u32)request.mode)); + param.ClearCaches(); int retval = param.SetPspParam(&request); const u32 mode = (u32)param.GetPspParam()->mode; @@ -239,6 +264,7 @@ int PSPSaveDialog::Init(int paramAddr) ChangeStatusInit(SAVEDATA_INIT_DELAY_US); } + param.ClearCaches(); UpdateButtons(); StartFade(true); @@ -345,7 +371,7 @@ void PSPSaveDialog::DisplaySaveList(bool canMove) { PPGeImageStyle imageStyle = FadedImageStyle(); auto fileInfo = param.GetFileInfo(displayCount); - if (fileInfo.size == 0 && fileInfo.texture != NULL) + if (fileInfo.size == 0 && fileInfo.texture && fileInfo.texture->IsValid()) imageStyle.color = CalcFadedColor(0xFF777777); // Calc save image position on screen @@ -370,7 +396,7 @@ void PSPSaveDialog::DisplaySaveList(bool canMove) { continue; int pad = 0; - if (fileInfo.texture != nullptr) { + if (fileInfo.texture != nullptr && fileInfo.texture->IsValid()) { fileInfo.texture->SetTexture(); int tw = fileInfo.texture->Width(); int th = fileInfo.texture->Height(); @@ -420,7 +446,7 @@ void PSPSaveDialog::DisplaySaveIcon(bool checkExists) int tw = 256; int th = 256; - if (curSave.texture != NULL) { + if (curSave.texture != nullptr && curSave.texture->IsValid()) { curSave.texture->SetTexture(); tw = curSave.texture->Width(); th = curSave.texture->Height(); @@ -618,6 +644,7 @@ int PSPSaveDialog::Update(int animSpeed) param.SetPspParam(&request); } + param.ClearCaches(); UpdateButtons(); UpdateFade(animSpeed); @@ -1035,11 +1062,13 @@ int PSPSaveDialog::Update(int animSpeed) if (ReadStatus() == SCE_UTILITY_STATUS_FINISHED || pendingStatus == SCE_UTILITY_STATUS_FINISHED) Memory::Memcpy(requestAddr, &request, request.common.size, "SaveDialogParam"); + param.ClearCaches(); return 0; } void PSPSaveDialog::ExecuteIOAction() { + param.ClearCaches(); auto &result = param.GetPspParam()->common.result; std::lock_guard guard(paramLock); switch (display) { @@ -1078,9 +1107,11 @@ void PSPSaveDialog::ExecuteIOAction() { } ioThreadStatus = SAVEIO_DONE; + param.ClearCaches(); } void PSPSaveDialog::ExecuteNotVisibleIOAction() { + param.ClearCaches(); auto &result = param.GetPspParam()->common.result; switch ((SceUtilitySavedataType)(u32)param.GetPspParam()->mode) { @@ -1161,6 +1192,8 @@ void PSPSaveDialog::ExecuteNotVisibleIOAction() { default: break; } + + param.ClearCaches(); } void PSPSaveDialog::JoinIOThread() { @@ -1198,6 +1231,7 @@ int PSPSaveDialog::Shutdown(bool force) { ChangeStatusShutdown(SAVEDATA_SHUTDOWN_DELAY_US); } param.SetPspParam(0); + param.ClearCaches(); return 0; } diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 67ef655ccf2b..53d6d819a356 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -95,6 +95,18 @@ namespace return result == dataSize; } + PSPFileInfo FileFromListing(const std::vector &listing, const std::string &filename) { + for (const PSPFileInfo &sub : listing) { + if (sub.name == filename) + return sub; + } + + PSPFileInfo info; + info.name = filename; + info.exists = false; + return info; + } + bool PSPMatch(std::string text, std::string regexp) { if(text.empty() && regexp.empty()) @@ -331,6 +343,7 @@ bool SavedataParam::Delete(SceUtilitySavedataParam* param, int saveId) { return false; } + ClearCaches(); pspFileSystem.RmDir(dirPath); return true; } @@ -366,6 +379,7 @@ int SavedataParam::DeleteData(SceUtilitySavedataParam* param) { return 0; } + ClearCaches(); pspFileSystem.RemoveFile(filePath); return 0; @@ -443,28 +457,23 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD } // SAVE PARAM.SFO - ParamSFOData sfoFile; std::string sfopath = dirPath + "/" + SFO_FILENAME; - { - std::vector sfoData; - if (pspFileSystem.ReadEntireFile(sfopath, sfoData) >= 0) - sfoFile.ReadSFO(sfoData); - } + std::shared_ptr sfoFile = LoadCachedSFO(sfopath, true); // Update values - sfoFile.SetValue("TITLE",param->sfoParam.title,128); - sfoFile.SetValue("SAVEDATA_TITLE",param->sfoParam.savedataTitle,128); - sfoFile.SetValue("SAVEDATA_DETAIL",param->sfoParam.detail,1024); - sfoFile.SetValue("PARENTAL_LEVEL",param->sfoParam.parentalLevel,4); - sfoFile.SetValue("CATEGORY","MS",4); - sfoFile.SetValue("SAVEDATA_DIRECTORY", GetSaveDir(param, saveDirName), 64); + sfoFile->SetValue("TITLE", param->sfoParam.title, 128); + sfoFile->SetValue("SAVEDATA_TITLE", param->sfoParam.savedataTitle, 128); + sfoFile->SetValue("SAVEDATA_DETAIL", param->sfoParam.detail, 1024); + sfoFile->SetValue("PARENTAL_LEVEL", param->sfoParam.parentalLevel, 4); + sfoFile->SetValue("CATEGORY", "MS", 4); + sfoFile->SetValue("SAVEDATA_DIRECTORY", GetSaveDir(param, saveDirName), 64); // Always write and update the file list. // For each file, 13 bytes for filename, 16 bytes for file hash (0 in PPSSPP), 3 byte for padding const int FILE_LIST_COUNT_MAX = 99; const u32 FILE_LIST_TOTAL_SIZE = sizeof(SaveSFOFileListEntry) * FILE_LIST_COUNT_MAX; u32 tmpDataSize = 0; - SaveSFOFileListEntry *tmpDataOrig = (SaveSFOFileListEntry *)sfoFile.GetValueData("SAVEDATA_FILE_LIST", &tmpDataSize); + SaveSFOFileListEntry *tmpDataOrig = (SaveSFOFileListEntry *)sfoFile->GetValueData("SAVEDATA_FILE_LIST", &tmpDataSize); SaveSFOFileListEntry *updatedList = new SaveSFOFileListEntry[FILE_LIST_COUNT_MAX]; if (tmpDataSize != 0) memcpy(updatedList, tmpDataOrig, std::min(tmpDataSize, FILE_LIST_TOTAL_SIZE)); @@ -485,28 +494,30 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD } } - sfoFile.SetValue("SAVEDATA_FILE_LIST", (u8 *)updatedList, FILE_LIST_TOTAL_SIZE, (int)FILE_LIST_TOTAL_SIZE); + sfoFile->SetValue("SAVEDATA_FILE_LIST", (u8 *)updatedList, FILE_LIST_TOTAL_SIZE, (int)FILE_LIST_TOTAL_SIZE); delete[] updatedList; // Init param with 0. This will be used to detect crypted save or not on loading u8 *tmpData = new u8[128]; memset(tmpData, 0, 128); - sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128); + sfoFile->SetValue("SAVEDATA_PARAMS", tmpData, 128, 128); delete[] tmpData; u8 *sfoData; size_t sfoSize; - sfoFile.WriteSFO(&sfoData,&sfoSize); + sfoFile->WriteSFO(&sfoData, &sfoSize); // Calc SFO hash for PSP. - if(cryptedData != 0) - { - int offset = sfoFile.GetDataOffset(sfoData,"SAVEDATA_PARAMS"); + if (cryptedData != 0) { + int offset = sfoFile->GetDataOffset(sfoData, "SAVEDATA_PARAMS"); if(offset >= 0) UpdateHash(sfoData, (int)sfoSize, offset, DetermineCryptMode(param)); } + + ClearCaches(); WritePSPFile(sfopath, sfoData, (SceSize)sfoSize); delete[] sfoData; + sfoData = nullptr; if(param->dataBuf.IsValid()) // Can launch save without save data in mode 13 { @@ -792,38 +803,31 @@ u32 SavedataParam::LoadNotCryptedSave(SceUtilitySavedataParam *param, u8 *data, } bool SavedataParam::LoadSFO(SceUtilitySavedataParam *param, const std::string& dirPath) { - ParamSFOData sfoFile; std::string sfopath = dirPath + "/" + SFO_FILENAME; - std::vector sfoData; - if (pspFileSystem.ReadEntireFile(sfopath, sfoData) >= 0) { - sfoFile.ReadSFO(sfoData); - + std::shared_ptr sfoFile = LoadCachedSFO(sfopath); + if (sfoFile) { // copy back info in request - strncpy(param->sfoParam.title,sfoFile.GetValueString("TITLE").c_str(),128); - strncpy(param->sfoParam.savedataTitle,sfoFile.GetValueString("SAVEDATA_TITLE").c_str(),128); - strncpy(param->sfoParam.detail,sfoFile.GetValueString("SAVEDATA_DETAIL").c_str(),1024); - param->sfoParam.parentalLevel = sfoFile.GetValueInt("PARENTAL_LEVEL"); + strncpy(param->sfoParam.title, sfoFile->GetValueString("TITLE").c_str(), 128); + strncpy(param->sfoParam.savedataTitle, sfoFile->GetValueString("SAVEDATA_TITLE").c_str(), 128); + strncpy(param->sfoParam.detail, sfoFile->GetValueString("SAVEDATA_DETAIL").c_str(), 1024); + param->sfoParam.parentalLevel = sfoFile->GetValueInt("PARENTAL_LEVEL"); return true; - } else { - return false; } + return false; } std::vector SavedataParam::GetSFOEntries(const std::string &dirPath) { std::vector result; const std::string sfoPath = dirPath + "/" + SFO_FILENAME; - ParamSFOData sfoFile; - std::vector sfoData; - if (pspFileSystem.ReadEntireFile(sfoPath, sfoData) >= 0) { - sfoFile.ReadSFO(sfoData); - } else { + std::shared_ptr sfoFile = LoadCachedSFO(sfoPath); + if (!sfoFile) { return result; } const int FILE_LIST_COUNT_MAX = 99; u32 sfoFileListSize = 0; - SaveSFOFileListEntry *sfoFileList = (SaveSFOFileListEntry *)sfoFile.GetValueData("SAVEDATA_FILE_LIST", &sfoFileListSize); + SaveSFOFileListEntry *sfoFileList = (SaveSFOFileListEntry *)sfoFile->GetValueData("SAVEDATA_FILE_LIST", &sfoFileListSize); const u32 count = std::min((u32)FILE_LIST_COUNT_MAX, sfoFileListSize / (u32)sizeof(SaveSFOFileListEntry)); for (u32 i = 0; i < count; ++i) { @@ -1094,13 +1098,12 @@ int SavedataParam::GetSizes(SceUtilitySavedataParam *param) const std::string saveName(msData->saveName, strnlen(msData->saveName, sizeof(msData->saveName))); // TODO: How should <> be handled? std::string path = GetSaveFilePath(param, gameName + (saveName == "<>" ? "" : saveName)); - PSPFileInfo finfo = pspFileSystem.GetFileInfo(path); - if (finfo.exists) - { + bool listingExists = false; + auto listing = pspFileSystem.GetDirListing(path, &listingExists); + if (listingExists) { param->msData->info.usedClusters = 0; - auto listing = pspFileSystem.GetDirListing(path); - for (auto it = listing.begin(), end = listing.end(); it != end; ++it) { - param->msData->info.usedClusters += (it->size + (u32)MemoryStick_SectorSize() - 1) / (u32)MemoryStick_SectorSize(); + for (auto &item : listing) { + param->msData->info.usedClusters += (item.size + (u32)MemoryStick_SectorSize() - 1) / (u32)MemoryStick_SectorSize(); } // The usedSpaceKB value is definitely based on clusters, not bytes or even KB. @@ -1251,7 +1254,9 @@ int SavedataParam::GetFilesList(SceUtilitySavedataParam *param, u32 requestAddr) } std::string dirPath = savePath + GetGameName(param) + GetSaveName(param); - if (!pspFileSystem.GetFileInfo(dirPath).exists) { + bool dirPathExists = false; + auto files = pspFileSystem.GetDirListing(dirPath, &dirPathExists); + if (!dirPathExists) { DEBUG_LOG(SCEUTILITY, "SavedataParam::GetFilesList(): directory %s does not exist", dirPath.c_str()); return SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; } @@ -1262,7 +1267,7 @@ int SavedataParam::GetFilesList(SceUtilitySavedataParam *param, u32 requestAddr) fileList->resultNumSystemEntries = 0; // We need PARAM.SFO's SAVEDATA_FILE_LIST to determine which entries are secure. - PSPFileInfo sfoFileInfo = pspFileSystem.GetFileInfo(dirPath + "/" + SFO_FILENAME); + PSPFileInfo sfoFileInfo = FileFromListing(files, SFO_FILENAME); std::set secureFilenames; if (sfoFileInfo.exists) { @@ -1279,7 +1284,7 @@ int SavedataParam::GetFilesList(SceUtilitySavedataParam *param, u32 requestAddr) requestPtr->bind = 1021; // Does not list directories, nor recurse into them, and ignores files not ALL UPPERCASE. - auto files = pspFileSystem.GetDirListing(dirPath); + bool isCrypted = GetSaveCryptMode(param, GetSaveDirName(param, 0)) != 0; for (auto file = files.begin(), end = files.end(); file != end; ++file) { if (file->type == FILETYPE_DIRECTORY) { continue; @@ -1304,7 +1309,6 @@ int SavedataParam::GetFilesList(SceUtilitySavedataParam *param, u32 requestAddr) entry = &fileList->secureEntries[fileList->resultNumSecureEntries++]; } // Secure files are slightly bigger. - bool isCrypted = GetSaveCryptMode(param, GetSaveDirName(param, 0)) != 0; if (isCrypted) { sizeOffset = -0x10; } @@ -1348,8 +1352,8 @@ bool SavedataParam::GetSize(SceUtilitySavedataParam *param) } const std::string saveDir = savePath + GetGameName(param) + GetSaveName(param); - PSPFileInfo info = pspFileSystem.GetFileInfo(saveDir); - bool exists = info.exists; + bool exists = false; + auto listing = pspFileSystem.GetDirListing(saveDir, &exists); if (param->sizeInfo.IsValid()) { @@ -1359,12 +1363,12 @@ bool SavedataParam::GetSize(SceUtilitySavedataParam *param) s64 writeBytes = 0; for (int i = 0; i < param->sizeInfo->numNormalEntries; ++i) { const auto &entry = param->sizeInfo->normalEntries[i]; - overwriteBytes += pspFileSystem.GetFileInfo(saveDir + "/" + entry.name).size; + overwriteBytes += FileFromListing(listing, entry.name).size; writeBytes += entry.size; } for (int i = 0; i < param->sizeInfo->numSecureEntries; ++i) { const auto &entry = param->sizeInfo->secureEntries[i]; - overwriteBytes += pspFileSystem.GetFileInfo(saveDir + "/" + entry.name).size; + overwriteBytes += FileFromListing(listing, entry.name).size; writeBytes += entry.size + 0x10; } @@ -1488,23 +1492,20 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) for (int i = 0; i < saveDataListCount; i++) { // "<>" means saveName can be anything... if (strncmp(saveNameListData[i], "<>", ARRAY_SIZE(saveNameListData[i])) == 0) { - std::string fileDataPath = ""; // TODO:Maybe we need a way to reorder the files? auto allSaves = pspFileSystem.GetDirListing(savePath); std::string gameName = GetGameName(param); - std::string saveName = ""; - for(auto it = allSaves.begin(); it != allSaves.end(); ++it) { - if(it->name.compare(0, gameName.length(), gameName) == 0) { - saveName = it->name.substr(gameName.length()); + 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()); - if(IsInSaveDataList(saveName, realCount)) // Already in SaveDataList, skip... + if (IsInSaveDataList(saveName, realCount)) // Already in SaveDataList, skip... continue; - fileDataPath = savePath + it->name; - PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataPath); - if (info.exists) { - SetFileInfo(realCount, info, saveName); - DEBUG_LOG(SCEUTILITY,"%s Exist",fileDataPath.c_str()); + std::string fileDataPath = savePath + it->name; + if (it->exists) { + SetFileInfo(realCount, *it, saveName); + DEBUG_LOG(SCEUTILITY, "%s Exist", fileDataPath.c_str()); ++realCount; } else { if (listEmptyFile) { @@ -1591,23 +1592,17 @@ void SavedataParam::SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std:: // Search save image icon0 // TODO : If icon0 don't exist, need to use icon1 which is a moving icon. Also play sound - std::string fileDataPath2 = savePath + saveDir + "/" + ICON0_FILENAME; - PSPFileInfo info2 = pspFileSystem.GetFileInfo(fileDataPath2); - if (info2.exists) - saveInfo.texture = new PPGeImage(fileDataPath2); + if (!ignoreTextures_) { + saveInfo.texture = new PPGeImage(savePath + saveDir + "/" + ICON0_FILENAME); + } // Load info in PARAM.SFO - fileDataPath2 = savePath + saveDir + "/" + SFO_FILENAME; - info2 = pspFileSystem.GetFileInfo(fileDataPath2); - if (info2.exists) { - std::vector sfoData; - pspFileSystem.ReadEntireFile(fileDataPath2, sfoData); - ParamSFOData sfoFile; - if (sfoFile.ReadSFO(sfoData)) { - SetStringFromSFO(sfoFile, "TITLE", saveInfo.title, sizeof(saveInfo.title)); - SetStringFromSFO(sfoFile, "SAVEDATA_TITLE", saveInfo.saveTitle, sizeof(saveInfo.saveTitle)); - SetStringFromSFO(sfoFile, "SAVEDATA_DETAIL", saveInfo.saveDetail, sizeof(saveInfo.saveDetail)); - } + std::string sfoFilename = savePath + saveDir + "/" + SFO_FILENAME; + std::shared_ptr sfoFile = LoadCachedSFO(sfoFilename); + if (sfoFile) { + SetStringFromSFO(*sfoFile, "TITLE", saveInfo.title, sizeof(saveInfo.title)); + SetStringFromSFO(*sfoFile, "SAVEDATA_TITLE", saveInfo.saveTitle, sizeof(saveInfo.saveTitle)); + SetStringFromSFO(*sfoFile, "SAVEDATA_DETAIL", saveInfo.saveDetail, sizeof(saveInfo.saveDetail)); } else { saveInfo.broken = true; truncate_cpy(saveInfo.title, saveDir.c_str()); @@ -1852,9 +1847,8 @@ bool SavedataParam::wouldHasMultiSaveName(SceUtilitySavedataParam* param) { } } -void SavedataParam::DoState(PointerWrap &p) -{ - auto s = p.Section("SavedataParam", 1); +void SavedataParam::DoState(PointerWrap &p) { + auto s = p.Section("SavedataParam", 1, 2); if (!s) return; @@ -1862,55 +1856,78 @@ void SavedataParam::DoState(PointerWrap &p) Do(p, selectedSave); Do(p, saveDataListCount); Do(p, saveNameListDataCount); - if (p.mode == p.MODE_READ) - { + if (p.mode == p.MODE_READ) { if (saveDataList != NULL) delete [] saveDataList; - if (saveDataListCount != 0) - { + if (saveDataListCount != 0) { saveDataList = new SaveFileInfo[saveDataListCount]; DoArray(p, saveDataList, saveDataListCount); - } - else + } else { saveDataList = NULL; + } } else DoArray(p, saveDataList, saveDataListCount); + + if (s >= 2) { + Do(p, ignoreTextures_); + } else { + ignoreTextures_ = false; + } } -int SavedataParam::GetSaveCryptMode(SceUtilitySavedataParam* param, const std::string &saveDirName) -{ - ParamSFOData sfoFile; +void SavedataParam::ClearCaches() { + std::lock_guard guard(cacheLock_); + sfoCache_.clear(); +} + +std::shared_ptr SavedataParam::LoadCachedSFO(const std::string &path, bool orCreate) { + std::lock_guard guard(cacheLock_); + if (sfoCache_.find(path) == sfoCache_.end()) { + std::vector data; + if (pspFileSystem.ReadEntireFile(path, data) < 0) { + // Mark as not existing for later. + sfoCache_[path].reset(); + } else { + sfoCache_.emplace(path, new ParamSFOData()); + // If it fails to load, also keep it to indicate failed. + if (!sfoCache_.at(path)->ReadSFO(data)) + sfoCache_.at(path).reset(); + } + } + + if (!sfoCache_.at(path)) { + if (!orCreate) + return nullptr; + sfoCache_.at(path).reset(new ParamSFOData()); + } + return sfoCache_.at(path); +} + +int SavedataParam::GetSaveCryptMode(SceUtilitySavedataParam *param, const std::string &saveDirName) { std::string dirPath = GetSaveFilePath(param, GetSaveDir(param, saveDirName)); std::string sfopath = dirPath + "/" + SFO_FILENAME; - PSPFileInfo sfoInfo = pspFileSystem.GetFileInfo(sfopath); - if(sfoInfo.exists) // Read sfo - { - std::vector sfoData; - if (pspFileSystem.ReadEntireFile(sfopath, sfoData) >= 0) - { - sfoFile.ReadSFO(sfoData); - - // save created in PPSSPP and not encrypted has '0' in SAVEDATA_PARAMS - u32 tmpDataSize = 0; - const u8 *tmpDataOrig = sfoFile.GetValueData("SAVEDATA_PARAMS", &tmpDataSize); - if (tmpDataSize == 0 || !tmpDataOrig) { - return 0; - } - switch (tmpDataOrig[0]) { - case 0: - return 0; - case 0x01: - return 1; - case 0x21: - return 3; - case 0x41: - return 5; - default: - // Well, it's not zero, so yes. - ERROR_LOG_REPORT(SCEUTILITY, "Unexpected SAVEDATA_PARAMS hash flag: %02x", tmpDataOrig[0]); - return 1; - } + std::shared_ptr sfoFile = LoadCachedSFO(sfopath); + if (sfoFile) { + // save created in PPSSPP and not encrypted has '0' in SAVEDATA_PARAMS + u32 tmpDataSize = 0; + const u8 *tmpDataOrig = sfoFile->GetValueData("SAVEDATA_PARAMS", &tmpDataSize); + if (tmpDataSize == 0 || !tmpDataOrig) { + return 0; + } + switch (tmpDataOrig[0]) { + case 0: + return 0; + case 0x01: + return 1; + case 0x21: + return 3; + case 0x41: + return 5; + default: + // Well, it's not zero, so yes. + ERROR_LOG_REPORT(SCEUTILITY, "Unexpected SAVEDATA_PARAMS hash flag: %02x", tmpDataOrig[0]); + return 1; } } return 0; diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index 8599a1428ddd..65a1ac5cd118 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -17,8 +17,12 @@ #pragma once +#include +#include #include +#include #include "Common/CommonTypes.h" +#include "Core/ELF/ParamSFO.h" #include "Core/MemMap.h" #include "Core/HLE/sceRtc.h" #include "Core/Dialog/PSPDialog.h" @@ -324,6 +328,9 @@ class SavedataParam static std::string GetSpaceText(u64 size, bool roundUp); + void SetIgnoreTextures(bool state) { + ignoreTextures_ = state; + } int SetPspParam(SceUtilitySavedataParam* param); SceUtilitySavedataParam *GetPspParam(); const SceUtilitySavedataParam *GetPspParam() const; @@ -348,6 +355,8 @@ class SavedataParam bool wouldHasMultiSaveName(SceUtilitySavedataParam* param); + void ClearCaches(); + void DoState(PointerWrap &p); private: @@ -373,10 +382,17 @@ class SavedataParam std::set GetSecureFileNames(const std::string &dirPath); bool GetExpectedHash(const std::string &dirPath, const std::string &filename, u8 hash[16]); + std::shared_ptr LoadCachedSFO(const std::string &path, bool orCreate = false); + SceUtilitySavedataParam* pspParam = nullptr; int selectedSave = 0; SaveFileInfo *saveDataList = nullptr; SaveFileInfo *noSaveIcon = nullptr; int saveDataListCount = 0; int saveNameListDataCount = 0; + bool ignoreTextures_ = false; + + // Cleared before returning to PSP, no need to save state. + std::mutex cacheLock_; + std::unordered_map> sfoCache_; }; diff --git a/Core/FileSystems/BlobFileSystem.cpp b/Core/FileSystems/BlobFileSystem.cpp index 46f22085e5ef..fb47eefa9de0 100644 --- a/Core/FileSystems/BlobFileSystem.cpp +++ b/Core/FileSystems/BlobFileSystem.cpp @@ -30,9 +30,11 @@ void BlobFileSystem::DoState(PointerWrap &p) { // Not used in real emulation. } -std::vector BlobFileSystem::GetDirListing(std::string path) { +std::vector BlobFileSystem::GetDirListing(const std::string &path, bool *exists) { std::vector listing; listing.push_back(GetFileInfo(alias_)); + if (exists) + *exists = true; return listing; } diff --git a/Core/FileSystems/BlobFileSystem.h b/Core/FileSystems/BlobFileSystem.h index f45576d6a7f3..6def55870d8e 100644 --- a/Core/FileSystems/BlobFileSystem.h +++ b/Core/FileSystems/BlobFileSystem.h @@ -34,7 +34,7 @@ class BlobFileSystem : public IFileSystem { ~BlobFileSystem(); void DoState(PointerWrap &p) override; - std::vector GetDirListing(std::string path) override; + std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override; int OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override; void CloseFile(u32 handle) override; size_t ReadFile(u32 handle, u8 *pointer, s64 size) override; diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index c2b69342d7e1..af8ea370a430 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -671,40 +671,34 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { PSPFileInfo x; x.name = filename; + File::FileInfo info; Path fullName = GetLocalPath(filename); - if (!File::Exists(fullName)) { + if (!File::GetFileInfo(fullName, &info)) { #if HOST_IS_CASE_SENSITIVE if (! FixPathCase(basePath, filename, FPC_FILE_MUST_EXIST)) return ReplayApplyDiskFileInfo(x, CoreTiming::GetGlobalTimeUs()); fullName = GetLocalPath(filename); - if (! File::Exists(fullName)) + if (!File::GetFileInfo(fullName, &info)) return ReplayApplyDiskFileInfo(x, CoreTiming::GetGlobalTimeUs()); #else return ReplayApplyDiskFileInfo(x, CoreTiming::GetGlobalTimeUs()); #endif } - // TODO: Consolidate to just a File::GetFileInfo call. - - x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; + x.type = info.isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; x.exists = true; if (x.type != FILETYPE_DIRECTORY) { - File::FileInfo info; - if (!File::GetFileInfo(fullName, &info)) { - ERROR_LOG(FILESYS, "DirectoryFileSystem::GetFileInfo: GetFileInfo failed: %s", fullName.c_str()); - } else { - x.size = info.size; - x.access = info.access; - time_t atime = info.atime; - time_t ctime = info.ctime; - time_t mtime = info.mtime; - - localtime_r((time_t*)&atime, &x.atime); - localtime_r((time_t*)&ctime, &x.ctime); - localtime_r((time_t*)&mtime, &x.mtime); - } + x.size = info.size; + x.access = info.access; + time_t atime = info.atime; + time_t ctime = info.ctime; + time_t mtime = info.mtime; + + localtime_r((time_t*)&atime, &x.atime); + localtime_r((time_t*)&ctime, &x.ctime); + localtime_r((time_t*)&mtime, &x.mtime); } return ReplayApplyDiskFileInfo(x, CoreTiming::GetGlobalTimeUs()); @@ -795,25 +789,28 @@ bool DirectoryFileSystem::ComputeRecursiveDirSizeIfFast(const std::string &path, } } -std::vector DirectoryFileSystem::GetDirListing(std::string path) { +std::vector DirectoryFileSystem::GetDirListing(const std::string &path, bool *exists) { std::vector myVector; std::vector files; Path localPath = GetLocalPath(path); const int flags = File::GETFILES_GETHIDDEN | File::GETFILES_GET_NAVIGATION_ENTRIES; - if (!File::GetFilesInDir(localPath, &files, nullptr, flags)) { - // TODO: Case sensitivity should be checked on a file system basis, right? + bool success = File::GetFilesInDir(localPath, &files, nullptr, flags); #if HOST_IS_CASE_SENSITIVE - if (FixPathCase(basePath, path, FPC_FILE_MUST_EXIST)) { + if (!success) { + // TODO: Case sensitivity should be checked on a file system basis, right? + std::string fixedPath = path; + if (FixPathCase(basePath, fixedPath, FPC_FILE_MUST_EXIST)) { // May have failed due to case sensitivity, try again - localPath = GetLocalPath(path); - if (!File::GetFilesInDir(localPath, &files, nullptr, 0)) { - return ReplayApplyDiskListing(myVector, CoreTiming::GetGlobalTimeUs()); - } + localPath = GetLocalPath(fixedPath); + success = File::GetFilesInDir(localPath, &files, nullptr, flags); } -#else - return ReplayApplyDiskListing(myVector, CoreTiming::GetGlobalTimeUs()); + } #endif + if (!success) { + if (exists) + *exists = false; + return ReplayApplyDiskListing(myVector, CoreTiming::GetGlobalTimeUs()); } bool hideISOFiles = PSP_CoreParameter().compat.flags().HideISOFiles; @@ -841,6 +838,7 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { entry.type = FILETYPE_NORMAL; } entry.access = file.access; + entry.exists = file.exists; localtime_r((time_t*)&file.atime, &entry.atime); localtime_r((time_t*)&file.ctime, &entry.ctime); @@ -849,6 +847,8 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { myVector.push_back(entry); } + if (exists) + *exists = true; return ReplayApplyDiskListing(myVector, CoreTiming::GetGlobalTimeUs()); } @@ -1079,9 +1079,11 @@ size_t VFSFileSystem::SeekFile(u32 handle, s32 position, FileMove type) { } } -std::vector VFSFileSystem::GetDirListing(std::string path) { +std::vector VFSFileSystem::GetDirListing(const std::string &path, bool *exists) { std::vector myVector; // TODO + if (exists) + *exists = false; return myVector; } diff --git a/Core/FileSystems/DirectoryFileSystem.h b/Core/FileSystems/DirectoryFileSystem.h index 779325ed65b2..5edfa9a1a34c 100644 --- a/Core/FileSystems/DirectoryFileSystem.h +++ b/Core/FileSystems/DirectoryFileSystem.h @@ -65,7 +65,7 @@ class DirectoryFileSystem : public IFileSystem { void CloseAll(); void DoState(PointerWrap &p) override; - std::vector GetDirListing(std::string path) override; + std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override; int OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override; void CloseFile(u32 handle) override; size_t ReadFile(u32 handle, u8 *pointer, s64 size) override; @@ -111,7 +111,7 @@ class VFSFileSystem : public IFileSystem { ~VFSFileSystem(); void DoState(PointerWrap &p) override; - std::vector GetDirListing(std::string path) override; + std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override; int OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override; void CloseFile(u32 handle) override; size_t ReadFile(u32 handle, u8 *pointer, s64 size) override; diff --git a/Core/FileSystems/FileSystem.h b/Core/FileSystems/FileSystem.h index 87c87ae5693a..350b97cd8f9d 100644 --- a/Core/FileSystems/FileSystem.h +++ b/Core/FileSystems/FileSystem.h @@ -118,7 +118,7 @@ class IFileSystem { virtual ~IFileSystem() {} virtual void DoState(PointerWrap &p) = 0; - virtual std::vector GetDirListing(std::string path) = 0; + virtual std::vector GetDirListing(const std::string &path, bool *exists = nullptr) = 0; virtual int OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) = 0; virtual void CloseFile(u32 handle) = 0; virtual size_t ReadFile(u32 handle, u8 *pointer, s64 size) = 0; @@ -143,7 +143,12 @@ class IFileSystem { class EmptyFileSystem : public IFileSystem { public: virtual void DoState(PointerWrap &p) override {} - std::vector GetDirListing(std::string path) override {std::vector vec; return vec;} + std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override { + if (exists) + *exists = false; + std::vector vec; + return vec; + } int OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override {return SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND;} void CloseFile(u32 handle) override {} size_t ReadFile(u32 handle, u8 *pointer, s64 size) override {return 0;} diff --git a/Core/FileSystems/ISOFileSystem.cpp b/Core/FileSystems/ISOFileSystem.cpp index 0d57bf284849..f52bc947c250 100644 --- a/Core/FileSystems/ISOFileSystem.cpp +++ b/Core/FileSystems/ISOFileSystem.cpp @@ -631,11 +631,14 @@ PSPFileInfo ISOFileSystem::GetFileInfo(std::string filename) { return x; } -std::vector ISOFileSystem::GetDirListing(std::string path) { +std::vector ISOFileSystem::GetDirListing(const std::string &path, bool *exists) { std::vector myVector; TreeEntry *entry = GetFromPath(path); - if (!entry) + if (!entry) { + if (exists) + *exists = false; return myVector; + } const std::string dot("."); const std::string dotdot(".."); @@ -651,6 +654,7 @@ std::vector ISOFileSystem::GetDirListing(std::string path) { x.name = e->name; // Strangely, it seems to be executable even for files. x.access = 0555; + x.exists = true; x.size = e->size; x.type = e->isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; x.isOnSectorSystem = true; @@ -659,6 +663,8 @@ std::vector ISOFileSystem::GetDirListing(std::string path) { x.numSectors = (u32)((e->size + sectorSize - 1) / sectorSize); myVector.push_back(x); } + if (exists) + *exists = true; return myVector; } diff --git a/Core/FileSystems/ISOFileSystem.h b/Core/FileSystems/ISOFileSystem.h index 608fa444e022..c7813bf1ac43 100644 --- a/Core/FileSystems/ISOFileSystem.h +++ b/Core/FileSystems/ISOFileSystem.h @@ -33,7 +33,7 @@ class ISOFileSystem : public IFileSystem { ~ISOFileSystem(); void DoState(PointerWrap &p) override; - std::vector GetDirListing(std::string path) override; + std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override; int OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override; void CloseFile(u32 handle) override; size_t ReadFile(u32 handle, u8 *pointer, s64 size) override; @@ -110,7 +110,11 @@ class ISOBlockSystem : public IFileSystem { isoFileSystem_->DoState(p); } - std::vector GetDirListing(std::string path) override { return std::vector(); } + std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override { + if (exists) + *exists = true; + return std::vector(); + } int OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override { return isoFileSystem_->OpenFile("", access, devicename); } diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 4ac716aa5701..49ddcc892b9d 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -369,19 +369,17 @@ PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename) } } -std::vector MetaFileSystem::GetDirListing(std::string path) -{ +std::vector MetaFileSystem::GetDirListing(const std::string &path, bool *exists) { std::lock_guard guard(lock); std::string of; IFileSystem *system; int error = MapFilePath(path, of, &system); - if (error == 0) - { - return system->GetDirListing(of); - } - else - { + if (error == 0) { + return system->GetDirListing(of, exists); + } else { std::vector empty; + if (exists) + *exists = false; return empty; } } @@ -593,7 +591,7 @@ int MetaFileSystem::ReadEntireFile(const std::string &filename, std::vector SeekFile(handle, 0, FILEMOVE_BEGIN); data.resize(dataSize); - size_t result = ReadFile(handle, (u8 *)&data[0], dataSize); + size_t result = ReadFile(handle, data.data(), dataSize); CloseFile(handle); if (result != dataSize) diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index 9a3b041c9362..545f21bddcde 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -103,7 +103,7 @@ class MetaFileSystem : public IHandleAllocator, public IFileSystem { std::string NormalizePrefix(std::string prefix) const; - std::vector GetDirListing(std::string path) override; + std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override; int OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override; void CloseFile(u32 handle) override; size_t ReadFile(u32 handle, u8 *pointer, s64 size) override; diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp index 9a9e0f8c8b0c..dbe130f30c08 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.cpp +++ b/Core/FileSystems/VirtualDiscFileSystem.cpp @@ -661,8 +661,7 @@ static void tmFromFiletime(tm &dest, FILETIME &src) } #endif -std::vector VirtualDiscFileSystem::GetDirListing(std::string path) -{ +std::vector VirtualDiscFileSystem::GetDirListing(const std::string &path, bool *exists) { std::vector myVector; // TODO(scoped): Switch this over to GetFilesInDir! @@ -681,9 +680,14 @@ std::vector VirtualDiscFileSystem::GetDirListing(std::string path) hFind = FindFirstFileEx(w32path.c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, 0); #endif if (hFind == INVALID_HANDLE_VALUE) { + if (exists) + *exists = false; return myVector; //the empty list } + if (exists) + *exists = true; + for (BOOL retval = 1; retval; retval = FindNextFile(hFind, &findData)) { if (!wcscmp(findData.cFileName, L"..") || !wcscmp(findData.cFileName, L".")) { continue; @@ -697,6 +701,7 @@ std::vector VirtualDiscFileSystem::GetDirListing(std::string path) } entry.access = 0555; + entry.exists = true; entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32); entry.name = ConvertWStringToUTF8(findData.cFileName); tmFromFiletime(entry.atime, findData.ftLastAccessTime); @@ -717,18 +722,24 @@ std::vector VirtualDiscFileSystem::GetDirListing(std::string path) DIR *dp = opendir(localPath.c_str()); #if HOST_IS_CASE_SENSITIVE - if(dp == NULL && FixPathCase(basePath, path, FPC_FILE_MUST_EXIST)) { + std::string fixedPath = path; + if(dp == NULL && FixPathCase(basePath, fixedPath, FPC_FILE_MUST_EXIST)) { // May have failed due to case sensitivity, try again - localPath = GetLocalPath(path); + localPath = GetLocalPath(fixedPath); dp = opendir(localPath.c_str()); } #endif if (dp == NULL) { ERROR_LOG(FILESYS,"Error opening directory %s\n", path.c_str()); + if (exists) + *exists = false; return myVector; } + if (exists) + *exists = true; + while ((dirp = readdir(dp)) != NULL) { if (!strcmp(dirp->d_name, "..") || !strcmp(dirp->d_name, ".")) { continue; @@ -736,13 +747,14 @@ std::vector VirtualDiscFileSystem::GetDirListing(std::string path) PSPFileInfo entry; struct stat s; - std::string fullName = (GetLocalPath(path) / std::string(dirp->d_name)).ToString(); + std::string fullName = (localPath / std::string(dirp->d_name)).ToString(); stat(fullName.c_str(), &s); if (S_ISDIR(s.st_mode)) entry.type = FILETYPE_DIRECTORY; else entry.type = FILETYPE_NORMAL; entry.access = 0555; + entry.exists = true; entry.name = dirp->d_name; entry.size = s.st_size; localtime_r((time_t*)&s.st_atime,&entry.atime); diff --git a/Core/FileSystems/VirtualDiscFileSystem.h b/Core/FileSystems/VirtualDiscFileSystem.h index 0c1b6db87279..1af7b5d84213 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.h +++ b/Core/FileSystems/VirtualDiscFileSystem.h @@ -40,7 +40,7 @@ class VirtualDiscFileSystem: public IFileSystem { bool OwnsHandle(u32 handle) override; int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override; PSPDevType DevType(u32 handle) override; - std::vector GetDirListing(std::string path) override; + std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override; FileSystemFlags Flags() override { return FileSystemFlags::UMD; } u64 FreeSpace(const std::string &path) override { return 0; } diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index d55ce61514d5..f819b3a2c75e 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -858,22 +858,21 @@ static void __LoadInternalFonts() { } const std::string fontPath = "flash0:/font/"; const std::string fontOverridePath = "ms0:/PSP/flash0/font/"; - const std::string userfontPath = "disc0:/PSP_GAME/USRDIR/"; - + const std::string gameFontPath = "disc0:/PSP_GAME/USRDIR/"; + if (!pspFileSystem.GetFileInfo(fontPath).exists) { pspFileSystem.MkDir(fontPath); } if ((pspFileSystem.GetFileInfo("disc0:/PSP_GAME/USRDIR/zh_gb.pgf").exists) && (pspFileSystem.GetFileInfo("disc0:/PSP_GAME/USRDIR/oldfont.prx").exists)) { for (size_t i = 0; i < ARRAY_SIZE(fontRegistry); i++) { const FontRegistryEntry &entry = fontRegistry[i]; - std::string fontFilename = userfontPath + entry.fileName; - PSPFileInfo info = pspFileSystem.GetFileInfo(fontFilename); - DEBUG_LOG(SCEFONT, "Loading internal font %s (%i bytes)", fontFilename.c_str(), (int)info.size); + std::string fontFilename = gameFontPath + entry.fileName; std::vector buffer; if (pspFileSystem.ReadEntireFile(fontFilename, buffer) < 0) { - ERROR_LOG(SCEFONT, "Failed opening font"); + ERROR_LOG(SCEFONT, "Failed opening font %s", fontFilename.c_str()); continue; } + DEBUG_LOG(SCEFONT, "Loading internal font %s (%i bytes)", fontFilename.c_str(), (int)buffer.size()); internalFonts.push_back(new Font(buffer, entry)); DEBUG_LOG(SCEFONT, "Loaded font %s", fontFilename.c_str()); return; @@ -882,29 +881,26 @@ static void __LoadInternalFonts() { for (size_t i = 0; i < ARRAY_SIZE(fontRegistry); i++) { const FontRegistryEntry &entry = fontRegistry[i]; - std::string fontFilename = userfontPath + entry.fileName; - PSPFileInfo info = pspFileSystem.GetFileInfo(fontFilename); + std::vector buffer; + bool bufferRead = false; - if (!info.exists) { - // No user font, let's try override path. + std::string fontFilename = gameFontPath + entry.fileName; + bufferRead = pspFileSystem.ReadEntireFile(fontFilename, buffer) >= 0; + + if (!bufferRead) { + // No game font, let's try override path. fontFilename = fontOverridePath + entry.fileName; - info = pspFileSystem.GetFileInfo(fontFilename); + bufferRead = pspFileSystem.ReadEntireFile(fontFilename, buffer) >= 0; } - if (!info.exists) { + if (!bufferRead) { // No override, let's use the default path. fontFilename = fontPath + entry.fileName; - info = pspFileSystem.GetFileInfo(fontFilename); + bufferRead = pspFileSystem.ReadEntireFile(fontFilename, buffer) >= 0; } - if (info.exists) { - DEBUG_LOG(SCEFONT, "Loading internal font %s (%i bytes)", fontFilename.c_str(), (int)info.size); - std::vector buffer; - if (pspFileSystem.ReadEntireFile(fontFilename, buffer) < 0) { - ERROR_LOG(SCEFONT, "Failed opening font"); - continue; - } - + if (bufferRead) { + DEBUG_LOG(SCEFONT, "Loading internal font %s (%i bytes)", fontFilename.c_str(), (int)buffer.size()); internalFonts.push_back(new Font(buffer, entry)); DEBUG_LOG(SCEFONT, "Loaded font %s", fontFilename.c_str()); diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 9e161828a869..f4c98dfb6b1f 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -230,6 +230,17 @@ class FileNode : public KernelObject { return pendingAsyncResult || hasAsyncResult; } + const PSPFileInfo &FileInfo() { + if (!infoReady) { + info = pspFileSystem.GetFileInfo(fullpath); + if (!info.exists) { + ERROR_LOG(IO, "File %s no longer exists when reading info", fullpath.c_str()); + } + infoReady = true; + } + return info; + } + void DoState(PointerWrap &p) override { auto s = p.Section("FileNode", 1, 3); if (!s) @@ -246,6 +257,9 @@ class FileNode : public KernelObject { Do(p, closePending); Do(p, info); Do(p, openMode); + if (p.mode == p.MODE_READ) { + infoReady = info.exists; + } Do(p, npdrm); Do(p, pgd_offset); @@ -285,6 +299,7 @@ class FileNode : public KernelObject { // TODO: Use an enum instead? bool closePending = false; + bool infoReady = false; PSPFileInfo info; u32 openMode = 0; @@ -1356,7 +1371,7 @@ static s64 __IoLseekDest(FileNode *f, s64 offset, int whence, FileMove &seek) { seek = FILEMOVE_CURRENT; break; case 2: - newPos = f->info.size + offset; + newPos = f->FileInfo().size + offset; seek = FILEMOVE_END; break; default: @@ -1489,8 +1504,6 @@ static FileNode *__IoOpen(int &error, const char *filename, int flags, int mode) isTTY = true; } else { - info = pspFileSystem.GetFileInfo(filename); - h = pspFileSystem.OpenFile(filename, (FileAccess)access); if (h < 0) { error = h; @@ -1504,7 +1517,10 @@ static FileNode *__IoOpen(int &error, const char *filename, int flags, int mode) f->handle = h; f->fullpath = filename; f->asyncResult = h; - f->info = info; + if (isTTY) { + f->info = info; + f->infoReady = true; + } f->openMode = access; f->isTTY = isTTY; @@ -2320,16 +2336,19 @@ class DirListing : public KernelObject { static u32 sceIoDopen(const char *path) { DEBUG_LOG(SCEIO, "sceIoDopen(\"%s\")", path); - if (!pspFileSystem.GetFileInfo(path).exists) { + double startTime = time_now_d(); + + bool listingExists = false; + auto listing = pspFileSystem.GetDirListing(path, &listingExists); + + if (!listingExists) { return SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; } DirListing *dir = new DirListing(); SceUID id = kernelObjects.Create(dir); - double startTime = time_now_d(); - - dir->listing = pspFileSystem.GetDirListing(path); + dir->listing = listing; dir->index = 0; dir->name = std::string(path); @@ -2528,7 +2547,7 @@ static int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, if(f->pgdInfo) return f->pgdInfo->data_size; else - return (int)f->info.size; + return (int)f->FileInfo().size; break; // Get UMD sector size @@ -2571,7 +2590,7 @@ static int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, const auto seekInfo = PSPPointer::Create(indataPtr); FileMove seek; s64 newPos = __IoLseekDest(f, seekInfo->offset, seekInfo->whence, seek); - if (newPos < 0 || newPos > f->info.size) { + if (newPos < 0 || newPos > f->FileInfo().size) { // Not allowed to seek past the end of the file with this API. return ERROR_ERRNO_IO_ERROR; } @@ -2587,7 +2606,7 @@ static int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. INFO_LOG(SCEIO, "sceIoIoctl: Asked for start sector of file %i", id); if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { - Memory::Write_U32(f->info.startSector, outdataPtr); + Memory::Write_U32(f->FileInfo().startSector, outdataPtr); } else { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } @@ -2599,7 +2618,7 @@ static int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. INFO_LOG(SCEIO, "sceIoIoctl: Asked for size of file %i", id); if (Memory::IsValidAddress(outdataPtr) && outlen >= 8) { - Memory::Write_U64(f->info.size, outdataPtr); + Memory::Write_U64(f->FileInfo().size, outdataPtr); } else { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } @@ -2676,7 +2695,7 @@ static int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, FileMove seek; s64 newPos = __IoLseekDest(f, seekInfo->offset, seekInfo->whence, seek); // Position is in sectors, don't forget. - if (newPos < 0 || newPos > f->info.size) { + if (newPos < 0 || newPos > f->FileInfo().size) { // Not allowed to seek past the end of the file with this API. return SCE_KERNEL_ERROR_ERRNO_INVALID_FILE_SIZE; } diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 4f3d5866724d..db190c45f713 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -1634,16 +1634,9 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load } SceUID KernelLoadModule(const std::string &filename, std::string *error_string) { - PSPFileInfo info = pspFileSystem.GetFileInfo(filename); - if (!info.exists) - return SCE_KERNEL_ERROR_NOFILE; - std::vector buffer; - buffer.resize((size_t)info.size); - - u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ); - pspFileSystem.ReadFile(handle, &buffer[0], info.size); - pspFileSystem.CloseFile(handle); + if (pspFileSystem.ReadEntireFile(filename, buffer) < 0) + return SCE_KERNEL_ERROR_NOFILE; u32 error = SCE_KERNEL_ERROR_ILLEGAL_OBJECT; u32 magic; @@ -1796,8 +1789,8 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str __KernelLoadReset(); - PSPFileInfo info = pspFileSystem.GetFileInfo(filename); - if (!info.exists) { + std::vector fileData; + if (pspFileSystem.ReadEntireFile(filename, fileData) < 0) { ERROR_LOG(LOADER, "Failed to load executable %s - file doesn't exist", filename); *error_string = StringFromFormat("Could not find executable %s", filename); delete[] param_argp; @@ -1806,14 +1799,11 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str return false; } - u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ); - - u8 *temp = new u8[(int)info.size + 0x01000000]; - - pspFileSystem.ReadFile(handle, temp, (size_t)info.size); - PSP_SetLoading("Loading modules..."); - PSPModule *module = __KernelLoadModule(temp, (size_t)info.size, 0, error_string); + size_t size = fileData.size(); + // TODO: Why do we add this padding? Crash avoidance? + fileData.resize(fileData.size() + 0x01000000); + PSPModule *module = __KernelLoadModule(fileData.data(), size, 0, error_string); if (!module || module->isFake) { if (module) { @@ -1822,7 +1812,6 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str } ERROR_LOG(LOADER, "Failed to load module %s", filename); *error_string = "Failed to load executable: " + *error_string; - delete [] temp; delete[] param_argp; delete[] param_key; return false; @@ -1834,10 +1823,6 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str INFO_LOG(LOADER, "Module entry: %08x", mipsr4k.pc); - delete [] temp; - - pspFileSystem.CloseFile(handle); - SceKernelSMOption option; option.size = sizeof(SceKernelSMOption); option.attribute = PSP_THREAD_ATTR_USER; @@ -2007,15 +1992,12 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { } } - PSPFileInfo info = pspFileSystem.GetFileInfo(name); - s64 size = (s64)info.size; - - if (!info.exists) { + std::vector fileData; + if (pspFileSystem.ReadEntireFile(name, fileData) < 0) { const u32 error = hleLogError(LOADER, SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND, "file does not exist"); return hleDelayResult(error, "module loaded", 500); } - - if (!size) { + if (fileData.empty()) { const u32 error = hleLogError(LOADER, SCE_KERNEL_ERROR_FILEERR, "module file size is 0"); return hleDelayResult(error, "module loaded", 500); } @@ -2045,15 +2027,10 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { } PSPModule *module = nullptr; - u8 *temp = new u8[(int)size]; - u32 handle = pspFileSystem.OpenFile(name, FILEACCESS_READ); - pspFileSystem.ReadFile(handle, temp, (size_t)size); u32 magic; u32 error; std::string error_string; - module = __KernelLoadELFFromPtr(temp, (size_t)size, 0, lmoption ? lmoption->position == PSP_SMEM_High : false, &error_string, &magic, error); - delete [] temp; - pspFileSystem.CloseFile(handle); + module = __KernelLoadELFFromPtr(fileData.data(), fileData.size(), 0, lmoption ? lmoption->position == PSP_SMEM_High : false, &error_string, &magic, error); if (!module) { if (magic == 0x46535000) { @@ -2063,6 +2040,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { return hleDelayResult(error, "module loaded", 500); } + PSPFileInfo info = pspFileSystem.GetFileInfo(name); if (info.name == "BOOT.BIN") { NOTICE_LOG_REPORT(LOADER, "Module %s is blacklisted or undecryptable - we try __KernelLoadExec", name); // Name might get deleted. diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index 13fd62a22fb0..d7559c0fa129 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -1256,11 +1256,11 @@ void PPGeDisableTexture() std::vector PPGeImage::loadedTextures_; PPGeImage::PPGeImage(const std::string &pspFilename) - : filename_(pspFilename), texture_(0) { + : filename_(pspFilename) { } PPGeImage::PPGeImage(u32 pngPointer, size_t pngSize) - : filename_(""), png_(pngPointer), size_(pngSize), texture_(0) { + : filename_(""), png_(pngPointer), size_(pngSize) { } PPGeImage::~PPGeImage() { @@ -1268,6 +1268,7 @@ PPGeImage::~PPGeImage() { } bool PPGeImage::Load() { + loadFailed_ = false; Free(); // In case it fails to load. @@ -1281,7 +1282,8 @@ bool PPGeImage::Load() { } else { std::vector pngData; if (pspFileSystem.ReadEntireFile(filename_, pngData) < 0) { - WARN_LOG(SCEGE, "Bad PPGeImage - cannot load file"); + WARN_LOG(SCEGE, "PPGeImage cannot load file %s", filename_.c_str()); + loadFailed_ = true; return false; } @@ -1289,6 +1291,7 @@ bool PPGeImage::Load() { } if (!success) { WARN_LOG(SCEGE, "Bad PPGeImage - not a valid png"); + loadFailed_ = true; return false; } @@ -1298,6 +1301,7 @@ bool PPGeImage::Load() { if (texture_ == 0) { free(textureData); WARN_LOG(SCEGE, "Bad PPGeImage - unable to allocate space for texture"); + // Don't set loadFailed_ here, we'll try again if there's more memory later. return false; } @@ -1310,16 +1314,28 @@ bool PPGeImage::Load() { return true; } +bool PPGeImage::IsValid() { + if (loadFailed_) + return false; + + if (texture_ == 0) { + Decimate(); + return Load(); + } + return true; +} + void PPGeImage::Free() { if (texture_ != 0) { kernelMemory.Free(texture_); texture_ = 0; loadedTextures_.erase(std::remove(loadedTextures_.begin(), loadedTextures_.end(), this), loadedTextures_.end()); + loadFailed_ = false; } } void PPGeImage::DoState(PointerWrap &p) { - auto s = p.Section("PPGeImage", 1); + auto s = p.Section("PPGeImage", 1, 2); if (!s) return; @@ -1330,6 +1346,11 @@ void PPGeImage::DoState(PointerWrap &p) { Do(p, width_); Do(p, height_); Do(p, lastFrame_); + if (s >= 2) { + Do(p, loadFailed_); + } else { + loadFailed_ = false; + } } void PPGeImage::CompatLoad(u32 texture, int width, int height) { @@ -1337,6 +1358,7 @@ void PPGeImage::CompatLoad(u32 texture, int width, int height) { texture_ = texture; width_ = width; height_ = height; + loadFailed_ = false; } void PPGeImage::Decimate(int age) { @@ -1351,7 +1373,7 @@ void PPGeImage::Decimate(int age) { } void PPGeImage::SetTexture() { - if (texture_ == 0) { + if (texture_ == 0 && !loadFailed_) { Decimate(); Load(); } diff --git a/Core/Util/PPGeDraw.h b/Core/Util/PPGeDraw.h index 409b56564bf8..ee02acb8cc6a 100644 --- a/Core/Util/PPGeDraw.h +++ b/Core/Util/PPGeDraw.h @@ -122,6 +122,7 @@ class PPGeImage { // Does not normally need to be called (except to force preloading.) bool Load(); void Free(); + bool IsValid(); void DoState(PointerWrap &p); @@ -147,11 +148,12 @@ class PPGeImage { u32 png_; size_t size_; - u32 texture_; + u32 texture_ = 0; int width_; int height_; int lastFrame_; + bool loadFailed_ = false; }; void PPGeDrawRect(float x1, float y1, float x2, float y2, u32 color); diff --git a/android/src/org/ppsspp/ppsspp/PpssppActivity.java b/android/src/org/ppsspp/ppsspp/PpssppActivity.java index 3142995042b9..aa383a1568a0 100644 --- a/android/src/org/ppsspp/ppsspp/PpssppActivity.java +++ b/android/src/org/ppsspp/ppsspp/PpssppActivity.java @@ -273,15 +273,13 @@ public String[] listContentUriDir(String uriString) { // Is ArrayList weird or what? String[] strings = new String[listing.size()]; return listing.toArray(strings); - } - catch (IllegalArgumentException e) { + } catch (IllegalArgumentException e) { // Due to sloppy exception handling in resolver.query, we get this wrapping // a FileNotFoundException if the directory doesn't exist. - return new String[]{}; - } - catch (Exception e) { + return new String[]{ "X" }; + } catch (Exception e) { Log.e(TAG, "listContentUriDir exception: " + e.toString()); - return new String[]{}; + return new String[]{ "X" }; } finally { if (c != null) { c.close();