Example #1
0
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)
		{
			bool isCrypted = IsSaveEncrypted(param,0);
			Memory::Write_U32(0x21FF, curFileInfoAddr+0);
			if(isCrypted)	// Crypted save are 16 bytes bigger
				Memory::Write_U64(info.size - 0x10, curFileInfoAddr+8);
			else
				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;
}
Example #2
0
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());
	u8* saveData = 0;
	int saveSize = -1;
	if (!ReadPSPFile(filePath, &saveData, saveSize, &readSize))
	{
		ERROR_LOG(HLE,"Error reading file %s",filePath.c_str());
		return false;
	}
	saveSize = (int)readSize;

	// copy back save name in request
	strncpy(param->saveName,GetSaveDirName(param, saveId).c_str(),20);

	ParamSFOData sfoFile;
	std::string sfopath = dirPath+"/"+sfoName;
	PSPFileInfo sfoInfo = pspFileSystem.GetFileInfo(sfopath);
	if(sfoInfo.exists) // Read sfo
	{
		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);

			// 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");
		}
		delete[] sfoData;
	}
	// Don't know what it is, but PSP always respond this and this unlock some game
	param->bind = 1021;

	bool isCrypted = IsSaveEncrypted(param,saveId);
	bool saveDone = false;
	if(isCrypted)// Try to decrypt
	{
		int align_len = align16(saveSize);
		u8* data_base = new u8[align_len];
		u8* cryptKey = new u8[0x10];
		memset(cryptKey,0,0x10);

		if(param->key[0] != 0)
		{
			memcpy(cryptKey, param->key, 0x10);
		}
		memset(data_base + saveSize, 0, align_len - saveSize);
		memcpy(data_base, saveData, saveSize);

		int decryptMode = 1;
		if(param->key[0] != 0)
		{
			decryptMode = (GetSDKMainVersion(sceKernelGetCompiledSdkVersion()) >= 4 ? 5 : 3);
		}

		if(DecryptSave(decryptMode, data_base, &saveSize, &align_len, ((param->key[0] != 0)?cryptKey:0)) == 0)
		{
			memcpy(data_, data_base, saveSize);
			saveDone = true;
		}
		delete[] data_base;
		delete[] cryptKey;
	}
	if(!saveDone) // not crypted or decrypt fail
	{
		memcpy(data_, saveData, saveSize);
	}
	param->dataSize = (SceSize)saveSize;
	delete[] saveData;

	return true;
}
Example #3
0
int SavedataParam::GetFilesList(SceUtilitySavedataParam *param)
{
	if (!param)	{
		return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_STATUS;
	}

	if (!param->fileList.Valid()) {
		ERROR_LOG_REPORT(HLE, "SavedataParam::GetFilesList(): bad fileList address %08x", param->fileList.ptr);
		// Should crash.
		return -1;
	}

	auto &fileList = param->fileList;
	if (fileList->secureEntries.Valid() && fileList->maxSecureEntries > 99) {
		ERROR_LOG_REPORT(HLE, "SavedataParam::GetFilesList(): too many secure entries, %d", fileList->maxSecureEntries);
		return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS;
	}
	if (fileList->normalEntries.Valid() && fileList->maxNormalEntries > 8192) {
		ERROR_LOG_REPORT(HLE, "SavedataParam::GetFilesList(): too many normal entries, %d", fileList->maxNormalEntries);
		return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS;
	}
	if (fileList->systemEntries.Valid() && fileList->maxSystemEntries > 5) {
		ERROR_LOG_REPORT(HLE, "SavedataParam::GetFilesList(): too many system entries, %d", fileList->maxSystemEntries);
		return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS;
	}

	std::string dirPath = savePath + GetGameName(param) + GetSaveName(param);
	if (!pspFileSystem.GetFileInfo(dirPath).exists) {
		DEBUG_LOG(HLE, "SavedataParam::GetFilesList(): directory %s does not exist", dirPath.c_str());
		return SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA;
	}

	// Even if there are no files, initialize to 0.
	fileList->resultNumSecureEntries = 0;
	fileList->resultNumNormalEntries = 0;
	fileList->resultNumSystemEntries = 0;

	// We need PARAMS.SFO's SAVEDATA_FILE_LIST to determine which entries are secure.
	PSPFileInfo sfoFileInfo = pspFileSystem.GetFileInfo(dirPath + "/" + SFO_FILENAME);
	std::set<std::string> secureFilenames;
	// TODO: Error code if not?
	if (sfoFileInfo.exists) {
		ParamSFOData sfoFile;
		size_t sfoSize = (size_t)sfoFileInfo.size;
		u8 *sfoData = new u8[sfoSize];
		if (ReadPSPFile(dirPath + "/" + SFO_FILENAME, &sfoData, sfoSize, NULL)){
			sfoFile.ReadSFO(sfoData, sfoSize);
		}
		delete[] sfoData;

		u32 sfoFileListSize = 0;
		char *sfoFileList = (char *)sfoFile.GetValueData("SAVEDATA_FILE_LIST", &sfoFileListSize);
		const int FILE_LIST_ITEM_SIZE = 13 + 16 + 3;
		const int FILE_LIST_COUNT_MAX = 99;

		// Filenames are 13 bytes long at most.  Add a NULL so there's no surprises.
		char temp[14];
		temp[13] = '\0';

		for (u32 i = 0; i < FILE_LIST_COUNT_MAX; ++i) {
			// Ends at a NULL filename.
			if (i * FILE_LIST_ITEM_SIZE >= sfoFileListSize || sfoFileList[i * FILE_LIST_ITEM_SIZE] == '\0') {
				break;
			}

			strncpy(temp, &sfoFileList[i * FILE_LIST_ITEM_SIZE], 13);
			secureFilenames.insert(temp);
		}
	}

	// Does not list directories, nor recurse into them, and ignores files not ALL UPPERCASE.
	auto files = pspFileSystem.GetDirListing(dirPath);
	for (auto file = files.begin(), end = files.end(); file != end; ++file) {
		if (file->type == FILETYPE_DIRECTORY) {
			continue;
		}
		// TODO: What are the exact rules?  It definitely skips lowercase, and allows FILE or FILE.EXT.
		if (file->name.find_first_of("abcdefghijklmnopqrstuvwxyz") != file->name.npos) {
			DEBUG_LOG(HLE, "SavedataParam::GetFilesList(): skipping file %s with lowercase", file->name.c_str());
			continue;
		}

		bool isSystemFile = file->name == ICON0_FILENAME || file->name == ICON1_FILENAME || file->name == PIC1_FILENAME;
		isSystemFile = isSystemFile || file->name == SND0_FILENAME || file->name == SFO_FILENAME;

		SceUtilitySavedataFileListEntry *entry = NULL;
		int sizeOffset = 0;
		if (isSystemFile) {
			if (fileList->systemEntries.Valid() && fileList->resultNumSystemEntries < fileList->maxSystemEntries) {
				entry = &fileList->systemEntries[fileList->resultNumSystemEntries++];
			}
		} else if (secureFilenames.find(file->name) != secureFilenames.end()) {
			if (fileList->secureEntries.Valid() && fileList->resultNumSecureEntries < fileList->maxSecureEntries) {
				entry = &fileList->secureEntries[fileList->resultNumSecureEntries++];
			}
			// Secure files are slightly bigger.
			bool isCrypted = IsSaveEncrypted(param, GetSaveDirName(param, 0));
			if (isCrypted) {
				sizeOffset = -0x10;
			}
		} else {
			if (fileList->normalEntries.Valid() && fileList->resultNumNormalEntries < fileList->maxNormalEntries) {
				entry = &fileList->normalEntries[fileList->resultNumNormalEntries++];
			}
		}

		// Out of space for this file in the list.
		if (entry == NULL) {
			continue;
		}

		entry->st_mode = 0x21FF;
		entry->st_size = file->size + sizeOffset;
		// TODO: ctime, atime, mtime
		// TODO: Probably actually 13 + 3 pad...
		strncpy(entry->name, file->name.c_str(), 16);
		entry->name[15] = '\0';
	}

	return 0;
}