void AddGameInfo(UrlEncoder &postdata) { // TODO: Maybe ParamSFOData shouldn't include nulls in std::strings? Don't work to break savedata, though... postdata.Add("game", StripTrailingNull(g_paramSFO.GetValueString("DISC_ID")) + "_" + StripTrailingNull(g_paramSFO.GetValueString("DISC_VERSION"))); postdata.Add("game_title", StripTrailingNull(g_paramSFO.GetValueString("TITLE"))); postdata.Add("sdkver", sceKernelGetCompiledSdkVersion()); }
//Subroutine sceUmd_040A7090 - Address 0x000002CC s32 sceUmd_040A7090(s32 errorState) { s32 sdkVersion; if (errorState == SCE_ERROR_OK) return SCE_ERROR_OK; sdkVersion = sceKernelGetCompiledSdkVersion(); if (sdkVersion != 0) return errorState; switch (errorState) { case SCE_ERROR_ERRNO_NAME_TOO_LONG: return SCE_ERROR_ERRNO150_ENAMETOOLONG; case SCE_ERROR_ERRNO_EADDRINUSE: return SCE_ERROR_ERRNO150_EADDRINUSE; case SCE_ERROR_ERRNO_CONNECTION_ABORTED: return SCE_ERROR_ERRNO150_ECONNABORTED; case SCE_ERROR_ERRNO_ETIMEDOUT: return SCE_ERROR_ERRNO150_ETIMEDOUT; case SCE_ERROR_ERRNO_NOT_SUPPORTED: return SCE_ERROR_ERRNO150_ENOTSUP; case SCE_ERROR_ERRNO_ENOMEDIUM: return SCE_ERROR_ERRNO150_ENOMEDIUM; case SCE_ERROR_ERRNO_WRONG_MEDIUM_TYPE: return SCE_ERROR_ERRNO150_EMEDIUMTYPE; default: return errorState; } }
u32 GPUCommon::Continue() { easy_guard guard(listLock); if (!currentList) return 0; if (currentList->state == PSP_GE_DL_STATE_PAUSED) { if (!isbreak) { if (currentList->signal == PSP_GE_SIGNAL_HANDLER_PAUSE) return 0x80000021; currentList->state = PSP_GE_DL_STATE_RUNNING; currentList->signal = PSP_GE_SIGNAL_NONE; // TODO Restore context of DL is necessary // TODO Restore BASE // We have a list now, so it's not complete. drawCompleteTicks = (u64)-1; } else currentList->state = PSP_GE_DL_STATE_QUEUED; } else if (currentList->state == PSP_GE_DL_STATE_RUNNING) { if (sceKernelGetCompiledSdkVersion() >= 0x02000000) return 0x80000020; return -1; } else { if (sceKernelGetCompiledSdkVersion() >= 0x02000000) return 0x80000004; return -1; } guard.unlock(); ProcessDLQueue(); return 0; }
static void __KernelUmdActivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE; // PSP_UMD_READY will be returned when sceKernelGetCompiledSdkVersion() != 0 if (sceKernelGetCompiledSdkVersion() != 0) { notifyArg |= PSP_UMD_READY; } if (driveCBId != 0) __KernelNotifyCallback(driveCBId, notifyArg); // Don't activate immediately, take time to "spin up." CoreTiming::RemoveAllEvents(umdStatChangeEvent); CoreTiming::ScheduleEvent(usToCycles(MICRO_DELAY_ACTIVATE), umdStatChangeEvent, 1); }
static int sceUmdUnRegisterUMDCallBack(int cbId) { int retVal; if (cbId != driveCBId) { retVal = PSP_ERROR_UMD_INVALID_PARAM; } else { if (sceKernelGetCompiledSdkVersion() > 0x3000000) { retVal = 0; } else { retVal = cbId; } driveCBId = 0; } DEBUG_LOG(SCEIO, "%08x=sceUmdUnRegisterUMDCallBack(id=%08x)", retVal, cbId); return retVal; }
int Process(int pos) { Payload &payload = payloadBuffer[pos]; std::string gpuPrimary, gpuFull; if (gpu) gpu->GetReportingInfo(gpuPrimary, gpuFull); UrlEncoder postdata; postdata.Add("version", PPSSPP_GIT_VERSION); // TODO: Maybe ParamSFOData shouldn't include nulls in std::strings? Don't work to break savedata, though... postdata.Add("game", StripTrailingNull(g_paramSFO.GetValueString("DISC_ID")) + "_" + StripTrailingNull(g_paramSFO.GetValueString("DISC_VERSION"))); postdata.Add("game_title", StripTrailingNull(g_paramSFO.GetValueString("TITLE"))); postdata.Add("gpu", gpuPrimary); postdata.Add("gpu_full", gpuFull); postdata.Add("cpu", cpu_info.Summarize()); postdata.Add("platform", GetPlatformIdentifer()); postdata.Add("sdkver", sceKernelGetCompiledSdkVersion()); postdata.Add("pixel_width", PSP_CoreParameter().pixelWidth); postdata.Add("pixel_height", PSP_CoreParameter().pixelHeight); postdata.Add("ticks", (const uint64_t)CoreTiming::GetTicks()); if (g_Config.iShowFPSCounter) { float vps, fps; __DisplayGetAveragedFPS(&vps, &fps); postdata.Add("vps", vps); postdata.Add("fps", fps); } // TODO: Settings, savestate/savedata status, some measure of speed/fps? switch (payload.type) { case MESSAGE: postdata.Add("message", payload.string1); postdata.Add("value", payload.string2); payload.string1.clear(); payload.string2.clear(); SendReportRequest("/report/message", postdata.ToString()); break; } return 0; }
//Subroutine sceUmd_598EC4DC - Address 0x000009A0 - Aliases: sceUmdUser_BD2BDE07 s32 sceUmdUnRegisterUMDCallBack(SceUID callbackId) { s32 oldK1 = pspShiftK1(); if (callbackId != g_umdCallbackId) { pspSetK1(oldK1); return SCE_ERROR_ERRNO_INVALID_ARGUMENT; } g_umdCallbackId = 0; /* Only support PSP SDK versions >= 3.00 */ if (sceKernelGetCompiledSdkVersion() >= 0x03000000) { pspSetK1(oldK1); return SCE_ERROR_OK; } pspSetK1(oldK1); return SCE_ERROR_ERRNO_INVALID_ARGUMENT; }
virtual void handleResult(PendingInterrupt& pend) { GeInterruptData intrdata = ge_pending_cb.front(); ge_pending_cb.pop_front(); DisplayList* dl = gpu->getList(intrdata.listid); if (!dl->interruptsEnabled) { ERROR_LOG_REPORT(SCEGE, "Unable to finish GE interrupt: list has interrupts disabled, should not happen"); return; } switch (dl->signal) { case PSP_GE_SIGNAL_HANDLER_SUSPEND: if (sceKernelGetCompiledSdkVersion() <= 0x02000010) { // uofw says dl->state = endCmd & 0xFF; DisplayListState newState = static_cast<DisplayListState>(Memory::ReadUnchecked_U32(intrdata.pc - 4) & 0xFF); //dl->status = static_cast<DisplayListStatus>(Memory::ReadUnchecked_U32(intrdata.pc) & 0xFF); //if(dl->status < 0 || dl->status > PSP_GE_LIST_PAUSED) // ERROR_LOG(SCEGE, "Weird DL status after signal suspend %x", dl->status); if (newState != PSP_GE_DL_STATE_RUNNING) DEBUG_LOG_REPORT(SCEGE, "GE Interrupt: newState might be %d", newState); if (dl->state != PSP_GE_DL_STATE_NONE && dl->state != PSP_GE_DL_STATE_COMPLETED) { dl->state = PSP_GE_DL_STATE_QUEUED; } } break; default: break; } gpu->InterruptEnd(intrdata.listid); }
bool run(PendingInterrupt& pend) { GeInterruptData intrdata = ge_pending_cb.front(); DisplayList* dl = gpu->getList(intrdata.listid); if (dl == NULL) { WARN_LOG(SCEGE, "Unable to run GE interrupt: list doesn't exist: %d", intrdata.listid); return false; } if (!dl->interruptsEnabled) { ERROR_LOG_REPORT(SCEGE, "Unable to run GE interrupt: list has interrupts disabled, should not happen"); return false; } gpu->InterruptStart(intrdata.listid); const u32 cmd = intrdata.cmd; int subintr = -1; if (dl->subIntrBase >= 0) { switch (dl->signal) { case PSP_GE_SIGNAL_SYNC: case PSP_GE_SIGNAL_JUMP: case PSP_GE_SIGNAL_CALL: case PSP_GE_SIGNAL_RET: // Do nothing. break; case PSP_GE_SIGNAL_HANDLER_PAUSE: if (cmd == GE_CMD_FINISH) subintr = dl->subIntrBase | PSP_GE_SUBINTR_SIGNAL; break; default: if (cmd == GE_CMD_SIGNAL) subintr = dl->subIntrBase | PSP_GE_SUBINTR_SIGNAL; else subintr = dl->subIntrBase | PSP_GE_SUBINTR_FINISH; break; } } // Set the list as complete once the interrupt starts. // In other words, not before another interrupt finishes. if (dl->signal != PSP_GE_SIGNAL_HANDLER_PAUSE && cmd == GE_CMD_FINISH) { dl->state = PSP_GE_DL_STATE_COMPLETED; } SubIntrHandler* handler = get(subintr); if (handler != NULL) { DEBUG_LOG(CPU, "Entering GE interrupt handler %08x", handler->handlerAddress); currentMIPS->pc = handler->handlerAddress; u32 data = dl->subIntrToken; currentMIPS->r[MIPS_REG_A0] = data & 0xFFFF; currentMIPS->r[MIPS_REG_A1] = handler->handlerArg; currentMIPS->r[MIPS_REG_A2] = sceKernelGetCompiledSdkVersion() <= 0x02000010 ? 0 : intrdata.pc + 4; // RA is already taken care of in __RunOnePendingInterrupt return true; } if (dl->signal == PSP_GE_SIGNAL_HANDLER_SUSPEND) { if (sceKernelGetCompiledSdkVersion() <= 0x02000010) { if (dl->state != PSP_GE_DL_STATE_NONE && dl->state != PSP_GE_DL_STATE_COMPLETED) { dl->state = PSP_GE_DL_STATE_QUEUED; } } } ge_pending_cb.pop_front(); gpu->InterruptEnd(intrdata.listid); // Seen in GoW. if (subintr >= 0) DEBUG_LOG(SCEGE, "Ignoring interrupt for display list %d, already been released.", intrdata.listid); return false; }
u32 GPUCommon::Break(int mode) { easy_guard guard(listLock); if (mode < 0 || mode > 1) return SCE_KERNEL_ERROR_INVALID_MODE; if (!currentList) return 0x80000020; if (mode == 1) { // Clear the queue dlQueue.clear(); for (int i = 0; i < DisplayListMaxCount; ++i) { dls[i].state = PSP_GE_DL_STATE_NONE; dls[i].signal = PSP_GE_SIGNAL_NONE; } currentList = NULL; return 0; } if (currentList->state == PSP_GE_DL_STATE_NONE || currentList->state == PSP_GE_DL_STATE_COMPLETED) { if (sceKernelGetCompiledSdkVersion() >= 0x02000000) return 0x80000004; return -1; } if (currentList->state == PSP_GE_DL_STATE_PAUSED) { if (sceKernelGetCompiledSdkVersion() > 0x02000010) { if (currentList->signal == PSP_GE_SIGNAL_HANDLER_PAUSE) { ERROR_LOG_REPORT(G3D, "sceGeBreak: can't break signal-pausing list"); } else return 0x80000020; } return 0x80000021; } if (currentList->state == PSP_GE_DL_STATE_QUEUED) { currentList->state = PSP_GE_DL_STATE_PAUSED; return currentList->id; } // TODO Save BASE // TODO Adjust pc to be just before SIGNAL/END // TODO: Is this right? if (currentList->signal == PSP_GE_SIGNAL_SYNC) currentList->pc += 8; currentList->interrupted = true; currentList->state = PSP_GE_DL_STATE_PAUSED; currentList->signal = PSP_GE_SIGNAL_HANDLER_SUSPEND; isbreak = true; return currentList->id; }
u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) { easy_guard guard(listLock); // TODO Check the stack values in missing arg and ajust the stack depth // Check alignment // TODO Check the context and stack alignement too if (((listpc | stall) & 3) != 0) return 0x80000103; int id = -1; bool oldCompatibility = true; if (sceKernelGetCompiledSdkVersion() > 0x01FFFFFF) { //numStacks = 0; //stack = NULL; oldCompatibility = false; } u64 currentTicks = CoreTiming::GetTicks(); for (int i = 0; i < DisplayListMaxCount; ++i) { if (dls[i].state != PSP_GE_DL_STATE_NONE && dls[i].state != PSP_GE_DL_STATE_COMPLETED) { if (dls[i].pc == listpc && !oldCompatibility) { ERROR_LOG(G3D, "sceGeListEnqueue: can't enqueue, list address %08X already used", listpc); return 0x80000021; } //if(dls[i].stack == stack) { // ERROR_LOG(G3D, "sceGeListEnqueue: can't enqueue, list stack %08X already used", context); // return 0x80000021; //} } if (dls[i].state == PSP_GE_DL_STATE_NONE && !dls[i].pendingInterrupt) { // Prefer a list that isn't used id = i; break; } if (id < 0 && dls[i].state == PSP_GE_DL_STATE_COMPLETED && !dls[i].pendingInterrupt && dls[i].waitTicks < currentTicks) { id = i; } } if (id < 0) { ERROR_LOG_REPORT(G3D, "No DL ID available to enqueue"); for(auto it = dlQueue.begin(); it != dlQueue.end(); ++it) { DisplayList &dl = dls[*it]; DEBUG_LOG(G3D, "DisplayList %d status %d pc %08x stall %08x", *it, dl.state, dl.pc, dl.stall); } return SCE_KERNEL_ERROR_OUT_OF_MEMORY; } DisplayList &dl = dls[id]; dl.id = id; dl.startpc = listpc & 0x0FFFFFFF; dl.pc = listpc & 0x0FFFFFFF; dl.stall = stall & 0x0FFFFFFF; dl.subIntrBase = std::max(subIntrBase, -1); dl.stackptr = 0; dl.signal = PSP_GE_SIGNAL_NONE; dl.interrupted = false; dl.waitTicks = (u64)-1; dl.interruptsEnabled = interruptsEnabled_; if (head) { if (currentList) { if (currentList->state != PSP_GE_DL_STATE_PAUSED) return SCE_KERNEL_ERROR_INVALID_VALUE; currentList->state = PSP_GE_DL_STATE_QUEUED; } dl.state = PSP_GE_DL_STATE_PAUSED; currentList = &dl; dlQueue.push_front(id); } else if (currentList) { dl.state = PSP_GE_DL_STATE_QUEUED; dlQueue.push_back(id); } else { dl.state = PSP_GE_DL_STATE_RUNNING; currentList = &dl; dlQueue.push_front(id); drawCompleteTicks = (u64)-1; // TODO save context when starting the list if param is set guard.unlock(); ProcessDLQueue(); } return id; }
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); SceSize 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); // copy back save name in request strncpy(param->saveName,GetSaveDirName(param, saveId).c_str(),20); 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, (SceSize)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; SceSize 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()); 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; }
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); u8* cryptedData = 0; int cryptedSize = 0; u8 cryptedHash[0x10]; memset(cryptedHash,0,0x10); // Encrypt save. if(param->dataBuf != 0 && g_Config.bEncryptSave) { cryptedSize = param->dataSize; if(cryptedSize == 0 || (SceSize)cryptedSize > param->dataBufSize) cryptedSize = param->dataBufSize; // fallback, should never use this u8* data_ = (u8*)Memory::GetPointer(param->dataBuf); int aligned_len = align16(cryptedSize); cryptedData = new u8[aligned_len + 0x10]; memcpy(cryptedData, data_, cryptedSize); int decryptMode = 1; if(param->key[0] != 0) { decryptMode = (GetSDKMainVersion(sceKernelGetCompiledSdkVersion()) >= 4 ? 5 : 3); } if(EncryptData(decryptMode, cryptedData, &cryptedSize, &aligned_len, cryptedHash, ((param->key[0] != 0)?param->key:0)) == 0) { } else { ERROR_LOG(HLE,"Save encryption failed. This save won't work on real PSP"); delete[] cryptedData; cryptedData = 0; } } // 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; fName += FILE_LIST_ITEM_SIZE; } if (fName + 13 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE) snprintf(fName, 13, "%s",GetFileName(param).c_str()); if (fName + 13 + 16 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE) memcpy(fName+13, cryptedHash, 16); } sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, FILE_LIST_TOTAL_SIZE, FILE_LIST_TOTAL_SIZE); delete[] tmpData; // Init param with 0. This will be used to detect crypted save or not on loading 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); // Calc SFO hash for PSP. if(cryptedData != 0) { int offset = sfoFile.GetDataOffset(sfoData,"SAVEDATA_PARAMS"); if(offset >= 0) UpdateHash(sfoData, sfoSize, offset, (param->key[0]?3:1)); } WritePSPFile(sfopath, sfoData, (SceSize)sfoSize); delete[] sfoData; if(param->dataBuf != 0) // Can launch save without save data in mode 13 { std::string filePath = dirPath+"/"+GetFileName(param); u8* data_ = 0; SceSize saveSize = 0; if(cryptedData == 0) // Save decrypted data { saveSize = param->dataSize; if(saveSize == 0 || saveSize > param->dataBufSize) saveSize = param->dataBufSize; // fallback, should never use this data_ = (u8*)Memory::GetPointer(param->dataBuf); } else { data_ = cryptedData; saveSize = cryptedSize; } INFO_LOG(HLE,"Saving file with size %u in %s",saveSize,filePath.c_str()); // copy back save name in request strncpy(param->saveName,GetSaveDirName(param, saveId).c_str(),20); if (!WritePSPFile(filePath, data_, saveSize)) { ERROR_LOG(HLE,"Error writing file %s",filePath.c_str()); if(cryptedData != 0) { delete[] cryptedData; } return false; } delete[] cryptedData; } // 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; SceSize 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; }
void AddGameInfo(UrlEncoder &postdata) { postdata.Add("game", CurrentGameID()); postdata.Add("game_title", StripTrailingNull(g_paramSFO.GetValueString("TITLE"))); postdata.Add("sdkver", sceKernelGetCompiledSdkVersion()); }