diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index b9eea87b95..9aa2b2b47f 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -218,7 +218,7 @@ std::string fmt::merge(std::vector source, const std::string& separ result += source[i] + separator; } - return result + source[source.size() - 1]; + return result + source.back(); } std::string fmt::merge(std::initializer_list> sources, const std::string& separator) diff --git a/Utilities/rFile.cpp b/Utilities/rFile.cpp index 706dae3750..bf018601ab 100644 --- a/Utilities/rFile.cpp +++ b/Utilities/rFile.cpp @@ -155,7 +155,7 @@ bool rMkpath(const std::string& path) bool rRmdir(const std::string& dir) { #ifdef _WIN32 - if (!RemoveDirectory(ConvertUTF8ToWChar(dir).get())) + if (!RemoveDirectoryW(ConvertUTF8ToWChar(dir).get())) #else if (rmdir(dir.c_str())) #endif @@ -171,7 +171,7 @@ bool rRename(const std::string& from, const std::string& to) { // TODO: Deal with case-sensitivity #ifdef _WIN32 - if (!MoveFile(ConvertUTF8ToWChar(from).get(), ConvertUTF8ToWChar(to).get())) + if (!MoveFileW(ConvertUTF8ToWChar(from).get(), ConvertUTF8ToWChar(to).get())) #else if (rename(from.c_str(), to.c_str())) #endif @@ -222,7 +222,7 @@ int OSCopyFile(const char* source, const char* destination, bool overwrite) bool rCopy(const std::string& from, const std::string& to, bool overwrite) { #ifdef _WIN32 - if (!CopyFile(ConvertUTF8ToWChar(from).get(), ConvertUTF8ToWChar(to).get(), !overwrite)) + if (!CopyFileW(ConvertUTF8ToWChar(from).get(), ConvertUTF8ToWChar(to).get(), !overwrite)) #else if (OSCopyFile(from.c_str(), to.c_str(), overwrite)) #endif @@ -237,7 +237,7 @@ bool rCopy(const std::string& from, const std::string& to, bool overwrite) bool rExists(const std::string& file) { #ifdef _WIN32 - return GetFileAttributes(ConvertUTF8ToWChar(file).get()) != 0xFFFFFFFF; + return GetFileAttributesW(ConvertUTF8ToWChar(file).get()) != 0xFFFFFFFF; #else struct stat buffer; return stat(file.c_str(), &buffer) == 0; @@ -247,7 +247,7 @@ bool rExists(const std::string& file) bool rRemoveFile(const std::string& file) { #ifdef _WIN32 - if (!DeleteFile(ConvertUTF8ToWChar(file).get())) + if (!DeleteFileW(ConvertUTF8ToWChar(file).get())) #else if (unlink(file.c_str())) #endif diff --git a/rpcs3/Emu/FS/VFS.h b/rpcs3/Emu/FS/VFS.h index 4970af6bdb..99ea1825e9 100644 --- a/rpcs3/Emu/FS/VFS.h +++ b/rpcs3/Emu/FS/VFS.h @@ -46,6 +46,9 @@ struct VFSManagerEntry std::vector simplify_path_blocks(const std::string& path); std::string simplify_path(const std::string& path, bool is_dir, bool is_ps3); +#undef CreateFile +#undef CopyFile + struct VFS { ~VFS(); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 93e326ae48..2a9254f430 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -835,6 +835,11 @@ s32 cellDmuxOpenEx(vm::ptr type, vm::ptr type, vm::ptr resEx, vm::ptr cb, vm::ptr handle) +{ + return cellDmuxOpenEx(type, resEx, cb, handle); +} + s32 cellDmuxOpen2(vm::ptr type2, vm::ptr res2, vm::ptr cb, vm::ptr handle) { cellDmux.Warning("cellDmuxOpen2(type2=*0x%x, res2=*0x%x, cb=*0x%x, handle=*0x%x)", type2, res2, cb, handle); @@ -1190,6 +1195,7 @@ Module cellDmux("cellDmux", []() REG_FUNC(cellDmux, cellDmuxQueryAttr2); REG_FUNC(cellDmux, cellDmuxOpen); REG_FUNC(cellDmux, cellDmuxOpenEx); + REG_UNNAMED(cellDmux, e075fabc); REG_FUNC(cellDmux, cellDmuxOpen2); REG_FUNC(cellDmux, cellDmuxClose); REG_FUNC(cellDmux, cellDmuxSetStream); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp index 85c7cab81d..18ff13b582 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp @@ -7,17 +7,10 @@ #include "Emu/FS/VFS.h" #include "Emu/FS/vfsFile.h" #include "Emu/FS/vfsDir.h" +#include "Utilities/rFile.h" #include "Loader/PSF.h" #include "cellSaveData.h" -#ifdef _WIN32 -#include -#undef CreateFile -#else -#include -#include -#endif - extern Module cellSysutil; std::unique_ptr g_savedata_dialog; @@ -71,214 +64,6 @@ public: } }; -// Auxiliary Functions -void addNewSaveDataEntry(std::vector& saveEntries, vm::ptr newData) -{ - SaveDataEntry saveEntry; - saveEntry.dirName = newData->dirName.get_ptr(); - saveEntry.title = newData->icon->title.get_ptr(); - saveEntry.subtitle = newData->icon->title.get_ptr(); - //saveEntry.iconBuf = newData->icon->iconBuf.get_ptr(); - //saveEntry.iconBufSize = newData->icon->iconBufSize; - saveEntry.isNew = true; - // TODO: Add information stored in newData->iconPosition. (It's not very relevant) - - saveEntries.push_back(saveEntry); -} - -u32 focusSaveDataEntry(const std::vector& saveEntries, u32 focusPosition) -{ - // TODO: Get the correct index. Right now, this returns the first element of the list. - return 0; -} - -void setSaveDataList(std::vector& saveEntries, vm::ptr fixedList, u32 fixedListNum) -{ - std::vector::iterator entry = saveEntries.begin(); - while (entry != saveEntries.end()) - { - bool found = false; - for (u32 j = 0; j < fixedListNum; j++) - { - if (entry->dirName == (char*)fixedList[j].dirName) - { - found = true; - break; - } - } - if (!found) - entry = saveEntries.erase(entry); - else - entry++; - } -} - -void setSaveDataFixed(std::vector& saveEntries, vm::ptr fixedSet) -{ - std::vector::iterator entry = saveEntries.begin(); - while (entry != saveEntries.end()) - { - if (entry->dirName == fixedSet->dirName.get_ptr()) - entry = saveEntries.erase(entry); - else - entry++; - } - - if (saveEntries.size() == 0) - { - SaveDataEntry entry; - entry.dirName = fixedSet->dirName.get_ptr(); - entry.isNew = true; - saveEntries.push_back(entry); - } - - if (fixedSet->newIcon) - { - //saveEntries[0].iconBuf = fixedSet->newIcon->iconBuf.get_ptr(); - //saveEntries[0].iconBufSize = fixedSet->newIcon->iconBufSize; - saveEntries[0].title = fixedSet->newIcon->title.get_ptr(); - saveEntries[0].subtitle = fixedSet->newIcon->title.get_ptr(); - } -} - -void getSaveDataStat(SaveDataEntry entry, vm::ptr statGet) -{ - if (entry.isNew) - statGet->isNewData = CELL_SAVEDATA_ISNEWDATA_YES; - else - statGet->isNewData = CELL_SAVEDATA_ISNEWDATA_NO; - - statGet->bind = 0; // TODO ? - statGet->sizeKB = entry.size / 1024; - statGet->hddFreeSizeKB = 40000000; // 40 GB. TODO ? - statGet->sysSizeKB = 0; // TODO: This is the size of PARAM.SFO + PARAM.PDF - statGet->dir.st_atime_ = 0; // TODO ? - statGet->dir.st_mtime_ = 0; // TODO ? - statGet->dir.st_ctime_ = 0; // TODO ? - strcpy_trunc(statGet->dir.dirName, entry.dirName); - - statGet->getParam.attribute = 0; // TODO ? - strcpy_trunc(statGet->getParam.title, entry.title); - strcpy_trunc(statGet->getParam.subTitle, entry.subtitle); - strcpy_trunc(statGet->getParam.detail, entry.details); - strcpy_trunc(statGet->getParam.listParam, entry.listParam); - - statGet->fileNum = 0; - statGet->fileList.set(0); - statGet->fileListNum = 0; - std::string saveDir = "/dev_hdd0/home/00000001/savedata/" + entry.dirName; // TODO: Get the path of the current user - vfsDir dir(saveDir); - if (!dir.IsOpened()) - return; - - std::vector fileEntries; - for(const DirEntryInfo* dirEntry = dir.Read(); dirEntry; dirEntry = dir.Read()) { - if (dirEntry->flags & DirEntry_TypeFile) { - if (dirEntry->name == "PARAM.SFO" || dirEntry->name == "PARAM.PFD") - continue; - - statGet->fileNum++; - statGet->fileListNum++; - CellSaveDataFileStat fileEntry; - vfsFile file(saveDir + "/" + dirEntry->name); - - if (dirEntry->name == "ICON0.PNG") - fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0; - else if (dirEntry->name == "ICON1.PAM") - fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1; - else if (dirEntry->name == "PIC1.PNG") - fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1; - else if (dirEntry->name == "SND0.AT3") - fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0; - - fileEntry.st_size = file.GetSize(); - fileEntry.st_atime_ = 0; // TODO ? - fileEntry.st_mtime_ = 0; // TODO ? - fileEntry.st_ctime_ = 0; // TODO ? - strcpy_trunc(fileEntry.fileName, dirEntry->name); - - fileEntries.push_back(fileEntry); - } - } - - statGet->fileList.set((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * fileEntries.size(), 8)); - for (u32 i = 0; i < fileEntries.size(); i++) { - CellSaveDataFileStat *dst = &statGet->fileList[i]; - memcpy(dst, &fileEntries[i], sizeof(CellSaveDataFileStat)); - } -} - -s32 modifySaveDataFiles(vm::ptr funcFile, vm::ptr result, const std::string& saveDataDir) -{ - vm::var fileGet; - vm::var fileSet; - - if (!Emu.GetVFS().ExistsDir(saveDataDir)) - Emu.GetVFS().CreateDir(saveDataDir); - - fileGet->excSize = 0; - while (true) - { - funcFile(result, fileGet, fileSet); - if (result->result < 0) { - cellSysutil.Error("modifySaveDataFiles: CellSaveDataFileCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. - return CELL_SAVEDATA_ERROR_CBRESULT; - } - if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM) { - break; - } - - std::string filepath = saveDataDir + '/'; - vfsStream* file = NULL; - void* buf = fileSet->fileBuf.get_ptr(); - - switch ((u32)fileSet->fileType) - { - case CELL_SAVEDATA_FILETYPE_SECUREFILE: filepath += fileSet->fileName.get_ptr(); break; - case CELL_SAVEDATA_FILETYPE_NORMALFILE: filepath += fileSet->fileName.get_ptr(); break; - case CELL_SAVEDATA_FILETYPE_CONTENT_ICON0: filepath += "ICON0.PNG"; break; - case CELL_SAVEDATA_FILETYPE_CONTENT_ICON1: filepath += "ICON1.PAM"; break; - case CELL_SAVEDATA_FILETYPE_CONTENT_PIC1: filepath += "PIC1.PNG"; break; - case CELL_SAVEDATA_FILETYPE_CONTENT_SND0: filepath += "SND0.AT3"; break; - - default: - cellSysutil.Error("modifySaveDataFiles: Unknown fileType! Aborting..."); - return CELL_SAVEDATA_ERROR_PARAM; - } - - switch ((u32)fileSet->fileOperation) - { - case CELL_SAVEDATA_FILEOP_READ: - file = Emu.GetVFS().OpenFile(filepath, vfsRead); - fileGet->excSize = (u32)file->Read(buf, (u32)std::min(fileSet->fileSize, fileSet->fileBufSize)); // TODO: This may fail for big files because of the dest pointer. - break; - - case CELL_SAVEDATA_FILEOP_WRITE: - Emu.GetVFS().CreateFile(filepath); - file = Emu.GetVFS().OpenFile(filepath, vfsWrite); - fileGet->excSize = (u32)file->Write(buf, (u32)std::min(fileSet->fileSize, fileSet->fileBufSize)); // TODO: This may fail for big files because of the dest pointer. - break; - - case CELL_SAVEDATA_FILEOP_DELETE: - Emu.GetVFS().RemoveFile(filepath); - fileGet->excSize = 0; - break; - - case CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC: - cellSysutil.Todo("modifySaveDataFiles: CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC"); - break; - - default: - cellSysutil.Error("modifySaveDataFiles: Unknown fileOperation! Aborting..."); - return CELL_SAVEDATA_ERROR_PARAM; - } - - if (file && file->IsOpened()) - file->Close(); - } - return CELL_OK; -} - enum : u32 { SAVEDATA_OP_AUTO_SAVE = 0, @@ -321,20 +106,26 @@ __noinline s32 savedata_op( return CELL_SAVEDATA_ERROR_BUSY; } - static const std::string base_dir = "/dev_hdd0/home/00000001/savedata/"; // TODO: Get the path of the current or specified user + std::string base_dir = "/dev_hdd0/home/00000001/savedata/"; // TODO: Get the path of the current or specified user vm::stackvar result(CPU); vm::stackvar listGet(CPU); vm::stackvar listSet(CPU); + vm::stackvar fixedSet(CPU); vm::stackvar statGet(CPU); vm::stackvar statSet(CPU); + vm::stackvar fileGet(CPU); + vm::stackvar fileSet(CPU); + vm::stackvar doneGet(CPU); - result->userdata = userdata; + result->userdata = userdata; // probably should be assigned only once (allows the callback to change it) - std::vector save_entries; + SaveDataEntry save_entry; if (setList) { + std::vector save_entries; + listGet->dirNum = 0; listGet->dirListNum = 0; listGet->dirList.set(setBuf->buf.addr()); @@ -344,7 +135,7 @@ __noinline s32 savedata_op( for (const auto entry : vfsDir(base_dir)) { - if ((entry->flags & DirEntry_TypeMask) != DirEntry_TypeDir) + if (!(entry->flags & DirEntry_TypeDir)) { continue; } @@ -360,32 +151,34 @@ __noinline s32 savedata_op( // PSF parameters const PSFLoader psf(vfsFile(base_dir + entry->name + "/PARAM.SFO")); + if (!psf) { break; } - SaveDataEntry save_entry; - save_entry.dirName = psf.GetString("SAVEDATA_DIRECTORY"); - save_entry.listParam = psf.GetString("SAVEDATA_LIST_PARAM"); - save_entry.title = psf.GetString("TITLE"); - save_entry.subtitle = psf.GetString("SUB_TITLE"); - save_entry.details = psf.GetString("DETAIL"); + SaveDataEntry save_entry2; + save_entry2.dirName = psf.GetString("SAVEDATA_DIRECTORY"); + save_entry2.listParam = psf.GetString("SAVEDATA_LIST_PARAM"); + save_entry2.title = psf.GetString("TITLE"); + save_entry2.subtitle = psf.GetString("SUB_TITLE"); + save_entry2.details = psf.GetString("DETAIL"); - save_entry.atime = entry->access_time; - save_entry.mtime = entry->modify_time; - save_entry.ctime = entry->create_time; - //save_entry.iconBuf = NULL; // TODO: Here should be the PNG buffer - //save_entry.iconBufSize = 0; // TODO: Size of the PNG file - save_entry.isNew = false; + save_entry2.size = 0; - save_entry.size = 0; for (const auto entry2 : vfsDir(base_dir + entry->name)) { - save_entry.size += entry2->size; + save_entry2.size += entry2->size; } - save_entries.push_back(save_entry); + save_entry2.atime = entry->access_time; + save_entry2.mtime = entry->modify_time; + save_entry2.ctime = entry->create_time; + //save_entry2.iconBuf = NULL; // TODO: Here should be the PNG buffer + //save_entry2.iconBufSize = 0; // TODO: Size of the PNG file + save_entry2.isNew = false; + + save_entries.push_back(save_entry2); } break; @@ -407,42 +200,403 @@ __noinline s32 savedata_op( memset(dir.reserved, 0, sizeof(dir.reserved)); } - // Data List Callback - funcList(result, listGet, listSet); + s32 selected = -1; + + if (funcList) + { + // List Callback + funcList(CPU, result, listGet, listSet); + + if (result->result < 0) + { + return CELL_SAVEDATA_ERROR_CBRESULT; + } + + // Clean save data list + save_entries.erase(std::remove_if(save_entries.begin(), save_entries.end(), [&listSet](const SaveDataEntry& entry) -> bool + { + for (u32 i = 0; i < listSet->fixedListNum; i++) + { + if (entry.dirName == listSet->fixedList[i].dirName) + { + return false; + } + } + + return true; + }), save_entries.end()); + + // Focus save data + s32 focused = -1; + + switch (const u32 pos_type = listSet->focusPosition.value()) + { + case CELL_SAVEDATA_FOCUSPOS_DIRNAME: + { + for (s32 i = 0; i < save_entries.size(); i++) + { + if (save_entries[i].dirName == listSet->focusDirName.get_ptr()) + { + focused = i; + break; + } + } + + break; + } + case CELL_SAVEDATA_FOCUSPOS_LISTHEAD: + { + focused = save_entries.empty() ? -1 : 0; + break; + } + case CELL_SAVEDATA_FOCUSPOS_LISTTAIL: + { + focused = save_entries.size() - 1; + break; + } + case CELL_SAVEDATA_FOCUSPOS_LATEST: + { + s64 max = INT64_MIN; + + for (s32 i = 0; i < save_entries.size(); i++) + { + if (save_entries[i].mtime > max) + { + focused = i; + max = save_entries[i].mtime; + } + } + + break; + } + case CELL_SAVEDATA_FOCUSPOS_OLDEST: + { + s64 min = INT64_MAX; + + for (s32 i = 0; i < save_entries.size(); i++) + { + if (save_entries[i].mtime < min) + { + focused = i; + min = save_entries[i].mtime; + } + } + + break; + } + case CELL_SAVEDATA_FOCUSPOS_NEWDATA: + { + break; + } + default: + { + cellSysutil.Error("savedata_op(): unknown listSet->focusPosition (0x%x)", pos_type); + return CELL_SAVEDATA_ERROR_PARAM; + } + } + + // Display Save Data List + selected = g_savedata_dialog->ShowSaveDataList(save_entries, focused, listSet); + + if (selected == -1) + { + if (listSet->newData) + { + save_entry.dirName = listSet->newData->dirName.get_ptr(); + } + else + { + return CELL_OK; // ??? + } + } + } + + if (funcFixed) + { + // Fixed Callback + funcFixed(CPU, result, listGet, fixedSet); + + if (result->result < 0) + { + return CELL_SAVEDATA_ERROR_CBRESULT; + } + + for (s32 i = 0; i < save_entries.size(); i++) + { + if (save_entries[i].dirName == fixedSet->dirName.get_ptr()) + { + selected = i; + break; + } + } + + if (selected == -1) + { + save_entry.dirName = fixedSet->dirName.get_ptr(); + } + } + + if (selected >= 0) + { + save_entry.dirName = std::move(save_entries[selected < save_entries.size() ? selected : throw __FUNCTION__].dirName); + } } - - - - setSaveDataList(save_entries, listSet->fixedList, listSet->fixedListNum); - if (listSet->newData) - addNewSaveDataEntry(save_entries, listSet->newData); - if (save_entries.size() == 0) { - cellSysutil.Error("cellSaveDataListLoad2: No save entries found!"); // TODO: Find a better way to handle this error - return CELL_OK; + if (dirName) + { + save_entry.dirName = dirName.get_ptr(); } - u32 focusIndex = focusSaveDataEntry(save_entries, listSet->focusPosition); - // TODO: Display the dialog here - u32 selectedIndex = focusIndex; // TODO: Until the dialog is implemented, select always the focused entry - getSaveDataStat(save_entries[selectedIndex], statGet); - result->userdata = userdata; + // get save stats + std::string dir_path = base_dir + save_entry.dirName + "/"; + std::string sfo_path = dir_path + "PARAM.SFO"; - funcStat(result, statGet, statSet); - Memory.Free(statGet->fileList.addr()); - if (result->result < 0) { - cellSysutil.Error("cellSaveDataListLoad2: CellSaveDataStatCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. + PSFLoader psf(vfsFile(sfo_path, vfsRead)); + + std::string dir_local_path; + + Emu.GetVFS().GetDevice(dir_path, dir_local_path); + + FileInfo dir_info = {}; + + get_file_info(dir_local_path, dir_info); + + statGet->hddFreeSizeKB = 40 * 1024 * 1024; // 40 GB + statGet->isNewData = save_entry.isNew = !psf; + + statGet->dir.atime = save_entry.atime = dir_info.atime; + statGet->dir.mtime = save_entry.mtime = dir_info.mtime; + statGet->dir.ctime = save_entry.ctime = dir_info.ctime; + strcpy_trunc(statGet->dir.dirName, save_entry.dirName); + + statGet->getParam.attribute = psf.GetInteger("ATTRIBUTE"); // ??? + strcpy_trunc(statGet->getParam.title, save_entry.title = psf.GetString("TITLE")); + strcpy_trunc(statGet->getParam.subTitle, save_entry.subtitle = psf.GetString("SUB_TITLE")); + strcpy_trunc(statGet->getParam.detail, save_entry.details = psf.GetString("DETAIL")); + strcpy_trunc(statGet->getParam.listParam, save_entry.listParam = psf.GetString("SAVEDATA_LIST_PARAM")); + + statGet->bind = 0; + statGet->sizeKB = save_entry.size / 1024; + statGet->sysSizeKB = 0; // This is the size of system files, but PARAM.SFO is very small and PARAM.PDF is not used + + statGet->fileNum = 0; + statGet->fileList.set(setBuf->buf.addr()); + statGet->fileListNum = 0; + memset(statGet->reserved, 0, sizeof(statGet->reserved)); + + auto file_list = statGet->fileList.get_ptr(); + + for (const auto entry : vfsDir(dir_path)) + { + // only files, system files ignored, fileNum is limited by setBuf->fileListMax + if (entry->flags & DirEntry_TypeFile && entry->name != "PARAM.SFO" && statGet->fileListNum++ < setBuf->fileListMax) + { + statGet->fileNum++; + + auto& file = *file_list++; + + if (entry->name == "ICON0.PNG") + { + file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0; + } + else if (entry->name == "ICON1.PAM") + { + file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1; + } + else if (entry->name == "PIC1.PNG") + { + file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1; + } + else if (entry->name == "SND0.AT3") + { + file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0; + } + else + { + file.fileType = CELL_SAVEDATA_FILETYPE_NORMALFILE; // protected files are not supported + } + + file.size = entry->size; + file.atime = entry->access_time; + file.mtime = entry->modify_time; + file.ctime = entry->create_time; + strcpy_trunc(file.fileName, entry->name); + } + } + + // Stat Callback + funcStat(CPU, result, statGet, statSet); + + if (result->result < 0) + { return CELL_SAVEDATA_ERROR_CBRESULT; } - /*if (statSet->setParam) - // TODO: Write PARAM.SFO file - */ + // Update PARAM.SFO + if (statSet->setParam) + { + psf.Clear(); + psf.SetString("ACCOUNT_ID", ""); // ??? + psf.SetInteger("ATTRIBUTE", statSet->setParam->attribute); + psf.SetString("CATEGORY", "SD"); // ??? + psf.SetString("PARAMS", ""); // ??? + psf.SetString("PARAMS2", ""); // ??? + psf.SetInteger("PARENTAL_LEVEL", 0); // ??? + psf.SetString("DETAIL", statSet->setParam->detail); + psf.SetString("SAVEDATA_DIRECTORY", save_entry.dirName); + psf.SetString("SAVEDATA_LIST_PARAM", statSet->setParam->listParam); + psf.SetString("SUB_TITLE", statSet->setParam->subTitle); + psf.SetString("TITLE", statSet->setParam->title); + } - // Enter the loop where the save files are read/created/deleted. - s32 ret = modifySaveDataFiles(funcFile, result, base_dir + (char*)statGet->dir.dirName); + switch (const auto mode = statSet->reCreateMode.value() & 0xffff) + { + case CELL_SAVEDATA_RECREATE_NO: + case CELL_SAVEDATA_RECREATE_NO_NOBROKEN: + { + break; + } + case CELL_SAVEDATA_RECREATE_YES: + case CELL_SAVEDATA_RECREATE_YES_RESET_OWNER: + { + // kill it with fire + for (const auto entry : vfsDir(dir_path)) + { + if (entry->flags & DirEntry_TypeFile) + { + Emu.GetVFS().RemoveFile(dir_path + entry->name); + } + } - return ret; + break; + } + default: + { + cellSysutil.Error("savedata_op(): unknown statSet->reCreateMode (0x%x)", statSet->reCreateMode); + return CELL_SAVEDATA_ERROR_PARAM; + } + } + + // Create save directory if necessary + if (save_entry.isNew && !Emu.GetVFS().CreateDir(dir_path)) + { + // error + } + + // Write PARAM.SFO + if (psf) + { + Emu.GetVFS().CreateFile(sfo_path, true); + psf.Save(vfsFile(sfo_path, vfsWrite)); + } + + // Enter the loop where the save files are read/created/deleted + fileGet->excSize = 0; + memset(fileGet->reserved, 0, sizeof(fileGet->reserved)); + + while (true) + { + funcFile(CPU, result, fileGet, fileSet); + + if (result->result < 0) + { + return CELL_SAVEDATA_ERROR_CBRESULT; + } + + if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM) + { + break; + } + + std::string filepath = dir_path; + + switch (const auto type = fileSet->fileType.value()) + { + case CELL_SAVEDATA_FILETYPE_SECUREFILE: + case CELL_SAVEDATA_FILETYPE_NORMALFILE: + { + filepath += fileSet->fileName.get_ptr(); + break; + } + + case CELL_SAVEDATA_FILETYPE_CONTENT_ICON0: + { + filepath += "ICON0.PNG"; + break; + } + + case CELL_SAVEDATA_FILETYPE_CONTENT_ICON1: + { + filepath += "ICON1.PAM"; + break; + } + + case CELL_SAVEDATA_FILETYPE_CONTENT_PIC1: + { + filepath += "PIC1.PNG"; + break; + } + + case CELL_SAVEDATA_FILETYPE_CONTENT_SND0: + { + filepath += "SND0.AT3"; + break; + } + + default: + { + cellSysutil.Error("savedata_op(): unknown fileSet->fileType (0x%x)", type); + return CELL_SAVEDATA_ERROR_PARAM; + } + } + + std::unique_ptr file; + + switch (const auto op = fileSet->fileOperation.value()) + { + case CELL_SAVEDATA_FILEOP_READ: + { + file.reset(Emu.GetVFS().OpenFile(filepath, vfsRead)); + file->Seek(fileSet->fileOffset); + fileGet->excSize = file->Read(fileSet->fileBuf.get_ptr(), std::min(fileSet->fileSize, fileSet->fileBufSize)); + break; + } + + case CELL_SAVEDATA_FILEOP_WRITE: + { + Emu.GetVFS().CreateFile(filepath); + file.reset(Emu.GetVFS().OpenFile(filepath, vfsReadWrite)); + file->Seek(fileSet->fileOffset); + fileGet->excSize = file->Write(fileSet->fileBuf.get_ptr(), std::min(fileSet->fileSize, fileSet->fileBufSize)); + // TODO: truncate this fucked shit + break; + } + + case CELL_SAVEDATA_FILEOP_DELETE: + { + Emu.GetVFS().RemoveFile(filepath); + fileGet->excSize = 0; + break; + } + + case CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC: + { + Emu.GetVFS().CreateFile(filepath); + file.reset(Emu.GetVFS().OpenFile(filepath, vfsReadWrite)); + file->Seek(fileSet->fileOffset); + fileGet->excSize = file->Write(fileSet->fileBuf.get_ptr(), std::min(fileSet->fileSize, fileSet->fileBufSize)); + break; + } + + default: + { + cellSysutil.Error("savedata_op(): unknown fileSet->fileOperation (0x%x)", op); + return CELL_SAVEDATA_ERROR_PARAM; + } + } + } + + return CELL_OK; } // Functions diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.h b/rpcs3/Emu/SysCalls/Modules/cellSaveData.h index 224f8a9a9f..cd5174656c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.h @@ -85,6 +85,13 @@ enum CELL_SAVEDATA_FILETYPE_CONTENT_ICON1 = 3, CELL_SAVEDATA_FILETYPE_CONTENT_PIC1 = 4, CELL_SAVEDATA_FILETYPE_CONTENT_SND0 = 5, + + // reCreateMode + CELL_SAVEDATA_RECREATE_NO = 0, + CELL_SAVEDATA_RECREATE_NO_NOBROKEN = 1, + CELL_SAVEDATA_RECREATE_YES = 2, + CELL_SAVEDATA_RECREATE_YES_RESET_OWNER = 3, + CELL_SAVEDATA_RECREATE_MASK = 0xffff, }; @@ -167,9 +174,9 @@ struct CellSaveDataSystemFileParam struct CellSaveDataDirStat { - be_t st_atime_; - be_t st_mtime_; - be_t st_ctime_; + be_t atime; + be_t mtime; + be_t ctime; char dirName[CELL_SAVEDATA_DIRNAME_SIZE]; }; @@ -177,10 +184,10 @@ struct CellSaveDataFileStat { be_t fileType; u8 reserved1[4]; - be_t st_size; - be_t st_atime_; - be_t st_mtime_; - be_t st_ctime_; + be_t size; + be_t atime; + be_t mtime; + be_t ctime; char fileName[CELL_SAVEDATA_FILENAME_SIZE]; u8 reserved2[3]; }; @@ -286,4 +293,6 @@ struct SaveDataDialogInstance SaveDataDialogInstance(); virtual ~SaveDataDialogInstance() = default; + + virtual s32 ShowSaveDataList(std::vector& save_entries, s32 focused, vm::ptr listSet) = 0; }; diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 9f918a4364..463f729695 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -982,6 +982,13 @@ vm::ptr _sys_strcat(vm::ptr dest, vm::ptr source) return dest; } +vm::ptr _sys_strchr(vm::ptr str, s32 ch) +{ + sysPrxForUser.Log("_sys_strchr(str=*0x%x, ch=0x%x)", str, ch); + + return vm::ptr::make(vm::get_addr(strchr(str.get_ptr(), ch))); +} + vm::ptr _sys_strncat(vm::ptr dest, vm::ptr source, u32 len) { sysPrxForUser.Log("_sys_strncat(dest=*0x%x, source=*0x%x, len=%d)", dest, source, len); @@ -1363,6 +1370,7 @@ Module sysPrxForUser("sysPrxForUser", []() REG_FUNC(sysPrxForUser, _sys_strcmp); REG_FUNC(sysPrxForUser, _sys_strncmp); REG_FUNC(sysPrxForUser, _sys_strcat); + REG_FUNC(sysPrxForUser, _sys_strchr); REG_FUNC(sysPrxForUser, _sys_strncat); REG_FUNC(sysPrxForUser, _sys_strcpy); REG_FUNC(sysPrxForUser, _sys_strncpy); diff --git a/rpcs3/Gui/SaveDataDialog.cpp b/rpcs3/Gui/SaveDataDialog.cpp index ddd9d8b78e..36749a61db 100644 --- a/rpcs3/Gui/SaveDataDialog.cpp +++ b/rpcs3/Gui/SaveDataDialog.cpp @@ -2,3 +2,8 @@ #include "Emu/Memory/Memory.h" #include "SaveDataDialog.h" + +s32 SaveDataDialogFrame::ShowSaveDataList(std::vector& save_entries, s32 focused, vm::ptr listSet) +{ + return focused; +} diff --git a/rpcs3/Gui/SaveDataDialog.h b/rpcs3/Gui/SaveDataDialog.h index ab113cc084..8ca49ec487 100644 --- a/rpcs3/Gui/SaveDataDialog.h +++ b/rpcs3/Gui/SaveDataDialog.h @@ -5,5 +5,5 @@ class SaveDataDialogFrame : public SaveDataDialogInstance { public: - + virtual s32 ShowSaveDataList(std::vector& save_entries, s32 focused, vm::ptr listSet) override; }; diff --git a/rpcs3/Loader/PSF.cpp b/rpcs3/Loader/PSF.cpp index 28c6886e9c..cf2aed6ea7 100644 --- a/rpcs3/Loader/PSF.cpp +++ b/rpcs3/Loader/PSF.cpp @@ -115,7 +115,7 @@ bool PSFLoader::Load(vfsStream& stream) return true; } -bool PSFLoader::Save(vfsStream& stream) +bool PSFLoader::Save(vfsStream& stream) const { std::vector indices; diff --git a/rpcs3/Loader/PSF.h b/rpcs3/Loader/PSF.h index 131a73ec07..a1fef680a2 100644 --- a/rpcs3/Loader/PSF.h +++ b/rpcs3/Loader/PSF.h @@ -50,7 +50,7 @@ public: bool Load(vfsStream& stream); - bool Save(vfsStream& stream); + bool Save(vfsStream& stream) const; void Clear();