ppsspp/Core/Dialog/SavedataParam.cpp
Xele02 88296468e4 Some save are smaller than the buffer. This correct K-on Houkago Live
Game which should check save size returned.
2013-01-05 02:00:41 +01:00

795 lines
21 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/.
#include "SavedataParam.h"
#include "image/png_load.h"
#include "../HLE/sceKernelMemory.h"
#include "../ELF/ParamSFO.h"
#include "Core/HW/MemoryStick.h"
#include "PSPSaveDialog.h"
std::string icon0Name = "ICON0.PNG";
std::string icon1Name = "ICON1.PMF";
std::string pic1Name = "PIC1.PNG";
std::string snd0Name = "SND0.AT3";
std::string sfoName = "PARAM.SFO";
std::string savePath = "ms0:/PSP/SAVEDATA/";
namespace
{
int getSizeNormalized(int size)
{
int sizeCluster = (int)MemoryStick_SectorSize();
return ((int)((size + sizeCluster - 1) / sizeCluster)) * sizeCluster;
}
void SetStringFromSFO(ParamSFOData &sfoFile, const char *name, char *str, int strLength)
{
std::string value = sfoFile.GetValueString(name);
strncpy(str, value.c_str(), strLength - 1);
str[strLength - 1] = 0;
}
bool ReadPSPFile(std::string filename, u8 *data, s64 dataSize, s64 *readSize)
{
u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ);
if (handle == 0)
return false;
int result = pspFileSystem.ReadFile(handle, data, dataSize);
pspFileSystem.CloseFile(handle);
if(readSize)
*readSize = result;
return result != 0;
}
bool WritePSPFile(std::string filename, u8 *data, int dataSize)
{
u32 handle = pspFileSystem.OpenFile(filename, (FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE));
if (handle == 0)
return false;
int result = pspFileSystem.WriteFile(handle, data, dataSize);
pspFileSystem.CloseFile(handle);
return result != 0;
}
struct EncryptFileInfo
{
int fileVersion;
u8 key[16];
int sdkVersion;
};
bool PSPMatch(std::string text, std::string regexp)
{
if(text.empty() && regexp.empty())
return true;
else if(regexp == "*")
return true;
else if(text.empty())
return false;
else if(regexp.empty())
return false;
else if(regexp == "?" && text.length() == 1)
return true;
else if(text == regexp)
return true;
else if(regexp.data()[0] == '*')
{
bool res = PSPMatch(text.substr(1),regexp.substr(1));
if(!res)
res = PSPMatch(text.substr(1),regexp);
return res;
}
else if(regexp.data()[0] == '?')
{
return PSPMatch(text.substr(1),regexp.substr(1));
}
else if(regexp.data()[0] == text.data()[0])
{
return PSPMatch(text.substr(1),regexp.substr(1));
}
return false;
}
}
SavedataParam::SavedataParam()
: pspParam(0)
, selectedSave(0)
, saveDataList(0)
, saveDataListCount(0)
, saveNameListDataCount(0)
{
}
void SavedataParam::Init()
{
if (!pspFileSystem.GetFileInfo(savePath).exists)
{
pspFileSystem.MkDir(savePath);
}
}
std::string SavedataParam::GetSaveDir(SceUtilitySavedataParam* param, int saveId)
{
if (!param) {
return "";
}
std::string dirPath = GetGameName(param)+GetSaveName(param);
if (saveId >= 0 && saveNameListDataCount > 0) // if user selection, use it
dirPath = std::string(GetGameName(param))+GetFilename(saveId);
return dirPath;
}
std::string SavedataParam::GetSaveFilePath(SceUtilitySavedataParam* param, int saveId)
{
if (!param) {
return "";
}
return savePath + GetSaveDir(param,saveId);
}
std::string SavedataParam::GetGameName(SceUtilitySavedataParam* param)
{
char gameName[14];
memcpy(gameName,param->gameName,13);
gameName[13] = 0;
return gameName;
}
std::string SavedataParam::GetSaveName(SceUtilitySavedataParam* param)
{
char saveName[21];
memcpy(saveName,param->saveName,20);
saveName[20] = 0;
if(strcmp(saveName,"<>") == 0)
return "";
return saveName;
}
std::string SavedataParam::GetFileName(SceUtilitySavedataParam* param)
{
char fileName[14];
memcpy(fileName,param->fileName,13);
fileName[13] = 0;
return fileName;
}
bool SavedataParam::Delete(SceUtilitySavedataParam* param, int saveId)
{
if (!param)
{
return false;
}
std::string dirPath = GetSaveFilePath(param,saveId);
if (saveId >= 0 && saveNameListDataCount > 0) // if user selection, use it
{
if (saveDataList[saveId].size == 0) // don't delete no existing file
{
return false;
}
}
pspFileSystem.RmDir(dirPath);
return true;
}
bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
{
if (!param) {
return false;
}
std::string dirPath = GetSaveFilePath(param, saveId);
if (!pspFileSystem.GetFileInfo(dirPath).exists)
pspFileSystem.MkDir(dirPath);
if(param->dataBuf != 0) // Can launch save without save data in mode 13
{
std::string filePath = dirPath+"/"+GetFileName(param);
int saveSize = param->dataSize;
if(saveSize == 0 || saveSize > param->dataBufSize)
saveSize = param->dataBufSize; // fallback, should never use this
INFO_LOG(HLE,"Saving file with size %u in %s",saveSize,filePath.c_str());
u8 *data_ = (u8*)Memory::GetPointer(param->dataBuf);
if (!WritePSPFile(filePath, data_, saveSize))
{
ERROR_LOG(HLE,"Error writing file %s",filePath.c_str());
return false;
}
}
// SAVE PARAM.SFO
ParamSFOData sfoFile;
std::string sfopath = dirPath+"/"+sfoName;
PSPFileInfo sfoInfo = pspFileSystem.GetFileInfo(sfopath);
if(sfoInfo.exists) // Read old sfo if exist
{
u8 *sfoData = new u8[(size_t)sfoInfo.size];
size_t sfoSize = (size_t)sfoInfo.size;
if(ReadPSPFile(sfopath,sfoData,sfoSize, NULL))
{
sfoFile.ReadSFO(sfoData,sfoSize);
delete[] sfoData;
}
}
// 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,saveId),64);
// For each file, 13 bytes for filename, 16 bytes for file hash (0 in PPSSPP), 3 byte for padding
const int FILE_LIST_ITEM_SIZE = 13 + 16 + 3;
const int FILE_LIST_COUNT_MAX = 99;
const int FILE_LIST_TOTAL_SIZE = FILE_LIST_ITEM_SIZE * FILE_LIST_COUNT_MAX;
u32 tmpDataSize = 0;
u8* tmpDataOrig = sfoFile.GetValueData("SAVEDATA_FILE_LIST", &tmpDataSize);
u8* tmpData = new u8[FILE_LIST_TOTAL_SIZE];
if (tmpDataOrig != NULL)
memcpy(tmpData, tmpDataOrig, tmpDataSize > FILE_LIST_TOTAL_SIZE ? FILE_LIST_TOTAL_SIZE : tmpDataSize);
else
memset(tmpData, 0, FILE_LIST_TOTAL_SIZE);
if (param->dataBuf != 0)
{
char *fName = (char*)tmpData;
for(int i = 0; i < FILE_LIST_COUNT_MAX; i++)
{
if(fName[0] == 0)
break; // End of list
if(strncmp(fName,GetFileName(param).c_str(),20) == 0)
break; // File already in SFO
fName += FILE_LIST_ITEM_SIZE;
}
if (fName + 20 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE)
snprintf(fName, 20, "%s",GetFileName(param).c_str());
}
sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, FILE_LIST_TOTAL_SIZE, FILE_LIST_TOTAL_SIZE);
delete[] tmpData;
// No crypted save, so fill with 0
tmpData = new u8[128];
memset(tmpData, 0, 128);
sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128);
delete[] tmpData;
u8 *sfoData;
size_t sfoSize;
sfoFile.WriteSFO(&sfoData,&sfoSize);
WritePSPFile(sfopath, sfoData, sfoSize);
delete[] sfoData;
// SAVE ICON0
if (param->icon0FileData.buf)
{
u8* data_ = (u8*)Memory::GetPointer(param->icon0FileData.buf);
std::string icon0path = dirPath+"/"+icon0Name;
WritePSPFile(icon0path, data_, param->icon0FileData.bufSize);
}
// SAVE ICON1
if (param->icon1FileData.buf)
{
u8* data_ = (u8*)Memory::GetPointer(param->icon1FileData.buf);
std::string icon1path = dirPath+"/"+icon1Name;
WritePSPFile(icon1path, data_, param->icon1FileData.bufSize);
}
// SAVE PIC1
if (param->pic1FileData.buf)
{
u8* data_ = (u8*)Memory::GetPointer(param->pic1FileData.buf);
std::string pic1path = dirPath+"/"+pic1Name;
WritePSPFile(pic1path, data_, param->pic1FileData.bufSize);
}
// Save SND
if (param->snd0FileData.buf)
{
u8* data_ = (u8*)Memory::GetPointer(param->snd0FileData.buf);
std::string snd0path = dirPath+"/"+snd0Name;
WritePSPFile(snd0path, data_, param->snd0FileData.bufSize);
}
// Save Encryption Data
{
EncryptFileInfo encryptInfo;
int dataSize = sizeof(encryptInfo); // version + key + sdkVersion
memset(&encryptInfo,0,dataSize);
encryptInfo.fileVersion = 1;
encryptInfo.sdkVersion = sceKernelGetCompiledSdkVersion();
if(param->size > 1500)
memcpy(encryptInfo.key,param->key,16);
std::string encryptInfoPath = dirPath+"/"+"ENCRYPT_INFO.BIN";
WritePSPFile(encryptInfoPath, (u8*)&encryptInfo, dataSize);
}
return true;
}
bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId)
{
if (!param) {
return false;
}
u8 *data_ = (u8*)Memory::GetPointer(param->dataBuf);
std::string dirPath = GetSaveFilePath(param, saveId);
if (saveId >= 0 && saveNameListDataCount > 0) // if user selection, use it
{
if (saveDataList[saveId].size == 0) // don't read no existing file
{
return false;
}
}
std::string filePath = dirPath+"/"+GetFileName(param);
s64 readSize;
INFO_LOG(HLE,"Loading file with size %u in %s",param->dataBufSize,filePath.c_str());
if (!ReadPSPFile(filePath, data_, param->dataBufSize, &readSize))
{
ERROR_LOG(HLE,"Error reading file %s",filePath.c_str());
return false;
}
param->dataSize = readSize;
return true;
}
std::string SavedataParam::GetSpaceText(int size)
{
char text[50];
if(size < 1024)
{
sprintf(text,"%d B",size);
return std::string(text);
}
size /= 1024;
if(size < 1024)
{
sprintf(text,"%d KB",size);
return std::string(text);
}
size /= 1024;
if(size < 1024)
{
sprintf(text,"%d MB",size);
return std::string(text);
}
size /= 1024;
sprintf(text,"%d GB",size);
return std::string(text);
}
bool SavedataParam::GetSizes(SceUtilitySavedataParam *param)
{
if (!param) {
return false;
}
bool ret = true;
if (Memory::IsValidAddress(param->msFree))
{
Memory::Write_U32((u32)MemoryStick_SectorSize(),param->msFree); // cluster Size
Memory::Write_U32((u32)(MemoryStick_FreeSpace() / MemoryStick_SectorSize()),param->msFree+4); // Free cluster
Memory::Write_U32((u32)(MemoryStick_FreeSpace() / 0x400),param->msFree+8); // Free space (in KB)
std::string spaceTxt = SavedataParam::GetSpaceText((int)MemoryStick_FreeSpace());
Memory::Memset(param->msFree+12,0,spaceTxt.size()+1);
Memory::Memcpy(param->msFree+12,spaceTxt.c_str(),spaceTxt.size()); // Text representing free space
}
if (Memory::IsValidAddress(param->msData))
{
std::string path = GetSaveFilePath(param,0);
PSPFileInfo finfo = pspFileSystem.GetFileInfo(path);
if(finfo.exists)
{
// TODO : fill correctly with the total save size
Memory::Write_U32(1,param->msData+36); //1
Memory::Write_U32(0x20,param->msData+40); // 0x20
Memory::Write_U8(0,param->msData+44); // "32 KB" // 8 u8
Memory::Write_U32(0x20,param->msData+52); // 0x20
Memory::Write_U8(0,param->msData+56); // "32 KB" // 8 u8
}
else
{
Memory::Write_U32(0,param->msData+36);
Memory::Write_U32(0,param->msData+40);
Memory::Write_U8(0,param->msData+44);
Memory::Write_U32(0,param->msData+52);
Memory::Write_U8(0,param->msData+56);
ret = false;
// this should return SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_DATA
}
}
if (Memory::IsValidAddress(param->utilityData))
{
int total_size = 0;
total_size += getSizeNormalized(1); // SFO;
total_size += getSizeNormalized(param->dataSize); // Save Data
total_size += getSizeNormalized(param->icon0FileData.size);
total_size += getSizeNormalized(param->icon1FileData.size);
total_size += getSizeNormalized(param->pic1FileData.size);
total_size += getSizeNormalized(param->snd0FileData.size);
Memory::Write_U32(total_size / (u32)MemoryStick_SectorSize(),param->utilityData); // num cluster
Memory::Write_U32(total_size / 0x400,param->utilityData+4); // save size in KB
std::string spaceTxt = SavedataParam::GetSpaceText(total_size);
Memory::Memset(param->utilityData+8,0,spaceTxt.size()+1);
Memory::Memcpy(param->utilityData+8,spaceTxt.c_str(),spaceTxt.size()); // save size in text
Memory::Write_U32(total_size / 0x400,param->utilityData+16); // save size in KB
spaceTxt = SavedataParam::GetSpaceText(total_size);
Memory::Memset(param->utilityData+20,0,spaceTxt.size()+1);
Memory::Memcpy(param->utilityData+20,spaceTxt.c_str(),spaceTxt.size()); // save size in text
}
return ret;
}
bool SavedataParam::GetList(SceUtilitySavedataParam *param)
{
if (!param) {
return false;
}
if (Memory::IsValidAddress(param->idListAddr))
{
u32 outputBuffer = Memory::Read_U32(param->idListAddr + 8);
u32 maxFile = Memory::Read_U32(param->idListAddr + 0);
std::vector<PSPFileInfo> validDir;
std::vector<PSPFileInfo> allDir = pspFileSystem.GetDirListing(savePath);
if (Memory::IsValidAddress(outputBuffer))
{
std::string searchString = GetGameName(param)+GetSaveName(param);
for (size_t i = 0; i < allDir.size() && i < maxFile; i++)
{
std::string dirName = allDir[i].name;
if(PSPMatch(dirName, searchString))
{
validDir.push_back(allDir[i]);
}
}
for (size_t i = 0; i < validDir.size(); i++)
{
u32 baseAddr = outputBuffer + (i*72);
Memory::Write_U32(0x11FF,baseAddr + 0); // mode
Memory::Write_U64(0,baseAddr + 4); // TODO ctime
Memory::Write_U64(0,baseAddr + 12); // TODO unknow
Memory::Write_U64(0,baseAddr + 20); // TODO atime
Memory::Write_U64(0,baseAddr + 28); // TODO unknow
Memory::Write_U64(0,baseAddr + 36); // TODO mtime
Memory::Write_U64(0,baseAddr + 44); // TODO unknow
// folder name without gamename (max 20 u8)
std::string outName = validDir[i].name.substr(GetGameName(param).size());
Memory::Memset(baseAddr + 52,0,20);
Memory::Memcpy(baseAddr + 52, outName.c_str(), outName.size());
}
}
// Save num of folder found
Memory::Write_U32(validDir.size(),param->idListAddr+4);
}
return true;
}
bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param)
{
if (!param)
{
return false;
}
u32 dataAddr = param->fileListAddr;
if (!Memory::IsValidAddress(dataAddr))
return false;
// TODO : Need to be checked against more game
u32 fileInfosAddr = Memory::Read_U32(dataAddr + 24);
//for Valkyria2, dataAddr+0 and dataAddr+12 has "5" for 5 files
int numFiles = Memory::Read_U32(dataAddr+12);
int foundFiles = 0;
for (int i = 0; i < numFiles; i++)
{
// for each file (80 bytes):
// u32 mode, u32 ??, u64 size, u64 ctime, u64 ??, u64 atime, u64 ???, u64 mtime, u64 ???
// u8[16] filename (or 13 + padding?)
u32 curFileInfoAddr = fileInfosAddr + i*80;
char fileName[16];
strncpy(fileName, Memory::GetCharPointer(curFileInfoAddr + 64),16);
std::string filePath = savePath + GetGameName(param) + GetSaveName(param) + "/" + fileName;
PSPFileInfo info = pspFileSystem.GetFileInfo(filePath);
if (info.exists)
{
Memory::Write_U32(0x21FF, curFileInfoAddr+0);
Memory::Write_U64(info.size, curFileInfoAddr+8);
Memory::Write_U64(0,curFileInfoAddr + 16); // TODO ctime
Memory::Write_U64(0,curFileInfoAddr + 24); // TODO unknow
Memory::Write_U64(0,curFileInfoAddr + 32); // TODO atime
Memory::Write_U64(0,curFileInfoAddr + 40); // TODO unknow
Memory::Write_U64(0,curFileInfoAddr + 48); // TODO mtime
Memory::Write_U64(0,curFileInfoAddr + 56); // TODO unknow
foundFiles++;
}
}
// TODO : verify if return true if at least 1 file found or only if all found
return foundFiles > 0;
}
bool SavedataParam::GetSizes22(SceUtilitySavedataParam *param)
{
if (!param)
{
return false;
}
// TODO code this
return false;
}
void SavedataParam::Clear()
{
if (saveDataList)
{
for (int i = 0; i < saveNameListDataCount; i++)
{
if (saveDataList[i].textureData != 0)
kernelMemory.Free(saveDataList[i].textureData);
saveDataList[i].textureData = 0;
}
delete[] saveDataList;
saveDataList = 0;
saveDataListCount = 0;
}
}
int SavedataParam::SetPspParam(SceUtilitySavedataParam *param)
{
pspParam = param;
if (!pspParam)
{
Clear();
return 0;
}
bool listEmptyFile = true;
if (param->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTLOAD ||
param->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE)
{
listEmptyFile = false;
}
char (*saveNameListData)[20];
if (param->saveNameList != 0)
{
Clear();
saveNameListData = (char(*)[20])Memory::GetPointer(param->saveNameList);
// Get number of fileName in array
saveDataListCount = 0;
do
{
saveDataListCount++;
} while(saveNameListData[saveDataListCount][0] != 0);
saveDataList = new SaveFileInfo[saveDataListCount];
// get and stock file info for each file
int realCount = 0;
for (int i = 0; i < saveDataListCount; i++)
{
DEBUG_LOG(HLE,"Name : %s",saveNameListData[i]);
std::string fileDataPath = savePath+GetGameName(param)+saveNameListData[i]+"/"+param->fileName;
PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataPath);
if (info.exists)
{
SetFileInfo(realCount, info, saveNameListData[i]);
DEBUG_LOG(HLE,"%s Exist",fileDataPath.c_str());
realCount++;
}
else
{
if (listEmptyFile)
{
saveDataList[realCount].size = 0;
saveDataList[realCount].saveName = saveNameListData[i];
saveDataList[realCount].idx = i;
saveDataList[realCount].textureData = 0;
DEBUG_LOG(HLE,"Don't Exist");
realCount++;
}
}
}
saveNameListDataCount = realCount;
}
else // Load info on only save
{
saveNameListData = 0;
Clear();
saveDataList = new SaveFileInfo[1];
saveDataListCount = 1;
// get and stock file info for each file
DEBUG_LOG(HLE,"Name : %s",GetSaveName(param).c_str());
std::string fileDataPath = savePath+GetGameName(param)+GetSaveName(param)+"/"+param->fileName;
PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataPath);
if (info.exists)
{
SetFileInfo(0, info, GetSaveName(pspParam));
DEBUG_LOG(HLE,"%s Exist",fileDataPath.c_str());
saveNameListDataCount = 1;
}
else
{
if (listEmptyFile)
{
saveDataList[0].size = 0;
saveDataList[0].saveName = GetSaveName(param);
saveDataList[0].idx = 0;
saveDataList[0].textureData = 0;
DEBUG_LOG(HLE,"Don't Exist");
}
saveNameListDataCount = 0;
return 0;
}
}
return 0;
}
void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName)
{
saveDataList[idx].size = info.size;
saveDataList[idx].saveName = saveName;
saveDataList[idx].idx = 0;
saveDataList[idx].modif_time = info.mtime;
// Start with a blank slate.
saveDataList[idx].textureData = 0;
saveDataList[idx].title[0] = 0;
saveDataList[idx].saveTitle[0] = 0;
saveDataList[idx].saveDetail[0] = 0;
// 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 + GetGameName(pspParam) + saveName + "/" + icon0Name;
PSPFileInfo info2 = pspFileSystem.GetFileInfo(fileDataPath2);
if (info2.exists)
{
u8 *textureDataPNG = new u8[(size_t)info2.size];
ReadPSPFile(fileDataPath2, textureDataPNG, info2.size, NULL);
unsigned char *textureData;
int w,h;
int success = pngLoadPtr(textureDataPNG, (int)info2.size, &w, &h, &textureData, false);
delete[] textureDataPNG;
u32 texSize = w*h*4;
u32 atlasPtr;
if (success)
atlasPtr = kernelMemory.Alloc(texSize, true, "SaveData Icon");
if (success && atlasPtr > 0)
{
saveDataList[idx].textureData = atlasPtr;
Memory::Memcpy(atlasPtr, textureData, texSize);
free(textureData);
saveDataList[idx].textureWidth = w;
saveDataList[idx].textureHeight = h;
}
else
WARN_LOG(HLE, "Unable to load PNG data for savedata.");
}
// Load info in PARAM.SFO
fileDataPath2 = savePath + GetGameName(pspParam) + saveName + "/" + sfoName;
info2 = pspFileSystem.GetFileInfo(fileDataPath2);
if (info2.exists)
{
u8 *sfoParam = new u8[(size_t)info2.size];
ReadPSPFile(fileDataPath2, sfoParam, info2.size, NULL);
ParamSFOData sfoFile;
if (sfoFile.ReadSFO(sfoParam,(size_t)info2.size))
{
SetStringFromSFO(sfoFile, "TITLE", saveDataList[idx].title, sizeof(saveDataList[idx].title));
SetStringFromSFO(sfoFile, "SAVEDATA_TITLE", saveDataList[idx].saveTitle, sizeof(saveDataList[idx].saveTitle));
SetStringFromSFO(sfoFile, "SAVEDATA_DETAIL", saveDataList[idx].saveDetail, sizeof(saveDataList[idx].saveDetail));
}
delete [] sfoParam;
}
}
SceUtilitySavedataParam* SavedataParam::GetPspParam()
{
return pspParam;
}
int SavedataParam::GetFilenameCount()
{
return saveNameListDataCount;
}
const SaveFileInfo& SavedataParam::GetFileInfo(int idx)
{
return saveDataList[idx];
}
std::string SavedataParam::GetFilename(int idx)
{
return saveDataList[idx].saveName;
}
int SavedataParam::GetSelectedSave()
{
return selectedSave;
}
void SavedataParam::SetSelectedSave(int idx)
{
selectedSave = idx;
}
void SavedataParam::DoState(PointerWrap &p)
{
// pspParam is handled in PSPSaveDialog.
p.Do(selectedSave);
p.Do(saveDataListCount);
p.Do(saveNameListDataCount);
if (p.mode == p.MODE_READ)
{
if (saveDataList != NULL)
delete [] saveDataList;
saveDataList = new SaveFileInfo[saveDataListCount];
}
p.DoArray(saveDataList, saveDataListCount);
p.DoMarker("SavedataParam");
}