mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Replaces the temporary fix that did the hidden modes' IO inside Update. The IO thread read and wrote the dialog's request, display state and save list, all shared with the emulator thread, which kept using them to draw the dialog and reload the request from the game. Now the IO thread works on its own copy of the request, its own SavedataParam and directory names resolved up front, and shares nothing else with the emulator thread but the (locked) file system, MemoryStick_FreeSpace's cached use and sceChnnlsv's scratch buffer and kirk state, the last two now under locks too. It still reads and writes the game's buffers directly, like a PSP's utility threads and sceIoReadAsync do, so a savestate waits for it before it saves or loads memory. Save bookkeeping, the save indicator and display changes happen on the emulator thread when the results are taken, and only the request fields the IO changed are copied back, so a game's own edits in the meantime survive. Hidden modes take the results at the next Update (or, with Host IO timing, the first Update that finds them done). The visible dialogs keep drawing and take them once the IO is done; save and load used to stall the emulator thread for the whole operation. Savestates keep results that haven't been taken yet. When the results land in PSP memory doesn't matter to games, so utility/savedata/filelist now only prints them once the utility has finished. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
405 lines
13 KiB
C++
405 lines
13 KiB
C++
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <set>
|
|
#include <unordered_map>
|
|
#include <cstdint>
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Core/ELF/ParamSFO.h"
|
|
#include "Core/MemMap.h"
|
|
#include "Core/HLE/sceRtc.h"
|
|
#include "Core/Dialog/PSPDialog.h"
|
|
|
|
#undef st_ctime
|
|
#undef st_atime
|
|
#undef st_mtime
|
|
|
|
class PPGeImage;
|
|
struct PSPFileInfo;
|
|
typedef u32_le SceSize_le;
|
|
|
|
enum SceUtilitySavedataType
|
|
{
|
|
SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD = 0,
|
|
SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE = 1,
|
|
SCE_UTILITY_SAVEDATA_TYPE_LOAD = 2,
|
|
SCE_UTILITY_SAVEDATA_TYPE_SAVE = 3,
|
|
SCE_UTILITY_SAVEDATA_TYPE_LISTLOAD = 4,
|
|
SCE_UTILITY_SAVEDATA_TYPE_LISTSAVE = 5,
|
|
SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE = 6,
|
|
SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE = 7,// When run on a PSP, displays a list of all saves on the PSP. Weird. (Not really, it's to let you free up space)
|
|
SCE_UTILITY_SAVEDATA_TYPE_SIZES = 8,
|
|
SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE = 9,
|
|
SCE_UTILITY_SAVEDATA_TYPE_DELETE = 10,
|
|
SCE_UTILITY_SAVEDATA_TYPE_LIST = 11,
|
|
SCE_UTILITY_SAVEDATA_TYPE_FILES = 12,
|
|
SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE = 13,
|
|
SCE_UTILITY_SAVEDATA_TYPE_MAKEDATA = 14,
|
|
SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE = 15,
|
|
SCE_UTILITY_SAVEDATA_TYPE_READDATA = 16,
|
|
SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE = 17,
|
|
SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA = 18,
|
|
SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE = 19,
|
|
SCE_UTILITY_SAVEDATA_TYPE_ERASE = 20,
|
|
SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA = 21,
|
|
SCE_UTILITY_SAVEDATA_TYPE_GETSIZE = 22,
|
|
};
|
|
|
|
static const char *const utilitySavedataTypeNames[] = {
|
|
"AUTOLOAD",
|
|
"AUTOSAVE",
|
|
"LOAD",
|
|
"SAVE",
|
|
"LISTLOAD",
|
|
"LISTSAVE",
|
|
"LISTDELETE",
|
|
"LISTALLDELETE",
|
|
"SIZES",
|
|
"AUTODELETE",
|
|
"DELETE",
|
|
"LIST",
|
|
"FILES",
|
|
"MAKEDATASECURE",
|
|
"MAKEDATA",
|
|
"READDATASECURE",
|
|
"READDATA",
|
|
"WRITEDATASECURE",
|
|
"WRITEDATA",
|
|
"ERASESECURE",
|
|
"ERASE",
|
|
"DELETEDATA",
|
|
"GETSIZE",
|
|
};
|
|
|
|
enum SceUtilitySavedataFocus
|
|
{
|
|
SCE_UTILITY_SAVEDATA_FOCUS_NAME = 0, // specified by saveName[]
|
|
SCE_UTILITY_SAVEDATA_FOCUS_FIRSTLIST = 1, // first listed (on screen or of all?)
|
|
SCE_UTILITY_SAVEDATA_FOCUS_LASTLIST = 2, // last listed (on screen or of all?)
|
|
SCE_UTILITY_SAVEDATA_FOCUS_LATEST = 3, // latest by modification date (first if none)
|
|
SCE_UTILITY_SAVEDATA_FOCUS_OLDEST = 4, // oldest by modification date (first if none)
|
|
SCE_UTILITY_SAVEDATA_FOCUS_FIRSTDATA = 5, // first non-empty (first if none)
|
|
SCE_UTILITY_SAVEDATA_FOCUS_LASTDATA = 6, // last non-empty (first if none)
|
|
SCE_UTILITY_SAVEDATA_FOCUS_FIRSTEMPTY = 7, // first empty (what if no empty?)
|
|
SCE_UTILITY_SAVEDATA_FOCUS_LASTEMPTY = 8, // last empty (what if no empty?)
|
|
};
|
|
|
|
#if COMMON_LITTLE_ENDIAN
|
|
typedef SceUtilitySavedataType SceUtilitySavedataType_le;
|
|
typedef SceUtilitySavedataFocus SceUtilitySavedataFocus_le;
|
|
#else
|
|
typedef swap_struct_t<SceUtilitySavedataType, swap_32_t<SceUtilitySavedataType> > SceUtilitySavedataType_le;
|
|
typedef swap_struct_t<SceUtilitySavedataFocus, swap_32_t<SceUtilitySavedataFocus> > SceUtilitySavedataFocus_le;
|
|
#endif
|
|
|
|
typedef char SceUtilitySavedataSaveName[20];
|
|
|
|
// title, savedataTitle, detail: parts of the unencrypted SFO
|
|
// data, it contains what the VSH and standard load screen shows
|
|
struct PspUtilitySavedataSFOParam
|
|
{
|
|
char title[0x80];
|
|
char savedataTitle[0x80];
|
|
char detail[0x400];
|
|
unsigned char parentalLevel;
|
|
unsigned char unknown[3];
|
|
};
|
|
|
|
struct PspUtilitySavedataFileData {
|
|
PSPPointer<u8> buf;
|
|
SceSize_le bufSize; // Size of the buffer pointed to by buf
|
|
SceSize_le size; // Actual file size to write / was read
|
|
s32_le unknown;
|
|
};
|
|
|
|
struct PspUtilitySavedataSizeEntry {
|
|
u64_le size;
|
|
char name[16];
|
|
};
|
|
|
|
struct PspUtilitySavedataSizeInfo {
|
|
s32_le numSecureEntries;
|
|
s32_le numNormalEntries;
|
|
PSPPointer<PspUtilitySavedataSizeEntry> secureEntries;
|
|
PSPPointer<PspUtilitySavedataSizeEntry> normalEntries;
|
|
s32_le sectorSize;
|
|
s32_le freeSectors;
|
|
s32_le freeKB;
|
|
char freeString[8];
|
|
s32_le neededKB;
|
|
char neededString[8];
|
|
s32_le overwriteKB;
|
|
char overwriteString[8];
|
|
};
|
|
|
|
struct SceUtilitySavedataIdListEntry
|
|
{
|
|
s32_le st_mode;
|
|
ScePspDateTime st_ctime;
|
|
ScePspDateTime st_atime;
|
|
ScePspDateTime st_mtime;
|
|
SceUtilitySavedataSaveName name;
|
|
};
|
|
|
|
struct SceUtilitySavedataIdListInfo
|
|
{
|
|
s32_le maxCount;
|
|
s32_le resultCount;
|
|
PSPPointer<SceUtilitySavedataIdListEntry> entries;
|
|
};
|
|
|
|
struct SceUtilitySavedataFileListEntry
|
|
{
|
|
s32_le st_mode;
|
|
u32_le st_unk0;
|
|
u64_le st_size;
|
|
ScePspDateTime st_ctime;
|
|
ScePspDateTime st_atime;
|
|
ScePspDateTime st_mtime;
|
|
char name[16];
|
|
};
|
|
|
|
struct SceUtilitySavedataFileListInfo
|
|
{
|
|
u32_le maxSecureEntries;
|
|
u32_le maxNormalEntries;
|
|
u32_le maxSystemEntries;
|
|
u32_le resultNumSecureEntries;
|
|
u32_le resultNumNormalEntries;
|
|
u32_le resultNumSystemEntries;
|
|
PSPPointer<SceUtilitySavedataFileListEntry> secureEntries;
|
|
PSPPointer<SceUtilitySavedataFileListEntry> normalEntries;
|
|
PSPPointer<SceUtilitySavedataFileListEntry> systemEntries;
|
|
};
|
|
|
|
struct SceUtilitySavedataMsFreeInfo
|
|
{
|
|
s32_le clusterSize;
|
|
s32_le freeClusters;
|
|
s32_le freeSpaceKB;
|
|
char freeSpaceStr[8];
|
|
};
|
|
|
|
struct SceUtilitySavedataUsedDataInfo
|
|
{
|
|
s32_le usedClusters;
|
|
s32_le usedSpaceKB;
|
|
char usedSpaceStr[8];
|
|
s32_le usedSpace32KB;
|
|
char usedSpace32Str[8];
|
|
};
|
|
|
|
struct SceUtilitySavedataMsDataInfo
|
|
{
|
|
char gameName[13];
|
|
char pad[3];
|
|
SceUtilitySavedataSaveName saveName;
|
|
SceUtilitySavedataUsedDataInfo info;
|
|
};
|
|
|
|
// Structure to hold the parameters for the sceUtilitySavedataInitStart function.
|
|
struct SceUtilitySavedataParam
|
|
{
|
|
pspUtilityDialogCommon common;
|
|
|
|
SceUtilitySavedataType_le mode; // 0 to load, 1 to save
|
|
s32_le bind;
|
|
|
|
s32_le overwriteMode; // use 0x10 ?
|
|
|
|
/** gameName: name used from the game for saves, equal for all saves */
|
|
char gameName[13];
|
|
char unused[3];
|
|
/** saveName: name of the particular save, normally a number */
|
|
SceUtilitySavedataSaveName saveName;
|
|
PSPPointer<SceUtilitySavedataSaveName> saveNameList;
|
|
/** fileName: name of the data file of the game for example DATA.BIN */
|
|
char fileName[13];
|
|
char unused2[3];
|
|
|
|
/** pointer to a buffer that will contain data file unencrypted data */
|
|
PSPPointer<u8> dataBuf;
|
|
/** size of allocated space to dataBuf */
|
|
SceSize_le dataBufSize;
|
|
SceSize_le dataSize; // Size of the actual save data
|
|
|
|
PspUtilitySavedataSFOParam sfoParam;
|
|
|
|
PspUtilitySavedataFileData icon0FileData;
|
|
PspUtilitySavedataFileData icon1FileData;
|
|
PspUtilitySavedataFileData pic1FileData;
|
|
PspUtilitySavedataFileData snd0FileData;
|
|
|
|
PSPPointer<PspUtilitySavedataFileData> newData;
|
|
SceUtilitySavedataFocus_le focus;
|
|
s32_le abortStatus;
|
|
|
|
// Function SCE_UTILITY_SAVEDATA_TYPE_SIZES
|
|
PSPPointer<SceUtilitySavedataMsFreeInfo> msFree;
|
|
PSPPointer<SceUtilitySavedataMsDataInfo> msData;
|
|
PSPPointer<SceUtilitySavedataUsedDataInfo> utilityData;
|
|
|
|
u8 key[16];
|
|
|
|
u32_le secureVersion;
|
|
s32_le multiStatus;
|
|
|
|
// Function 11 LIST
|
|
PSPPointer<SceUtilitySavedataIdListInfo> idList;
|
|
|
|
// Function 12 FILES
|
|
PSPPointer<SceUtilitySavedataFileListInfo> fileList;
|
|
|
|
// Function 22 GETSIZES
|
|
PSPPointer<PspUtilitySavedataSizeInfo> sizeInfo;
|
|
};
|
|
|
|
// Non native, this one we can reorganize as we like
|
|
struct SaveFileInfo
|
|
{
|
|
s64 size = 0;
|
|
std::string saveName;
|
|
std::string saveDir;
|
|
int idx = 0;
|
|
|
|
char title[128]{};
|
|
char saveTitle[128]{};
|
|
char saveDetail[1024]{};
|
|
|
|
bool broken = false;
|
|
|
|
tm modif_time{};
|
|
|
|
PPGeImage *texture = nullptr;
|
|
|
|
void DoState(PointerWrap &p);
|
|
};
|
|
|
|
struct SaveSFOFileListEntry {
|
|
char filename[13];
|
|
u8 hash[16];
|
|
u8 pad[3];
|
|
};
|
|
|
|
class SavedataParam
|
|
{
|
|
public:
|
|
SavedataParam();
|
|
|
|
static void Init();
|
|
std::string GetSaveFilePath(const SceUtilitySavedataParam *param, int saveId = -1) const;
|
|
std::string GetSaveFilePath(const SceUtilitySavedataParam *param, const std::string &saveDir) const;
|
|
std::string GetSaveDirName(const SceUtilitySavedataParam *param, int saveId = -1) const;
|
|
std::string GetSaveDir(const SceUtilitySavedataParam *param, int saveId = -1) const;
|
|
std::string GetSaveDir(const SceUtilitySavedataParam *param, const std::string &saveDirName) const;
|
|
bool Delete(SceUtilitySavedataParam* param, const std::string &saveDir);
|
|
int DeleteData(SceUtilitySavedataParam* param);
|
|
int Save(SceUtilitySavedataParam* param, const std::string &saveDirName, bool secureMode = true);
|
|
int Load(SceUtilitySavedataParam* param, const std::string &saveDirName, int saveId = -1, bool secureMode = true);
|
|
int GetSizes(SceUtilitySavedataParam* param);
|
|
bool GetList(SceUtilitySavedataParam* param);
|
|
int GetFilesList(SceUtilitySavedataParam* param, u32 requestAddr, const std::string &saveDirName);
|
|
bool GetSize(SceUtilitySavedataParam* param);
|
|
int GetSaveCryptMode(const SceUtilitySavedataParam *param, const std::string &saveDirName);
|
|
bool IsInSaveDataList(const std::string &saveName, int count);
|
|
|
|
std::string GetGameName(const SceUtilitySavedataParam *param) const;
|
|
std::string GetSaveName(const SceUtilitySavedataParam *param) const;
|
|
std::string GetFileName(const SceUtilitySavedataParam *param) const;
|
|
std::string GetKey(const SceUtilitySavedataParam *param) const;
|
|
bool HasKey(const SceUtilitySavedataParam *param) const;
|
|
|
|
static std::string GetSpaceText(u64 size, bool roundUp);
|
|
|
|
void SetIgnoreTextures(bool state) {
|
|
ignoreTextures_ = state;
|
|
}
|
|
int SetPspParam(SceUtilitySavedataParam* param);
|
|
SceUtilitySavedataParam *GetPspParam();
|
|
const SceUtilitySavedataParam *GetPspParam() const;
|
|
|
|
int GetFilenameCount();
|
|
const SaveFileInfo& GetFileInfo(int idx);
|
|
std::string GetFilename(int idx) const;
|
|
std::string GetSaveDir(int idx) const;
|
|
|
|
int GetSelectedSave();
|
|
void SetSelectedSave(int idx);
|
|
|
|
int GetFirstListSave();
|
|
int GetLastListSave();
|
|
int GetLatestSave();
|
|
int GetOldestSave();
|
|
int GetFirstDataSave();
|
|
int GetLastDataSave();
|
|
int GetFirstEmptySave();
|
|
int GetLastEmptySave();
|
|
int GetSaveNameIndex(const SceUtilitySavedataParam *param);
|
|
|
|
bool WouldHaveMultiSaveName(const SceUtilitySavedataParam *param);
|
|
|
|
void ClearSFOCache();
|
|
|
|
void DoState(PointerWrap &p);
|
|
|
|
private:
|
|
void Clear();
|
|
void SetFileInfo(int idx, PSPFileInfo &info, const std::string &saveName, const std::string &saveDir = "");
|
|
void SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, const std::string &saveName, const std::string &saveDir = "");
|
|
void ClearFileInfo(SaveFileInfo &saveInfo, const std::string &saveName);
|
|
PSPFileInfo GetSaveInfo(const std::string &saveDir);
|
|
|
|
int LoadSaveData(SceUtilitySavedataParam *param, const std::string &saveDirName, const std::string& dirPath, bool secureMode);
|
|
u32 LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, const u8 *saveData, int &saveSize, int prevCryptMode, const u8 *expectedHash, bool &saveDone);
|
|
u32 LoadNotCryptedSave(SceUtilitySavedataParam *param, u8 *data, u8 *saveData, int &saveSize);
|
|
bool LoadSFO(SceUtilitySavedataParam *param, const std::string& dirPath);
|
|
void LoadFile(const std::string& dirPath, const std::string& filename, PspUtilitySavedataFileData *fileData);
|
|
|
|
int DecryptData(unsigned int mode, unsigned char *data, int *dataLen, int *alignedLen, const u8 *cryptkey, const u8 *expectedHash);
|
|
int EncryptData(unsigned int mode, unsigned char *data, int *dataLen, int *alignedLen, u8 *hash, const u8 *cryptkey);
|
|
int UpdateHash(u8* sfoData, int sfoSize, int sfoDataParamsOffset, int encryptmode);
|
|
|
|
// data must be zero-padded from len to alignedLen (which should be the next multiply of 16)!
|
|
int BuildHash(uint8_t *output, const uint8_t *data, unsigned int len, unsigned int alignedLen, int mode, const uint8_t *cryptkey);
|
|
int DetermineCryptMode(const SceUtilitySavedataParam *param) const;
|
|
bool UsesSecureVersion(const SceUtilitySavedataParam *param) const;
|
|
bool MissingRequiredKey(const SceUtilitySavedataParam *param) const;
|
|
|
|
std::vector<SaveSFOFileListEntry> GetSFOEntries(const std::string &dirPath);
|
|
std::set<std::string> GetSecureFileNames(const std::string &dirPath);
|
|
bool GetExpectedHash(const std::string &dirPath, const std::string &filename, u8 hash[16]);
|
|
|
|
std::shared_ptr<ParamSFOData> 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<std::string, std::shared_ptr<ParamSFOData>> sfoCache_;
|
|
};
|